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

View File

@@ -0,0 +1,91 @@
-----------------------------------------------------
3.1
-----------------------------------------------------
-----------------------------------------------------
Primary
-----------------------------------------------------
Truenaming:
Truenamer
62/63 Utterances
4 Prestige Classes
Truenamer Class: See the Named to go.
Truename PrCs:
Acolyte of the Ego - Unstarted
Fiendbinder - Unstarted
Utterances: Incarnation of Angels skipped, needs Primo to work on templates.
-----------------------------------------------------
Secondary
-----------------------------------------------------
Base Classes:
Dread Necromancer - All to do, Spells
Beguiler - All to do, Spells
Psionic PrCs:
Metamind - All to do
Psion Uncarnate - All to do
Pyrokineticist - All to do
Cryokineticist - All to do
Normal PrCs:
Stormsinger - All to do
Blood Magus - Check what is done and what needs doing.
Pale master -> 3.1:
Fighter vassal -> Use TNecro
Incorp vassal
Cleric vassal
Summon Undead
Summon Greater Undead
Poke attacks
Death Touch -> create undead on failed save
Domains (PGtF):
Balance
Cold
Mentalism
Repose
Suffering
Trade
-----------------------------------------------------
Feats to do in spare time
-----------------------------------------------------
Complete Divine:
Cheetah's Speed
Elephant's Hide
Extra Wildshape
Grizzly Claws
Oaken Resilience
Quicken Turning
Sacred Healing
True Believer
Wolverine's Rage
Complete Warrior:
Axiomatic Strike
Dash
Extend Rage
Extra Rage
Extra Smiting
Freezing the Lifeblood
Improved Rapid Shot
Intimidating Rage
Karmic Strike
Weakening Touch
Divine Cleansing
Divine Resistance
Divine Vigor
Sacred Vengeance
Champions of Ruin:
Doomspeak

Binary file not shown.

View File

@@ -0,0 +1,402 @@
// Use this function to get the adjustments to a spell or SLAs saving throw
// from the various class effects
// Update this function if any new classes change saving throws
int PRCGetSaveDC(object oTarget, object oCaster, int nSpellID = -1);
//called just from above and from inc_epicspells
int GetChangesToSaveDC(object oTarget, object oCaster = OBJECT_SELF, int nSpellID = -1);
#include "prc_inc_spells"
#include "prc_class_const"
#include "prc_feat_const"
#include "lookup_2da_spell"
#include "prcsp_archmaginc"
#include "prc_alterations"
#include "prc_add_spl_pen"
// Check for CLASS_TYPE_HIEROPHANT > 0 in caller
int GetWasLastSpellHieroSLA(int spell_id, object oCaster = OBJECT_SELF)
{
int iAbility = PRCGetLastSpellCastClass() == CLASS_TYPE_INVALID;
int iSpell = spell_id == SPELL_HOLY_AURA ||
spell_id == SPELL_UNHOLY_AURA ||
spell_id == SPELL_BANISHMENT ||
spell_id == SPELL_BATTLETIDE ||
spell_id == SPELL_BLADE_BARRIER ||
spell_id == SPELL_CIRCLE_OF_DOOM ||
spell_id == SPELL_CONTROL_UNDEAD ||
spell_id == SPELL_CREATE_GREATER_UNDEAD ||
spell_id == SPELL_CREATE_UNDEAD ||
spell_id == SPELL_CURE_CRITICAL_WOUNDS ||
spell_id == SPELL_DEATH_WARD ||
spell_id == SPELL_DESTRUCTION ||
spell_id == SPELL_DISMISSAL ||
spell_id == SPELL_DIVINE_POWER ||
spell_id == SPELL_EARTHQUAKE ||
spell_id == SPELL_ENERGY_DRAIN ||
spell_id == SPELL_ETHEREALNESS ||
spell_id == SPELL_FIRE_STORM ||
spell_id == SPELL_FLAME_STRIKE ||
spell_id == SPELL_FREEDOM_OF_MOVEMENT ||
spell_id == SPELL_GATE ||
spell_id == SPELL_GREATER_DISPELLING ||
spell_id == SPELL_GREATER_MAGIC_WEAPON ||
spell_id == SPELL_GREATER_RESTORATION ||
spell_id == SPELL_HAMMER_OF_THE_GODS ||
spell_id == SPELL_HARM ||
spell_id == SPELL_HEAL ||
spell_id == SPELL_HEALING_CIRCLE ||
spell_id == SPELL_IMPLOSION ||
spell_id == SPELL_INFLICT_CRITICAL_WOUNDS ||
spell_id == SPELL_MASS_HEAL ||
spell_id == SPELL_MONSTROUS_REGENERATION ||
spell_id == SPELL_NEUTRALIZE_POISON ||
spell_id == SPELL_PLANAR_ALLY ||
spell_id == SPELL_POISON ||
spell_id == SPELL_RAISE_DEAD ||
spell_id == SPELL_REGENERATE ||
spell_id == SPELL_RESTORATION ||
spell_id == SPELL_RESURRECTION ||
spell_id == SPELL_SLAY_LIVING ||
spell_id == SPELL_SPELL_RESISTANCE ||
spell_id == SPELL_STORM_OF_VENGEANCE ||
spell_id == SPELL_SUMMON_CREATURE_IV ||
spell_id == SPELL_SUMMON_CREATURE_IX ||
spell_id == SPELL_SUMMON_CREATURE_V ||
spell_id == SPELL_SUMMON_CREATURE_VI ||
spell_id == SPELL_SUMMON_CREATURE_VII ||
spell_id == SPELL_SUMMON_CREATURE_VIII ||
spell_id == SPELL_SUNBEAM ||
spell_id == SPELL_TRUE_SEEING ||
spell_id == SPELL_UNDEATH_TO_DEATH ||
spell_id == SPELL_UNDEATHS_ETERNAL_FOE ||
spell_id == SPELL_WORD_OF_FAITH;
return iAbility && iSpell;
}
int GetHierophantSLAAdjustment(int spell_id, object oCaster = OBJECT_SELF)
{
int retval = 0;
if (GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster) > 0 && GetWasLastSpellHieroSLA(spell_id, oCaster) )
{
retval = StringToInt( lookup_spell_cleric_level(spell_id) );
retval -= GetLevelByClass(CLASS_TYPE_HIEROPHANT, oCaster);
}
return retval;
}
int GetHeartWarderDC(int spell_id, object oCaster = OBJECT_SELF)
{
// Check the curent school
if (GetLocalInt(oCaster, "X2_L_LAST_SPELLSCHOOL_VAR") != SPELL_SCHOOL_ENCHANTMENT)
return 0;
if (!GetHasFeat(FEAT_VOICE_SIREN, oCaster)) return 0;
// Bonus Requires Verbal Spells
string VS = lookup_spell_vs(PRCGetSpellId());
if (VS != "v" && VS != "vs")
return 0;
// These feats provide greater bonuses or remove the Verbal requirement
if (PRCGetMetaMagicFeat() & METAMAGIC_SILENT
|| GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ENCHANTMENT, oCaster)
|| GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ENCHANTMENT, oCaster))
return 0;
return 2;
}
//Elemental Savant DC boost based on elemental spell type.
int ElementalSavantDC(int spell_id, object oCaster = OBJECT_SELF)
{
int nDC = 0;
int nES;
// All Elemental Savants will have this feat
// when they first gain a DC bonus.
if (GetHasFeat(FEAT_ES_FOCUS_1, oCaster)) {
// get spell elemental type
string element = ChangedElementalType(spell_id, oCaster);
// Any value that does not match one of the enumerated feats
int feat = 0;
// Specify the elemental type rather than lookup by class?
if (element == "Fire")
{
feat = FEAT_ES_FIRE;
nES = GetLevelByClass(CLASS_TYPE_ES_FIRE,oCaster);
}
else if (element == "Cold")
{
feat = FEAT_ES_COLD;
nES = GetLevelByClass(CLASS_TYPE_ES_COLD,oCaster);
}
else if (element == "Electricity")
{
feat = FEAT_ES_ELEC;
nES = GetLevelByClass(CLASS_TYPE_ES_ELEC,oCaster);
}
else if (element == "Acid")
{
feat = FEAT_ES_ACID;
nES = GetLevelByClass(CLASS_TYPE_ES_ACID,oCaster);
}
// Now determine the bonus
if (feat && GetHasFeat(feat, oCaster))
{
if (nES > 28) nDC = 10;
else if (nES > 25) nDC = 9;
else if (nES > 22) nDC = 8;
else if (nES > 19) nDC = 7;
else if (nES > 16) nDC = 6;
else if (nES > 13) nDC = 5;
else if (nES > 10) nDC = 4;
else if (nES > 7) nDC = 3;
else if (nES > 4) nDC = 2;
else if (nES > 1) nDC = 1;
}
}
// SendMessageToPC(GetFirstPC(), "Your Elemental Focus modifier is " + IntToString(nDC));
return nDC;
}
//Red Wizard DC boost based on spell school specialization
int RedWizardDC(int spell_id, object oCaster = OBJECT_SELF)
{
int iRedWizard = GetLevelByClass(CLASS_TYPE_RED_WIZARD, oCaster);
int nDC;
if (iRedWizard > 0)
{
int nSpell = PRCGetSpellId();
string sSpellSchool = lookup_spell_school(nSpell);
int iSpellSchool;
int iRWSpec;
if (sSpellSchool == "A") iSpellSchool = SPELL_SCHOOL_ABJURATION;
else if (sSpellSchool == "C") iSpellSchool = SPELL_SCHOOL_CONJURATION;
else if (sSpellSchool == "D") iSpellSchool = SPELL_SCHOOL_DIVINATION;
else if (sSpellSchool == "E") iSpellSchool = SPELL_SCHOOL_ENCHANTMENT;
else if (sSpellSchool == "V") iSpellSchool = SPELL_SCHOOL_EVOCATION;
else if (sSpellSchool == "I") iSpellSchool = SPELL_SCHOOL_ILLUSION;
else if (sSpellSchool == "N") iSpellSchool = SPELL_SCHOOL_NECROMANCY;
else if (sSpellSchool == "T") iSpellSchool = SPELL_SCHOOL_TRANSMUTATION;
if (GetHasFeat(FEAT_RW_TF_ABJ, oCaster)) iRWSpec = SPELL_SCHOOL_ABJURATION;
else if (GetHasFeat(FEAT_RW_TF_CON, oCaster)) iRWSpec = SPELL_SCHOOL_CONJURATION;
else if (GetHasFeat(FEAT_RW_TF_DIV, oCaster)) iRWSpec = SPELL_SCHOOL_DIVINATION;
else if (GetHasFeat(FEAT_RW_TF_ENC, oCaster)) iRWSpec = SPELL_SCHOOL_ENCHANTMENT;
else if (GetHasFeat(FEAT_RW_TF_EVO, oCaster)) iRWSpec = SPELL_SCHOOL_EVOCATION;
else if (GetHasFeat(FEAT_RW_TF_ILL, oCaster)) iRWSpec = SPELL_SCHOOL_ILLUSION;
else if (GetHasFeat(FEAT_RW_TF_NEC, oCaster)) iRWSpec = SPELL_SCHOOL_NECROMANCY;
else if (GetHasFeat(FEAT_RW_TF_TRS, oCaster)) iRWSpec = SPELL_SCHOOL_TRANSMUTATION;
if (iSpellSchool == iRWSpec)
{
nDC = 1;
if (iRedWizard > 29) nDC = 16;
else if (iRedWizard > 27) nDC = 15;
else if (iRedWizard > 25) nDC = 14;
else if (iRedWizard > 23) nDC = 13;
else if (iRedWizard > 21) nDC = 12;
else if (iRedWizard > 19) nDC = 11;
else if (iRedWizard > 17) nDC = 10;
else if (iRedWizard > 15) nDC = 9;
else if (iRedWizard > 13) nDC = 8;
else if (iRedWizard > 11) nDC = 7;
else if (iRedWizard > 9) nDC = 6;
else if (iRedWizard > 7) nDC = 5;
else if (iRedWizard > 5) nDC = 4;
else if (iRedWizard > 3) nDC = 3;
else if (iRedWizard > 1) nDC = 2;
}
}
// SendMessageToPC(GetFirstPC(), "Your Spell Power modifier is " + IntToString(nDC));
return nDC;
}
//Tattoo Focus DC boost based on spell school specialization
int TattooFocus(int spell_id, object oCaster = OBJECT_SELF)
{
int nDC;
int nSpell = PRCGetSpellId();
string sSpellSchool = lookup_spell_school(nSpell);
int iSpellSchool;
int iRWSpec;
if (sSpellSchool == "A") iSpellSchool = SPELL_SCHOOL_ABJURATION;
else if (sSpellSchool == "C") iSpellSchool = SPELL_SCHOOL_CONJURATION;
else if (sSpellSchool == "D") iSpellSchool = SPELL_SCHOOL_DIVINATION;
else if (sSpellSchool == "E") iSpellSchool = SPELL_SCHOOL_ENCHANTMENT;
else if (sSpellSchool == "V") iSpellSchool = SPELL_SCHOOL_EVOCATION;
else if (sSpellSchool == "I") iSpellSchool = SPELL_SCHOOL_ILLUSION;
else if (sSpellSchool == "N") iSpellSchool = SPELL_SCHOOL_NECROMANCY;
else if (sSpellSchool == "T") iSpellSchool = SPELL_SCHOOL_TRANSMUTATION;
if (GetHasFeat(FEAT_RW_TF_ABJ, oCaster)) iRWSpec = SPELL_SCHOOL_ABJURATION;
else if (GetHasFeat(FEAT_RW_TF_CON, oCaster)) iRWSpec = SPELL_SCHOOL_CONJURATION;
else if (GetHasFeat(FEAT_RW_TF_DIV, oCaster)) iRWSpec = SPELL_SCHOOL_DIVINATION;
else if (GetHasFeat(FEAT_RW_TF_ENC, oCaster)) iRWSpec = SPELL_SCHOOL_ENCHANTMENT;
else if (GetHasFeat(FEAT_RW_TF_EVO, oCaster)) iRWSpec = SPELL_SCHOOL_EVOCATION;
else if (GetHasFeat(FEAT_RW_TF_ILL, oCaster)) iRWSpec = SPELL_SCHOOL_ILLUSION;
else if (GetHasFeat(FEAT_RW_TF_NEC, oCaster)) iRWSpec = SPELL_SCHOOL_NECROMANCY;
else if (GetHasFeat(FEAT_RW_TF_TRS, oCaster)) iRWSpec = SPELL_SCHOOL_TRANSMUTATION;
if (iSpellSchool == iRWSpec)
{
nDC = 1;
}
return nDC;
}
// Shadow Weave Feat
// DC +1 (school Ench,Illu,Necro)
int ShadowWeaveDC(int spell_id, object oCaster = OBJECT_SELF)
{
int iShadow = GetLevelByClass(CLASS_TYPE_SHADOW_ADEPT, oCaster);
int nDC;
if (iShadow > 0)
{
int nSpell = PRCGetSpellId();
string sSpellSchool = lookup_spell_school(nSpell);
int iSpellSchool;
if (sSpellSchool == "A") iSpellSchool = SPELL_SCHOOL_ABJURATION;
else if (sSpellSchool == "C") iSpellSchool = SPELL_SCHOOL_CONJURATION;
else if (sSpellSchool == "D") iSpellSchool = SPELL_SCHOOL_DIVINATION;
else if (sSpellSchool == "E") iSpellSchool = SPELL_SCHOOL_ENCHANTMENT;
else if (sSpellSchool == "V") iSpellSchool = SPELL_SCHOOL_EVOCATION;
else if (sSpellSchool == "I") iSpellSchool = SPELL_SCHOOL_ILLUSION;
else if (sSpellSchool == "N") iSpellSchool = SPELL_SCHOOL_NECROMANCY;
else if (sSpellSchool == "T") iSpellSchool = SPELL_SCHOOL_TRANSMUTATION;
if (iSpellSchool == SPELL_SCHOOL_ENCHANTMENT || iSpellSchool == SPELL_SCHOOL_NECROMANCY || iSpellSchool == SPELL_SCHOOL_ILLUSION)
{
if (iShadow > 29) nDC = 10;
else if (iShadow > 26) nDC = 9;
else if (iShadow > 23) nDC = 8;
else if (iShadow > 20) nDC = 7;
else if (iShadow > 17) nDC = 6;
else if (iShadow > 14) nDC = 5;
else if (iShadow > 11) nDC = 4;
else if (iShadow > 8) nDC = 3;
else if (iShadow > 5) nDC = 2;
else if (iShadow > 2) nDC = 1;
}
}
//SendMessageToPC(GetFirstPC(), "Your Spell DC modifier is " + IntToString(nDC));
return nDC;
}
int KOTCSpellFocusVsDemons(object oTarget, object oCaster)
{
int nDC = 0;
int iKOTC = GetLevelByClass(CLASS_TYPE_KNIGHT_CHALICE, oCaster);
if (iKOTC >= 1)
{
if (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_OUTSIDER)
{
if (GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL)
{
nDC = 2;
}
}
}
return nDC;
}
int BloodMagusBloodComponent(object oCaster)
{
int nDC = 0;
if (GetLevelByClass(CLASS_TYPE_BLOOD_MAGUS, oCaster) > 0 && GetLocalInt(oCaster, "BloodComponent") == TRUE)
{
nDC = 1;
effect eSelfDamage = EffectDamage(1, DAMAGE_TYPE_MAGICAL);
// To make sure it doesn't cause a conc check
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eSelfDamage, oCaster));
}
return nDC;
}
int RunecasterRunePowerDC(object oCaster)
{
int nDC = 0;
int nClass = GetLevelByClass(CLASS_TYPE_RUNECASTER, oCaster);
if (nClass >= 2)
{
if (nClass >= 30) nDC = 10;
else if (nClass >= 27) nDC = 9;
else if (nClass >= 24) nDC = 8;
else if (nClass >= 21) nDC = 7;
else if (nClass >= 18) nDC = 6;
else if (nClass >= 15) nDC = 5;
else if (nClass >= 12) nDC = 4;
else if (nClass >= 9) nDC = 3;
else if (nClass >= 5) nDC = 2;
else if (nClass >= 2) nDC = 1;
}
return nDC;
}
int PRCGetSaveDC(object oTarget, object oCaster, int nSpellID = -1)
{
if(nSpellID == -1)
nSpellID = PRCGetSpellId();
//10+spelllevel+stat(cha default)
int nDC = GetSpellSaveDC();
// For when you want to assign the caster DC
//this does take feat/race/class into account, it only overrides the baseDC
if (GetLocalInt(oCaster, PRC_DC_BASE_OVERRIDE) != 0)
{
nDC = GetLocalInt(oCaster, PRC_DC_BASE_OVERRIDE);
SendMessageToPC(oCaster, "Forced Base-DC casting at DC " + IntToString(nDC));
}
nDC += GetChangesToSaveDC(oTarget, oCaster, nSpellID);
return nDC;
}
//called just from above and from inc_epicspells
int GetChangesToSaveDC(object oTarget, object oCaster = OBJECT_SELF, int nSpellID = -1)
{
if(nSpellID == -1)
nSpellID = PRCGetSpellId();
int nDC;
nDC += ElementalSavantDC(nSpellID, oCaster);
nDC += GetHierophantSLAAdjustment(nSpellID, oCaster);
nDC += GetHeartWarderDC(nSpellID, oCaster);
nDC += GetSpellPowerBonus(oCaster);
nDC += ShadowWeaveDC(nSpellID, oCaster);
nDC += RedWizardDC(nSpellID, oCaster);
nDC += TattooFocus(nSpellID, oCaster);
nDC += KOTCSpellFocusVsDemons(oTarget, oCaster);
nDC += BloodMagusBloodComponent(oCaster);
nDC += RunecasterRunePowerDC(oCaster);
nDC += GetLocalInt(oCaster, PRC_DC_ADJUSTMENT);//this is for builder use
return nDC;
}

View File

