Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
730 lines
31 KiB
Plaintext
730 lines
31 KiB
Plaintext
/* Core functions taken from high up the branch
|
|
which are needed lower. */
|
|
|
|
//:: Updated for .35 by Jaysyn 2023/03/10
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function Prototypes */
|
|
//////////////////////////////////////////////////
|
|
|
|
// wrapper for getspelltargetlocation
|
|
location PRCGetSpellTargetLocation(object oCaster = OBJECT_SELF);
|
|
|
|
// Avoids adding passive spellcasting to the character's action queue by
|
|
// creating an object specifically to cast the spell on the character.
|
|
//
|
|
// NOTE: The spell script must refer to the PC as PRCGetSpellTargetObject()
|
|
// otherwise this function WILL NOT WORK. Do not make any assumptions
|
|
// about the PC being OBJECT_SELF.
|
|
void ActionCastSpellOnSelf(int iSpell, int nMetaMagic = METAMAGIC_NONE, object oTarget = OBJECT_SELF);
|
|
|
|
// This is a wrapper function that causes OBJECT_SELF to fire the defined spell
|
|
// at the defined level. The target is automatically the object or location
|
|
// that the user selects. Useful for SLA's to perform the casting of a true
|
|
// spell. This is useful because:
|
|
//
|
|
// 1) If the original's spell script is updated, so is this one.
|
|
// 2) The spells are identified as the true spell. That is, they ARE the true spell.
|
|
// 3) Spellhooks (such as item crafting) that can only identify true spells
|
|
// will easily work.
|
|
//
|
|
// This function should only be used when SLA's are meant to simulate true
|
|
// spellcasting abilities, such as those seen when using feats with subradials
|
|
// to simulate spellbooks.
|
|
void ActionCastSpell(int iSpell, int iCasterLev = 0, int iBaseDC = 0, int iTotalDC = 0,
|
|
int nMetaMagic = METAMAGIC_NONE, int nClass = CLASS_TYPE_INVALID,
|
|
int bUseOverrideTargetLocation=FALSE, int bUseOverrideTargetObject=FALSE,
|
|
object oOverrideTarget=OBJECT_INVALID, int bInstantCast=TRUE, int bUseOverrideMetaMagic=FALSE);
|
|
|
|
/**
|
|
* Checks whether the given creature is committing an action, or
|
|
* under such effects that cause a breach of concentration.
|
|
*
|
|
* @param oConcentrator The creature to test
|
|
* @return TRUE if concentration is broken, FALSE otherwise
|
|
*/
|
|
int GetBreakConcentrationCheck(object oConcentrator);
|
|
|
|
/**
|
|
* Checks for breaks in concentration for an ongoing effect, and removes
|
|
* the effect if concentration is broken.
|
|
*
|
|
* @param oCaster The creature who cast the effect
|
|
* @param SpellID The id of the spell the effect belongs to
|
|
* @param oTarget The creature or object that is the target of the effect
|
|
* @param nDuration The duration the effect lasts in seconds.
|
|
*/
|
|
void CheckConcentrationOnEffect(object oCaster, int SpellID, object oTarget, int nDuration);
|
|
|
|
// gets the spell level adjustment to the nMetaMagic, including boni from the Improved Metamagic (epic) feat
|
|
int GetMetaMagicSpellLevelAdjustment(int nMetaMagic);
|
|
|
|
// Returns true if a spellcaster
|
|
int GetIsBioSpellCastClass(int nClass);
|
|
|
|
// Returns true for spell casters with spellbooks
|
|
int GetIsNSBClass(int nClass);
|
|
|
|
// returns the spelllevel of nSpell as it can be cast by oCreature
|
|
int PRCGetSpellLevel(object oCreature, int nSpell);
|
|
|
|
// returns if a character should be using the newspellbook when casting
|
|
int UseNewSpellBook(object oCreature);
|
|
|
|
// wrapper for GetHasSpell, works for newspellbook 'fake' spells too
|
|
// should return 0 if called with a normal spell when a character should be using the newspellbook
|
|
int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF);
|
|
|
|
// checks if oPC knows the specified spell
|
|
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
|
|
int PRCGetIsRealSpellKnown(int nRealSpellID, object oPC = OBJECT_SELF);
|
|
|
|
// checks if oPC knows the specified spell
|
|
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
|
|
// this will only check the spellbook of the class specified
|
|
int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJECT_SELF);
|
|
|
|
//routes to action cast spell, but puts a wrapper around to tell other functions its a
|
|
//SLA, so dont craft etc
|
|
//also defaults the totalDC to 10+spellevel+chamod
|
|
// moved from prc_inc_racial
|
|
void DoRacialSLA(int nSpellID, int nCasterlevel = 0, int nTotalDC = 0, int bInstantCast = FALSE);
|
|
|
|
/**
|
|
* Deletes a stored manifestation structure.
|
|
*
|
|
* @param oObject The object on which the structure is stored
|
|
* @param sName The name under which the structure is stored
|
|
*/
|
|
void DeleteLocalManifestation(object oObject, string sName);
|
|
|
|
/**
|
|
* Deletes a stored mystery structure.
|
|
*
|
|
* @param oObject The object on which the structure is stored
|
|
* @param sName The name under which the structure is stored
|
|
*/
|
|
void DeleteLocalMystery(object oObject, string sName);
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Constants */
|
|
//////////////////////////////////////////////////
|
|
|
|
// metamagic spell level adjustments for Bioware provided metamagic feats
|
|
const int METAMAGIC_EXTEND_LEVEL = 1;
|
|
const int METAMAGIC_SILENT_LEVEL = 1;
|
|
const int METAMAGIC_STILL_LEVEL = 1;
|
|
const int METAMAGIC_EMPOWER_LEVEL = 2;
|
|
const int METAMAGIC_MAXIMIZE_LEVEL = 3;
|
|
const int METAMAGIC_QUICKEN_LEVEL = 4;
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Includes */
|
|
//////////////////////////////////////////////////
|
|
|
|
#include "lookup_2da_spell"
|
|
#include "inc_lookups"
|
|
#include "prc_inc_damage"
|
|
#include "prc_inc_sb_const" // Spell Book Constants
|
|
#include "x0_i0_position"
|
|
|
|
/*
|
|
access to prc_inc_nwscript via prc_inc_damage
|
|
access to PRCGetSpell* via prc_inc_damage
|
|
*/
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function Definitions */
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
//wrapper for GetSpellTargetLocation()
|
|
location PRCGetSpellTargetLocation(object oCaster = OBJECT_SELF)
|
|
{
|
|
// check if there is an override location on the module, and return that
|
|
// bioware did not define a LOCATION_INVALID const, so we must signal a valid override location by setting a local int on the module
|
|
if(GetLocalInt(GetModule(), PRC_SPELL_TARGET_LOCATION_OVERRIDE))
|
|
{
|
|
if (DEBUG) DoDebug("PRCGetSpellTargetLocation: found override target location on module");
|
|
return GetLocalLocation(GetModule(), PRC_SPELL_TARGET_LOCATION_OVERRIDE);
|
|
}
|
|
|
|
|
|
// check if there is an override location on the caster, and return that
|
|
// bioware did not define a LOCATION_INVALID const, so we signal a valid override location by setting a local int on oCaster
|
|
if (GetLocalInt(oCaster, PRC_SPELL_TARGET_LOCATION_OVERRIDE))
|
|
{
|
|
if (DEBUG) DoDebug("PRCGetSpellTargetLocation: found override target location on caster "+GetName(oCaster));
|
|
return GetLocalLocation(oCaster, PRC_SPELL_TARGET_LOCATION_OVERRIDE);
|
|
}
|
|
|
|
|
|
// The rune/gem/skull always targets the one who activates it.
|
|
object oItem = PRCGetSpellCastItem(oCaster);
|
|
if(GetIsObjectValid(oItem) && (GetResRef(oItem) == "prc_rune_1" ||
|
|
GetResRef(oItem) == "prc_skulltalis" || GetTag(oItem) == "prc_attunegem"))
|
|
return GetLocation(GetItemPossessor(oItem));
|
|
|
|
if (GetLocalInt(oCaster, "BlackLabyrinth") && d10() < 3)
|
|
return GenerateNewLocationFromLocation(GetSpellTargetLocation(), FeetToMeters(5.0*d4()), IntToFloat(Random(360)), IntToFloat(Random(360)));
|
|
|
|
// if we made it here, we must use Bioware's function
|
|
return GetSpellTargetLocation();
|
|
}
|
|
|
|
void ActionCastSpellOnSelf(int iSpell, int nMetaMagic = METAMAGIC_NONE, object oTarget = OBJECT_SELF)
|
|
{
|
|
if(!GetIsObjectValid(oTarget)) oTarget = OBJECT_SELF;
|
|
object oCastingObject = CreateObject(OBJECT_TYPE_PLACEABLE, "x0_rodwonder", GetLocation(oTarget));
|
|
|
|
AssignCommand(oCastingObject, ActionCastSpellAtObject(iSpell, oTarget, nMetaMagic, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
|
|
if (DEBUG) DoDebug("ActionCastSpellOnSelf: Casting Spell "+IntToString(iSpell)+" on "+GetName(oTarget));
|
|
|
|
DestroyObject(oCastingObject, 6.0);
|
|
}
|
|
|
|
void ActionCastSpell(int iSpell, int iCasterLev = 0, int iBaseDC = 0, int iTotalDC = 0,
|
|
int nMetaMagic = METAMAGIC_NONE, int nClass = CLASS_TYPE_INVALID,
|
|
int bUseOverrideTargetLocation=FALSE, int bUseOverrideTargetObject=FALSE,
|
|
object oOverrideTarget=OBJECT_INVALID, int bInstantCast=TRUE, int bUseOverrideMetaMagic=FALSE)
|
|
{
|
|
|
|
//if its a hostile spell, clear the action queue
|
|
//this stops people stacking hostile spells to be instacast
|
|
//at the end, for example when coming out of invisibility
|
|
// X - hope this is not needed if spells are cast normally
|
|
//if(Get2DACache("spells", "HostileSetting", iSpell) == "1" && bInstantCast)
|
|
// ClearAllActions();
|
|
|
|
object oTarget = PRCGetSpellTargetObject();
|
|
location lLoc = PRCGetSpellTargetLocation();
|
|
|
|
//set the overriding values
|
|
if (iCasterLev != 0)
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_CASTERLEVEL_OVERRIDE, iCasterLev));
|
|
if (iTotalDC != 0)
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_DC_TOTAL_OVERRIDE, iTotalDC));
|
|
if (iBaseDC != 0)
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_DC_BASE_OVERRIDE, iBaseDC));
|
|
if (nClass != CLASS_TYPE_INVALID)
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_CASTERCLASS_OVERRIDE, nClass));
|
|
if (bUseOverrideMetaMagic)
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_METAMAGIC_OVERRIDE, nMetaMagic));
|
|
else if (nMetaMagic != METAMAGIC_NONE)
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_METAMAGIC_ADJUSTMENT, nMetaMagic));
|
|
if (bUseOverrideTargetLocation)
|
|
{
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_LOCATION_OVERRIDE, TRUE));
|
|
//location must be set outside of this function at the moment
|
|
//cant pass a location into a function as an optional parameter
|
|
//go bioware for not defining an invalid location constant
|
|
}
|
|
if (bUseOverrideTargetObject)
|
|
{
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE, TRUE));
|
|
ActionDoCommand(SetLocalObject(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE, oOverrideTarget));
|
|
}
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, "UsingActionCastSpell", TRUE));
|
|
|
|
if(DEBUG) DoDebug("ActionCastSpell SpellId: " + IntToString(iSpell));
|
|
if(DEBUG) DoDebug("ActionCastSpell Caster Level: " + IntToString(iCasterLev));
|
|
if(DEBUG) DoDebug("ActionCastSpell Base DC: " + IntToString(iBaseDC));
|
|
if(DEBUG) DoDebug("ActionCastSpell Total DC: " + IntToString(iTotalDC));
|
|
if(DEBUG) DoDebug("ActionCastSpell Metamagic: " + IntToString(nMetaMagic));
|
|
if(DEBUG) DoDebug("ActionCastSpell Caster Class: " + IntToString(nClass));
|
|
if(DEBUG) DoDebug("ActionCastSpell Target: " + GetName(oTarget));
|
|
if(DEBUG) DoDebug("ActionCastSpell Override Target: " + GetName(oOverrideTarget));
|
|
|
|
//cast the spell
|
|
if (GetIsObjectValid(oOverrideTarget))
|
|
ActionCastSpellAtObject(iSpell, oOverrideTarget, nMetaMagic, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstantCast);
|
|
else if (GetIsObjectValid(oTarget))
|
|
ActionCastSpellAtObject(iSpell, oTarget, nMetaMagic, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstantCast);
|
|
else
|
|
ActionCastSpellAtLocation(iSpell, lLoc, nMetaMagic, TRUE, PROJECTILE_PATH_TYPE_DEFAULT, bInstantCast);
|
|
|
|
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, "UsingActionCastSpell"));
|
|
|
|
//clean up afterwards
|
|
if(bInstantCast)//give scripts time to read the variables
|
|
{
|
|
if (iCasterLev != 0)
|
|
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_CASTERLEVEL_OVERRIDE)));
|
|
if (iTotalDC != 0)
|
|
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_DC_TOTAL_OVERRIDE)));
|
|
if (iBaseDC != 0)
|
|
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_DC_BASE_OVERRIDE)));
|
|
if (nClass != CLASS_TYPE_INVALID)
|
|
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_CASTERCLASS_OVERRIDE)));
|
|
if (nMetaMagic != METAMAGIC_NONE)
|
|
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_METAMAGIC_OVERRIDE)));
|
|
if (bUseOverrideTargetLocation)
|
|
{
|
|
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_LOCATION_OVERRIDE)));
|
|
//location must be set outside of this function at the moment
|
|
//cant pass a location into a function as an optional parameter
|
|
//go bioware for not defining an invalid location constant
|
|
}
|
|
if (bUseOverrideTargetObject)
|
|
{
|
|
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE)));
|
|
ActionDoCommand(DelayCommand(1.0, DeleteLocalObject(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (iCasterLev != 0)
|
|
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_CASTERLEVEL_OVERRIDE));
|
|
if (iTotalDC != 0)
|
|
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_DC_TOTAL_OVERRIDE));
|
|
if (iBaseDC != 0)
|
|
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_DC_BASE_OVERRIDE));
|
|
if (nClass != CLASS_TYPE_INVALID)
|
|
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_CASTERCLASS_OVERRIDE));
|
|
if (bUseOverrideMetaMagic)
|
|
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_METAMAGIC_OVERRIDE));
|
|
else if (nMetaMagic != METAMAGIC_NONE)
|
|
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_METAMAGIC_ADJUSTMENT));
|
|
if (bUseOverrideTargetLocation)
|
|
{
|
|
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_LOCATION_OVERRIDE));
|
|
//location must be set outside of this function at the moment
|
|
//cant pass a location into a function as an optional parameter
|
|
//go bioware for not defining an invalid location constant
|
|
}
|
|
if (bUseOverrideTargetObject)
|
|
{
|
|
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE));
|
|
ActionDoCommand(DeleteLocalObject(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE));
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
//The problem with this approace is that the effects are then applies by the original spell, which could go wrong. What to do?
|
|
SetLocalInt(OBJECT_SELF, PRC_SPELLID_OVERRIDE, GetSpellId());
|
|
DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_SPELLID_OVERRIDE));
|
|
string sScript = Get2DACache("spells", "ImpactScript", iSpell);
|
|
ExecuteScript(sScript, OBJECT_SELF);
|
|
*/
|
|
}
|
|
|
|
int GetBreakConcentrationCheck(object oConcentrator)
|
|
{
|
|
if (GetHasSpellEffect(VESTIGE_DAHLVERNAR, oConcentrator) && !GetLocalInt(oConcentrator, "PactQuality"+IntToString(VESTIGE_DAHLVERNAR))) return TRUE;
|
|
|
|
int nAction = GetCurrentAction(oConcentrator);
|
|
// creature doing anything that requires attention and breaks concentration
|
|
if (nAction == ACTION_DISABLETRAP || nAction == ACTION_TAUNT ||
|
|
nAction == ACTION_PICKPOCKET || nAction == ACTION_ATTACKOBJECT ||
|
|
nAction == ACTION_COUNTERSPELL || nAction == ACTION_FLAGTRAP ||
|
|
nAction == ACTION_CASTSPELL || nAction == ACTION_ITEMCASTSPELL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
//suffering a mental effect
|
|
effect e1 = GetFirstEffect(oConcentrator);
|
|
int nType;
|
|
while (GetIsEffectValid(e1))
|
|
{
|
|
nType = GetEffectType(e1);
|
|
if (nType == EFFECT_TYPE_STUNNED || nType == EFFECT_TYPE_PARALYZE ||
|
|
nType == EFFECT_TYPE_SLEEP || nType == EFFECT_TYPE_FRIGHTENED ||
|
|
nType == EFFECT_TYPE_PETRIFY || nType == EFFECT_TYPE_CONFUSED ||
|
|
nType == EFFECT_TYPE_DOMINATED || nType == EFFECT_TYPE_POLYMORPH)
|
|
{
|
|
return TRUE;
|
|
}
|
|
e1 = GetNextEffect(oConcentrator);
|
|
}
|
|
// add to on damage event
|
|
AddEventScript(oConcentrator, EVENT_VIRTUAL_ONDAMAGED, "prc_od_conc", FALSE, FALSE);
|
|
if(GetLocalInt(oConcentrator, "CONC_BROKEN")) // won't be set first time around regardless
|
|
{
|
|
DeleteLocalInt(oConcentrator, "CONC_BROKEN"); // reset for next spell
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void CheckConcentrationOnEffect(object oCaster, int SpellID, object oTarget, int nDuration)
|
|
{
|
|
int nDur = GetLocalInt(oCaster, "Conc" + IntToString(SpellID));
|
|
if(GetBreakConcentrationCheck(oCaster) == TRUE && nDur < nDuration)
|
|
{
|
|
FloatingTextStringOnCreature("*Concentration Broken*", oCaster);
|
|
DeleteLocalInt(oCaster, "Conc" + IntToString(SpellID));
|
|
PRCRemoveSpellEffects(SpellID, oCaster, oTarget);
|
|
}
|
|
else if(nDur < nDuration)
|
|
{
|
|
SetLocalInt(oCaster, "Conc" + IntToString(SpellID), nDur + 3);
|
|
DelayCommand(3.0, CheckConcentrationOnEffect(oCaster, SpellID, oTarget, nDuration));
|
|
}
|
|
else
|
|
{
|
|
DeleteLocalInt(oCaster, "Conc" + IntToString(SpellID));
|
|
}
|
|
}
|
|
|
|
int PRCGetSpellLevelForClass(int nSpell, int nClass)
|
|
{
|
|
string sSpellLevel = "";
|
|
if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER)
|
|
sSpellLevel = Get2DACache("spells", "Wiz_Sorc", nSpell);
|
|
else if (nClass == CLASS_TYPE_RANGER)
|
|
sSpellLevel = Get2DACache("spells", "Ranger", nSpell);
|
|
else if (nClass == CLASS_TYPE_PALADIN)
|
|
sSpellLevel = Get2DACache("spells", "Paladin", nSpell);
|
|
else if (nClass == CLASS_TYPE_DRUID)
|
|
sSpellLevel = Get2DACache("spells", "Druid", nSpell);
|
|
else if (nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_UR_PRIEST || nClass == CLASS_TYPE_OCULAR)
|
|
sSpellLevel = Get2DACache("spells", "Cleric", nSpell);
|
|
else if (nClass == CLASS_TYPE_BARD)
|
|
sSpellLevel = Get2DACache("spells", "Bard", nSpell);
|
|
else if (nClass == CLASS_TYPE_CULTIST_SHATTERED_PEAK)
|
|
sSpellLevel = Get2DACache("spells", "Cultist", nSpell);
|
|
else if (nClass == CLASS_TYPE_NENTYAR_HUNTER)
|
|
sSpellLevel = Get2DACache("spells", "Nentyar", nSpell);
|
|
else if (nClass == CLASS_TYPE_SHADOWLORD)
|
|
sSpellLevel = Get2DACache("spells", "Telflammar", nSpell);
|
|
else if (nClass == CLASS_TYPE_SLAYER_OF_DOMIEL)
|
|
sSpellLevel = Get2DACache("spells", "Domiel", nSpell);
|
|
else if (nClass == CLASS_TYPE_SOHEI)
|
|
sSpellLevel = Get2DACache("spells", "Sohei", nSpell);
|
|
else if (nClass == CLASS_TYPE_VASSAL)
|
|
sSpellLevel = Get2DACache("spells", "Bahamut", nSpell);
|
|
else if (nClass == CLASS_TYPE_BLACKGUARD)
|
|
sSpellLevel = Get2DACache("spells", "Blackguard", nSpell);
|
|
else if (nClass == CLASS_TYPE_KNIGHT_CHALICE)
|
|
sSpellLevel = Get2DACache("spells", "Chalice", nSpell);
|
|
else if (nClass == CLASS_TYPE_KNIGHT_MIDDLECIRCLE)
|
|
sSpellLevel = Get2DACache("spells", "MiddleCircle", nSpell);
|
|
else if (nClass == CLASS_TYPE_SOLDIER_OF_LIGHT)
|
|
sSpellLevel = Get2DACache("spells", "SoLight", nSpell);
|
|
else if (nClass == CLASS_TYPE_BLIGHTER)
|
|
sSpellLevel = Get2DACache("spells", "Blighter", nSpell);
|
|
else if (nClass == CLASS_TYPE_HEALER)
|
|
sSpellLevel = Get2DACache("spells", "Healer", nSpell);
|
|
else if (nClass == CLASS_TYPE_SHAMAN)
|
|
sSpellLevel = Get2DACache("spells", "Shaman", nSpell);
|
|
else if (nClass == CLASS_TYPE_INVALID)
|
|
sSpellLevel = Get2DACache("spells", "Innate", nSpell);
|
|
|
|
if (sSpellLevel != "")
|
|
return StringToInt(sSpellLevel);
|
|
|
|
// 2009-9-21: Support real spell ID's. -N-S
|
|
// PRCGetSpellLevel() is called several times in the Bioware spellhooking script.
|
|
// That means it will always pass a "real" spell ID to this function, but new-spellbook users won't have the real spell!
|
|
// GetSpellLevel() takes the fake spell ID, so this function was always failing.
|
|
//int nSpellLevel = GetSpellLevel(nSpell, nClass);
|
|
int nSpellLevel = -1;
|
|
int nSpellbookID = RealSpellToSpellbookID(nClass, nSpell);
|
|
if (nSpellbookID == -1)
|
|
nSpellLevel = GetSpellLevel(nSpell, nClass);
|
|
else
|
|
{
|
|
string sFile = GetFileForClass(nClass);
|
|
string sSpellLevel = Get2DACache(sFile, "Level", nSpellbookID);
|
|
if (sSpellLevel != "")
|
|
nSpellLevel = StringToInt(sSpellLevel);
|
|
}
|
|
|
|
return nSpellLevel;
|
|
}
|
|
|
|
// returns the spelllevel of nSpell as it can be cast by oCreature
|
|
int PRCGetSpellLevel(object oCreature, int nSpell)
|
|
{
|
|
/*if (!PRCGetHasSpell(nSpell, oCreature))
|
|
return -1;*/
|
|
|
|
int nClass = PRCGetLastSpellCastClass();
|
|
int nSpellLevel = PRCGetSpellLevelForClass(nSpell, nClass);
|
|
if (nSpellLevel != -1)
|
|
return nSpellLevel;
|
|
|
|
int i;
|
|
for (i=1;i<=8;i++)
|
|
{
|
|
nClass = GetClassByPosition(i, oCreature);
|
|
int nCharLevel = GetLevelByClass(nClass, oCreature);
|
|
if (nCharLevel)
|
|
{
|
|
nSpellLevel = PRCGetSpellLevelForClass(nSpell, nClass);
|
|
if (nSpellLevel != -1)
|
|
return nSpellLevel;
|
|
}
|
|
}
|
|
|
|
//return innate level
|
|
return StringToInt(Get2DACache("spells", "Innate", nSpell));
|
|
}
|
|
|
|
// gets the spell level adjustment to the nMetaMagic, including boni from the Improved Metamagic (epic) feat
|
|
int GetMetaMagicSpellLevelAdjustment(int nMetaMagic)
|
|
{
|
|
int nAdj;
|
|
if (nMetaMagic == 0) return nAdj;
|
|
|
|
if (nMetaMagic & METAMAGIC_EXTEND) nAdj += METAMAGIC_EXTEND_LEVEL;
|
|
if (nMetaMagic & METAMAGIC_SILENT) nAdj += METAMAGIC_SILENT_LEVEL;
|
|
if (nMetaMagic & METAMAGIC_STILL) nAdj += METAMAGIC_STILL_LEVEL;
|
|
if (nMetaMagic & METAMAGIC_EMPOWER) nAdj += METAMAGIC_EMPOWER_LEVEL;
|
|
if (nMetaMagic & METAMAGIC_MAXIMIZE) nAdj += METAMAGIC_MAXIMIZE_LEVEL;
|
|
if (nMetaMagic & METAMAGIC_QUICKEN) nAdj += METAMAGIC_QUICKEN_LEVEL;
|
|
|
|
return nAdj;
|
|
}
|
|
|
|
int GetIsBioSpellCastClass(int nClass)
|
|
{
|
|
return nClass == CLASS_TYPE_WIZARD
|
|
|| nClass == CLASS_TYPE_SORCERER
|
|
|| nClass == CLASS_TYPE_BARD
|
|
|| nClass == CLASS_TYPE_CLERIC
|
|
|| nClass == CLASS_TYPE_HEALER
|
|
|| nClass == CLASS_TYPE_BLIGHTER
|
|
|| nClass == CLASS_TYPE_BLACKGUARD
|
|
|| nClass == CLASS_TYPE_UR_PRIEST
|
|
|| nClass == CLASS_TYPE_OCULAR
|
|
|| nClass == CLASS_TYPE_SLAYER_OF_DOMIEL
|
|
|| nClass == CLASS_TYPE_CULTIST_SHATTERED_PEAK
|
|
|| nClass == CLASS_TYPE_NENTYAR_HUNTER
|
|
|| nClass == CLASS_TYPE_SHADOWLORD
|
|
|| nClass == CLASS_TYPE_SOHEI
|
|
|| nClass == CLASS_TYPE_SOLDIER_OF_LIGHT
|
|
|| nClass == CLASS_TYPE_VASSAL
|
|
|| nClass == CLASS_TYPE_KNIGHT_MIDDLECIRCLE
|
|
|| nClass == CLASS_TYPE_KNIGHT_CHALICE
|
|
|| nClass == CLASS_TYPE_SHAMAN
|
|
|| nClass == CLASS_TYPE_DRUID
|
|
|| nClass == CLASS_TYPE_PALADIN
|
|
|| nClass == CLASS_TYPE_RANGER;
|
|
}
|
|
|
|
int GetIsNSBClass(int nClass)
|
|
{
|
|
return !GetIsBioSpellCastClass(nClass)
|
|
&& GetSpellbookTypeForClass(nClass) != SPELLBOOK_TYPE_INVALID;
|
|
}
|
|
|
|
// returns if a character should be using the newspellbook when casting
|
|
int UseNewSpellBook(object oCreature)
|
|
{
|
|
int i;
|
|
for (i = 1; i <= 8; i++)
|
|
{
|
|
int nClass = GetClassByPosition(i, oCreature);
|
|
if(GetIsNSBClass(nClass))
|
|
return TRUE;
|
|
}
|
|
|
|
// Special case
|
|
if(GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oCreature))
|
|
return TRUE;
|
|
|
|
int nPrimaryArcane = GetPrimaryArcaneClass(oCreature);
|
|
|
|
//check they have bard/sorc in first arcane slot
|
|
if(nPrimaryArcane != CLASS_TYPE_BARD && nPrimaryArcane != CLASS_TYPE_SORCERER)
|
|
return FALSE;
|
|
//check they have arcane PrC or Draconic Breath/Arcane Grace
|
|
if(!GetArcanePRCLevels(oCreature)
|
|
&& !(GetHasFeat(FEAT_DRACONIC_GRACE, oCreature) || GetHasFeat(FEAT_DRACONIC_BREATH, oCreature)))
|
|
return FALSE;
|
|
//check if the newspellbooks are disabled
|
|
if((GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK) && nPrimaryArcane == CLASS_TYPE_SORCERER) ||
|
|
(GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK) && nPrimaryArcane == CLASS_TYPE_BARD))
|
|
return FALSE;
|
|
//check they have bard/sorc levels
|
|
if(!GetLevelByClass(CLASS_TYPE_BARD) && !GetLevelByClass(CLASS_TYPE_SORCERER))
|
|
return FALSE;
|
|
|
|
//at this point, they should be using the new spellbook
|
|
return TRUE;
|
|
}
|
|
|
|
// wrapper for GetHasSpell, works for newspellbook 'fake' spells too (and metamagic)
|
|
// should return 0 if called with a normal spell when a character should be using the newspellbook
|
|
int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF)
|
|
{
|
|
if(!PRCGetIsRealSpellKnown(nRealSpellID, oCreature))
|
|
return 0;
|
|
int nUses = GetHasSpell(nRealSpellID, oCreature);
|
|
|
|
int nClass, nSpellbookID, nCount, nMeta, i, j;
|
|
int nSpellbookType, nSpellLevel;
|
|
string sFile, sFeat;
|
|
for(i = 1; i <= 8; i++)
|
|
{
|
|
nClass = GetClassByPosition(i, oCreature);
|
|
sFile = GetFileForClass(nClass);
|
|
nSpellbookType = GetSpellbookTypeForClass(nClass);
|
|
nSpellbookID = RealSpellToSpellbookID(nClass, nRealSpellID);
|
|
nMeta = RealSpellToSpellbookIDCount(nClass, nRealSpellID);
|
|
if (nSpellbookID != -1)
|
|
{ //non-spellbook classes should return -1
|
|
for(j = nSpellbookID; j <= nSpellbookID + nMeta; j++)
|
|
{
|
|
sFeat = Get2DACache(sFile, "ReqFeat", j);
|
|
if(sFeat != "")
|
|
{
|
|
if(!GetHasFeat(StringToInt(sFeat), oCreature))
|
|
continue;
|
|
}
|
|
if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
|
|
{
|
|
nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), j);
|
|
if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
|
|
if(nCount > 0)
|
|
{
|
|
nUses += nCount;
|
|
}
|
|
}
|
|
else if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
|
|
{
|
|
nSpellLevel = StringToInt(Get2DACache(sFile, "Level", j));
|
|
nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), nSpellLevel);
|
|
if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
|
|
if(nCount > 0)
|
|
{
|
|
nUses += nCount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(DEBUG) DoDebug("PRCGetHasSpell: RealSpellID = " + IntToString(nRealSpellID) + ", Uses = " + IntToString(nUses));
|
|
return nUses;
|
|
}
|
|
|
|
// checks if oPC knows the specified spell
|
|
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
|
|
int PRCGetIsRealSpellKnown(int nRealSpellID, object oPC = OBJECT_SELF)
|
|
{
|
|
if(GetHasSpell(nRealSpellID, oPC)) //FUGLY HACK: bioware class having uses of the spell
|
|
return TRUE; // means they know the spell (close enough)
|
|
int nClass;
|
|
int nClassSlot = 1;
|
|
while(nClassSlot <= 8)
|
|
{
|
|
nClass = GetClassByPosition(nClassSlot, oPC);
|
|
if(GetIsDivineClass(nClass) || GetIsArcaneClass(nClass))
|
|
if(PRCGetIsRealSpellKnownByClass(nRealSpellID, nClass, oPC))
|
|
return TRUE;
|
|
nClassSlot++;
|
|
}
|
|
// got here means no match
|
|
return FALSE;
|
|
}
|
|
|
|
// checks if oPC knows the specified spell
|
|
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
|
|
// this will only check the spellbook of the class specified
|
|
int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJECT_SELF)
|
|
{
|
|
// check for whether bard and sorc are using the prc spellbooks
|
|
if (nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER)
|
|
{
|
|
if(!UseNewSpellBook(oPC))
|
|
return FALSE;
|
|
}
|
|
|
|
// get the cls_spell_***.2da index for the real spell
|
|
int nSpellbookSpell = RealSpellToSpellbookID(nClass, nRealSpellID);
|
|
// if the spell does not exist in the spellbook, return FALSE
|
|
if (nSpellbookSpell == -1)
|
|
return FALSE;
|
|
// next check if the PC is high enough level to know the spell
|
|
string sFile = GetFileForClass(nClass);
|
|
int nSpellLevel = -1;
|
|
string sSpellLevel = Get2DACache(sFile, "Level", nSpellbookSpell);
|
|
if (sSpellLevel != "")
|
|
nSpellLevel = StringToInt(sSpellLevel);
|
|
if ((GetLevelByClass(nClass) < nSpellLevel) || nSpellLevel == -1)
|
|
return FALSE; // not high enough level
|
|
// at this stage, prepared casters know the spell and only spontaneous classes need checking
|
|
// there are exceptions and these need hardcoding:
|
|
|
|
if((GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED) && nClass != CLASS_TYPE_ARCHIVIST)
|
|
return TRUE;
|
|
|
|
// spontaneous casters have all their known spells as hide feats
|
|
// get the featID of the spell
|
|
int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookSpell));
|
|
if (GetHasFeat(nFeatID, oPC))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//routes to action cast spell, but puts a wrapper around to tell other functions its a
|
|
//SLA, so dont craft etc
|
|
//also defaults th totalDC to 10+spellevel+chamod
|
|
//this is Base DC, not total DC. SLAs are still spells, so spell focus should still apply.
|
|
void DoRacialSLA(int nSpellID, int nCasterlevel = 0, int nTotalDC = 0, int bInstantCast = FALSE)
|
|
{
|
|
if(DEBUG) DoDebug("Spell DC passed to DoRacialSLA: " + IntToString(nTotalDC));
|
|
if(nTotalDC == 0)
|
|
nTotalDC = 10
|
|
+StringToInt(Get2DACache("spells", "Innate", nSpellID))
|
|
+GetAbilityModifier(ABILITY_CHARISMA);
|
|
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, "SpellIsSLA", TRUE));
|
|
if(DEBUG) DoDebug("Spell DC entered in ActionCastSpell: " + IntToString(nTotalDC));
|
|
ActionCastSpell(nSpellID, nCasterlevel, 0, nTotalDC, METAMAGIC_NONE, CLASS_TYPE_INVALID, FALSE, FALSE, OBJECT_INVALID, bInstantCast);
|
|
//ActionCastSpell(nSpellID, nCasterlevel, 0, nTotalDC);
|
|
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, "SpellIsSLA"));
|
|
}
|
|
|
|
void DeleteLocalManifestation(object oObject, string sName)
|
|
{
|
|
DeleteLocalObject(oObject, sName + "_oManifester");
|
|
|
|
DeleteLocalInt(oObject, sName + "_bCanManifest");
|
|
DeleteLocalInt(oObject, sName + "_nPPCost");
|
|
DeleteLocalInt(oObject, sName + "_nPsiFocUsesRemain");
|
|
DeleteLocalInt(oObject, sName + "_nManifesterLevel");
|
|
DeleteLocalInt(oObject, sName + "_nSpellID");
|
|
|
|
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_1");
|
|
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_2");
|
|
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_3");
|
|
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_4");
|
|
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_5");
|
|
DeleteLocalInt(oObject, sName + "_nTimesGenericAugUsed");
|
|
|
|
DeleteLocalInt(oObject, sName + "_bChain");
|
|
DeleteLocalInt(oObject, sName + "_bEmpower");
|
|
DeleteLocalInt(oObject, sName + "_bExtend");
|
|
DeleteLocalInt(oObject, sName + "_bMaximize");
|
|
DeleteLocalInt(oObject, sName + "_bSplit");
|
|
DeleteLocalInt(oObject, sName + "_bTwin");
|
|
DeleteLocalInt(oObject, sName + "_bWiden");
|
|
DeleteLocalInt(oObject, sName + "_bQuicken");
|
|
}
|
|
|
|
void DeleteLocalMystery(object oObject, string sName)
|
|
{
|
|
DeleteLocalObject(oObject, sName + "_oShadow");
|
|
|
|
DeleteLocalInt(oObject, sName + "_bCanMyst");
|
|
DeleteLocalInt(oObject, sName + "_nShadowcasterLevel");
|
|
DeleteLocalInt(oObject, sName + "_nMystId");
|
|
DeleteLocalInt(oObject, sName + "_nPen");
|
|
DeleteLocalInt(oObject, sName + "_bIgnoreSR");
|
|
|
|
DeleteLocalInt(oObject, sName + "_bEmpower");
|
|
DeleteLocalInt(oObject, sName + "_bExtend");
|
|
DeleteLocalInt(oObject, sName + "_bMaximize");
|
|
DeleteLocalInt(oObject, sName + "_bQuicken");
|
|
|
|
DeleteLocalInt(oObject, sName + "_nSaveDC");
|
|
DeleteLocalFloat(oObject, sName + "_fDur");
|
|
}
|
|
|