729 lines
31 KiB
Plaintext
729 lines
31 KiB
Plaintext
/* Core functions taken from high up the branch
|
|
which are needed lower. */
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* 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<=3;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 <= 3; 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 <= 3; 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 <= 3)
|
|
{
|
|
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");
|
|
}
|
|
|