@@ -0,0 +1,280 @@
// Use this function to get the adjustments to a spell or SLAs spell penetration
// from the various class effects
// Update this function if any new classes change spell pentration
int add_spl_pen(object oCaster = OBJECT_SELF);
#include "prc_inc_spells"
#include "prc_alterations"
#include "prcsp_archmaginc"
int GetHeartWarderPene(int spell_id, object oCaster = OBJECT_SELF) {
// Guard Expensive Calculations
if (!GetHasFeat(FEAT_VOICE_SIREN, oCaster)) return 0;
int nSchool = GetLocalInt(OBJECT_SELF,"X2_L_LAST_SPELLSCHOOL_VAR");
if ( nSchool != SPELL_SCHOOL_ENCHANTMENT) return 0;
// Bonus Requires Verbal Spells
string VS = lookup_spell_vs(spell_id);
if (VS != "v" && VS != "vs")
return 0;
// These feats provide greater bonuses or remove the Verbal requirement
if (PRCGetMetaMagicFeat() & METAMAGIC_SILENT
|| GetHasFeat(FEAT_SPELL_PENETRATION, oCaster)
|| GetHasFeat(FEAT_GREATER_SPELL_PENETRATION, oCaster)
|| GetHasFeat(FEAT_EPIC_SPELL_PENETRATION, oCaster))
return 0;
return 2;
}
//
// Calculate Elemental Savant Contributions
//
int ElementalSavantSP(int spell_id, object oCaster = OBJECT_SELF)
{
int nSP = 0;
int nES;
// All Elemental Savants will have this feat
// when they first gain a penetration bonus.
// Otherwise this would require checking ~4 items (class or specific feats)
if (GetHasFeat(FEAT_ES_PEN_1, oCaster)) {
// get spell elemental type
string element = ChangedElementalType(spell_id, oCaster);
// Any value that does not match one of the enumerated feats
int feat = 0;
// Specify the elemental type rather than lookup by class?
if (element == "Fire")
{
feat = FEAT_ES_FIRE;
nES = GetLevelByClass(CLASS_TYPE_ES_FIRE,oCaster);
}
else if (element == "Cold")
{
feat = FEAT_ES_COLD;
nES = GetLevelByClass(CLASS_TYPE_ES_COLD,oCaster);
}
else if (element == "Electricity")
{
feat = FEAT_ES_ELEC;
nES = GetLevelByClass(CLASS_TYPE_ES_ELEC,oCaster);
}
else if (element == "Acid")
{
feat = FEAT_ES_ACID;
nES = GetLevelByClass(CLASS_TYPE_ES_ACID,oCaster);
}
// Now determine the bonus
if (feat && GetHasFeat(feat, oCaster))
{
if (nES > 28) nSP = 10;
else if (nES > 25) nSP = 9;
else if (nES > 22) nSP = 8;
else if (nES > 19) nSP = 7;
else if (nES > 16) nSP = 6;
else if (nES > 13) nSP = 5;
else if (nES > 10) nSP = 4;
else if (nES > 7) nSP = 3;
else if (nES > 4) nSP = 2;
else if (nES > 1) nSP = 1;
}
}
// SendMessageToPC(GetFirstPC(), "Your Elemental Penetration modifier is " + IntToString(nSP));
return nSP;
}
//Red Wizard SP boost based on spell school specialization
int RedWizardSP(int spell_id, object oCaster = OBJECT_SELF)
{
int iRedWizard = GetLevelByClass(CLASS_TYPE_RED_WIZARD, oCaster);
int nSP;
if (iRedWizard > 0)
{
int nSpell = PRCGetSpellId();
string sSpellSchool = lookup_spell_school(nSpell);
int iSpellSchool;
int iRWSpec;
if (sSpellSchool == "A") iSpellSchool = SPELL_SCHOOL_ABJURATION;
else if (sSpellSchool == "C") iSpellSchool = SPELL_SCHOOL_CONJURATION;
else if (sSpellSchool == "D") iSpellSchool = SPELL_SCHOOL_DIVINATION;
else if (sSpellSchool == "E") iSpellSchool = SPELL_SCHOOL_ENCHANTMENT;
else if (sSpellSchool == "V") iSpellSchool = SPELL_SCHOOL_EVOCATION;
else if (sSpellSchool == "I") iSpellSchool = SPELL_SCHOOL_ILLUSION;
else if (sSpellSchool == "N") iSpellSchool = SPELL_SCHOOL_NECROMANCY;
else if (sSpellSchool == "T") iSpellSchool = SPELL_SCHOOL_TRANSMUTATION;
if (GetHasFeat(FEAT_RW_TF_ABJ, oCaster)) iRWSpec = SPELL_SCHOOL_ABJURATION;
else if (GetHasFeat(FEAT_RW_TF_CON, oCaster)) iRWSpec = SPELL_SCHOOL_CONJURATION;
else if (GetHasFeat(FEAT_RW_TF_DIV, oCaster)) iRWSpec = SPELL_SCHOOL_DIVINATION;
else if (GetHasFeat(FEAT_RW_TF_ENC, oCaster)) iRWSpec = SPELL_SCHOOL_ENCHANTMENT;
else if (GetHasFeat(FEAT_RW_TF_EVO, oCaster)) iRWSpec = SPELL_SCHOOL_EVOCATION;
else if (GetHasFeat(FEAT_RW_TF_ILL, oCaster)) iRWSpec = SPELL_SCHOOL_ILLUSION;
else if (GetHasFeat(FEAT_RW_TF_NEC, oCaster)) iRWSpec = SPELL_SCHOOL_NECROMANCY;
else if (GetHasFeat(FEAT_RW_TF_TRS, oCaster)) iRWSpec = SPELL_SCHOOL_TRANSMUTATION;
if (iSpellSchool == iRWSpec)
{
nSP = 1;
if (iRedWizard > 29) nSP = 16;
else if (iRedWizard > 27) nSP = 15;
else if (iRedWizard > 25) nSP = 14;
else if (iRedWizard > 23) nSP = 13;
else if (iRedWizard > 21) nSP = 12;
else if (iRedWizard > 19) nSP = 11;
else if (iRedWizard > 17) nSP = 10;
else if (iRedWizard > 15) nSP = 9;
else if (iRedWizard > 13) nSP = 8;
else if (iRedWizard > 11) nSP = 7;
else if (iRedWizard > 9) nSP = 6;
else if (iRedWizard > 7) nSP = 5;
else if (iRedWizard > 5) nSP = 4;
else if (iRedWizard > 3) nSP = 3;
else if (iRedWizard > 1) nSP = 2;
}
}
// SendMessageToPC(GetFirstPC(), "Your Spell Power modifier is " + IntToString(nSP));
return nSP;
}
int GetSpellPenetreFocusSchool(object oCaster = OBJECT_SELF)
{
int nSchool = GetLocalInt(OBJECT_SELF,"X2_L_LAST_SPELLSCHOOL_VAR");
if (nSchool >0){
if (GetHasFeat(FEAT_FOCUSED_SPELL_PENETRATION_ABJURATION+nSchool-1, oCaster))
return 4;}
return 0;
}
int GetSpellPowerBonus(object oCaster = OBJECT_SELF)
{
int nBonus = 0;
if(GetHasFeat(FEAT_SPELLPOWER_10, oCaster))
nBonus = 10;
else if(GetHasFeat(FEAT_SPELLPOWER_8, oCaster))
nBonus = 8;
else if(GetHasFeat(FEAT_SPELLPOWER_6, oCaster))
nBonus = 6;
else if(GetHasFeat(FEAT_SPELLPOWER_4, oCaster))
nBonus = 4;
else if(GetHasFeat(FEAT_SPELLPOWER_2, oCaster))
nBonus = 2;
return nBonus;
}
// Shadow Weave Feat
// +1 caster level vs SR (school Ench,Illu,Necro)
int ShadowWeavePen(int spell_id, object oCaster = OBJECT_SELF)
{
int iShadow = GetLevelByClass(CLASS_TYPE_SHADOW_ADEPT, oCaster);
int nSP;
if (iShadow > 0)
{
int nSpell = PRCGetSpellId();
string sSpellSchool = lookup_spell_school(nSpell);
int iSpellSchool;
if (sSpellSchool == "A") iSpellSchool = SPELL_SCHOOL_ABJURATION;
else if (sSpellSchool == "C") iSpellSchool = SPELL_SCHOOL_CONJURATION;
else if (sSpellSchool == "D") iSpellSchool = SPELL_SCHOOL_DIVINATION;
else if (sSpellSchool == "E") iSpellSchool = SPELL_SCHOOL_ENCHANTMENT;
else if (sSpellSchool == "V") iSpellSchool = SPELL_SCHOOL_EVOCATION;
else if (sSpellSchool == "I") iSpellSchool = SPELL_SCHOOL_ILLUSION;
else if (sSpellSchool == "N") iSpellSchool = SPELL_SCHOOL_NECROMANCY;
else if (sSpellSchool == "T") iSpellSchool = SPELL_SCHOOL_TRANSMUTATION;
if (iSpellSchool == SPELL_SCHOOL_ENCHANTMENT || iSpellSchool == SPELL_SCHOOL_NECROMANCY || iSpellSchool == SPELL_SCHOOL_ILLUSION)
{
if (iShadow > 29) nSP = 10;
else if (iShadow > 26) nSP = 9;
else if (iShadow > 23) nSP = 8;
else if (iShadow > 20) nSP = 7;
else if (iShadow > 17) nSP = 6;
else if (iShadow > 14) nSP = 5;
else if (iShadow > 11) nSP = 4;
else if (iShadow > 8) nSP = 3;
else if (iShadow > 5) nSP = 2;
else if (iShadow > 2) nSP = 1;
}
}
//SendMessageToPC(GetFirstPC(), "Your Spell Pen modifier is " + IntToString(nSP));
return nSP;
}
int KOTCSpellPenVsDemons(object oCaster)
{
int nSP = 0;
int iKOTC = GetLevelByClass(CLASS_TYPE_KNIGHT_CHALICE, oCaster);
object oTarget = PRCGetSpellTargetObject();
if (iKOTC >= 1)
{
if (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_OUTSIDER)
{
if (GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL)
{
nSP = 2;
}
}
}
return nSP;
}
int RunecasterRunePowerSP(object oCaster)
{
int nSP = 0;
int nClass = GetLevelByClass(CLASS_TYPE_RUNECASTER, oCaster);
if (nClass >= 2)
{
if (nClass >= 30) nSP = 10;
else if (nClass >= 27) nSP = 9;
else if (nClass >= 24) nSP = 8;
else if (nClass >= 21) nSP = 7;
else if (nClass >= 18) nSP = 6;
else if (nClass >= 15) nSP = 5;
else if (nClass >= 12) nSP = 4;
else if (nClass >= 9) nSP = 3;
else if (nClass >= 5) nSP = 2;
else if (nClass >= 2) nSP = 1;
}
return nSP;
}
int add_spl_pen(object oCaster = OBJECT_SELF)
{
int spell_id = PRCGetSpellId();
int nSP = ElementalSavantSP(spell_id, oCaster);
nSP += GetHeartWarderPene(spell_id, oCaster);
nSP += RedWizardSP(spell_id, oCaster);
nSP += GetSpellPowerBonus(oCaster);
nSP += GetSpellPenetreFocusSchool(oCaster);
nSP += ShadowWeavePen(spell_id,oCaster);
nSP += KOTCSpellPenVsDemons(oCaster);
nSP += RunecasterRunePowerSP(oCaster);
return nSP;
}

View File

@@ -0,0 +1,23 @@
// Written by Stratovarius
// Turns Blood Component on and off.
void main()
{
object oPC = OBJECT_SELF;
string nMes = "";
if(!GetLocalInt(oPC, "BloodComponent"))
{
SetLocalInt(oPC, "BloodComponent", TRUE);
nMes = "*Blood Component Activated*";
}
else
{
// Removes effects
DeleteLocalInt(oPC, "BloodComponent");
nMes = "*Blood Component Deactivated*";
}
FloatingTextStringOnCreature(nMes, oPC, FALSE);
}

View File

@@ -0,0 +1,23 @@
// Written by Stratovarius
// Turns Bloodseeking Spell on and off.
void main()
{
object oPC = OBJECT_SELF;
string nMes = "";
if(!GetLocalInt(oPC, "BloodSeeking"))
{
SetLocalInt(oPC, "BloodSeeking", TRUE);
nMes = "*Blood Seeking Activated*";
}
else
{
// Removes effects
DeleteLocalInt(oPC, "BloodSeeking");
nMes = "*Blood Seeking Deactivated*";
}
FloatingTextStringOnCreature(nMes, oPC, FALSE);
}

View File

@@ -0,0 +1,89 @@
//::///////////////////////////////////////////////
//:: Death Knell
//:: prc_blm_dthknell.nss
//:://////////////////////////////////////////////
/*
If target creature with less than 10 HP fails save
caster gains 1d8 temp HP, +2 Str, and +1 Caster level
*/
//:://////////////////////////////////////////////
//:: Created By: Stratovarius
//:: Created On: Sept 3, 2005
//:://////////////////////////////////////////////
#include "prc_alterations"
#include "prc_inc_spells"
#include "prc_alterations"
#include "prc_alterations"
void DeathKnellCheck(object oPC)
{
if (!GetHasSpellEffect(2086, oPC)) // Death Knell
{
DeleteLocalInt(oPC, "DeathKnell");
}
else
{
DelayCommand(6.0, DeathKnellCheck(oPC));
}
}
void main()
{
DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_NECROMANCY);
//Declare major variables
object oTarget = PRCGetSpellTargetObject();
int iHP = GetCurrentHitPoints(oTarget);
int nCaster = PRCGetCasterLevel(OBJECT_SELF);
int nDuration = nCaster;
int nBonus = d8(1);
int nPenetr = nCaster + SPGetPenetr();
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
effect eStr = EffectAbilityIncrease(ABILITY_STRENGTH, 2);
effect eHP = EffectTemporaryHitpoints(nBonus);
effect eVis2 = EffectVisualEffect(VFX_IMP_DEATH_L);
effect eVis = EffectVisualEffect(VFX_IMP_HOLY_AID);
effect eLink = EffectLinkEffects(eStr, eDur);
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId()));
//Resist magic check
if (iHP < 10)
{
if(!PRCDoResistSpell(OBJECT_SELF, oTarget,nPenetr))
{
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, PRCGetSaveDC(oTarget, OBJECT_SELF)))
{
//Apply the VFX impact and effects
DeathlessFrenzyCheck(oTarget);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oTarget);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget);
//Apply the bonuses to the PC
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, OBJECT_SELF, TurnsToSeconds(nDuration),TRUE,-1,nCaster);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eHP, OBJECT_SELF, TurnsToSeconds(nDuration),TRUE,-1,nCaster);
SetLocalInt(OBJECT_SELF, "DeathKnell", TRUE);
DelayCommand(9.0, DeathKnellCheck(OBJECT_SELF));
}
}
}
else
{
FloatingTextStringOnCreature("*Death Knell failure: The target isn't weak enough*", OBJECT_SELF, FALSE);
}
DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
// Getting rid of the local integer storing the spellschool name
}

View File

@@ -0,0 +1,26 @@
#include "prc_alterations"
void main()
{
//Declare major variables
object oTarget = PRCGetSpellTargetObject();
int nDamage = d10(10);
effect eVis = EffectVisualEffect(VFX_IMP_DEATH_L);
effect eDam = EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL);
int nTouchAttack = PRCDoMeleeTouchAttack(oTarget);;
if (nTouchAttack > 0)
{
// This ability does not work on critical immunes.
if(!GetIsReactionTypeFriendly(oTarget) && !GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT))
{
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId()));
//Apply the VFX impact and effects
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
}
}
}

View File

@@ -0,0 +1,51 @@
//::///////////////////////////////////////////////
//:: Blood Magus
//:: prc_bloodmagus.nss
//:://////////////////////////////////////////////
//:: Check to see which Blood Magus feats a creature
//:: has and apply the appropriate bonuses.
//:://////////////////////////////////////////////
//:: Created By: Stratovarius
//:: Created On: Sept 3, 2005
//:://////////////////////////////////////////////
#include "prc_alterations"
/// Class level to Conc /////////
void DurableCasting(object oPC, object oSkin, int nBlood)
{
if(GetLocalInt(oSkin, "DurableCasting") == nBlood) return;
SetCompositeBonus(oSkin, "DurableCasting", nBlood, ITEM_PROPERTY_SKILL_BONUS, SKILL_CONCENTRATION);
}
void Infusion(object oPC, object oSkin, int iLevel)
{
string sFlag = "BloodMagusInfusion";
if(GetLocalInt(oSkin, sFlag) == iLevel) return;
SetCompositeBonus(oSkin, sFlag, iLevel, ITEM_PROPERTY_ABILITY_BONUS, IP_CONST_ABILITY_CON);
SetLocalInt(oSkin, sFlag, iLevel);
}
void ThickerThanWater(object oPC, object oSkin)
{
if(GetLocalInt(oSkin, "ThickerThanWater") == TRUE) return;
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_PIERCING, IP_CONST_DAMAGERESIST_1), oSkin);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_SLASHING, IP_CONST_DAMAGERESIST_1), oSkin);
SetLocalInt(oSkin, "ThickerThanWater", TRUE);
}
void main()
{
object oPC = OBJECT_SELF;
object oSkin = GetPCSkin(oPC);
int nBlood = GetLevelByClass(CLASS_TYPE_BLOOD_MAGUS, oPC);
if(nBlood >= 1) DurableCasting(oPC, oSkin, nBlood);
if(nBlood >= 7) ThickerThanWater(oPC, oSkin);
if(nBlood >= 9) Infusion(oPC, oSkin, 2);
}

View File

@@ -0,0 +1,4 @@
NWN_DIR = F:\Program Files (x86)\GOG Galaxy\Games\Neverwinter Nights Enhanced Edition\
PRC_VERSION = 4.0.2
PRC_INSTALLVERSION = 4.0.2
NWN_DOC_DIR = C:\Users\wesle\OneDrive\Documents\Neverwinter Nights

2657
trunk/users/Tenjac/nss.syn Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
//////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////

View File

@@ -0,0 +1,295 @@
///////////////////////////////////////////////////
// Craft Poison Convo
// prc_crft_poison
///////////////////////////////////////////////////
#include "prc_inc_spells"
#include "inc_dynconv"
//////////////////////////////////////////////////
/* Constant defintions */
//////////////////////////////////////////////////
const int STAGE_ENTRY =0;
const int STAGE_POISON =1;
const int STAGE_CONFIRM =2;
//////////////////////////////////////////////////
/* Aid functions */
//////////////////////////////////////////////////
void AddToTempList(object oPC, string sChoice, int nChoice)
{
if(DEBUG_LIST) DoDebug("\nAdding to temp list: '" + sChoice + "' - " + IntToString(nChoice));
if(DEBUG_LIST) PrintList(oPC);
// If there is nothing yet
if(!GetLocalInt(oPC, "PRC_CRAFT_CONVO_ListInited"))
{
SetLocalString(oPC, "PRC_CRAFT_CONVO_List_Head", sChoice);
SetLocalInt(oPC, "PRC_CRAFT_CONVO_List_" + sChoice, nChoice);
SetLocalInt(oPC, "PRC_CRAFT_CONVO_ListInited", TRUE);
}
else
{
// Find the location to instert into
string sPrev = "", sNext = GetLocalString(oPC, "PRC_CRAFT_CONVO_List_Head");
while(sNext != "" && StringCompare(sChoice, sNext) >= 0)
{
if(DEBUG_LIST) DoDebug("Comparison between '" + sChoice + "' and '" + sNext + "' = " + IntToString(StringCompare(sChoice, sNext)));
sPrev = sNext;
sNext = GetLocalString(oPC, "PRC_CRAFT_CONVO_List_Next_" + sNext);
}
// Insert the new entry
// Does it replace the head?
if(sPrev == "")
{
if(DEBUG_LIST) DoDebug("New head");
SetLocalString(oPC, "PRC_CRAFT_CONVO_List_Head", sChoice);
}
else
{
if(DEBUG_LIST) DoDebug("Inserting into position between '" + sPrev + "' and '" + sNext + "'");
SetLocalString(oPC, "PRC_CRAFT_CONVO_List_Next_" + sPrev, sChoice);
}
SetLocalString(oPC, "PRC_CRAFT_CONVO_List_Next_" + sChoice, sNext);
SetLocalInt(oPC, "PRC_CRAFT_CONVO_List_" + sChoice, nChoice);
}
}
//Adds names to a list based on sTable (2da), delayed recursion
// to avoid TMI
void PopulateList(object oPC, int MaxValue, int bSort, string sTable, object oItem = OBJECT_INVALID, int i = 0)
{
if(GetLocalInt(oPC, "DynConv_Waiting") == FALSE)
return;
if(i <= MaxValue)
{
int bValid = TRUE;
string sTemp = "";
bValid = array_get_int(oPC, PRC_CRAFT_ITEMPROP_ARRAY, i);
sTemp = Get2DACache(sTable, "Name", i);
if((sTemp != "") && bValid)//this is going to kill
{
if(sTable == "iprp_spells")
{
string sIndex = Get2DACache(sTable, "SpellIndex", i);
if(sIndex != GetLocalString(oPC, "LastSpell"))
{ //don't add if it's a repeat
if(bSort) AddToTempList(oPC, ActionString(GetStringByStrRef(StringToInt(sTemp))), i);
else AddChoice(ActionString(GetStringByStrRef(StringToInt(sTemp))), i, oPC);
SetLocalString(oPC, "LastSpell", sIndex);
}
}
else
{
if(bSort) AddToTempList(oPC, ActionString(GetStringByStrRef(StringToInt(sTemp))), i);
else AddChoice(ActionString(GetStringByStrRef(StringToInt(sTemp))), i, oPC);
}
}
if(!(i % 100) && i) //i != 0, i % 100 == 0
FloatingTextStringOnCreature("*Tick*", oPC, FALSE);
}
else
{
if(bSort) TransferTempList(oPC);
DeleteLocalInt(oPC, "DynConv_Waiting");
FloatingTextStringOnCreature("*Done*", oPC, FALSE);
return;
}
DelayCommand(0.01, PopulateList(oPC, MaxValue, bSort, sTable, oItem, i + 1));
}
//////////////////////////////////////////////////
/* 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);
int nPoison = GetSkillRank(SKILL_CRAFT_POISON, oPC);
int nAlchem = GetSkillRank(SKILL_CRAFT_ALCHEMY, 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))
{
// variable named nStage determines the current conversation node
// Function SetHeader to set the text displayed to the PC
// Function AddChoice to add a response option for the PC. The responses are show in order added
if(nStage == STAGE_ENTRY)
{
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
SetHeader("Would you like to craft a poison?");
AddChoice("Yes.", 1);
MarkStageSetUp(nStage, oPC);
SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
}
if(nStage == STAGE_POISON)
{
if(DEBUG) DoDebug("prc_crft_poison: Building poison selection");
SetHeader("Which poison would you like to create?");
//Read 2da and setup choices
PopulateList(oPC, PRCGetFileEnd("prc_craft_poison"), TRUE, "prc_craft_poison");
MarkStageSetUp(nStage, oPC);
SetDefaultTokens();
}
else if (nStage == STAGE_CONFIRM)
{
SetHeader("Are you sure you want to create this item?");
AddChoice("Back", CHOICE_BACK, oPC);
if(GetGold(oPC) >= nCost) AddChoice("Confirm", CHOICE_CONFIRM_CRAFT, oPC);
MarkStageSetUp(nStage);
}
else
{
if(DEBUG) DoDebug("Invalid Stage: " + IntToString(nStage));
return;
}
}
// Do token setup
SetupTokens();
// End of conversation cleanup
else if(nValue == DYNCONV_EXITED)
{
// Add any locals set through this conversation
DeleteLocalInt(oPC, "PRC_CRAFT_COST");
DeleteLocalInt(oPC, "PRC_CRAFT_DC");
DeleteLocalString(oPC, "PRC_CRAFT_RESREF");
DeleteLocalInt(oPC, "PRC_CRAFT_SKILLUSED");
}
// Abort conversation cleanup.
// NOTE: This section is only run when the conversation is aborted
// while aborting is allowed. When it isn't, the dynconvo infrastructure
// handles restoring the conversation in a transparent manner
else if(nValue == DYNCONV_ABORTED)
{
DeleteLocalInt(oPC, "PRC_CRAFT_COST");
DeleteLocalInt(oPC, "PRC_CRAFT_DC");
DeleteLocalString(oPC, "PRC_CRAFT_RESREF");
DeleteLocalInt(oPC, "PRC_CRAFT_SKILLUSED");
// Add any locals set through this conversation
if(DEBUG) DoDebug("prc_craft: ERROR: Conversation abort section run");
}
// Handle PC responses
else
{
// variable named nChoice is the value of the player's choice as stored when building the choice list
// variable named nStage determines the current conversation node
int nChoice = GetChoice(oPC);
if(nStage == STAGE_ENTRY)
{
if(nChoice == 1) nStage = STAGE_POISON;
// Move to another stage based on response, for example
//nStage = STAGE_QUUX;
}
else if(nStage == STAGE_POISON)
{
//Create choice list
}
else if(nStage == STAGE_CONFIRM)
{
if(nChoice == CHOICE_ABORT_CRAFT)
{
nStage = STAGE_ENTRY;
}
else if(nChoice == CHOICE_CONFIRM_CRAFT)
{
int n2daLine = nChoice--;
if(n2daLine < 0) SendMessageToPC(oPC, "Invalid prc_crft_poison.2da line");
int nDC = StringToInt(Get2daCache("prc_crft_poison", "CraftDC", n2daLine));
int nCost = StringToInt(Get2daCache("prc_crft_poison", "GoldCost", n2daLine));
string sPoison = Get2daCache("prc_crft_poison", "Poison2daLine", n2daLine);
int nName = StringToInt(Get2daCache("prc_crft_poison", "Name", n2daLine));
int nDesc = StringToInt(Get2daCache("prc_crft_poison", "Description", n2daLine));
int nType = StringToInt(Get2daCache("prc_crft_poison", "PoisonType", n2daLine));
nSkill = SKILL_CRAFT_POISON;
//Use alchemy skill if it is 5 or more higher than craft(poisonmaking). DC is increased by 4.
if((nAlchem - nPoison) >4)
{
nSkill = SKILL_CRAFT_ALCHEMY;
nDC += 4;
SendMessageToPC(oPC, "Using craft(alchemy) instead of craft(poison). New DC is "+ IntToString(nDC) + ".");
}
TakeGoldFromCreature(nCost, oPC, TRUE);
if(GetIsSkillSuccessful(oPC, nSkill), nDC))
{
SendMessageToPc(oPC, "Item successfully created.");
object oTarget; CreateItemOnObject("prc_it_poison", oPC, 1, "prc_it_pois" + sPoison);
if(nType == 0) CreateItemOnObject("prc_it_poist0", oPC, 1, "prc_it_pois" + sPoison);
else if(nType == 1) CreateItemOnObject("prc_it_poist1", oPC, 1, "prc_it_pois" + sPoison);
else if(nType == 2) CreateItemOnObject("prc_it_poist2", oPC, 1, "prc_it_pois" + sPoison);
else if(nType == 3) CreateItemOnObject("prc_it_poist3", oPC, 1, "prc_it_pois" + sPoison);
else
{
SendMessageToPC(oPC, "Invalid poison type. Aborting."
GiveGoldToCreature(oPC, nCost);
return;
}
//Set name and descrip
SetName(oTarget, GetStringByStrRef(nName));
SetDescription(oTarget, GetStringByStrRef(nDesc));
}
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
}
}
// Store the stage value. If it has been changed, this clears out the choices
SetStage(nStage, oPC);
}
}

Binary file not shown.

View File

@@ -0,0 +1,27 @@
//:://////////////////////////////////////////////
//:: Name
//:: FileName sp_.nss
//:://////////////////////////////////////////////
/** @file
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
PRCSetSchool();
}

View File

@@ -0,0 +1,100 @@
//:://////////////////////////////////////////////
//:: Name Axiomatic Water Impact Script
//:: FileName prc_axiowater.nss
//:://////////////////////////////////////////////
/** @file Transmutation [Lawful]
Level: Cleric 1, Paladin 1,
Components: V, S, M,
Casting Time: 1 minute
Range: Touch
Target: Flask of water touched
Duration: Instantaneous
Saving Throw: Will negates (object)
Spell Resistance: Yes (object)
You speak the ancient, slippery words as you pour the iron and silver into the flask. Despite the fact that there
is more powder than will fit in the container, all of it dissolves, leaving a flask of water dotted with motes of gunmetal gray.
This transmutation imbues a flask (1 pint) of water with the order of law, turning it into axiomatic water. Axiomati
water damages chaotic outsiders the way holy water damages undead and evil outsiders. A flask of axiomatic water can
be thrown as a splash weapon. Treat this attack as a ranged touch attack with a range increment of 10 feet. A flask
breaks if thrown against the body of a corporeal creature, but to use it against an incorporeal creature, the bearer
must open the flask and pout the axiomatic water out onto the target. Thus, a character can douse an incorporeal
creature with axiomatic water only if he is adjacent to it. Doing so is a ranged touch attack that does not provoke
attacks of opportunity.
A direct hit by a flask of axiomatic water deals 2d4 points of damage to a chaotic outsider. Each such creature
within 5 feet of the point where the flask hits takes 1 point of damage from the splash.
Material Component: 5 pounds of powdered iron and silver (worth 25 gp).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/10/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
#include "prc_inc_sp_tch"
void main()
{
location lTarget = GetSpellTargetLocation();
float fRadius = FeetToMeters(5);
int nTouch;
effect eVis = EffectVisualEffect(VFX_IMP_HEAD_HOLY);
object oTarget = PRCGetSpellTargetObject();
//Targeted a creature
if (GetIsObjectValid(oTarget) == TRUE)
{
nTouch = PRCDoRangedTouchAttack(oTarget);
}
//Hit
if(nTouch >= 1)
{
int nDirectDam = d4(2);
}
//Critical
if(nTouch == 2)
{
nDam += nDam;
}
effect eDam = EffectDamage(nDam, DAMAGE_TYPE_DIVINE);
object oDoNotDam = oTarget;
//Outsider
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_OUTSIDER)
{
//Chaotic
if(GetAlignmentLawChaos(oTarget) == ALIGNMENT_CHAOTIC)
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
}
}
oTarget = MyGetFirstObjectInShape(SHAPE_SPHERE, fRadius, lTarget);
while(GetIsObjectValid(oTarget))
{
if(oTarget != oDoNotDam)
{
//Outsider
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_OUTSIDER)
{
//Chaotic
if(GetAlignmentLawChaos(oTarget) == ALIGNMENT_CHAOTIC)
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(1, DAMAGE_TYPE_DIVINE), oTarget);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
}
}
}
MyGetNextObjectInShape(SHAPE_SPHERE, fRadius, lTarget);
}
}

View File

@@ -0,0 +1,115 @@
//:://////////////////////////////////////////////
//:: Short description Bladebane Conversation
//:: filename prc_c_bladebane.nss
//:://////////////////////////////////////////////
/** @file
@author Tenjac
@date Created - 7/29/22
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "inc_dynconv"
//////////////////////////////////////////////////
/* Constant defintions */
//////////////////////////////////////////////////
const int STAGE_ENTRY = 0;
//////////////////////////////////////////////////
/* Aid functions */
//////////////////////////////////////////////////
//////////////////////////////////////////////////
/* 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))
{
// variable named nStage determines the current conversation node
// Function SetHeader to set the text displayed to the PC
// Function AddChoice to add a response option for the PC. The responses are show in order added
if(nStage == STAGE_ENTRY)
{
// Set the header
SetHeader("Choose racial type.");
int i;
for (i=0; i <=254; i++)
{
string sName = Get2daCache("racialtypes", "Constant", i);
// Add responses for the PC
if(sName != "")
{
AddChoice(sName, i, oPC);
}
}
MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
}
//add more stages for more nodes with Else If clauses
}
// Do token setup
SetupTokens();
}
// End of conversation cleanup
else if(nValue == DYNCONV_EXITED)
{
// Add any locals set through this conversation
}
// Abort conversation cleanup.
// NOTE: This section is only run when the conversation is aborted
// while aborting is allowed. When it isn't, the dynconvo infrastructure
// handles restoring the conversation in a transparent manner
else if(nValue == DYNCONV_ABORTED)
{
// Add any locals set through this conversation
}
// Handle PC responses
else
{
// variable named nChoice is the value of the player's choice as stored when building the choice list
// variable named nStage determines the current conversation node
int nChoice = GetChoice(oPC);
if(nStage == STAGE_ENTRY)
{
int n2daLine = nChoice--;
SetLocalInt(oPC, "BladebaneRace", n2daLine);
// Move to another stage based on response, for example
//nStage = STAGE_QUUX;
}
// Store the stage value. If it has been changed, this clears out the choices
SetStage(nStage, oPC);
}
}

View File

@@ -0,0 +1,70 @@
//:://////////////////////////////////////////////
//:: Name Smite of Sacred Fire
//:: FileName sp_smitesacfire.nss
//:://////////////////////////////////////////////
/** @file Evocation [Good]
Level: Paladin 2,
Components: V, DF,
Casting Time: 1 swift action
Range: Personal
Target: You
Duration: 1 round/level; see text
You must cast this spell in the same round when you
attempt a smite attack. If the attack hits, you deal
an extra 2d6 points of damage to the target of the
smite. Whether or not you succeed on the smite attempt,
during each subsequent round of the spell?s duration,
you deal an extra 2d6 points of damage on any successful
melee attack against the target you attempted to smite.
The spell ends prematurely after any round when you do not
attempt a melee attack against the target you previously
attempted to smite, or if you fail to hit with any of
your attacks in a round.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/25/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oSpellOrigin = OBJECT_SELF;
// find the weapon
object oWeapon = PRCGetSpellCastItem(oSpellOrigin);
// find the target of the spell
object oTarget = PRCGetSpellTargetObject(oSpellOrigin);
//Hit in the last round
if(GetHasSpellEffect(SPELL_SMITE_SACRED_FIRE_HIT))
{
//Target of the original smite
if(GetLocalInt(oTarget, "PRCSSFTarget"));
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(DAMAGE_TYPE_DIVINE, d6(2)), oTarget);
ActionCastSpellOnSelf(SPELL_SMITE_SACRED_FIRE_HIT);
}
}
else //We've missed; effect ends, make sure this doesn't trigger the first time
{
effect eToDispel = GetFirstEffect(oSpellOrigin);
while(GetIsEffectValid(eToDispel))
{
if(GetEffectSpellId(eToDispel) == SPELL_SMITE_OF_SACRED_FIRE)
{
RemoveEffect(oSpellOrigin, eToDispel);
}
eToDispel = GetNextEffect(oSpellOrigin);
}
}
}

View File

@@ -0,0 +1,42 @@
//:://////////////////////////////////////////////
//:: Name Righteous Aura On Death
//:: FileName prc_rightaura.nss
//:://////////////////////////////////////////////
/** @file
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/20/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oPC = OBJECT_SELF;
int nDice = min(20, PRCGetCasterLevel(oPC) * 2);
location lLoc = GetLocation(oPC);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_STRIKE_HOLY), lLoc);
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(20), lLoc, FALSE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oTarget))
{
if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_GOOD)
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectHeal(d6(nDice)), oTarget);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HOLY_AID), oTarget);
}
if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL)
{
int nDam = d6(nDice);
//Double damage for undead
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) nDam+=nDam;
effect eLink = EffectLinkEffects(EffectVisualEffect(VFX_IMP_HOLY_AID), EffectDamage(DAMAGE_TYPE_DIVINE, nDam));
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eLink, oTarget);
}
oTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(20), lLoc, FALSE, OBJECT_TYPE_CREATURE);
}
}

View File

@@ -0,0 +1,115 @@
//:://////////////////////////////////////////////
//:: Name Aligned Aura Discarge
//:: FileName sp_algnaurdisc.nss
//:://////////////////////////////////////////////
/** @file
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/25/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
int nMetaMagic = PRCGetMetaMagicFeat();
location lLoc = GetLocation(oPC);
int nDC;
int nAlign;
int nAlignTarget;
if (GetHasSpellEffect(SPELL_ALIGNED_AURA_LAW,oPC)) nAlign == ALIGNMENT_LAWFUL;
else if(GetHasSpellEffect(SPELL_ALIGNED_AURA_CHAOS,oPC)) nAlign = ALIGNMENT_CHAOTIC;
else if (GetHasSpellEffect(SPELL_ALIGNED_AURA_GOOD,oPC)) nAlign = ALIGNMENT_GOOD;
else if (GetHasSpellEffect(SPELL_ALIGNED_AURA_EVIL,oPC)) nAlign = ALIGNMENT_EVIL;
else SendMessageToPC(oPC, "Invalid alignment passed in script sp_algnaurdisc.nss");
//Get duration left
int nEffectDuration, nEffectDurationRemaining;
effect eEffect = GetFirstEffect(OBJECT_SELF);
while(GetIsEffectValid(eEffect))
{
if(GetEffectSpellId(eEffect) == SPELL_ALIGNED_AURA_LAW)
{
nEffectDuration = GetEffectDuration(eEffect);
nEffectDurationRemaining = GetEffectDurationRemaining(eEffect);
nAlign = ALIGNMENT_LAWFUL;
}
else if(GetSpellId(eEffect) == SPELL_ALIGNED_AURA_CHAOS)
{
nEffectDuration = GetEffectDuration(eEffect);
nEffectDurationRemaining = GetEffectDurationRemaining(eEffect);
nAlign = ALIGNMENT_CHAOTIC;
}
else if(GetSpellId(eEffect) == SPELL_ALIGNED_AURA_GOOD)
{
nEffectDuration = GetEffectDuration(eEffect);
nEffectDurationRemaining = GetEffectDurationRemaining(eEffect);
nAlign = ALIGNMENT_GOOD;
}
else if(GetSpellId(eEffect) == SPELL_ALIGNED_AURA_EVIL)
{
nEffectDuration = GetEffectDuration(eEffect);
nEffectDurationRemaining = GetEffectDurationRemaining(eEffect);
nAlign = ALIGNMENT_EVIL;
}
eEffect = GetNextEffect(OBJECT_SELF);
}
//GetEffectDurationRemaining returns seconds, need rounds
int nDice = nEffectDurationRemaining / 6;
int nDam = d4(min(15, nDice));
//Do the AoE
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE,FeetToMeters(60.0), lLoc);
{
while(GetIsObjectValid(oTarget))
{
if(oTarget != oPC)
{
//lawful or chaotic
if(nAlign == ALIGNMENT_LAWFUL || nAlign == ALIGNMENT_CHAOTIC) nAlignTarget = GetAlignmentLawChaos(oTarget);
else if (nAlign == ALIGNMENT_GOOD || nAlign == ALIGNMENT_EVIL) nAlignTarget = GetAlignmentGoodEvil(oTarget);
//Same alignment, heal
if(nAlign == nAlignTarget)
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectHeal(nDam, oTarget), oTarget);
}
//Opposing alignment, damage
if(nAlign != nAlignTarget)
{
nDC = PRCGetSaveDC(oTarget, oPC);
//SR
if(!PRCDoResistSpell(oPC, oTarget, nCasterLvl + SPGetPenetr()))
{
//Fort Save half
if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_DIVINE)
{
nDam = nDam/2;
}
effect eDam = PRCEffectDamage(oTarget, nDam, DAMAGE_TYPE_MAGICAL);
effect eVis = EffectVisualEffect(VFX_IMP_DIVINE_STRIKE_HOLY);
effect eLink = EffectLinkEffects(eDam, eVis);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eLink, oTarget);
}
}
}
oTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0), lLoc);
}
}
PRCSetSchool();
}

View File

@@ -0,0 +1,68 @@
//:://////////////////////////////////////////////
//:: Name Aligned Aura
//:: FileName sp_alignedaura.nss
//:://////////////////////////////////////////////
/** @file
Abjuration
Level: Blackguard 4, Cleric 4, Paladin 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: 20 ft. or 60 ft.
Area: 20-ft.-radius emanation or 60-ft.-radius burst, centered on you
Duration: 1 round/level or until discharged
Saving Throw: Fortitude partial
Spell Resistance: Yes
A rush of divine energy flows through your holy symbol, infusing your body
with the essence of the divine ethos. When you cast this spell, choose one
non-neutral aspect of your own alignment<6E>chaos, evil, good, or law.
(If you are neutral, you can select whichever alignment you wish each time
you cast this spell). You are immediately surrounded in a 20-foot aura of
invisible energy associated with the chosen alignment component. Anyone in
that area who shares that alignment component gains a bonus, and anyone with
the opposed alignment component must make a Fortitude save or take a penalty.
The values of these modifiers and the features to which they apply are given
on the following table. These modifiers end when the affected creature leaves
the spell's area.
Alignment Bonus Penalty
Chaos +1 on attack rolls -1 on saving throws
Evil +1 on damage rolls -1 to Armor Class
Good +1 on saving throws -1 on attack rolls
Law +1 to Armor Class -1 on damage rolls
At any point before the duration expires, you can choose to unleash the spell's
remaining power in a 60-foot burst that deals 1d4 points of damage per round of
duration remaining (maximum 15d4) to each creature of the opposed alignment in
the area. Each affected creature can attempt a Fortitude save for half damage.
The burst also heals 1 point of damage per round of duration remaining
(maximum 15 points) for each creature of the same alignment in the area. Once
this option is invoked, the spell ends immediately.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/24/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
int nMetaMagic = PRCGetMetaMagicFeat();
int nGood = GetAlignmentGoodEvil(oPC);
int nLaw = GetLawChaosValue(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nSpellID = PRCGetSpellId();
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAreaOfEffect(AOE_MOB_ALIGNED_AURA), oPC, fDur);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_PULSE_YELLOW_WHITE), oPC, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,119 @@
//:://////////////////////////////////////////////
//:: Name Aligned Aura
//:: FileName sp_alignedaura.nss
//:://////////////////////////////////////////////
/** @file
Abjuration
Level: Blackguard 4, Cleric 4, Paladin 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: 20 ft. or 60 ft.
Area: 20-ft.-radius emanation or 60-ft.-radius burst, centered on you
Duration: 1 round/level or until discharged
Saving Throw: Fortitude partial
Spell Resistance: Yes
A rush of divine energy flows through your holy symbol, infusing your body
with the essence of the divine ethos. When you cast this spell, choose one
non-neutral aspect of your own alignment<6E>chaos, evil, good, or law.
(If you are neutral, you can select whichever alignment you wish each time
you cast this spell). You are immediately surrounded in a 20-foot aura of
invisible energy associated with the chosen alignment component. Anyone in
that area who shares that alignment component gains a bonus, and anyone with
the opposed alignment component must make a Fortitude save or take a penalty.
The values of these modifiers and the features to which they apply are given
on the following table. These modifiers end when the affected creature leaves
the spell's area.
Alignment Bonus Penalty
Chaos +1 on attack rolls -1 on saving throws
Evil +1 on damage rolls -1 to Armor Class
Good +1 on saving throws -1 on attack rolls
Law +1 to Armor Class -1 on damage rolls
At any point before the duration expires, you can choose to unleash the spell's
remaining power in a 60-foot burst that deals 1d4 points of damage per round of
duration remaining (maximum 15d4) to each creature of the opposed alignment in
the area. Each affected creature can attempt a Fortitude save for half damage.
The burst also heals 1 point of damage per round of duration remaining
(maximum 15 points) for each creature of the same alignment in the area. Once
this option is invoked, the spell ends immediately.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/24/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oCreator = GetAreaOfEffectCreator();
int nGood = GetAlignmentGoodEvil(oCreator);
int nLaw = GetLawChaosValue(oCreator);
int nCasterLvl = PRCGetCasterLevel(oCreator);
float fDur = RoundsToSeconds(nCasterLvl);
int nSpellID = PRCGetSpellId();
int nSaveType;
object oTarget = GetEnteringObject();
effect eBuff;
effect eDebuff;
effect eVisHelp;
effect eVisHarm;
effect eLink;
if(nSpellID == SPELL_ALIGNED_AURA_CHAOS)
{
eBuff = EffectAttackIncrease(1);
eDebuff = EffectSavingThrowDecrease(SAVING_THROW_ALL, 1, SAVING_THROW_TYPE_ALL);
eVisHelp = EffectVisualEffect(VFX_IMP_DESTRUCTION);
eVisHarm = EffectVisualEffect(VFX_IMP_HEAD_ODD);
nSaveType = SAVING_THROW_TYPE_CHAOS;
}
if(nSpellID == SPELL_ALIGNED_AURA_EVIL)
{
eBuff = EffectDamageIncrease(DAMAGE_BONUS_1);
eDebuff = EffectACDecrease(1);
eVisHelp = EffectVisualEffect(VFX_IMP_EVIL_HELP);
eVisHarm = EffectVisualEffect(VFX_IMP_HEAD_EVIL);
nSaveType = SAVING_THROW_TYPE_EVIL;
}
if(nSpellID == SPELL_ALIGNED_AURA_GOOD)
{
eBuff = EffectSavingThrowIncrease(SAVING_THROW_ALL, 1, SAVING_THROW_TYPE_ALL;
eDebuff = EffectAttackDecrease(1);
eVisHelp = EffectVisualEffect(VFX_IMP_GOOD_HELP);
eVisHarm = EffectVisualEffect(VFX_IMP_HEAD_HOLY);
nSaveType = SAVING_THROW_TYPE_GOOD;
}
if(nSpellID == SPELL_ALIGNED_AURA_LAW)
{
eBuff = EffectACIncrease(1);
eDebuff = EffectDamageDecrease(DAMAGE_BONUS_1, DAMAGE_TYPE_BLUDGEONING|DAMAGE_TYPE_PIERCING|DAMAGE_TYPE_SLASHING);
eVisHelp = EffectVisualEffect(VFX_IMP_AC_BONUS);
eVisHarm = EffectVisualEffect(VFX_IMP_HEAD_COLD);
nSaveType = SAVING_THROW_TYPE_LAW;
}
if(GetIsReactionTypeFriendly(oTarget) || GetFactionEqual(oTarget))
{
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBuff, oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVisHelp, oTarget);
}
else
{ //Spell Resist
if(!PRCDoResistSpell(oCaster, oTarget,nCasterLvl + SPGetPenetr()))
{
//Save
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, (PRCGetSaveDC(oTarget,oCreator)), nSaveType))
{
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDebuff, oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVisHarm, oTarget);
}
}
}
PRCSetSchool();
}

View File

@@ -0,0 +1,68 @@
//:://////////////////////////////////////////////
//:: Name Aligned Aura
//:: FileName sp_alignedaura.nss
//:://////////////////////////////////////////////
/** @file
Abjuration
Level: Blackguard 4, Cleric 4, Paladin 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: 20 ft. or 60 ft.
Area: 20-ft.-radius emanation or 60-ft.-radius burst, centered on you
Duration: 1 round/level or until discharged
Saving Throw: Fortitude partial
Spell Resistance: Yes
A rush of divine energy flows through your holy symbol, infusing your body
with the essence of the divine ethos. When you cast this spell, choose one
non-neutral aspect of your own alignment<6E>chaos, evil, good, or law.
(If you are neutral, you can select whichever alignment you wish each time
you cast this spell). You are immediately surrounded in a 20-foot aura of
invisible energy associated with the chosen alignment component. Anyone in
that area who shares that alignment component gains a bonus, and anyone with
the opposed alignment component must make a Fortitude save or take a penalty.
The values of these modifiers and the features to which they apply are given
on the following table. These modifiers end when the affected creature leaves
the spell's area.
Alignment Bonus Penalty
Chaos +1 on attack rolls -1 on saving throws
Evil +1 on damage rolls -1 to Armor Class
Good +1 on saving throws -1 on attack rolls
Law +1 to Armor Class -1 on damage rolls
At any point before the duration expires, you can choose to unleash the spell's
remaining power in a 60-foot burst that deals 1d4 points of damage per round of
duration remaining (maximum 15d4) to each creature of the opposed alignment in
the area. Each affected creature can attempt a Fortitude save for half damage.
The burst also heals 1 point of damage per round of duration remaining
(maximum 15 points) for each creature of the same alignment in the area. Once
this option is invoked, the spell ends immediately.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/24/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oCaster = GetAreaOfEffectCreator();
object oTarget = GetExitingObject();
int nSpellId
effect eToDispel = GetFirstEffect(oTarget);
while(GetIsEffectValid(eToDispel))
{
nSpellId = GetEffectSpellId(eToDispel);
if(nSpellId == SPELL_ALIGNED_AURA_CHAOS || nSpellId == SPELL_ALIGNED_AURA_LAW || nSpellId == SPELL_ALIGNED_AURA_GOOD || nSpellId == SPELL_ALIGNED_AURA_EVIL)
{
RemoveEffect(oTarget, eToDispel);
}
eToDispel = GetNextEffect(oTarget);
}
}
}

View File

@@ -0,0 +1,60 @@
//:://////////////////////////////////////////////
//:: Name Angelskin
//:: FileName sp_angelskin.nss
//:://////////////////////////////////////////////
/** @file
Abjuration [Good]
Level: Paladin 2
Components: V, S, DF,
Casting Time: 1 standard action
Range: Touch
Target: Lawful good creature touched
Duration: 1 round/level
Saving Throw: Will negates (harmless)
Spell Resistance: Yes (harmless)
You touch your ally with the holy symbol and invoke the blessed words. An opalescent
glow spreads across her skin, imbuing it with a pearl-like sheen.
The subject gains damage reduction 5/evil.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/22/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
object oTarget = PRCGetSpellTargetObject();
int nCasterLvl = PRCGetCasterLevel(oPC);
int nMetaMagic = PRCGetMetaMagicFeat();
float fDur = RoundsToSeconds(nCasterLvl);
if(nMetaMagic & METAMAGIC_EXTEND)
{
fDur += fDur;
}
//Alignment check
if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_GOOD) && (GetAlignmentLawChaos(oTarget) == ALIGNMENT_LAWFUL)
{
effect eDR = EffectDamageReduction(5,DAMAGE_POWER_PLUS_THREE,0);
effect eVFX = EffectVisualEffect(VFX_DUR_AURA_WHITE);
effect eSpell = EffectLinkEffects(eDR, eVFX);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSpell, oTarget, fDur);
}
//Invalid target alignment
else
{
SendMessageToPC(oPC, "This spell must target a lawful good creature.");
}
PRCSetSchool();
}

View File

@@ -0,0 +1,67 @@
//:://////////////////////////////////////////////
//:: Name Aura of Cold
//:: FileName sp_auracold.nss
//:://////////////////////////////////////////////
/** @file Transmutation [Cold]
Level: Cleric 3, Druid 3, Disciple of Thrym 3, Paladin 4, Ranger 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: 5 ft.
Area: 5-ft.-radius spherical emanation, centered on you
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: Yes
You are covered in a thin layer of white frost and frigid cold emanates from your
body, dealing 1d6 points of cold damage at the start of your round to each creature
within 5 feet.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/8/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void DoCold(object oPC, int nRounds)
{
if(nRounds > 0)
{
location lLoc=GetLocation(oPC);
//Do the AoE
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE,FeetToMeters(5.0), lLoc);
{
while(GetIsObjectValid(oTarget))
{
if(oTarget != oPC)
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6(1), DAMAGE_TYPE_COLD), oTarget);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FROST_S), oTarget);
}
oTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(5.0), lLoc);
}
}
nRounds--;
DelayCommand(6.0f, DoCold(oPC, nRounds));
}
}
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
int nRounds = nCasterLvl;
if(nMetaMagic & METAMAGIC_EXTEND) nRounds += nRounds;
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_PULSE_BLUE_WHITE), oPC, fDur);
DoCold(oPC, nRounds);
PRCSetSchool();
}

View File

@@ -0,0 +1,48 @@
//:://////////////////////////////////////////////
//:: Name Aura of the Sun
//:: FileName sp_aurasun.nss
//:://////////////////////////////////////////////
/** @file Aura of the Sun
Abjuration [Light]
Level: Cleric 4, Paladin 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: 10 ft.
Area: 10-ft.-radius emanation centered on you
Duration: 1 round/level (D)
Saving Throw: No
Spell Resistance: None
By casting aura of the sun, you fill the area around you with warm, glowing light that eliminates natural
shadows and hampers magical darkness.Any creature attempting to cast a spell from the shadow subschool or
a spell with the darkness descriptor within an aura of the sun must succeed on a caster level check (DC 11 +
your caster level), or the spell fails. Areas of magical darkness originating from 3rd-level or lower spells
and effects are temporarily suppressed when overlapping with an aura of the sun. Creatures that take penalties
in bright light also take them while within an aura of the sun, and an undead creature takes 1d6 points of positive
energy damage at the end of its turn every round that it spends within the spell's area.Furthermore, any creature
attempting to hide within the aura takes a -4 penalty on Hide checks.
This effect is centered on you and moves with you.
Anyone who enters the aura immediately becomes subject to its effect, but creatures that leave are no longer affected.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAreaOfEffect(AOE_MOB_AURASUN), fDur, oPC);
PRCSetSchool();
}

View File

@@ -0,0 +1,42 @@
//:://////////////////////////////////////////////
//:: Name Aura of the Sun On Enter
//:: FileName sp_aurasunA.nss
//:://////////////////////////////////////////////
/** @file Aura of the Sun
Abjuration [Light]
Level: Cleric 4, Paladin 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: 10 ft.
Area: 10-ft.-radius emanation centered on you
Duration: 1 round/level (D)
Saving Throw: No
Spell Resistance: None
By casting aura of the sun, you fill the area around you with warm, glowing light that eliminates natural
shadows and hampers magical darkness.Any creature attempting to cast a spell from the shadow subschool or
a spell with the darkness descriptor within an aura of the sun must succeed on a caster level check (DC 11 +
your caster level), or the spell fails. Areas of magical darkness originating from 3rd-level or lower spells
and effects are temporarily suppressed when overlapping with an aura of the sun. Creatures that take penalties
in bright light also take them while within an aura of the sun, and an undead creature takes 1d6 points of positive
energy damage at the end of its turn every round that it spends within the spell's area.Furthermore, any creature
attempting to hide within the aura takes a -4 penalty on Hide checks.
This effect is centered on you and moves with you.
Anyone who enters the aura immediately becomes subject to its effect, but creatures that leave are no longer affected.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 8/10/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main
{
object oCreator = GetAreaOfEffectCreator();
int nCasterLvl = PRCGetCasterLvl(oCreator);
object oTarget = GetEnteringObject();
SPApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectSkillDecrease(SKILL_HIDE), oTarget);
SetLocalInt(oTarget, "PRCAuraSunDC", 11 + nCasterLvl);
}

View File

@@ -0,0 +1,54 @@
//:://////////////////////////////////////////////
//:: Name Aura of the Sun On Exit
//:: FileName sp_aurasunB.nss
//:://////////////////////////////////////////////
/** @file Aura of the Sun
Abjuration [Light]
Level: Cleric 4, Paladin 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: 10 ft.
Area: 10-ft.-radius emanation centered on you
Duration: 1 round/level (D)
Saving Throw: No
Spell Resistance: None
By casting aura of the sun, you fill the area around you with warm, glowing light that eliminates natural
shadows and hampers magical darkness.Any creature attempting to cast a spell from the shadow subschool or
a spell with the darkness descriptor within an aura of the sun must succeed on a caster level check (DC 11 +
your caster level), or the spell fails. Areas of magical darkness originating from 3rd-level or lower spells
and effects are temporarily suppressed when overlapping with an aura of the sun. Creatures that take penalties
in bright light also take them while within an aura of the sun, and an undead creature takes 1d6 points of positive
energy damage at the end of its turn every round that it spends within the spell's area.Furthermore, any creature
attempting to hide within the aura takes a -4 penalty on Hide checks.
This effect is centered on you and moves with you.
Anyone who enters the aura immediately becomes subject to its effect, but creatures that leave are no longer affected.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 8/10/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oCaster = GetAreaOfEffectCreator();
object oTarget = GetExitingObject();
effect eToDispel = GetFirstEffect(oTarget);
while(GetIsEffectValid(eToDispel))
{
if(GetEffectSpellId(eToDispel) == SPELL_AURA_OF_THE_SUN)
{
RemoveEffect(oTarget, eToDispel);
}
eToDispel = GetNextEffect(oTarget);
}
}
DeleteLocalInt(oTarget, "PRCAuraSunDC");
}

View File

@@ -0,0 +1,49 @@
//:://////////////////////////////////////////////
//:: Name Aura of the Sun Heartbeat
//:: FileName sp_aurasunC.nss
//:://////////////////////////////////////////////
/** @file Aura of the Sun
Abjuration [Light]
Level: Cleric 4, Paladin 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: 10 ft.
Area: 10-ft.-radius emanation centered on you
Duration: 1 round/level (D)
Saving Throw: No
Spell Resistance: None
By casting aura of the sun, you fill the area around you with warm, glowing light that eliminates natural
shadows and hampers magical darkness.Any creature attempting to cast a spell from the shadow subschool or
a spell with the darkness descriptor within an aura of the sun must succeed on a caster level check (DC 11 +
your caster level), or the spell fails. Areas of magical darkness originating from 3rd-level or lower spells
and effects are temporarily suppressed when overlapping with an aura of the sun. Creatures that take penalties
in bright light also take them while within an aura of the sun, and an undead creature takes 1d6 points of positive
energy damage at the end of its turn every round that it spends within the spell's area.Furthermore, any creature
attempting to hide within the aura takes a -4 penalty on Hide checks.
This effect is centered on you and moves with you.
Anyone who enters the aura immediately becomes subject to its effect, but creatures that leave are no longer affected.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 8/10/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main
{
object oTarget = GetFirstInPersistentObject();
while(GetIsObjectValid(oTarget))
{
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD)
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_HIT_DIVINE), oTarget);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectDamage(oTarget, d6(1), DAMAGE_TYPE_DIVINE), oTarget);
}
oTarget = GetNextInPersistentObject();
}
}

View File

@@ -0,0 +1,105 @@
//:://////////////////////////////////////////////
//:: Name Axiomatic Storm
//:: FileName sp_axio_storm.nss
//:://////////////////////////////////////////////
/** @file
Conjuration (Creation)
Level: Cleric 3, Paladin 3,
Components: V, S, M, DF,
Casting Time: 1 standard action
Area: Cylinder (20-ft. radius, 20 ft. high)
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: No
You call upon the forces of law and a heavy rain
begins to fall around you, its raindrops harsh and
metallic. Above you, a jet of caustic acid lances
down from the heavens.
A driving rain falls around you. It falls in a fixed
area once created. The storm reduces hearing and
visibility, resulting in a <20>4 penalty on Listen, Spot,
and Search checks. It also applies a <20>4 penalty on ranged
attacks made into, out of, or through the storm. Finally,
it automatically extinguishes any unprotected flames and
has a 50% chance to extinguish protected flames (such as
those of lanterns).
The rain damages chaotic creatures, dealing 2d6 points
of damage per round (chaotic outsiders take double damage).
In addition, each round, a gout of acid strikes a randomly
selected chaotic outsider within the spell's area, dealing
5d6 points of acid damage.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void DoAcid(int nCount, location lLoc, object oPC)
{
if(nCount >0)
{
object oChaotic = GetFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(20), lLoc);
{
while(GetIsObjectValid(oChaotic))
{
if(GetAlignmentLawChaos(oChaotic) == ALIGNMENT_CHAOTIC))
{
if(PRCGetRacialType(oChaotic) == RACIAL_TYPE_OUTSIDER))
{
//increment count of chaotic outsiders
nOutsiders++;
//Set as a target
SetLocalObject(oPC, "oAxioStorm" + IntToString(nOutsiders), oChaotic);
}
}
oChaotic = GetNextObjectInShape(SHAPE_SPHERE, FeetToMeters(20), lLoc);
}
}
//get a random number
int nRandom = Random(nOutsiders);
//Get the target
object oTarget = GetLocalObject(oPC, "oAxioStorm" + IntToString(nRandom));
//Deal acid damage
SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectDamage(oTarget, d6(5), DAMAGE_TYPE_ACID));
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_ACID), oTarget);
//another round down
nCount--;
nOutsiders=0;
if(nCount >0) DelayCommand(6.0f, DoAcid(nCount, lLoc, oPC));
}
}
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nCount = nCasterLvl;
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND)
{
fDur += fDur;
nCount += nCount;
}
//Apply AoE
effect eAoe = EffectAreaOfEffect(AOE_PER_AXIOMATIC_STORM);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAoe, lLoc, fDur);
DoAcid(nCount, lLoc, oPC);
PRCSetSchool();
}

View File

@@ -0,0 +1,60 @@
//:://////////////////////////////////////////////
//:: Name Axiomatic Storm On Enter
//:: FileName sp_axio_stormA.nss
//:://////////////////////////////////////////////
/** @file
Conjuration (Creation)
Level: Cleric 3, Paladin 3,
Components: V, S, M, DF,
Casting Time: 1 standard action
Area: Cylinder (20-ft. radius, 20 ft. high)
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: No
You call upon the forces of law and a heavy rain
begins to fall around you, its raindrops harsh and
metallic. Above you, a jet of caustic acid lances
down from the heavens.
A driving rain falls around you. It falls in a fixed
area once created. The storm reduces hearing and
visibility, resulting in a <20>4 penalty on Listen, Spot,
and Search checks. It also applies a <20>4 penalty on ranged
attacks made into, out of, or through the storm. Finally,
it automatically extinguishes any unprotected flames and
has a 50% chance to extinguish protected flames (such as
those of lanterns).
The rain damages chaotic creatures, dealing 2d6 points
of damage per round (chaotic outsiders take double damage).
In addition, each round, a gout of acid strikes a randomly
selected chaotic outsider within the spell's area, dealing
5d6 points of acid damage.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oTarget = GetEnteringObject();
object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
effect eLink = EffectLinkEffects(EffectSkillDecrease(SKILL_LISTEN, 4), EffectSkillDecrease(SKILL_SPOT, 4));
eLink = EffectLinkEffects(eLink, EffectSkillDecrease(SKILL_SEARCH, 4));
//Apply permanently, AoE exit will remove
SPApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget);
if GetWeaponRanged(oItem)
{
SPApplyEffectToObject(DURAITON_TYPE_TEMPORARY, EffectAttackDecrease(4), oTarget, 6.0f)
}
//Can't do hit penalty to ranged, approximate with hit chance
SPApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectConcealment(20, MISS_CHANCE_TYPE_VS_RANGED), oTarget);
}

View File

@@ -0,0 +1,60 @@
//:://////////////////////////////////////////////
//:: Name Axiomatic Storm
//:: FileName sp_axio_storm.nss
//:://////////////////////////////////////////////
/** @file
Conjuration (Creation)
Level: Cleric 3, Paladin 3,
Components: V, S, M, DF,
Casting Time: 1 standard action
Area: Cylinder (20-ft. radius, 20 ft. high)
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: No
You call upon the forces of law and a heavy rain
begins to fall around you, its raindrops harsh and
metallic. Above you, a jet of caustic acid lances
down from the heavens.
A driving rain falls around you. It falls in a fixed
area once created. The storm reduces hearing and
visibility, resulting in a <20>4 penalty on Listen, Spot,
and Search checks. It also applies a <20>4 penalty on ranged
attacks made into, out of, or through the storm. Finally,
it automatically extinguishes any unprotected flames and
has a 50% chance to extinguish protected flames (such as
those of lanterns).
The rain damages chaotic creatures, dealing 2d6 points
of damage per round (chaotic outsiders take double damage).
In addition, each round, a gout of acid strikes a randomly
selected chaotic outsider within the spell's area, dealing
5d6 points of acid damage.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oCaster = GetAreaOfEffectCreator();
object oTarget = GetExitingObject();
effect eToDispel = GetFirstEffect(oTarget);
while(GetIsEffectValid(eToDispel))
{
if(GetEffectSpellId(eToDispel) == SPELL_AXIOMATIC_STORM)
{
RemoveEffect(oTarget, eToDispel);
}
eToDispel = GetNextEffect(oTarget);
}
}
}

View File

@@ -0,0 +1,51 @@
//:://////////////////////////////////////////////
//:: Name Axiomatic Storm
//:: FileName sp_axio_storm.nss
//:://////////////////////////////////////////////
/** @file
Conjuration (Creation)
Level: Cleric 3, Paladin 3,
Components: V, S, M, DF,
Casting Time: 1 standard action
Area: Cylinder (20-ft. radius, 20 ft. high)
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: No
You call upon the forces of law and a heavy rain
begins to fall around you, its raindrops harsh and
metallic. Above you, a jet of caustic acid lances
down from the heavens.
A driving rain falls around you. It falls in a fixed
area once created. The storm reduces hearing and
visibility, resulting in a <20>4 penalty on Listen, Spot,
and Search checks. It also applies a <20>4 penalty on ranged
attacks made into, out of, or through the storm. Finally,
it automatically extinguishes any unprotected flames and
has a 50% chance to extinguish protected flames (such as
those of lanterns).
The rain damages chaotic creatures, dealing 2d6 points
of damage per round (chaotic outsiders take double damage).
In addition, each round, a gout of acid strikes a randomly
selected chaotic outsider within the spell's area, dealing
5d6 points of acid damage.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oTarget = GetEnteringObject();
object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
if GetWeaponRanged(oItem)
{
SPApplyEffectToObject(oTarget, EffectAttackDecrease(4), 6.0f);
}
}

View File

@@ -0,0 +1,45 @@
//:://////////////////////////////////////////////
//:: Name Axiomatic Water
//:: FileName sp_axiowater.nss
//:://////////////////////////////////////////////
/** @file Transmutation [Lawful]
Level: Cleric 1, Paladin 1,
Components: V, S, M,
Casting Time: 1 minute
Range: Touch
Target: Flask of water touched
Duration: Instantaneous
Saving Throw: Will negates (object)
Spell Resistance: Yes (object)
You speak the ancient, slippery words as you pour the iron and silver into the flask. Despite the fact that there is more powder than will fit in the container, all of it dissolves, leaving a flask of water dotted with motes of gunmetal gray.
This transmutation imbues a flask (1 pint) of water with the order of law, turning it into axiomatic water. Axiomatic water damages chaotic outsiders the way holy water damages undead and evil outsiders. A flask of axiomatic water can be thrown as a splash weapon. Treat this attack as a ranged touch attack with a range increment of 10 feet. A flask breaks if thrown against the body of a corporeal creature, but to use it against an incorporeal creature, the bearer must open the flask and pout the axiomatic water out onto the target. Thus, a character can douse an incorporeal creature with axiomatic water only if he is adjacent to it. Doing so is a ranged touch attack that does not provoke attacks of opportunity.
A direct hit by a flask of axiomatic water deals 2d4 points of damage to a chaotic outsider. Each such creature within 5 feet of the point where the flask hits takes 1 point of damage from the splash.
Material Component: 5 pounds of powdered iron and silver (worth 25 gp).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/10/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
CreateItemOnObject("prc_axiowater", oPC, 1);
PRCSetSchool();
PRCSetSchool();
}

View File

@@ -0,0 +1,69 @@
//:://////////////////////////////////////////////
//:: Name Bladebane
//:: FileName sp_bladebane.nss
//:://////////////////////////////////////////////
/** @file Transmutation
Level: Paladin 2, Cleric 3, Sorcerer 4, Wizard 4,
Components: V, S, M,
Casting Time: 1 standard action
Range: Touch
Target: Weapon touched
Duration: 1 round/level
Saving Throw: Will negates (harmless, object)
Spell Resistance: Yes (harmless, object)
You impart a deadly quality to a single bladed weapon
(any slashing weapon) for a short time.
Bladebane confers the bane ability on the weapon touched,
against a creature type (and subtype, if necessary) of
your choice.
The weapon's enhancement bonus increases by +2 against
the appropriate creature type, and it deals +2d6 points
of bonus damage to those creatures.
Material Component: A drop of blood and ruby dust worth 500 gp.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/27/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
object oWeapon = PRCGetSpellTargetObject();
//only bladed
if(GetDamageTypeOfWeapon(oWeapon) != DAMAGE_TYPE_SLASHING)
{
SendMessageToPC(oPC, "Invalid target. This spell must target slashing weapons.");
return;
}
//+2 increase
int nBonus = IPGetWeaponEnhancementBonus(oWeapon) + 2;
//convo for race
SetLocalInt(oPC, "BladebaneRace");
StartDynamicConversation("prc_c_bladebane", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
int nRace = GetLocalInt(oPC, "BladebaneRace");
itemproperty iEnhance = ItemPropertyEnhancementBonusVsRace(nRace, nBonus)
itemproperty iDam = ItemPropertyDamageBonusVsRace(nRace, IP_CONST_DAMAGETYPE_SLASHING, IP_CONST_DAMAGEBONUS_2d6);
IPSafeAddItemProperty(oWeapon, iEnhance, fDur);
IPSafeAddItemProperty(oWeapon, iDam, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,65 @@
//:://////////////////////////////////////////////
//:: Name Blaze of Light
//:: FileName sp_blazelight.nss
//:://////////////////////////////////////////////
/** @file Evocation [Light]
Level: Paladin 1, Druid 2,
Components: V, S,
Casting Time: 1 standard action
Range: 60 ft.
Area: Cone
Duration: Instantaneous
Saving Throw: Fortitude negates
Spell Resistance: Yes
A cone of bright light shines forth from just above the caster's head.
All creatures within the cone that fail a Fortitude saving throw are dazzled for 1 minute.
Sightless creatures are not affected by blaze of light.
A light spell (one with the light descriptor) counters and dispels a darkness spell
(one with the darkness descriptor) of an equal or lower level.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/10/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_EVOCATION);
object oPC = OBJECT_SELF;
float fDur = 60.0f;
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
effect eVis = EffectVisualEffect(VFX_IMP_HEAD_HOLY);
float fRadius = FeetToMeters(60);
location lLoc = PRCGetSpellTargetLocation();
effect eDazzled = EffectLinkEffects(EffectAttackDecrease(1), EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED));
eDazzled = EffectLinkEffects(eDazzled, EffectSkillDecrease(SKILL_SPOT, 1));
eDazzled = EffectLinkEffects(eDazzled, EffectSkillDecrease(SKILL_SEARCH, 1));
object oTarget = MyFirstObjectInShape(SHAPE_SPELLCONE, fRadius, lLoc, TRUE);
while(GetIsObjectValid(oTarget))
{
//Resist
if(!PRCDoResistSpell(OBJECT_SELF, oTarget,CasterLvl) && (oTarget != OBJECT_SELF))
{
//Fort Save
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, PRCGetSaveDC(oTarget, oPC), SAVING_THROW_TYPE_SPELL, oPC))
{
//Not blind
if(!GetHasEffect(EFFECT_TYPE_BLINDNESS, oTarget))
{
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDazzled, oTarget, fDur);
}
}
}
MyNextObjectInShape(SHAPE_SPELLCONE, fRadius, lLoc, TRUE);
}
PRCSetSchool();
}

View File

@@ -0,0 +1,45 @@
//:://////////////////////////////////////////////
//:: Name Blessed Aim
//:: FileName sp_blessedaim.nss
//:://////////////////////////////////////////////
/** @file Divination
Level: Blackguard 1, Cleric 1, Paladin 1,
Components: V, S,
Casting Time: 1 standard action
Range: 50 ft.
Effect: 50-ft.-radius spread centered on you
Duration: 1 minute/level
Saving Throw: Will negates (harmless)
Spell Resistance: No
With the blessing of your deity, you bolster your
allies' aim with an exhortation.
This spell grants your allies within the spread
a +2 morale bonus on ranged attack rolls.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On:
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_DIVINATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = 60 * nCasterLvl;
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
effect eAOE = EffectAreaOfEffect(AOE_PER_BLESSEDAIM);
SPApplyEffectToObejct(DURATION_TYPE_TEMPORARY, eAOE, oPC, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_PULSE_HOLY), oPC);
PRCSetSchool();
}

View File

@@ -0,0 +1,47 @@
//:://////////////////////////////////////////////
//:: Name Blessed Aim on Enter
//:: FileName sp_blessedaimA.nss
//:://////////////////////////////////////////////
/** @file
Blessed Aim
Divination
Level: Blackguard 1, Cleric 1, Paladin 1,
Components: V, S,
Casting Time: 1 standard action
Range: 50 ft.
Effect: 50-ft.-radius spread centered on you
Duration: 1 minute/level
Saving Throw: Will negates (harmless)
Spell Resistance: No
With the blessing of your deity, you bolster your allies' aim with an exhortation.
This spell grants your allies within the spread a +2 morale bonus on ranged attack rolls.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On:
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
location lLoc = GetLocation(OBJECT_SELF);
object oItem;
object oTarget = GetEnteringObject();
{
oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
if(GetIsReactionTypeFriendly(oTarget))
{
if GetWeaponRanged(oItem)
{
SPApplyEffectToObject(oTarget, EffectAttackIncrease(2), 6.0f)
}
}
}
}

View File

@@ -0,0 +1,32 @@
//::///////////////////////////////////////////////
//:: Name Blessed Aim On Exit
//:: FileName sp_blessedaimB.nss
//:://////////////////////////////////////////////
/**@file
Author: Tenjac
Created: 1/27/21
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "prc_inc_spells"
#include "prc_add_spell_dc"
void main()
{
object oCaster = GetAreaOfEffectCreator();
object oTarget = GetExitingObject();
effect eToDispel = GetFirstEffect(oTarget);
while(GetIsEffectValid(eToDispel))
{
if(GetEffectSpellId(eToDispel) == SPELL_BLESSED_AIM)
{
RemoveEffect(oTarget, eToDispel);
}
eToDispel = GetNextEffect(oTarget);
}
}
}

View File

@@ -0,0 +1,47 @@
//:://////////////////////////////////////////////
//:: Name Blessed Aim Heartbeat
//:: FileName sp_blessedaimc.nss
//:://////////////////////////////////////////////
/** @file
Blessed Aim
Divination
Level: Blackguard 1, Cleric 1, Paladin 1,
Components: V, S,
Casting Time: 1 standard action
Range: 50 ft.
Effect: 50-ft.-radius spread centered on you
Duration: 1 minute/level
Saving Throw: Will negates (harmless)
Spell Resistance: No
With the blessing of your deity, you bolster your allies' aim with an exhortation.
This spell grants your allies within the spread a +2 morale bonus on ranged attack rolls.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On:
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
location lLoc = GetLocation(OBJECT_SELF);
object oItem;
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(50.0), lLoc, FALSE, OBJECT_TYPE_CREATURE);
{
oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
if(GetIsReactionTypeFriendly(oTarget)
{
if GetWeaponRanged(oItem)
{
SPApplyEffectToObject(oTarget, EffectAttackIncrease(2), 6.0f)
}
}
oTarget = GetNextObjectInShape(SHAPE_SPHERE, FeetToMeters(50.0), lLoc, FALSE, OBJECT_TYPE_CREATURE);
}

View File

@@ -0,0 +1,61 @@
//:://////////////////////////////////////////////
//:: Name Blessing of the Righteous
//:: FileName sp_blessright.nss
//:://////////////////////////////////////////////
/** @file
Blessing of the Righteous
Evocation [Good]
Level: Cleric 4, Paladin 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: 40 ft.
Area: All allies in a 40-ft.-radius burst centered on you
Duration: 1 round/level
Saving Throw: Will negates (harmless)
Spell Resistance: Yes (harmless)
A sudden burst of warm, radiant light engulfs you and your allies.
The light fades quickly but lingers on the weapons of those affected.
You bless yourself and your allies.
You and your allies'melee and ranged attacks deal an extra 1d6 points
of holy damage and are considered good-aligned for the purpose of
overcoming damage reduction.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/26/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_EVOCATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
location lLoc = PRCGetSpellTargetLocation();
int nBonus = DAMAGE_BONUS_1d6;
if (nMetaMagic & METAMAGIC_EXTEND) fDur *= 2;
if (nMetaMagic & METAMAGIC_MAXIMIZE) nBonus = DAMAGE_BONUS_6;
object oTarget = GetFirstObjectinShape(SHAPE_SPHERE, FeetToMeters(40.0), lLoc);
while (GetIsObjectValid(oTarget))
{
//if it's friendly
if(GetIsReactionTypeFriendly(oTarget))
{
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectDamageIncrease(nBonus, DAMAGE_TYPE_POSITIVE), oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HOLY_AID), oTarget);
}
OTarget = GetNextObjectInShape(SHAPE_SPHERE, FeetToMeters(40.0), lLoc);
PRCSetSchool();
}

View File

@@ -0,0 +1,49 @@
//:://////////////////////////////////////////////
//:: Name Call Mount
//:: FileName sp_callmount.nss
//:://////////////////////////////////////////////
/** @file Conjuration (Calling) [Good]
Level: Paladin 2,
Components: V,
Casting Time: 1 round
Range: 10 ft.
Effect: Your special mount
Duration: 1 hour/level (D)
Saving Throw: None
Spell Resistance: No
You summon your special mount from the celestial
planes where it resides.
This works exactly as your normal, spell-like class a
bility to summon the creature, except that the duration
is shorter and you are not limited in how many times
you can call the mount in a day (except by how many
times you can cast call mount).
You can cast this spell even if you have already
called your mount using your class ability on the same day.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 8/9/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_CONJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = HoursToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
HorseSummonPaladinMount();
PRCSetSchool();
}

View File

@@ -0,0 +1,98 @@
//:://////////////////////////////////////////////
//:: Name Castigate
//:: FileName sp_castigate.nss
//:://////////////////////////////////////////////
/** @file Evocation [Sonic]
Level: Cleric 4, Paladin 4, Purification 4,
Components: V,
Casting Time: 1 standard action
Range: 10 ft.
Area: 10-ft.-radius burst centered on you
Duration: Instantaneous
Saving Throw: Fortitude half
Spell Resistance: Yes
Shouting your deity's teachings, you rebuke your foes with the magic
of your sacred words.
This spell has no effect on creatures that cannot hear.
All creatures whose alignment differs from yours on both
the law<61>chaos and the good<6F>evil axes take 1d4 points of damage
per caster level (maximum 10d4). All creatures whose alignment
differs from yours on one component take half damage, and this
spell does not deal damage to those who share your alignment.
A Fortitude saving throw reduces damage by half.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_EVOCATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
int nDC = PRCGetSaveDC(oTarget, oPC);
float fDur = 3600 * nCasterLvl;
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
location lLoc = PRCGetSpellTargetLocation();
int nAlignGE = GetAlignmentGoodEvil(oPC);
int nAlignLC = GetAlignmentLawChaos(oPC);
int nTargetAlignGE;
int nTargetAlignLC;
int nDam;
int nLevels = min(10, nCasterLvl);
float fRadius = FeetToMeters(10);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_HOWL_WAR_CRY), oPC);
object oTarget = (MyFirstObjectInShape(SHAPE_SPHERE, fRadius. lLoc, FALSE));
while(GetIsObjectValid(oTarget))
{
//Not deaf
if(GetHasEffect(EFFECT_TYPE_DEAF, oTarget) == FALSE)
{
//SR
if(!PRCDoResistSpell(oPC, oTarget, nCasterLvl + SPGetPenetr()))
{
nTargetAlignGE = GetAlignmentGoodEvil(oTarget);
nTargetAlignLC = GetAlignmentLawChaos(oTarget);
//Test alignment differences
//Both
if(nAlignGE != nTargetAlignGE) && (nAlignLC != nTargetAlignLC)
{
nDam = d4(nLevels);
}
//Half for one
else if(nAlignGE != nTargetAlignGE) || (nAlignLC != nTargetAlignLC)
{
nDam = d4(nLevels)/2;
}
//save for half
if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_DIVINE))
{
nDam = nDam/2;
}
if(nDam > 0)
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDam, DAMAGE_TYPE_DIVINE), oTarget);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectvisualEffect(VFX_IMP_HEAD_HOLY), oTarget);
}
}
}
oTarget = MyNextObjectInShape(SHAPE_SPHERE, fRadius. lLoc, FALSE);
}
PRCSetSchool();
}

View File

@@ -0,0 +1,72 @@
//:://////////////////////////////////////////////
//:: Name Checkmate's Light
//:: FileName sp_chkmlt.nss
//:://////////////////////////////////////////////
/** @file Evocation [Lawful]
Level: Paladin 2, Cleric 3,
Components: V, S, DF,
Casting Time: 1 standard action
Range: Touch
Target: Melee weapon touched
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: No
You intone your deity's name and the weapon you touch hums a
harmonic response before it lights up with a soothing red glow.
You imbue the touched weapon with a +1 enhancement bonus per
three caster levels (maximum +5 at 15th level), and it is treated
as lawful-aligned for the purpose of overcoming damage reduction.
In addition, you can cause it to cast a red glow as bright as a torch.
Any creature within the radius of its clear illumination (20 feet)
gets a +1 morale bonus on saving throws against fear effects.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/14/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_EVOCATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
object oWeapon = PRCGetSpellCastItem(oPC);
object oTarget = PRCGetSpellTargetObject(oPC);
if (GetIsObjectValid(oWeapon))
{
int nBonus = min(nCasterLvl, 15)/3;
//Simulating lawful as +3, so give +3 enhancement and penalty to damage and hit to offset
if(nBonus == 1)
{
AddItemProperty(oWeapon, DURATION_TYPE_TEMPORARY, ItemPropertyAttackPenalty(2), fDuration);
AddItemProperty(oWeapon, DURATION_TYPE_TEMPORARY, ItemPropertyDamagePenalty(2), fDuration);
nBonus=3;
}
if (nBonus == 2)
{
AddItemProperty(oWeapon, DURATION_TYPE_TEMPORARY, ItemPropertyAttackPenalty(1), fDuration);
AddItemProperty(oWeapon, DURATION_TYPE_TEMPORARY, ItemPropertyDamagePenalty(1), fDuration);
nBonus=3;
}
IPSafeAddItemProperty(oWeapon, DURATION_TYPE_TEMPORARY, ItemPropertyEnhancementBonus(nBonus), fDuration);
IPSafeAddItemProperty(oWeapon, DURATION_TYPE_TEMPORARY, ItemPropertyVisualEffect(ITEM_VISUAL_EVIL), fDuration);
PRCSetSchool();
}

View File

@@ -0,0 +1,45 @@
//:://////////////////////////////////////////////
//:: Name Clear Mind
//:: FileName sp_clearmind.nss
//:://////////////////////////////////////////////
/** @file
Clear Mind
Abjuration
Level: Paladin 1
Components: V, S, DF,
Casting Time: 1 standard action
Range: Personal
Target: You
Duration: 10 minutes/level
A silver glow sheathes your body as you complete the spell. As the glow fades, you feel a touch
of the divine at the back of your mind. This divine touch spreads until you feel your concerns
and anxieties fade away.
You gain a +4 sacred bonus on saving throws made against mind-affecting spells and effects.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/23/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = 600 * nCasterLvl;
effect eVis = EffectVisualEffect(VFX_DUR_AURA_BLUE_LIGHT);
effect eBuff = EffectSavingThrowIncrease(SAVING_THROW_ALL, 4, SAVING_THROW_TYPE_MIND_SPELLS);
SPApplyEffectToObject(oPC, DURATION_TYPE_TEMPORARY, eVis, 3.0f);
SPApplyEffectToObject(oPC, DURATION_TYPE_TEMPORARY, eBuff, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,47 @@
//:://////////////////////////////////////////////
//:: Name Cloak of Bravery
//:: FileName sp_cloakbrave.nss
//:://////////////////////////////////////////////
/** @file
Abjuration [Mind-Affecting]
Level: Paladin 2, Cleric 3, Courage 3,
Components: V, S,
Casting Time: 1 standard action
Range: 60 ft.
Area: 60-ft.-radius emanation centered on you
Duration: 10 minutes/level
Saving Throw: Will negates (harmless)
Spell Resistance: Yes (harmless)
Summoning up your courage, you throw out your arm and sweep
it over the area, cloaking all your allies in a glittering
mantle of magic that bolsters their bravery.
All allies within the emanation (including you) gain a morale
bonus on saves against fear effects equal to your caster level
(to a maximum of +10 at caster level 10th).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = HoursToSeconds(nCasterLvl)/6;
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAreaOfEffect(VFX_MOB_CLOAK_OF_BRAVERY), oPC, fDur);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_LIGHT_WHITE_20), oPC, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,49 @@
//:://////////////////////////////////////////////
//:: Name Cloak of Bravery On Enter
//:: FileName sp_cloakbraveA.nss
//:://////////////////////////////////////////////
/** @file
Abjuration [Mind-Affecting]
Level: Paladin 2, Cleric 3, Courage 3,
Components: V, S,
Casting Time: 1 standard action
Range: 60 ft.
Area: 60-ft.-radius emanation centered on you
Duration: 10 minutes/level
Saving Throw: Will negates (harmless)
Spell Resistance: Yes (harmless)
Summoning up your courage, you throw out your arm and sweep
it over the area, cloaking all your allies in a glittering
mantle of magic that bolsters their bravery.
All allies within the emanation (including you) gain a morale
bonus on saves against fear effects equal to your caster level
(to a maximum of +10 at caster level 10th).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oCreator = GetAreaOfEffectCreator();
int nCasterLvl = PRCGetCasterLevel(oCreator);
float fDur = HoursToSeconds(nCasterLvl)/6;
object oTarget = GetEnteringObject();
int nBonus = min(10, nCasterLvl);
if(GetFactionEqual(oCreator))
{
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSavingThrowIncrease(SAVING_THROW_ALL, nBonus, SAVING_THROW_TYPE_FEAR), oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HEAD_HOLY), oTarget);
}
PRCSetSchool();
}

View File

@@ -0,0 +1,51 @@
//:://////////////////////////////////////////////
//:: Name Cloak of Bravery On Exit
//:: FileName sp_cloakbraveB.nss
//:://////////////////////////////////////////////
/** @file
Abjuration [Mind-Affecting]
Level: Paladin 2, Cleric 3, Courage 3,
Components: V, S,
Casting Time: 1 standard action
Range: 60 ft.
Area: 60-ft.-radius emanation centered on you
Duration: 10 minutes/level
Saving Throw: Will negates (harmless)
Spell Resistance: Yes (harmless)
Summoning up your courage, you throw out your arm and sweep
it over the area, cloaking all your allies in a glittering
mantle of magic that bolsters their bravery.
All allies within the emanation (including you) gain a morale
bonus on saves against fear effects equal to your caster level
(to a maximum of +10 at caster level 10th).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oCaster = GetAreaOfEffectCreator();
object oTarget = GetExitingObject();
effect eToDispel = GetFirstEffect(oTarget);
while(GetIsEffectValid(eToDispel))
{
if(GetEffectSpellId(eToDispel) == SPELL_CLOAK_OF_BRAVERY)
{
RemoveEffect(oTarget, eToDispel);
}
eToDispel = GetNextEffect(oTarget);
}
}
}

View File

@@ -0,0 +1,61 @@
//:://////////////////////////////////////////////
//:: Name Conduit of Life
//:: FileName sp_conduitlife.nss
//:://////////////////////////////////////////////
/** @file Conjuration (Healing)
Level: Cleric 2, Paladin 2,
Components: V, S,
Casting Time: 1 standard action
Range: Personal
Target: You
Duration: 10 minutes/level or until discharged
A small kernel of positive energy grows within your
heart, warming your whole body.
The next time you use a class feature or racial ability
to channel positive energy (such as turn undead or lay on hands),
you also heal a number of points of damage to yourself equal to
2d10+1/caster level (maximum 10).
If you are already subject to an ongoing healing effect
(such as vigor), or if you receive a cure spell while conduit
of life is still in effect, this spell instead heals a number of
points of damage equal to 3d8+1/caster level and it is discharged.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 8/5/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_CONJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = nCasterLvl * 600.0f;
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
//Apply VFX
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_PULSE_YELLOW_WHITE), oPC, fDur);
//Ongoing healing triggering
effect eTest = GetFirstEffect(oTarget);
while(GetIsEffectValid(eTest))
{
if (eTest == EffectRegenerate())
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectHeal(d8(3) + nCasterLvl), oPC);
PRCRemoveSpellEffects(SPELL_CONDUIT_OF_LIFE, oPC, oPC);
break;
}
eTest = GetNextEffect(oTarget);
}
PRCSetSchool();
}

View File

@@ -0,0 +1,62 @@
//:://////////////////////////////////////////////
//:: Name Curse of the Brute
//:: FileName sp_cursebrute.nss
//:://////////////////////////////////////////////
/** @file Transmutation
Level: Paladin 2, Cleric 3,
Components: V, S,
Casting Time: 1 action
Range: Touch
Target: Creature touched
Duration: 1 round/level
Saving Throw: Fortitude negates
Spell Resistance: Yes
You can grant an enhancement bonus up to +1 per caster
level to one physical ability of the creature touched
(Strength, Constitution, or Dexterity).
However, this temporarily suppresses both the creature's
Intelligence and Charisma, each by the amount of the
enhancement bonus. If this lowers any ability below 3,
the spell fails.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/17/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
int nAbilBuff;
object oTarget = PRCGetSpellTargetObject();
int nSpell = PRCGetSpellId();
//Get ability by which spell is used
if (nSpell == SPELL_CURSE_BRUTE_STR) nAbilBuff = ABILITY_STRENGTH;
if (nSpell == SPELL_CURSE_BRUTE_DEX) nAbilBuff = ABILITY_DEXTERITY;
if (nSpell == SPELL_CURSE_BRUTE_CON) nAbilBuff = ABILITY_CONSTITUTION;
//Get maximum bonus without lowering either stat below 3
int nBonus = min(GetAbilityScore(oTarget, ABILITY_CHARISMA), GetAbilityScore(oTarget, ABILITY_INTELLIGENCE)) - 3;
nBonus = min(nCasterLvl, nBonus);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityIncrease(nAbilBuff, nBonus), oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_INTELLIGENCE, nBonus), oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_CHARISMA, nBonus), oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_RED_LIGHT), oTarget, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,93 @@
//:://////////////////////////////////////////////
//:: Name Denounce
//:: FileName sp_denounce.nss
//:://////////////////////////////////////////////
/** @file
Enchantment [Mind-Affecting]
Level: Cleric 2, Paladin 2
Components: V, S,
Casting Time: 1 standard action
Range: Close (25 ft. + 5 ft./2 levels)
Target: One outsider
Duration: 1 min./level (D); see text
Saving Throw: Will negates; see text
Spell Resistance: Yes
You point your finger and pronounce judgment.
You instill feelings of shame and guilt in a target outsider, imposing a -4 insight penalty
on its attack rolls, saves, and checks. Each round on its turn, the subject can attempt a new
saving throw to end the effect.
(This is a full-round action that does not provoke attacks of opportunity).
Outsiders with the good subtype are immune to denounce.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 5/25/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void SaveCheck(object oTarget, object oPC, int nRounds)
{
if(GetHasSpellEffect(SPELL_DENOUNCE, oTarget))
{
//Save
if(PRCMySavingThrow(SAVING_THROW_WILL, oTarget, PRCGetSaveDC(oTarget, OBJECT_SELF)))
{
RemoveSpellEffects(SPELL_DENOUNCE);
}
//Loop for another round
else
{
nRounds--;
DelayCommand(6.0f, SaveCheck(oTarget, oPC, nRounds));
}
}
}
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ENCHANTMENT);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = 60.0f *(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
object oTarget = SPGetSpellTargetObject();
int nPenetr = nCaster + SPGetPenetr();
if(GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
{
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_OUTSIDER)
{
//No good subtypes, interpret as good alignment
if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_GOOD)
{
SendMessageToPC(oPC, "Outsiders of good alignment are immune to Denounce."
}
//Non-good outsider; resolve spell
else
{
//SR
if(!PRCDoResistSpell(oCreator, oTarget, nPenetr))
{
//Save
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, PRCGetSaveDC(oTarget, OBJECT_SELF)))
{
effect eLink = EffectLinkEffects(EffectAttackDecrease(4), EffectSavingThrowDecrease(SAVING_THROW_ALL, 4));
eLink = EffectLinkEffects(eLink, EffectSkillDecrease(SKILL_ALL_SKILLS, 4));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_AURA_PULSE_ORANGE_WHITE));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, fDur);
DelayCommand(6.0f, SaveCheck(oTarget, oPC, FloatToInt(fDur / 6)));
}
}
}
}
PRCSetSchool();
}

View File

@@ -0,0 +1,48 @@
//:://////////////////////////////////////////////
//:: Name Devastating Smite
//:: FileName sp_devsmite.nss
//:://////////////////////////////////////////////
/** @file Transmutation
Level: Blackguard 1, Cleric 1, Paladin 1,
Components: V, S, DF,
Casting Time: 1 swift action
Range: Touch
Target: Creature touched
Duration: 1 round or until discharged; see text
Saving Throw: Will negates (harmless)
Spell Resistance: Yes (harmless)
The next smite attack made by the subject deals double
its normal smite damage. For instance, a 9th-level paladin
normally deals an extra 9 points of damage with her smite
evil ability. Under the effect of this spell, she would
deal an extra 18 points of damage. The spell applies to
only one smite attack; if that attack misses, the spell
is lost without effect.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(1);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
//Apply VFX, handle damage in smite script
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_PULSE_ORANGE_WHITE), oPC, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,77 @@
//:://////////////////////////////////////////////
//:: Name Diamondsteel
//:: FileName sp_diamondsteel.nss
//:://////////////////////////////////////////////
/** @file
Diamondsteel
Transmutation
Level: Paladin 3, Sorcerer 3, Wizard 3,
Components: V, S, M,
Casting Time: 1 standard action
Range: Touch
Target: Suit of metal armor touched
Duration: 1 round/level
Saving Throw: Will negates (object)
Spell Resistance: Yes (object)
You pass your hand over the suit of armor several times before finally touching it.
As you do so, you feel a warmth grow in the palm of your hand. The warmth passes into
the armor and manifests as a sparkling shine.
Diamondsteel enhances the strength of one suit of metal armor. The armor provides
damage reduction equal to half the AC bonus of the armor. This damage reduction can
be overcome only by adamantine weapons. For example, a suit of full plate would provide
damage reduction 4/adamantine, and a +1 breastplate (+6 AC) would provide damage reduction
3/adamantine.
Material Component: Diamond dust worth at least 50 gp.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/23/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
int oTarget = SPGetSpellTargetObject();
if(GetObjectType(oTarget)) == OBJECT_TYPE_ITEM
{
oArmor = oTarget;
}
if(GetObjectType(oTarget)) == OBJECT_TYPE_CREATURE
{
oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget);
}
int nMetaMagic = PRCGetMetaMagicFeat();
int nAC = GetBaseAC(oArmor);
//Must be metal
if(nAC > 3)
{
if(nMetaMagic & METAMAGIC_EXTEND)
{
fDur += fDur;
}
//Get amount for bonus - includes any +
int nBonus = GetItemACValue(oArmor)/2;
//Adamantine is x/+5
effect eDR = EffectDamageReduction(nBonus, DAMAGE_POWER_PLUS_FIVE);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDR, oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_AC_BONUS), oTarget);
}
else SendMessageToPC(oPC, "Invalid target. Target armor must be metal."
PRCSetSchool();
}

View File

@@ -0,0 +1,107 @@
//:://////////////////////////////////////////////
//:: Name Energy Shield
//:: FileName sp_enshield.nss
//:://////////////////////////////////////////////
/** @file Abjuration
Level: Paladin 2, Cleric 3
Components: V, S, DF,
Casting Time: 1 Standard Action
Range: Touch
Target: Shield touched
Duration: 1 round/level
Saving Throw: None
Spell Resistance: No
A silver aura surrounds the touched shield for a
moment before it appears to transform into the chosen
type of energy. The shield hums with power.
When this spell is cast, the shield touched appears
to be made entirely out of one type of energy (fire,
cold, electricity, acid, or sonic). Whoever bears the
shield gains resistance 10 against the chosen energy
type. Additionally, if the wielder successfully hits
someone with the shield with a shield bash attack, th
e victim takes 2d6 points of the appropriate energy
damage in addition to the normal shield bash damage.
The energy type must be chosen when the spell is cast
and cannot be changed during the duration of the spell.
The energy resistance overlaps (and does not stack)
with resist elements. A given shield cannot be the
subject of more than one lesser energized shield
or energized shield spell at the same time.
The descriptor of this spell is the same as the
energy type you choose when you cast it.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/19/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
#include "prc_inc_fork"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
object oTarget = PRCGetSpellTargetObject();
object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
//Check that this is a shield, if not abort
if(GetIsShield(oShield) == FALSE)
{
SendMessageToPC(OBJECT_SELF, "Target has no equipped shield.");
break;
}
//The type of damage resistance we're choosing
int nDR;
//Get the type by which subradial spell is used to cast
int nSpell = GetSpellId();
if(nSpell == SPELL_ENERGIZED_SHIELD_FIRE)
{
nDR = IP_CONST_DAMAGETYPE_FIRE;
SetLocalInt(oTarget, "EnShieldType", DAMAGE_TYPE_FIRE);
}
if(nSpell == SPELL_ENERGIZED_SHIELD_COLD)
{
nDR = IP_CONST_DAMAGETYPE_COLD;
SetLocalInt(oTarget, "EnShieldType", DAMAGE_TYPE_COLD);
}
if(nSpell == SPELL_ENERGIZED_SHIELD_ELEC)
{
nDR = IP_CONST_DAMAGETYPE_ELECTRICAL;
SetLocalInt(oTarget, "EnShieldType", DAMAGE_TYPE_ELECTRICAL);
}
if(nSpell == SPELL_ENERGIZED_SHIELD_ACID)
{
nDR = IP_CONST_DAMAGETYPE_ACID;
SetLocalInt(oTarget, "EnShieldType", DAMAGE_TYPE_ACID);
}
if(nSpell == SPELL_ENERGIZED_SHIELD_SONIC)
{
nDR = IP_CONST_DAMAGETYPE_SONIC;
SetLocalInt(oTarget, "EnShieldType", DAMAGE_TYPE_SONIC);
}
//Set local int for amount of shield damage on the wielder of the shield
SetLocalInt(oTarget, "EnShieldD6", 2);
//Schedule ints for deletion
DelayCommand(fDur, DeleteLocalInt(oTarget, "EnShieldType"));
DelayCommand(fDur, DeleteLocalInt(oTarget, "EnShieldD6"));
//Add resistance property
IPSafeAddItemProperty(oShield, ItemPropertyDamageResistance(nDR, 10), fDur, X2_IP_ADDPROP_POLICY_KEEP_EXISTING);
PRCSetSchool();
}

View File

@@ -0,0 +1,105 @@
//:://////////////////////////////////////////////
//:: Name Estana's Stew
//:: FileName sp_estanasstew.nss
//:://////////////////////////////////////////////
/** @file Conjuration (Healing)
Level: Cleric 2, Druid 2, Paladin 2,
Components: V, S, AF,
Casting Time: 1 round
Range: 0 ft.
Effect: Fills pot with healing stew (1 serving/2 levels)
Duration: Instantaneous (see text)
Saving Throw: Will half (harmless); see text
Spell Resistance: Yes (harmless)
This spell calls upon Estanna, goddess of hearth and home
, to fill a specially crafted stewpot with a potent healing stew.
The caster must be hold the pot in hand when Estanna's stew
is cast; otherwise, the spell fails and is wasted.
The spell creates one serving per two caster levels (maximum 5).
A single serving heals 1d6+1 points of damage and requires
a standard action to consume. Any portion of the stew that
is not consumed disappears after 1 hour.The stew can be
splashed onto a single undead creature within 10 feet.
If a ranged touch attack succeeds, the undead creature
takes 1d6+1 points of damage per serving splashed on it.
The undead creature can apply spell resistance and can
attempt a Will save to take half damage.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/20/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nSpell = GetSpellId();
if (nSpell == SPELL_ESTANAS_STEW)
{
object oItem = CreateItemOnObject("prc_estanasstew", oPC, 1);
int nServings = min(5, (nCasterLvl/2));
SetItemCharges(oItem, nServings);
}
if (nSpell == SPELL_ESTANAS_STEW_EAT)
{
int nHeal = d6(1) + 1;
SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectHeal(nHeal), oPC);
}
if (nSpell == SPELL_ESTANAS_STEW_SPLASH)
{
object oItem = PRCGetSpellCastItem(OBJECT_SELF);
object oTarget = GetSpellTargetObject();
if(GetIsObjectValid(oTarget))
{
nTouch = TouchAttackRanged(oTarget);
}
// Check if we hit, or even have anything to hit!
if(nTouch >= 1)
{
int nServings = GetItemCharges(oItem);
//Chuck all of it
int nDam = (d6(1) + 1) * nServings;
// Critical hit?
if(nTouch == 2)
{
nDam *= 2;
}
int nPenetr = SPGetPenetr();
//Resist
if(!PRCDoResistSpell(OBJECT_SELF, oTarget nPenetr);
{
if(PRCMySavingThrow(SAVING_THROW_WILL, oTarget, PRCGetSaveDC(oTarget, OBJECT_SELF)))
{
nDam = nDam/2'
}
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD)
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectDamage(oTarget, nDam, DAMAGE_TYPE_DIVINE), oTarget);
}
}
SPApplyEffectToObject(DURATION_TYPER_INSTANT, EffectVisualEffect(VFX_COM_CHUNK_YELLOW_SMALL), oTarget);
}
//Remove the object
DestroyObject(oItem);
}
PRCSetSchool();
}

View File

@@ -0,0 +1,72 @@
//:://////////////////////////////////////////////
//:: Name Favor of the Martyr
//:: FileName sp_favormartyr.nss
//:://////////////////////////////////////////////
/** @file
Necromancy
Level: Paladin 4,
Components: V, S,
Casting Time: 1 standard action
Range: Medium (100 ft. + 10 ft./level)
Target: One willing creature
Duration: 1 minute/level
Saving Throw: None
Spell Resistance: Yes (harmless)
Calling upon the saints of your order, you imbue the person
in need with the power to resist the dire forces arrayed
against you.
The subject gains immunity to nonlethal damage, charm and
compulsion effects, and attacks that function specifically
by causing pain, such as the wrack spell (see page 243). it
is further immune to effects that would cause it to be dazed,
exhausted, fatigued, nauseated, sickened, staggered, or stunned.
The subject remains conscious at -1 to -9 hit points and can
take a single action each round while in that state, and does
not lose hit point for acting. If any of the above conditions
were in effect on the subject at the time of casting, they are
suspended for the spell's duration. (Thus, an unconscious
subject becomes conscious and functional.)
When the spell ends, any effects suspended by the spell that
have not expired in the interim (such as the fatigued condition,
which normally requires 8 hours of rest to recover from) return.
Effects that expired during the duration of this spell do not
resume when it ends.
In addition to these effects, the subject gains the benefit of
the Endurance feat for the duration of the spell.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/29/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_NECROMANCY);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = 60.0f * (nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
object oTarget = PRCGetSpellTargetObject();
//Immunities
effect eLink = EffectLinkEffects(EffectImmunity(IMMUNITY_TYPE_CHARM), EffectImmunity(IMMUNITY_TYPE_DAZED));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_STUN));
//+4 Save vs Death
eLink = EffectLinkEffects(eLink, EffectSavingThrowIncrease(SAVING_THROW_ALL, 4, SAVING_THROW_TYPE_DEATH));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,67 @@
//:://////////////////////////////////////////////
//:: Name Forceward
//:: FileName sp_forceward.nss
//:://////////////////////////////////////////////
/** @file Abjuration
Level: Cleric 3 (Helm), Paladin 3, Knight of the Weave 3,
Components: V, S, DF,
Casting Time: 1 full round
Range: 10 ft.
Area: 10-ft.-radius emanation centered on you
Duration: 1 minute/level
Saving Throw: Will negates
Spell Resistance: Yes
You create an unmoving, transparent sphere of force
centered on your location.
The sphere illuminates its interior and everything
within 5 feet of its edge.
You and your allies may enter the sphere at will.
Any other creature that tries to enter the sphere must
make a Will saving throw, otherwise it cannot pass into
the area defined by the sphere.
A creature may leave the area freely, although it must
make a Will save to enter again, even if the creature
is you or one of your allies.
Creatures within the area when the spell is cast are not
forced out.
The forceward does not prevent spells or objects from
entering the forceward, so it is possible for two creatures
on opposite sides of the forceward's edge to fight without
penalties (although creatures using unarmed attacks or
natural weapons still have tomake Will saves every round
for their attacks to have a chance of entering the forceward).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 07/04/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
location lLoc = GetLocation(oPC);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectAreaOfEffect(VFX_PER_FORCEWARD), lLoc, fDur);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_LIGHT_ORANGE_15), lLoc, fDur);
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, 3.048f, lLoc, FALSE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oTarget))
{
SetLocalInt(oTarget, "PRCForcewardEntry", 1)
oTarget = MyNextObjectInShape(SHAPE_SPHERE, 3.048f, lLoc, FALSE, OBJECT_TYPE_CREATURE);
}
PRCSetSchool();
}

View File

@@ -0,0 +1,60 @@
//:://////////////////////////////////////////////
//:: Name Forceward On Enter
//:: FileName sp_forcewardA.nss
//:://////////////////////////////////////////////
/** @file Abjuration
Level: Cleric 3 (Helm), Paladin 3, Knight of the Weave 3,
Components: V, S, DF,
Casting Time: 1 full round
Range: 10 ft.
Area: 10-ft.-radius emanation centered on you
Duration: 1 minute/level
Saving Throw: Will negates
Spell Resistance: Yes
You create an unmoving, transparent sphere of force
centered on your location.
The sphere illuminates its interior and everything
within 5 feet of its edge.
You and your allies may enter the sphere at will.
Any other creature that tries to enter the sphere must
make a Will saving throw, otherwise it cannot pass into
the area defined by the sphere.
A creature may leave the area freely, although it must
make a Will save to enter again, even if the creature
is you or one of your allies.
Creatures within the area when the spell is cast are not
forced out.
The forceward does not prevent spells or objects from
entering the forceward, so it is possible for two creatures
on opposite sides of the forceward's edge to fight without
penalties (although creatures using unarmed attacks or
natural weapons still have tomake Will saves every round
for their attacks to have a chance of entering the forceward).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 07/04/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oTarget = GetEnteringObject();
object oCreator = GetAreaOfEffectCreator();
int nDC = PRCGetSaveDC(oTarget, oCreator);
int nCasterLvl = PRCGetCasterLevel(oCreator);
location lAOE = GetLocation(OBJECT_SELF);
//Will save if it doesn't have the local int
if(!GetLocalInt(oTarget, "PRCForcewardEntry"))
{
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_NONE, oCreator))
{
ActionMoveAwayFromLocation(lAOE, FALSE, 3.048f);
}
}
}

View File

@@ -0,0 +1,44 @@
//:://////////////////////////////////////////////
//:: Name Forceward On Exit
//:: FileName sp_forcewardB.nss
//:://////////////////////////////////////////////
/** @file
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/4/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oTarget = GetExitingObject();
if(GetLocalInt(oTarget, "PRCForcewardEntry"))
{
DeleteLocalInt(oTarget, "PRCForcewardEntry"));
}
effect eAOE;
if(GetHasSpellEffect(SPELL_SOLID_FOG, oTarget))
{
//Search through the valid effects on the target.
eAOE = GetFirstEffect(oTarget);
while (GetIsEffectValid(eAOE))
{
if (GetEffectCreator(eAOE) == GetAreaOfEffectCreator())
{
//If the effect was created by either half of Fog from the Void
if(GetEffectSpellId(eAOE) == SPELL_SOLID_FOG)
{
RemoveEffect(oTarget, eAOE);
}
}
}
//Get next effect on the target
eAOE = GetNextEffect(oTarget);
}
}

View File

@@ -0,0 +1,135 @@
//:://////////////////////////////////////////////
//:: Name Glory of the Martyr
//:: FileName sp_glorymartyr.nss
//:://////////////////////////////////////////////
/** @file Abjuration [Good]
Level: Champion of Gwynharwyf 4, Paladin 4,
Components: V, S, AF, DF,
Casting Time: 1 standard action
Range: Close (25 ft. + 5 ft./2 levels)
Target: One creature/level
Duration: 1 hour/level (D)
Saving Throw: Will negates (harmless)
Spell Resistance: Yes (harmless)
Like shield other, this spell wards the subjects,
creating a mystic connection between them and you
so that some of their wounds are transferred to you.
The subjects each gain a +1 deflection bonus to AC
and a +1 resistance bonus on saves.
All the subjects take only half damage from all
wounds and attacks that deal them hit point damage.
The amount of damage not taken by all the warded
creatures is taken by you.
Forms of harm that do not involve hit points, such
as charm effects, temporary ability damage, level
draining, and disintegration, are not affected.
If a subject suffers a reduction of hit points
from a lowered Constitution score, the reduction
is not split with you because it is not hit point damage.
When the spell ends, subsequent damage is no
longer divided between you and the subjects, but
damage already split is not reassigned to the
subjects.
If you die while this spell is in effect, the spell
ends in a burst of positive energy that restores 1d8
hit points to each subject.
If a subject moves out of range of the spell, that
subject's connection to you is severed but the spell
continues as long as there is at least one subject
remaining and you remain alive.
Focus: A platinum ring (worth at least 50 gp) worn
by you and each subject of the spell.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void DispelMonitor(object oManifester, object oTarget, int nSpellID, int nManifesterLevel, int nBeatsRemaining);
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = HoursToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
int nBeatsRemaining = FloatToInt(fDur)/6;
int nMaxTargets = nCasterLvl;
float fRadius = FeetToMeters(25.0f + (5.0f * (nCasterLvl / 2))))
location lLoc = GetLocation(oPC);
int nSpell = GetSpellId();
effect eDurPos = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_POSITIVE);
effect eDurNeg = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_NEGATIVE);
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oTarget) && nMaxTargets >0)
{
if(oTarget != oPC)
{
if(GetIsReactionTypeFriendly(oTarget))
{
// Get the OnHitCast: Unique on the caster's armor / hide
ExecuteScript("prc_keep_onhit_a", oPC);
// Hook eventscript
AddEventScript(oPC, EVENT_ONHIT, "psi_pow_shrpnaux", TRUE, FALSE);
// Store the target for use in the damage script
SetLocalObject(oPC, "PRC_Power_SharePain_Target", oTarget);
//Apply bonuses to target
effect eLink = EffectLinkEffects(EffectACIncrease(1, AC_DEFLECTION_BONUS), EffectSavingThrowIncrease(SAVING_THROW_ALL, 1, SAVING_THROW_TYPE_ALL));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, fDur);
// Do VFX for the monitor to look for
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDurNeg, oTarget, fDur, TRUE, nSpell, nCasterLvl);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDurPos, oPC, fDur, TRUE, nSpell, nCasterLvl);
// Start effect end monitor
DelayCommand(6.0f, DispelMonitor(oPC, oTarget, nSpell, nCasterLvl, nBeatsRemaining);
nMaxTargets--;
}
}
oTarget = MyNextObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_CREATURE);
}
PRCSetSchool();
}
void DispelMonitor(object oPC, object oTarget, int nSpellID, int CasterLvl, int nBeatsRemaining)
{
// Has the power ended since the last beat, or does the duration run out now
if((--nBeatsRemaining == 0) ||
GetIsDead(oTarget) ||
PRCGetDelayedSpellEffectsExpired(nSpellID, oTarget, oPC) ||
PRCGetDelayedSpellEffectsExpired(nSpellID, oPC, oPC) ||
GetDistanceBetween(oPC, oTarget) > FeetToMeters(25.0f + (5.0f * (nCasterLvl / 2))))
{
if(DEBUG) DoDebug("Glory of the Martyr: Effect expired, clearing");
// Clear the target local
DeleteLocalObject(PC, "PRC_Power_SharePain_Target");
// Remove the eventscript
RemoveEventScript(oPC, EVENT_ONHIT, "psi_pow_shrpnaux", TRUE, FALSE);
// Remove remaining effects
PRCRemoveSpellEffects(nSpellID, oPC, oTarget);
PRCRemoveSpellEffects(nSpellID, oPC, oPC);
}
else
{
nBeatsRemaining --;
DelayCommand(6.0f, DispelMonitor(oPC, oTarget, nSpellID, nCasterLvl, nBeatsRemaining));
}

View File

@@ -0,0 +1,46 @@
//:://////////////////////////////////////////////
//:: Name Holy Fire
//:: FileName sp_holyfire.nss
//:://////////////////////////////////////////////
/** @file Evocation [Fire, Good]
Level: Cleric 2, Paladin 3,
Components: V, S, DF,
Casting Time: 1 swift action
Range: Personal
Target: You
Duration: 1 round
All undead within range of your next turning attempt
(if you make it before this spell's duration expires)
are especially vulnerable to the attempt. Whether you
succeed in turning them or not, the undead take hit
point damage equal to the result of your turning damage
roll. This damage is half fire and half sacred energy.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/21/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(1);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
//Set a VFX
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_PROTECTION_GOOD_MAJOR), oPC);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAreaOfEffect(VFX_MOB_HOLYFIRE), oPC);
PRCSetSchool();
}

View File

@@ -0,0 +1,35 @@
//:://////////////////////////////////////////////
//:: Name Holy Fire On Enter
//:: FileName sp_holyfireA.nss
//:://////////////////////////////////////////////
/** @file Evocation [Fire, Good]
Level: Cleric 2, Paladin 3,
Components: V, S, DF,
Casting Time: 1 swift action
Range: Personal
Target: You
Duration: 1 round
All undead within range of your next turning attempt
(if you make it before this spell's duration expires)
are especially vulnerable to the attempt. Whether you
succeed in turning them or not, the undead take hit
point damage equal to the result of your turning damage
roll. This damage is half fire and half sacred energy.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/21/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oTarget = GetEnteringObject();
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_PULSE_YELLOW_ORANGE), oTarget, 6.0f);
}

View File

@@ -0,0 +1,46 @@
//:://////////////////////////////////////////////
//:: Name Holy Fire On Exit
//:: FileName sp_holyfireB.nss
//:://////////////////////////////////////////////
/** @file Evocation [Fire, Good]
Level: Cleric 2, Paladin 3,
Components: V, S, DF,
Casting Time: 1 swift action
Range: Personal
Target: You
Duration: 1 round
All undead within range of your next turning attempt
(if you make it before this spell's duration expires)
are especially vulnerable to the attempt. Whether you
succeed in turning them or not, the undead take hit
point damage equal to the result of your turning damage
roll. This damage is half fire and half sacred energy.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/21/2022
//:://////////////////////////////////////////////
#include "prc_inc_spells"
#include "prc_add_spell_dc"
void main()
{
object oCaster = GetAreaOfEffectCreator();
object oTarget = GetExitingObject();
effect eToDispel = GetFirstEffect(oTarget);
while(GetIsEffectValid(eToDispel))
{
if(GetEffectSpellId(eToDispel) == SPELL_HOLY_FIRE)
{
RemoveEffect(oTarget, eToDispel);
}
eToDispel = GetNextEffect(oTarget);
}
}
}

View File

@@ -0,0 +1,62 @@
//:://////////////////////////////////////////////
//:: Name Holy Storm
//:: FileName sp_holystorm.nss
//:://////////////////////////////////////////////
/** @file
Conjuration (Creation) [Good, Water]
Level: Cleric 3, Paladin 3,
Components: V, S, M, DF,
Casting Time: 1 standard action
Range: 20 ft.
Area: Cylinder (20-ft. radius, 20 ft. high)
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: No
You call upon the forces of good, and a heavy rain begins to fall
around you, its raindrops soft and warm.
A driving rain falls around you. It falls in a fixed area once
created. The storm reduces hearing and visibility, resulting in a
-4 penalty on Listen, Spot, and Search checks. It also applies a
-4 penalty on ranged attacks made into, out of, or through the
storm. Finally, it automatically extinguishes any unprotected
flames and has a 50% chance to extinguish protected flames
(such as those of lanterns).
The rain damages evil creatures, dealing 2d6 points of damage
per round (evil outsiders take double damage) at the beginning
of your turn.
Material Component: A flask of holy water (25 gp).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/9/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_CONJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
//VFX
effect eVis = EffectVisualEffect(VFX_FNF_STORM);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lTarget);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectAreaOfEffect(AOE_PER_STORM, "sp_holystormA", "sp_holystormB", "sp_holystormC"), lTarget, fDur);
object oAoE = GetAreaOfEffectObject(lTarget, "VFX_PER_STORM");
SetAllAoEInts(SPELL_HOLY_STORM, oAoE, PRCGetSpellSaveDC(SPELL_HOLY_STORM, SPELL_SCHOOL_CONJURATION), 0, PRCGetCasterLevel(oPC));
PRCSetSchool();
}

View File

@@ -0,0 +1,48 @@
//:://////////////////////////////////////////////
//:: Name Holy Storm On Enter
//:: FileName sp_holystormA.nss
//:://////////////////////////////////////////////
/** @file
Conjuration (Creation) [Good, Water]
Level: Cleric 3, Paladin 3,
Components: V, S, M, DF,
Casting Time: 1 standard action
Range: 20 ft.
Area: Cylinder (20-ft. radius, 20 ft. high)
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: No
You call upon the forces of good, and a heavy rain begins to fall
around you, its raindrops soft and warm.
A driving rain falls around you. It falls in a fixed area once
created. The storm reduces hearing and visibility, resulting in a
-4 penalty on Listen, Spot, and Search checks. It also applies a
-4 penalty on ranged attacks made into, out of, or through the
storm.
The rain damages evil creatures, dealing 2d6 points of damage
per round (evil outsiders take double damage) at the beginning
of your turn.
Material Component: A flask of holy water (25 gp).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/9/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oTarget = GetEnteringObject();
effect ePenalty = EffectLinkEffects(EffectSkillDecrease(SKILL_LISTEN, 4), EffectSkillDecrease(SKILL_SPOT), 4));
ePenalty = EffectLinkEffects(ePenalty, EffectSkillDecrease(SKILL_SEARCH, 4));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, ePenalty, oTarget, RoundsToSeconds(1));
}

View File

@@ -0,0 +1,53 @@
//:://////////////////////////////////////////////
//:: Name Holy Storm On Enter
//:: FileName sp_holystormA.nss
//:://////////////////////////////////////////////
/** @file
Conjuration (Creation) [Good, Water]
Level: Cleric 3, Paladin 3,
Components: V, S, M, DF,
Casting Time: 1 standard action
Range: 20 ft.
Area: Cylinder (20-ft. radius, 20 ft. high)
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: No
You call upon the forces of good, and a heavy rain begins to fall
around you, its raindrops soft and warm.
A driving rain falls around you. It falls in a fixed area once
created. The storm reduces hearing and visibility, resulting in a
-4 penalty on Listen, Spot, and Search checks. It also applies a
-4 penalty on ranged attacks made into, out of, or through the
storm.
The rain damages evil creatures, dealing 2d6 points of damage
per round (evil outsiders take double damage) at the beginning
of your turn.
Material Component: A flask of holy water (25 gp).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/9/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
object oTarget = GetExitingObject();
effect eToDispel = GetFirstEffect(oTarget);
while(GetIsEffectValid(eToDispel))
{
if(GetEffectSpellId(eToDispel) == SPELL_HOLY_STORM)
{
RemoveEffect(oTarget, eToDispel);
}
eToDispel = GetNextEffect(oTarget);
}
}

View File

@@ -0,0 +1,76 @@
//:://////////////////////////////////////////////
//:: Name Holy Storm On Enter
//:: FileName sp_holystormA.nss
//:://////////////////////////////////////////////
/** @file
Conjuration (Creation) [Good, Water]
Level: Cleric 3, Paladin 3,
Components: V, S, M, DF,
Casting Time: 1 standard action
Range: 20 ft.
Area: Cylinder (20-ft. radius, 20 ft. high)
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: No
You call upon the forces of good, and a heavy rain begins to fall
around you, its raindrops soft and warm.
A driving rain falls around you. It falls in a fixed area once
created. The storm reduces hearing and visibility, resulting in a
-4 penalty on Listen, Spot, and Search checks. It also applies a
-4 penalty on ranged attacks made into, out of, or through the
storm.
The rain damages evil creatures, dealing 2d6 points of damage
per round (evil outsiders take double damage) at the beginning
of your turn.
Material Component: A flask of holy water (25 gp).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/9/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
location lLoc = GetLocation(OBJECT_SELF);
int nDam;
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, 6.096f, lLoc, FALSE, OBJECT_TYPE_CREATURE);
effect ePenalty = EffectLinkEffects(EffectSkillDecrease(SKILL_LISTEN, 4), EffectSkillDecrease(SKILL_SPOT), 4));
ePenalty = EffectLinkEffects(ePenalty, EffectSkillDecrease(SKILL_SEARCH, 4));
while(GetIsObjectValid(oTarget))
{
//Penalties to skills
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, ePenalty, oTarget, RoundsToSeconds(1));
//Penalty to attack if ranged equipped
if(GetWeaponRanged(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget))
{
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAttackDecrease(4), 6.0f);
}
//Bonus AC vs Ranged?
//if evil
if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL)
{
nDam = d6(2);
//if outsider
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_OUTSIDER)
{
nDam+=nDam;
}
//damage
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(DAMAGE_TYPE_DIVINE, nDam, oTarget));
}
oTarget = MyNextObjectInShape(SHAPE_SPHERE, 6.096f, lLoc, FALSE, OBJECT_TYPE_CREATURE);
}
}

View File

@@ -0,0 +1,130 @@
//:://////////////////////////////////////////////
//:: Name Invoke the Cerulean Sign
//:: FileName sp_invCS.nss
//:://////////////////////////////////////////////
/** @file
Evocation
Level: Druid 2, Ranger 2, Bard 3, Cleric 3, Paladin 3, Sorcerer 3, Wizard 3,
Components: S,
Casting Time: 1 standard action
Range: 30 ft.
Area: Multiple aberrations whose combined total Hit Dice do not exceed twice
caster level in a spread emanating from the character to the extreme of the range
Duration: Instantaneous
Saving Throw: Fortitude negates
Spell Resistance: No
The cerulean sign is an ancient symbol said to embody
the purity of the natural world, and as such it is
anathema to aberrations.
While druids and rangers are the classes most often
known to cast this ancient spell, its magic is nearly
universal and can be mastered by all spellcasting classes.
When you cast this spell, you trace the cerulean sign
in the air with a hand, leaving a glowing blue rune
in the air for a brief moment before it flashes and fills
the area of effect with a pulse of cerulean light.
Any aberration within the area must make a Fortitude
saving throw or suffer the following ill effects.
Closer aberrations are affected first.
Each effect lasts for 1 round.
None: The aberration suffers no ill effect, even if it fails the
saving throw.
Sickened: The aberration takes a -2 penalty on attack
rolls, saving throws, skill checks, and ability checks for 1 round.
Nauseated: The aberration cannot attack, cast spells, concentrate
on spells, or do anything but take a single move action for 1 round.
Dazed: The aberration can take no actions, but has no penalty to
its Armor Class, for 1 round.
Stunned: The aberration drops everything held, can't take actions,
takes a -2 penalty to AC, and loses its Dexterity bonus to AC (if any)
for 1 round.
Once a creature recovers from an effect, it moves up one level on the table.
Thus, a creature that is stunned by this spell is dazed the round after
that, nauseated the round after that, sickened the round after that, and
then recovers fully the next round.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/13/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
#include "prc_effect_inc"
void DoDrop(object oTarget)
{
object oTargetWep = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
object oOffhand = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
object oNewWeap = CopyObject(oTargetWep, GetLocation(oTarget));
object oNewOff = CopyObject(oOffhand, GetLocation(oTarget));
DestroyObject(oTargetWep);
DestroyObject(oOffhand);
}
void DoSign(object oTarget)
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FROST_L), oTarget);
//2nd round sickened
DelayCommand(6.0f, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSickened(), oTarget, 6.0f));
//3rd round Nauseated
DelayCommand(12.0f, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectNausea(oTarget, 6.0f), oTarget, 6.0f));
//4th round Dazed
DelayCommand(18.0f, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneParalyze(), oTarget, 6.0f));
//5th round Stunned
DelayCommand(24.0f, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneParalyze(), oTarget, 6.0f));
DelayCommand(24.0f, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectACDecrease(2), oTarget, 6.0f));
DelayCommand(24.0f, DoDrop(oTarget));
//6th round Dazed
DelayCommand(30.0f, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneParalyze(), oTarget, 6.0f));
//7th round Nauseated
DelayCommand(36.0f, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectNausea(oTarget, 6.0f), oTarget, 6.0f));
//8th round sickened
DelayCommand(42.0f, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSickened(), oTarget, 6.0f));
}
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_EVOCATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
int nDice = nCasterLvl * 2;
location lLoc = GetLocation(oPC);
int nTargetDice;
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FROST_L), oPC);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HASTE), oPC);
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, 9.144f, lLocl, FALSE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid && nDice > 0)
{
//Aberration
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_ABERRATION)
{
//Save
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, PRCGetSaveDC(oTarget, oPC)))
{
nTargetDice = GetHitDice(oTarget);
if(nDice >= nTargetDice)
{
nDice -= nTargetDice;
DoSign(oTarget);
}
}
}
oTarget = MyNextObjectInShape(SHAPE_SPHERE, 9.144f, lLocl, FALSE, OBJECT_TYPE_CREATURE);
}
PRCSetSchool();
}

View File

@@ -0,0 +1,46 @@
//:://////////////////////////////////////////////
//:: Name Irresistable Force
//:: FileName sp_irresforce.nss
//:://////////////////////////////////////////////
/** @file Evocation
Level: Paladin 4,
Components: V, S,
Casting Time: 1 action
Range: Personal
Target: You
Duration: 1 round/level
Charging yourself with divine energy, you become the epitome of force in motion.
You are protected by freedom of movement.
You gain a +10 bonus on bull rush attempts.
You gain a +10 bonus on checks made to avoid being tripped.
When moving in combat, you act as if you had the Mobility feat.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/14/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_EVOCATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
//Freedom of Movement
effect eLink = EffectLinkEffects(EffectImmunity(IMMUNITY_TYPE_PARALYSIS), EffectImmunity(IMMUNITY_TYPE_SLOW));
eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_ENTANGLE));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, fDur);
//Mobility
IPSafeAddItemProperty(GetPCSkin(oPC), PRCItemPropertyBonusFeat(FEAT_MOBILITY), fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,49 @@
//:://////////////////////////////////////////////
//:: Name Lesser Aspect of the Diety
//:: FileName sp_laspdiety.nss
//:://////////////////////////////////////////////
/** @file
Transmutation [Good]
Level: Apostle of Peace 4, Exalted Arcanist 4, Paladin 4, Knight of the Chalice 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: Personal
Target: You
Duration: 1 round/level
When you cast this spell, your body changes into a form that is more like
your deity (in a very limited fashion, of course).
You gain a +4 enhancement bonus to your Charisma score.
You also gain acid, cold, and electricity resistance 10.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/7/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
effect eLink = EffectAbilityIncrease(ABILITY_CHARISMA, 4);
eLink = EffectLinkEffects(eLink, EffectDamageResistance(DAMAGE_TYPE_ACID, 10));
eLink = EffectLinkEffects(eLink, EffectDamageResistance(DAMAGE_TYPE_COLD, 10));
eLink = EffectLinkEffects(eLink, EffectDamageResistance(DAMAGE_TYPE_ELECTRICAL, 10));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_IOUNSTONE_YELLOW));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,67 @@
//:://////////////////////////////////////////////
//:: Name Lesser Aura of Cold
//:: FileName sp_lauracold.nss
//:://////////////////////////////////////////////
/** @file Transmutation [Cold]
Level: Cleric 3, Druid 3, Disciple of Thrym 3, Paladin 4, Ranger 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: 5 ft.
Area: 5-ft.-radius spherical emanation, centered on you
Duration: 1 round/level (D)
Saving Throw: None
Spell Resistance: Yes
You are covered in a thin layer of white frost and frigid cold emanates from your
body, dealing 1d6 points of cold damage at the start of your round to each creature
within 5 feet.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 6/8/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void DoCold(object oPC, int nRounds)
{
if(nRounds > 0)
{
location lLoc=GetLocation(oPC);
//Do the AoE
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE,FeetToMeters(5.0), lLoc);
{
while(GetIsObjectValid(oTarget))
{
if(oTarget != oPC)
{
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6(1), DAMAGE_TYPE_COLD), oTarget);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FROST_S), oTarget);
}
oTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(5.0), lLoc);
}
}
nRounds--;
DelayCommand(6.0f, DoCold(oPC, nRounds));
}
}
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
int nRounds = nCasterLvl;
if(nMetaMagic & METAMAGIC_EXTEND) nRounds += nRounds;
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_PULSE_BLUE_WHITE), oPC, fDur);
DoCold(oPC, nRounds);
PRCSetSchool();
}

View File

@@ -0,0 +1,67 @@
//:://////////////////////////////////////////////
//:: Name Lawful Sword
//:: FileName sp_lawsword.nss
//:://////////////////////////////////////////////
/** @file
Evocation
Level: Paladin 4,
Components: V, S,
Casting Time: 1 standard action
Range: Touch
Target: Weapon touched
Duration: 1 round/level
Saving Throw: None
Spell Resistance: No
Calling to mind thoughts of justice, you run your
fingers along the weapon, imbuing it with power.
This spell functions like holy sword (PH 242), except
as follows. The weapon functions as a +5 axiomatic
weapon (+5 enhancement bonus on attack rolls and damage
rolls, lawful-aligned, deals an extra 2d6 points of damage
against chaotic opponents). It also emits a magic circle
against chaos effect (as the spell).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 2/2/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
object oTarget = GetSpellTargetObject();
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
//+2d6 vs chaotic
itemproperty iDam = ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_CHAOTIC, IP_CONST_DAMAGETYPE_PHYSICAL, IP_CONST_DAMAGEBONUS_2d6);
//+5 vs everything
itemproperty iAttack = ItemPropertyEnhancementBonus(5);
if(GetObjectType(oTarget)) == OBJECT_TYPE_CREATURE
{
oTarget = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
}
IPSafeAddItemProperty(oTarget, iDam, fDur);
IPSafeAddItemProperty(oTarget, iAttack, fDur);
//magic circle on the weapon
effect eCircle = EffectAreaOfEffect(AOE_MOB_CIRCCHAOS);
effect eVis = EffectVisualEffect(VFX_IMP_EVIL_HELP);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCircle, oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);
PRCSetSchool();
}

View File

@@ -0,0 +1,107 @@
//:://////////////////////////////////////////////
//:: Name Lesser Energy Shield
//:: FileName sp_lenshield.nss
//:://////////////////////////////////////////////
/** @file Abjuration
Level: Paladin 1, Cleric 2
Components: V, S, DF,
Casting Time: 1 Standard Action
Range: Touch
Target: Shield touched
Duration: 1 round/level
Saving Throw: None
Spell Resistance: No
A silver aura surrounds the touched shield for a
moment before it appears to transform into the chosen
type of energy. The shield hums with power.
When this spell is cast, the shield touched appears
to be made entirely out of one type of energy (fire,
cold, electricity, acid, or sonic). Whoever bears the
shield gains resistance 5 against the chosen energy
type. Additionally, if the wielder successfully hits
someone with the shield with a shield bash attack, th
e victim takes 1d6 points of the appropriate energy
damage in addition to the normal shield bash damage.
The energy type must be chosen when the spell is cast
and cannot be changed during the duration of the spell.
The energy resistance overlaps (and does not stack)
with resist elements. A given shield cannot be the
subject of more than one lesser energized shield
or energized shield spell at the same time.
The descriptor of this spell is the same as the
energy type you choose when you cast it.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/28/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
#include "prc_inc_fork"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
object oTarget = PRCGetSpellTargetObject();
object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
//Check that this is a shield, if not abort
if(GetIsShield(oShield) == FALSE)
{
SendMessageToPC(OBJECT_SELF, "Target has no equipped shield.");
break;
}
//The type of damage resistance we're choosing
int nDR;
//Get the type by which subradial spell is used to cast
int nSpell = GetSpellId();
if(nSpell == SPELL_LESSER_ENERGIZED_SHIELD_FIRE)
{
nDR = IP_CONST_DAMAGETYPE_FIRE;
SetLocalInt(oTarget, "EnShieldType", DAMAGE_TYPE_FIRE);
}
if(nSpell == SPELL_LESSER_ENERGIZED_SHIELD_COLD)
{
nDR = IP_CONST_DAMAGETYPE_COLD;
SetLocalInt(oTarget, "EnShieldType", DAMAGE_TYPE_COLD);
}
if(nSpell == SPELL_LESSER_ENERGIZED_SHIELD_ELEC)
{
nDR = IP_CONST_DAMAGETYPE_ELECTRICAL;
SetLocalInt(oTarget, "EnShieldType", DAMAGE_TYPE_ELECTRICAL);
}
if(nSpell == SPELL_LESSER_ENERGIZED_SHIELD_ACID)
{
nDR = IP_CONST_DAMAGETYPE_ACID;
SetLocalInt(oTarget, "EnShieldType", DAMAGE_TYPE_ACID);
}
if(nSpell == SPELL_LESSER_ENERGIZED_SHIELD_SONIC)
{
nDR = IP_CONST_DAMAGETYPE_SONIC;
SetLocalInt(oTarget, "EnShieldType", DAMAGE_TYPE_SONIC);
}
//Set local int for amount of shield damage on the wielder of the shield
SetLocalInt(oTarget, "EnShieldD6", 1);
//Schedule ints for deletion
DelayCommand(fDur, DeleteLocalInt(oTarget, "EnShieldType"));
DelayCommand(fDur, DeleteLocalInt(oTarget, "EnShieldD6"));
//Add resistance property
IPSafeAddItemProperty(oShield, ItemPropertyDamageResistance(nDR, 5), fDur, X2_IP_ADDPROP_POLICY_KEEP_EXISTING);
PRCSetSchool();
}

View File

@@ -0,0 +1,56 @@
//:://////////////////////////////////////////////
//:: Name Legion's Magic Weapon
//:: FileName sp_lmagweap.nss
//:://////////////////////////////////////////////
/** @file
Transmutation
Level: Cleric 2, Paladin 2, Sorcerer 2, Wizard 2,
Components: V, S, DF,
Casting Time: 1 standard action
Range: Close (25 ft. + 5 ft./2 levels)
Target: Melee or ranged weapons held by allied creatures in a 20-ft.-radius burst
Duration: 1 round/level
Saving Throw: Will negates (harmless, object)
Spell Resistance: Yes (harmless, object)
This spell functions like magic weapon (see page 251 of the
Player's Handbook), except as noted above and as follows. It
affects only weapons held by allies when the spell is cast.
It has no effect on ammunition.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/13/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
location lLoc = GetLocation(oPC);
object oTarget = MyGetFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(30), lLoc, FALSE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oTarget))
{
if(GetIsReactionTypeFriendly(oTarget))
{
object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
if(GetIsObjectValid(oItem))
{
IPSafeAddItemProperty(oItem,ItemPropertyEnhancementBonus(1), fDur, X2_IP_ADDPROP_POLICY_KEEP_EXISTING ,TRUE,TRUE);
}
}
oTarget = MyGetNextObjectInShape(SHAPE_SPHERE, FeetToMeters(30), lLoc, FALSE, OBJECT_TYPE_CREATURE);
}
PRCSetSchool();
}

View File

@@ -0,0 +1,65 @@
//:://////////////////////////////////////////////
//:: Name Lesser Visage of the Deity
//:: FileName sp_lvisdiety.nss
//:://////////////////////////////////////////////
/** @file
Transmutation [Good or Evil]
Level: Cleric 3, Blackguard 4, Paladin 4, Mysticism 3,
Components: V, S, DF,
Casting Time: 1 standard action
Range: Personal
Target: You
Duration: 1 round/level
As you end your prayer, you can feel the hand of your
deity upon you. Your appearance reflects her divine power,
and her touch grants you resistance from some of the damage
of this world.
You gain a +4 enhancement bonus to Charisma. You also gain
resistance to acid 10, cold 10, and electricity 10 if you
are good, or resistance to cold 10 and fire 10 if you are evil.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/26/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
int nMetaMagic = PRCGetMetaMagicFeat();
int nAlign = GetAlignmentGoodEvil(oPC);
int nBonus = 4;
float fDur = RoundsToSeconds(nCasterLvl);
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityIncrease(ABILITY_CHARISMA, nBonus), oPC, fDur);
if (nAlign == ALIGNMENT_GOOD)
{
effect eResAcid = EffectDamageResistance(DAMAGE_TYPE_ACID, 10);
effect eResCold = EffectDamageResistance(DAMAGE_TYPE_COLD, 10);
effect eResElec = EffectDamageResistance(DAMAGE_TYPE_ELECTRICAL, 10);
effect eLink = EffectLinkEffects(eResAcid, eResCold);
eLink = EffectLinkEffects(eLink, eResElec);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_GOOD_HELP), oPC);
}
else if (nAlign == ALIGNMENT_EVIL)
{
effect eLink = EffectLinkEffects(EffectDamageResistance(DAMAGE_TYPE_COLD, 10), EffectDamageResistance(DAMAGE_TYPE_FIRE, 10));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_EVIL_HELP), oPC);
}
PRCSetSchool();
}

View File

@@ -0,0 +1,44 @@
//:://////////////////////////////////////////////
//:: Name Major Resistance
//:: FileName sp_majorresist.nss
//:://////////////////////////////////////////////
/** @file
Abjuration
Level: Bard 2, Cleric 2, Druid 2, Paladin 2, Sorcerer 2, Wizard 2,
Components: V, S, M, DF,
Casting Time: 1 action
Range: Touch
Target: Creature touched
Duration: 1 hour/level
Saving Throw: Will negates (harmless)
Spell Resistance: Yes (harmless)
You imbue the subject with a strong magical energy that protects
her from harm, granting a +3 resistance bonus on saves.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/14/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = HoursToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
object oTarget = GetSpellTargetObject();
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_WHITE), oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSavingThrowIncrease(SAVING_THROW_ALL, 3), oTarget, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,52 @@
//:://////////////////////////////////////////////
//:: Name Meteoric Strike
//:: FileName sp_meteoric.nss
//:://////////////////////////////////////////////
/** @file Transmutation [Fire]
Level: Druid 4, Paladin 4, Cleric 5,
Components: V, S,
Casting Time: 1 swift action
Range: 0 ft.
Target: Your melee weapon
Duration: 1 round or until discharged
Saving Throw: None or Reflex half; see text
Spell Resistance: See text
Your melee weapon bursts into orange, red, and gold
flames, and shining sparks trail in its wake.
Your next successful melee attack deals extra fire
damage equal to 1d6 points + 1d6 points per four caster
levels.
In addition, the flames splash into all squares adjacent
to the target.
Any creatures standing in these squares take half damage
from the explosion, with a Reflex save allowed to halve
this again.
If a creature has spell resistance, it applies to this
splash effect.
You are not harmed by your own meteoric strike.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/15/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
object oTarget = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
itemproperty ipHook = ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1);
IPSafeAddItemProperty(oTarget, ipHook, 6.0f)
AddEventScript(oTarget, "sp_meteoriconhit", FALSE, FALSE);
PRCSetSchool();
}

View File

@@ -0,0 +1,93 @@
//:://////////////////////////////////////////////
//:: Name Meteoric Strike On Hit
//:: FileName sp_meteoriconhit.nss
//:://////////////////////////////////////////////
/** @file Transmutation [Fire]
Level: Druid 4, Paladin 4, Cleric 5,
Components: V, S,
Casting Time: 1 swift action
Range: 0 ft.
Target: Your melee weapon
Duration: 1 round or until discharged
Saving Throw: None or Reflex half; see text
Spell Resistance: See text
Your melee weapon bursts into orange, red, and gold flames,
and shining sparks trail in its wake.
Your next successful melee attack deals extra fire damage equal
to 1d6 points + 1d6 points per four caster levels.
In addition, the flames splash into all squares adjacent to the t
arget.
Any creatures standing in these squares take half damage from the
explosion, with a Reflex save allowed to halve this again.
If a creature has spell resistance, it applies to this splash effect.
You are not harmed by your own meteoric strike.
You can cast meteoric strike before you make an unarmed attack.
If you do, your unarmed attack is considered armed.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/14/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
#include "prc_alterations"
#include "prc_inc_combat"
void main()
{
object oSpellOrigin = OBJECT_SELF;
// route all onhit-cast spells through the unique power script (hardcoded to "prc_onhitcast")
// in order to fix the Bioware bug, that only executes the first onhitcast spell found on an item
// any onhitcast spell should have the check ContinueOnHitCast() at the beginning of its code
// if you want to force the execution of an onhitcast spell script, that has the check, without routing the call
// through prc_onhitcast, you must use ForceExecuteSpellScript(), to be found in prc_inc_spells
if(!ContinueOnHitCastSpell(oSpellOrigin)) return;
// DeleteLocalInt(oSpellOrigin, "X2_L_LAST_SPELLSCHOOL_VAR");
SetLocalInt(oSpellOrigin, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_TRANSMUTATION);
// find the weapon
object oWeapon = PRCGetSpellCastItem(oSpellOrigin);
//Get Caster level
int nBonus = GetLocalInt(oWeapon, "MeteoricCasterLvl") / 4;
// find the target of the spell
object oTarget = PRCGetSpellTargetObject(oSpellOrigin);
// only do anything if we have a valid weapon and a valid living target
if (GetIsObjectValid(oWeapon) && GetIsObjectValid(oTarget)&& !GetIsDead(oTarget))
{
int nDam = d6(1 + nBonus);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FLAME_M), oTarget);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(oTarget, nDam, DAMAGE_TYPE_FIRE), oTarget);
//Burst
nDam = nDam/2;
location lLoc = GetLocation(oTarget);
object oTargetB = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(5), lLoc, TRUE);
while(GetIsObjectValid(oTargetB))
{
if(oTargetB != oPC)
{
if(!PRCDoResistSpell(oTargetB))
{
if (PRCMySavingThrow(SAVING_THROW_REFLEX, oTargetB, (PRCGetSaveDC(oTargetB, oSpellOrigin))))
{
nDam = nDam/2;
}
effect eLink = EffectLinkEffects(EffectDamage(DAMAGE_TYPE_FIRE, nDam), EffectVisualEffect(VFX_COM_HIT_FIRE));
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eLink, oTargetB);
}
}
oTargetB = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(5), lLoc, TRUE);
}
}
}

View File

@@ -0,0 +1,56 @@
//:://////////////////////////////////////////////
//:: Name Quick March
//:: FileName sp_quickmarch.nss
//:://////////////////////////////////////////////
/** @file Transmutation
Level: Cleric 2, Paladin 2,
Components: V, S, DF,
Casting Time: 1 swift action
Range: Medium (100 ft. + 10 ft./level)
Target: Allies in a 20-ft.-radius burst
Duration: 1 round
Saving Throw: Will negates (harmless)
Spell Resistance: Yes (harmless)
Upon casting this spell, your feet and those of your
allies glow with a yellow nimbus of light.
Quick march increases your allies' base land speed by
30 feet. (This adjustment is considered an enhancement
bonus.) There is no effect on other modes of movement,
such as burrow, climb, fly, or swim. As with any
effect that increases a creature's speed, this spell
affects maximum jumping distance.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/19/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
float fDur = RoundsToSeconds(1);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
effect eSpeed = EffectMovementSpeedIncrease(100);
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(20), lLoc, FALSE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oTarget))
{
if(GetIsReactionTypeFriendly(oTarget))
{
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSpeed, oTarget, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HASTE), oTarget);
}
oTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(20), lLoc, FALSE, OBJECT_TYPE_CREATURE);
}
PRCSetSchool();
}

View File

@@ -0,0 +1,93 @@
//:://////////////////////////////////////////////
//:: Name Resist Energy
//:: FileName sp_resenergy.nss
//:://////////////////////////////////////////////
/** @file Abjuration
Level: Ranger 1, Duskblade 1, Cleric 2, Death Master 2,
Sha'ir 2, Wu Jen 2 (All), Death Delver 2, Fatemaker 2,
Knight of the Chalice 2, Knight of the Weave 2,
Vassal of Bahamut 2, Hoardstealer 2, Adept 2, Wizard 2,
Sorcerer 2, Paladin 2, Druid 2, Urban Druid 2, Dragon 2,
Fire 3
Components: V, S, DF,
Casting Time: 1 standard action
Range: Touch
Target: Creature touched
Duration: 10 min./level
Saving Throw: Fortitude negates (harmless)
Spell Resistance: Yes (harmless)
This abjuration grants a creature limited protection from
damage of whichever one of five energy types you select:
acid, cold, electricity, fire, or sonic. The subject gains
energy resistance 10 against the energy type chosen, meaning
that each time the creature is subjected to such damage
(whether from a natural or magical source), that damage is
reduced by 10 points before being applied to the creature's
hit points. The value of the energy resistance granted increases
to 20 points at 7th level and to a maximum of 30 points at 11th
level. The spell protects the recipient's equipment as well.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/20/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = 600.0f * (nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
int nSpell = GetSpellId();
int nDamType;
int nVis;
if(nSpell == SPELL_RESIST_ENERGY_ACID)
{
nDamType = DAMAGE_TYPE_ACID;
nVis = VFX_DUR_AURA_GREEN;
}
else if (nSpell == SPELL_RESIST_ENERGY_COLD)
{
nDamType = DAMAGE_TYPE_COLD;
nVis = VFX_DUR_AURA_CYAN;
}
else if (nSpell == SPELL_RESIST_ENERGY_ELEC)
{
nDamType = DAMAGE_TYPE_ELECTRICAL;
nVis = VFX_DUR_AURA_WHITE;
}
else if (nSpell == SPELL_RESIST_ENERGY_FIRE)
{
nDamType = DAMAGE_TYPE_FIRE;
nVis = VFX_DUR_AURA_RED;
}
else if (nSpell == SPELL_RESIST_ENERGY_SONIC)
{
nDamType = DAMAGE_TYPE_SONIC;
nVis = VFX_DUR_AURA_BLUE_LIGHT;
}
else
{
SendMessageToPC(oPC, "Invalid spell ID.");
break;
}
int nDamRes = 10;
if(nCasterLvl > 6) nDamRes +=10;
if(nCasterLvl > 10) nDamRes +=10;
effect eLink = EffectLinkEffects(EffectVisualEffect(nVis), EffectDamageResistance(nDamType, nDamRes));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,62 @@
//:://////////////////////////////////////////////
//:: Name Revenance
//:: FileName sp_revenance.nss
//:://////////////////////////////////////////////
/** @file Conjuration (Healing)
Level: Blackguard 4, Cleric 4, Paladin 4, Bard 6
Components: V, S, DF,
Casting Time: 1 standard action
Range: Touch
Target: Dead ally touched
Duration: 1 minute/level
Saving Throw: None; see text
Spell Resistance: Yes (harmless)
You rush to your fallen companion amid the chaos of the
battle and cry out the words that will bring her back for
one last fight.
This spell brings a dead ally temporarily back to life.
The subject can have been dead for up to 1 round per level.
Your target functions as if a raise dead spell (PH 268)
had been cast upon her, except that she does not lose a level
and has half of her full normal hit points. She is alive
(not undead) for the duration of the spell and can be healed
normally, but dies as soon as the spell ends.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/20/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_CONJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = (nCasterLvl * 60);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
object oTarget = GetSpellTargetObject();
if(!GetIsDead(oTarget) || GetIsReactionTypeHostile(oTarget))
{
SendMessageToPC(oPC, "Must target a dead ally.");
break;
}
//resurrect
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), oTarget);
//Heal by half
SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectHeal(GetMaxHitPoints(oTarget) / 2, oTarget), oTarget);
//Schedule doom
DelayCommand(fDur, SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oTarget);
PRCSetSchool();
}

View File

@@ -0,0 +1,39 @@
//:://////////////////////////////////////////////
//:: Name Rhino's Rush
//:: FileName sp_rhinorush.nss
//:://////////////////////////////////////////////
/** @file Transmutation
Level: Paladin 1, Ranger 1, Wrath (SpC) 1,
Components: V, S,
Casting Time: 1 swift action
Range: Personal
Target: You
Duration: 1 round
This spell allows you to propel yourself in a single deadly
charge. The first charge attack you make before the end of
the round deals double damage on a successful hit.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/21/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(1);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_IOUNSTONE_RED), oPC, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,58 @@
//:://////////////////////////////////////////////
//:: Name Righteous Aura
//:: FileName sp_rightaura.nss
//:://////////////////////////////////////////////
/** @file Abjuration [Good, Light]
Level: Paladin 4,
Components: V, S, DF,
Casting Time: 1 standard action
Range: Personal
Target: You
Duration: 1 hour/level
You invoke the powers of good and law, and in response
to your pleas, you glow with the golden radiance of the sun.
You are bathed in an unearthly glow for the duration of the
spell, as if a daylight spell (PH 216) had been cast on you.
You get a +4 sacred bonus to Charisma.
If you die, your body is converted into an explosive blast
of energy in a 20-foot-radius burst centered where you fell,
dealing 2d6 points of damage per caster level (maximum 20d6)
to all evil creatures in the burst's area. Good creatures in
the area are healed by the same amount, and undead take
double this damage. Spell resistance cannot prevent this
damage, but a successful Reflex save reduces it to half.
Your body is disintegrated, so you cannot be raised with a
raise dead spell. Spells that do not require an intact body,
such as true resurrection, can be used to bring you back to
life as normal.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/20/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_CONJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = HoursToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityIncrease(ABILITY_CHARISMA, 4), fDur, oPC);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAreaOfEffect(VFX_MOB_DAYLIGHT), fDur, oPC);
AddEventScript(oPC, EVENT_ONPLAYERDEATH, "prc_rightaura", FALSE, TRUE);
AddEventScript(oPC, EVENT_NPC_ONDEATH, "prc_rightaura", FALSE, TRUE);
PRCSetSchool();
}

View File

@@ -0,0 +1,49 @@
//:://////////////////////////////////////////////
//:: Name Righteous Fury
//:: FileName sp_rightfury.nss
//:://////////////////////////////////////////////
/** @file
Transmutation
Level: Paladin 3,
Components: V, S, DF,
Casting Time: 1 standard action
Range: Personal
Target: You
Duration: 1 minute/level
You pull a holy aura about you that glows a golden red.
Summoning the power of your deity, you charge yourself
with positive energy. This gives you 5 temporary hit
points per caster level (maximum 50) and a +4 sacred
bonus to Strength. These temporary hit points last for
up to 1 hour.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/29/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = 60*(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
int nHP = min(50, nCasterLvl * 5);
effect eBuff = EffectAbilityIncrease(ABILITY_STRENGTH, 4);
effect eHP = EffectTemporaryHitpoints(nHP);
effect eLink = EffectLinkEffects(eBuff, eHP);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, fDur);
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_GOOD_HELP), oPC);
PRCSetSchool();
}

View File

@@ -0,0 +1,44 @@
//:://////////////////////////////////////////////
//:: Name Seek Eternal Rest
//:: FileName sp_seeketrest.nss
//:://////////////////////////////////////////////
/** @file
Conjuration (Healing)
Level: Paladin 3,
Components: V, DF,
Casting Time: 1 standard action
Range: Personal
Target: You
Duration: 1 hour/level
You invoke the greater powers and are infused with
a great, golden glow, empowering you with holy glory.
You improve your ability to turn undead. For the
purpose of turning or destroying undead, you are
treated as a cleric of your paladin level.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 1/29/21
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_CONJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = HoursToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
//Apply VFX, need to alter the turning script
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_YELLOW_LIGHT), oPC, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,63 @@
//:://////////////////////////////////////////////
//:: Name Shield of Warding
//:: FileName sp_shieldward.nss
//:://////////////////////////////////////////////
/** @file Abjuration [Good]
Level: Paladin 2, Cleric 3,
Components: V, S,
Casting Time: 1 standard action
Range: Touch
Target: One shield or buckler touched
Duration: 1 minute/level
Saving Throw: Will negates (object, harmless)
Spell Resistance: No
The touched shield or buckler grants its wielder a +1
sacred bonus to Armor Class and on Reflex saves, +1 per
five caster levels (maximum +5 at 20th level). The bonus
applies only when the shield is worn or carried normally
(but not, for instance, if it is slung over the shoulder).
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/21/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl) * 60;
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
object oTarget = PRCGetSpellTargetObject();
object oShield;
if GetObjectType(oTarget == OBJECT_TYPE_CREATURE) oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
if GetObjectType(oTarget == OBJECT_TYPE_ITEM) oShield = oTarget;
//Check that this is a shield, if not abort
if(GetIsShield(oShield) == FALSE)
{
SendMessageToPC(OBJECT_SELF, "Target has no equipped shield.");
break;
}
int nBonus = 1;
if nCasterLvl > 4 nBonus +=1;
if nCasterLvl > 9 nBonus +=1;
if nCasterLvl > 14 nBonus +=1;
if nCasterLvl > 19 nBonus +=1;
IPSafeAddItemProperty(oShield, ItemPropertyACBonus(nBonus), fDur);
IPSafeAddItemProperty(oShield, ItemProperBonusSavingThrow(IP_CONST_SAVEBASETYPE_REFLEX, nBonus), fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,43 @@
//:://////////////////////////////////////////////
//:: Name Smite Heretic
//:: FileName sp_smiteher.nss
//:://////////////////////////////////////////////
/** @file Conjuration
Level: Paladin 3,
Components: V, S, DF,
Casting Time: 1 standard action
Range: Personal
Target: You
Duration: 10 minutes/level
For the duration of the spell, when using your smite
evil class ability against an evil creature with the
ability to cast divine spells, you gain a +2 sacred
bonus on the attack roll.
Furthermore, the attack deals 2 extra points of damage
(instead of 1) per paladin level.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/25/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_CONJURATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = 600 * nCasterLvl;
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_PULSE_YELLOW_WHITE), oPC, fDur);
PRCSetSchool();
}

View File

@@ -0,0 +1,62 @@
//:://////////////////////////////////////////////
//:: Name Smite of Sacred Fire
//:: FileName sp_smitesacfire.nss
//:://////////////////////////////////////////////
/** @file Evocation [Good]
Level: Paladin 2,
Components: V, DF,
Casting Time: 1 swift action
Range: Personal
Target: You
Duration: 1 round/level; see text
You must cast this spell in the same round when you
attempt a smite attack. If the attack hits, you deal
an extra 2d6 points of damage to the target of the
smite. Whether or not you succeed on the smite attempt,
during each subsequent round of the spell?s duration,
you deal an extra 2d6 points of damage on any successful
melee attack against the target you attempted to smite.
The spell ends prematurely after any round when you do not
attempt a melee attack against the target you previously
attempted to smite, or if you fail to hit with any of
your attacks in a round.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 7/25/2022
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void SmiteCheck(object oWeapon)
{
//No smite attempt last round
if(!GetLocalInt(oWeapon, "PRCSmiteLastRound"))
{
RemoveEventScript(oWeapon, EVENT_ITEM_ONHIT, "prc_evnt_ssf", TRUE, FALSE);
}
}
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_EVOCATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = RoundsToSeconds(nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
itemproperty ipHook = ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1);
IPSafeAddItemProperty(oWeapon, ipHook, fDur);
//Add onhit
AddEventScript(oWeapon, EVENT_ITEM_ONHIT, "prc_evnt_ssf", TRUE, FALSE);
DelayCommand(6.0f, SmiteCheck(oWeapon));
PRCSetSchool();
}

View File

@@ -0,0 +1,76 @@
//:://////////////////////////////////////////////
//:: Name Soldiers of Sanctity
//:: FileName sp_soldsanc.nss
//:://////////////////////////////////////////////
/** @file Evocation [Good]
Level: Cleric 3, Paladin 3,
Components: V, S, DF,
Casting Time: 1 full round
Range: Close (25 ft. + 5 ft./2 levels)
Target: You, plus one willing creature/2 levels; see text
Duration: 1 min./level
Saving Throw: None
Spell Resistance: No
For the duration of soldiers of sanctity, you gain a
bonus on turning checks and turning damage rolls made
when you have allies within 30 feet of you. This is a
sacred bonus, equal to the number of allies within 30
feet, to a maximum of +6.
In addition, each target gains a +2 bonus to AC against
all attacks made by undead creatures. This bonus
applies for the duration of the spell as long as an
ally is within 30 feet of you.
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 8/4/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void AllyCheck(object oPC, float fDur)
{
int nCount;
object oTest = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(30), GetLocation(oPC), OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oTest))
{
if(GetIsReactionTypeFriendly(oTest))
{
nCount++;
}
oTest = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(30), GetLocation(oPC), OBJECT_TYPE_CREATURE);
}
SetLocalInt(oPC, "SOLDIERS_OF_SANCTITY_ALLIES", nCount);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, VersusRacialTypeEffect(EffectACIncrease(2), RACIAL_TYPE_UNDEAD), oPC, 6.0f);
DelayCommand(6.0f, AllyCheck(oPC, fDur- 6.0));
}
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_EVOCATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = 60.0f * (nCasterLvl);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
int nTargets = min(6, nCasterLvl/2);
AllyCheck(oPC, fDur);
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(30), GetLocation(oPC), OBJECT_TYPE_CREATURE);
while(nTargets > 0)
{
AllyCheck(oTarget, fDur);
oTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(30), GetLocation(oPC), OBJECT_TYPE_CREATURE);
nTargets--;
}
PRCSetSchool();
}

View File

@@ -0,0 +1,87 @@
//:://////////////////////////////////////////////
//:: Name Soul of Light
//:: FileName sp_soulight.nss
//:://////////////////////////////////////////////
/** @file Transmutation [Good]
Level: Paladin 2, Cleric 3,
Components: V, S,
Casting Time: 1 standard action
Range: Personal
Target: You
Duration: 1 hour
Bright, clear light sprouts from your body, quickly
flaring before fading to a faint white pulse. This spell
infuses your body with energy drawn from the Positive
Energy Plane, making it easier to repair injuries.
Whenever you cast or are the target of a conjuration
(healing) spell, you can choose for the spell to heal
a number of extra points of damage equal to twice the spell's level.
If such a spell heals at least 10 points of damage,
it also removes the fatigued condition from the
target (or reduces exhaustion to fatigue).
If soul of light and soul of order are active on you at the
same time, you gain damage reduction 3/+3
*/
//:://////////////////////////////////////////////
//:: Created By: Tenjac
//:: Created On: 8/8/22
//:://////////////////////////////////////////////
#include "prc_sp_func"
#include "prc_add_spell_dc"
void main()
{
if(!X2PreSpellCastCode()) return;
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
object oPC = OBJECT_SELF;
int nCasterLvl = PRCGetCasterLevel(oPC);
float fDur = HoursToSeconds(1);
int nMetaMagic = PRCGetMetaMagicFeat();
if(nMetaMagic & METAMAGIC_EXTEND) fDur += fDur;
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_AURA_WHITE), oPC, fDur);
if(GetHasSpellEffect(SPELL_SOUL_OF_ORDER, oPC))
{
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectDamageReduction(3, DAMAGE_POWER_PLUS_THREE, 0), oPC, fDur);
}
/**To add into PRCEffectHeal
if(GetHasSpellEffect(SPELL_SOUL_OF_LIGHT, oTarget))
{
//2x the spell level bonus
nHP += (StringToInt(Get2DACache("spells", "Innate", PRCGetSpellId()) *2);
if(nHP >= 10)
{
effect eEffect = GetFirstEffect(oPC);
while(GetIsEffectValid(eEffect))
{
//remove fatigue
if(GetEffectTag(eEffect) == "PRCFatigue")
{
RemoveEffect(oPC, eEffect);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffecVisualEffect(VFX_DUR_CESSATE_POSITIVE) oTarget, 6.0f);
}
//downgrade exhaustion
if(GetEffectTag(eEffect) == "PRCExhausted")
{
float fNew = IntToFloat(GetEffectDurationRemaining(eEffect));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectFatigue(), oTarget, fNew);
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffecVisualEffect(VFX_DUR_CESSATE_POSITIVE) oTarget, 6.0f);
}
eEffect = GetNextEffect(oPC);
}
}
*/
PRCSetSchool();
}

Some files were not shown because too many files have changed in this diff Show More