PRC8/nwn/nwnprc/trunk/include/inc_epicspells.nss
Jaysyn904 597359e5dc Fixed issue that was preventing certain character builds from replenishing epic spell slots.
Fixed issue that was preventing certain character builds from replenishing epic spell slots.  Updated release archive.
2024-09-25 14:04:14 -04:00

858 lines
30 KiB
Plaintext

//:://////////////////////////////////////////////
//:: FileName: "inc_epicspells"
/* Purpose: This is the #include file that contains all constants and
functions needed for the Epic Spellcasting System.
*/
//:://////////////////////////////////////////////
//:: Created By: Boneshank (Don Armstrong)
//:: Last Updated On: March 18, 2004
//:://////////////////////////////////////////////
/*
CONSTANTS FOR OPTIONAL FEATURES
*/
/* moved to prc_inc_switch as runtime switches rather than compiletime
// Use the "XP Costs" option, making casters expend some experience when they
// cast certain spells?
const int XP_COSTS = TRUE;
// Use the "Take 10" variant rule?
// If TRUE, all Spellcraft checks will be automatically equal to the caster's
// Spellcraft skill level, plus 10. The outcome is never a surprise.
// If FALSE, every Spellcraft check is a roll of the dice, being equal to the
// caster's Spellcraft skill level, plus 1d20. Risky, but more fun!
const int TAKE_TEN_RULE = FALSE;
// Use the "Primary Ability Modifier Bonus to Skills" variant rule?
// If TRUE, caster's use their primary ability (WISDOM for clerics and druids,
// CHARISMA for sorcerers) instead of intelligence as a modifier on their
// Spellcraft checks for casting and researching epic spells, as well as
// their total Lore skill level for determining spell slots per day.
const int PRIMARY_ABILITY_MODIFIER_RULE = TRUE;
// Enable BACKLASH damage on spells? TRUE for yes, FALSE for no.
const int BACKLASH_DAMAGE = TRUE;
// Sets the DC adjustment active or inactive for researching spells.
// If TRUE, the player's spell foci feats are used to lower the spell's DC which
// lowers the overall costs of researching the spell. For example, if the
// spell is from the school of Necromancy, and the player has the feat Epic
// Spell Focus: Necromancy, then the DC for the rearch would be lowered by
// six. This would (under default ELHB settings) lower the gold cost by
// 54000 gold and 2160 exp. points, as well as makee the spell accessible
// to the player earlier and with a greater chance of success (due to the
// Spellcraft check).
// Setting this to FALSE will disable this feature.
const int FOCI_ADJUST_DC = TRUE;
// This sets the multiplier for the cost, in gold, to a player for the
// researching of an epic spell. The number is multiplied by the DC of
// the spell to be researched. ELHB default is 9000.
const int GOLD_MULTIPLIER = 9000;
// This sets the number to divide the gold cost by to determine the cost,
// in experience, to research an epic spell. The formula is as follows:
// XP Cost = Spell's DC x GOLD_MULTIPLIER / XP_FRACTION. The default from
// the ELHB is 25.
const int XP_FRACTION = 25;
// Set the number you want to divide the gold cost by for research failures.
// Examples: 2 would result in half the loss of the researcher's gold.
// 3 would result in a third of the gold lost.
// 4 would result in a quarter, etc.
const int FAILURE_FRACTION_GOLD = 2;
// Sets the percentage chance that a seed book is destroyed on a use of it.
// 0 = the book is never randomly destroyed from reading (using) it.
// 100 = the book is always destroyed from reading it.
// NOTE! This function is only ever called when the player actually acquires
// the seed feat. It is a way to control mass "gift-giving" amongst players
const int BOOK_DESTRUCTION = 50;
*/
// Play cutscenes for learning Epic Spell Seeds and researching Epic Spells?
const int PLAY_RESEARCH_CUTS = FALSE;
const int PLAY_SPELLSEED_CUT = FALSE;
// What school of magic does each spell belong to? (for research cutscenes)
// A = Abjuration
// C = Conjuration
// D = Divination
// E = Enchantment
// V = Evocation
// I = Illusion
// N = Necromancy
// T = Transmutation
// Between the quotation marks, enter the name of the cutscene script.
const string SCHOOL_A = "";
const string SCHOOL_C = "";
const string SCHOOL_D = "";
const string SCHOOL_E = "";
const string SCHOOL_V = "";
const string SCHOOL_I = "";
const string SCHOOL_N = "";
const string SCHOOL_T = "";
const string SPELLSEEDS_CUT = "";
/******************************************************************************
FUNCTION DECLARATIONS
******************************************************************************/
// Returns the combined caster level of oPC.
int GetTotalCastingLevel(object oPC);
// returns TRUE if oPC is an Epic level Dread Necromancer
int GetIsEpicDreadNecromancer(object oPC);
// returns TRUE if oPC is an Epic level warmage
int GetIsEpicWarmage(object oPC);
// returns TRUE if oPC is an Epic level healer.
int GetIsEpicHealer(object oPC);
// returns TRUE if oPC is an Epic level favored soul.
int GetIsEpicFavSoul(object oPC);
// Returns TRUE if oPC is an Epic level cleric.
int GetIsEpicCleric(object oPC);
// Returns TRUE if oPC is an Epic level druid.
int GetIsEpicDruid(object oPC);
// Returns TRUE if oPC is an Epic level sorcerer.
int GetIsEpicSorcerer(object oPC);
// Returns TRUE if oPC is an Epic level wizard.
int GetIsEpicWizard(object oPC);
// returns TRUE if oPC is an epic level shaman.
int GetIsEpicShaman(object oPC);
// returns TRUE if oPC is an epic level witch.
int GetIsEpicWitch(object oPC);
// returns TRUE if oPC is an epic level sublime chord.
int GetIsEpicSublimeChord(object oPC);
// returns TRUE if oPC is an epic level archivist.
int GetIsEpicArchivist(object oPC);
// returns TRUE if oPC is an epic level beguiler.
int GetIsEpicBeguiler(object oPC);
// returns TRUE if oPC is an epic level ur-priest.
int GetIsEpicUrPriest(object oPC);
// returns TRUE if oPC is an epic level blighter.
int GetIsEpicBlighter(object oPC);
// returns TRUE if oPC is an Epic spellcaster
int GetIsEpicSpellcaster(object oPC);
// Performs a check on the book to randomly destroy it or not when used.
void DoBookDecay(object oBook, object oPC);
// Returns oPC's spell slot limit, based on Lore and on optional rules.
int GetEpicSpellSlotLimit(object oPC);
// Returns the number of remaining unused spell slots for oPC.
int GetSpellSlots(object oPC);
// Replenishes oPC's Epic spell slots.
void ReplenishSlots(object oPC);
// Decrements oPC's Epic spell slots by one.
void DecrementSpellSlots(object oPC);
// Lets oPC know how many Epic spell slots remain for use.
void MessageSpellSlots(object oPC);
// Returns a Spellcraft check for oPC, based on optional rules.
int GetSpellcraftCheck(object oPC);
// Returns the Spellcraft skill level of oPC, based on optional rules.
int GetSpellcraftSkill(object oPC);
// Returns TRUE if oPC has enough gold to research the spell.
int GetHasEnoughGoldToResearch(object oPC, int nSpellDC);
// Returns TRUE if oPC has enough excess experience to research the spell.
int GetHasEnoughExperienceToResearch(object oPC, int nSpellDC);
// Returns TRUE if oPC has the passed in required feats (Seeds or other Epic spells)... needs BLAH_IP's
int GetHasRequiredFeatsForResearch(object oPC, int nReq1, int nReq2 = 0, int nReq3 = 0, int nReq4 = 0,
int nSeed1 = 0, int nSeed2 = 0, int nSeed3 = 0, int nSeed4 = 0, int nSeed5 = 0);
// Returns success (TRUE) or failure (FALSE) in oPC's researching of a spell.
int GetResearchResult(object oPC, int nSpellDC);
// Takes the gold & experience (depending on success) from oPC for researching.
void TakeResourcesFromPC(object oPC, int nSpellDC, int nSuccess);
// Returns TRUE if oPC can cast the spell.
int GetCanCastSpell(object oPC, int nEpicSpell);
// Returns the adjusted DC of a spell that takes into account oPC's Spell Foci.
int GetDCSchoolFocusAdjustment(object oPC, string sChool);
// Checks to see if oPC has a creature hide. If not, create and equip one.
void EnsurePCHasSkin(object oPC);
// Add nFeatIP to oPC's creature hide.
void GiveFeat(object oPC, int nFeatIP);
// Remove nFeatIP from oPC's creature hide.
void TakeFeat(object oPC, int nFeatIP);
// Checks to see how many castable epic spell feats oPC has ready to use.
// This is used for the control of the radial menu issue.
int GetCastableFeatCount(object oPC);
// When a contingency spell is active, oCaster loses the use of one slot per day
void PenalizeSpellSlotForCaster(object oCaster);
// When a contingecy expires, restore the spell slot for the caster.
void RestoreSpellSlotForCaster(object oCaster);
// Researches an Epic Spell for the caster.
void DoSpellResearch(object oCaster, int nSpellDC, int nSpellIP, string sSchool, object oBook);
// Cycles through equipped items on oTarget, and unequips any having nImmunityType
void UnequipAnyImmunityItems(object oTarget, int nImmType);
// Finds a given spell's DC
int GetEpicSpellSaveDC(object oCaster = OBJECT_SELF, object oTarget = OBJECT_INVALID, int nSpellID = -1);
int GetHasEpicSpellKnown(int nEpicSpell, object oPC);
void SetEpicSpellKnown(int nEpicSpell, object oPC, int nState = TRUE);
int GetHasEpicSeedKnown(int nEpicSeed, object oPC);
void SetEpicSeedKnown(int nEpicSeed, object oPC, int nState = TRUE);
#include "prc_inc_spells"
#include "prc_class_const"
#include "inc_epicspelldef"
#include "inc_epicspellfnc"
#include "inc_utility"
#include "prc_add_spell_dc"
//#include "x2_inc_spellhook"
/******************************************************************************
FUNCTION BODIES
******************************************************************************/
int GetIsEpicArchivist(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_ARCHIVIST, oPC, FALSE) > 16
&& GetAbilityScore(oPC, ABILITY_INTELLIGENCE) > 18;
}
int GetIsEpicBeguiler(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_BEGUILER, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_INTELLIGENCE) > 18;
}
int GetIsEpicCleric(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_CLERIC, oPC, FALSE) > 16
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicDreadNecromancer(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_DREAD_NECROMANCER, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_CHARISMA) > 18;
}
int GetIsEpicDruid(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_DRUID, oPC, FALSE) > 16
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicFavSoul(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_FAVOURED_SOUL, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_CHARISMA) > 18;
}
int GetIsEpicHealer(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_HEALER, oPC, FALSE) > 16
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicUrPriest(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_UR_PRIEST, oPC, FALSE) > 8
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicShaman(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_SHAMAN, oPC, FALSE) > 16
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicSorcerer(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_SORCERER, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_CHARISMA) > 18;
}
int GetIsEpicSublimeChord(object oPC)
{
return GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oPC) > 8
&& GetAbilityScore(oPC, ABILITY_CHARISMA) > 18;
}
int GetIsEpicBlighter(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_BLIGHTER, oPC, FALSE) > 8
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicWarmage(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_WARMAGE, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_CHARISMA) > 18;
}
int GetIsEpicWitch(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_WITCH, oPC, FALSE) > 17
&& GetAbilityScore(oPC, ABILITY_WISDOM) > 18;
}
int GetIsEpicWizard(object oPC)
{
return GetPrCAdjustedCasterLevel(CLASS_TYPE_WIZARD, oPC, FALSE) >= 17
&& GetAbilityScore(oPC, ABILITY_INTELLIGENCE) > 18;
}
int GetIsEpicSpellcaster(object oPC)
{
if(GetHitDice(oPC) < 21)
return FALSE;
if(GetIsEpicArchivist(oPC)
|| GetIsEpicBeguiler(oPC)
|| GetIsEpicCleric(oPC)
|| GetIsEpicDreadNecromancer(oPC)
|| GetIsEpicDruid(oPC)
|| GetIsEpicFavSoul(oPC)
|| GetIsEpicHealer(oPC)
|| GetIsEpicUrPriest(oPC)
|| GetIsEpicShaman(oPC)
|| GetIsEpicSorcerer(oPC)
|| GetIsEpicSublimeChord(oPC)
|| GetIsEpicBlighter(oPC)
|| GetIsEpicWarmage(oPC)
|| GetIsEpicWitch(oPC)
|| GetIsEpicWizard(oPC))
return TRUE;
return FALSE;
}
void DoBookDecay(object oBook, object oPC)
{
if (d100() >= GetPRCSwitch(PRC_EPIC_BOOK_DESTRUCTION))
{
DestroyObject(oBook, 2.0);
SendMessageToPC(oPC, MES_BOOK_DESTROYED);
}
}
int GetEpicSpellSlotLimit(object oPC)
{
int nLimit;
int nPen = GetLocalInt(oPC, "nSpellSlotPenalty");
int nBon = GetLocalInt(oPC, "nSpellSlotBonus");
// What's oPC's Lore skill?.
nLimit = GetSkillRank(SKILL_LORE, oPC);
// Variant rule implementation.
if (GetPRCSwitch(PRC_EPIC_PRIMARY_ABILITY_MODIFIER_RULE) == TRUE)
{
if (GetIsEpicSorcerer(oPC) || GetIsEpicFavSoul(oPC) || GetIsEpicWarmage(oPC) || GetIsEpicDreadNecromancer(oPC))
{
nLimit -= GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
nLimit += GetAbilityModifier(ABILITY_CHARISMA, oPC);
}
else if (GetIsEpicCleric(oPC) || GetIsEpicDruid(oPC) || GetIsEpicHealer(oPC) || GetIsEpicBlighter(oPC) || GetIsEpicShaman(oPC) || GetIsEpicUrPriest(oPC))
{
nLimit -= GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
nLimit += GetAbilityModifier(ABILITY_WISDOM, oPC);
}
}
// Primary calculation of slots.
nLimit /= 10;
// Modified calculation (for contingencies, bonuses, etc)
nLimit = nLimit + nBon;
nLimit = nLimit - nPen;
return nLimit;
}
int GetSpellSlots(object oPC)
{
int nSlots = GetLocalInt(oPC, "nEpicSpellSlots");
if(!GetIsPC(oPC) && !GetLocalInt(oPC, "EpicSpellSlotsReplenished"))
{
nSlots = GetEpicSpellSlotLimit(oPC);
SetLocalInt(oPC, "EpicSpellSlotsReplenished", TRUE);
SetLocalInt(oPC, "nEpicSpellSlots", nSlots);
}
return nSlots;
}
void ReplenishSlots(object oPC)
{
SetLocalInt(oPC, "nEpicSpellSlots", GetEpicSpellSlotLimit(oPC));
MessageSpellSlots(oPC);
}
void DecrementSpellSlots(object oPC)
{
SetLocalInt(oPC, "nEpicSpellSlots", GetLocalInt(oPC, "nEpicSpellSlots")-1);
MessageSpellSlots(oPC);
}
void MessageSpellSlots(object oPC)
{
SendMessageToPC(oPC, "You now have " +
IntToString(GetSpellSlots(oPC)) +
" Epic spell slots available.");
}
int GetHasEpicSpellKnown(int nEpicSpell, object oPC)
{
int nReturn = GetPersistantLocalInt(oPC, "EpicSpellKnown_"+IntToString(nEpicSpell));
if(!nReturn)
nReturn = GetHasFeat(GetResearchFeatForSpell(nEpicSpell), oPC);
return nReturn;
}
void SetEpicSpellKnown(int nEpicSpell, object oPC, int nState = TRUE)
{
SetPersistantLocalInt(oPC, "EpicSpellKnown_"+IntToString(nEpicSpell), nState);
}
int GetHasEpicSeedKnown(int nEpicSeed, object oPC)
{
int nReturn = GetPersistantLocalInt(oPC, "EpicSeedKnown_"+IntToString(nEpicSeed));
if(!nReturn)
nReturn = GetHasFeat(GetFeatForSeed(nEpicSeed), oPC);
return nReturn;
}
void SetEpicSeedKnown(int nEpicSeed, object oPC, int nState = TRUE)
{
SetPersistantLocalInt(oPC, "EpicSeedKnown_"+IntToString(nEpicSeed), nState);
}
int GetSpellcraftCheck(object oPC)
{
// Get oPC's skill rank.
int nCheck = GetSpellcraftSkill(oPC);
// Do the check, dependant on "Take 10" variant rule.
if (GetPRCSwitch(PRC_EPIC_TAKE_TEN_RULE) == TRUE)
nCheck += 10;
else
nCheck += d20();
return nCheck;
}
int GetSpellcraftSkill(object oPC)
{
// Determine initial Spellcraft skill.
int nSkill = GetSkillRank(SKILL_SPELLCRAFT, oPC);
// Variant rule implementation.
if (GetPRCSwitch(PRC_EPIC_PRIMARY_ABILITY_MODIFIER_RULE) == TRUE)
{
if (GetIsEpicSorcerer(oPC) || GetIsEpicFavSoul(oPC) || GetIsEpicWarmage(oPC) || GetIsEpicDreadNecromancer(oPC))
{
nSkill -= GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
nSkill += GetAbilityModifier(ABILITY_CHARISMA, oPC);
}
else if (GetIsEpicCleric(oPC) || GetIsEpicDruid(oPC) || GetIsEpicHealer(oPC) || GetIsEpicBlighter(oPC) || GetIsEpicShaman(oPC) || GetIsEpicUrPriest(oPC))
{
nSkill -= GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
nSkill += GetAbilityModifier(ABILITY_WISDOM, oPC);
}
}
return nSkill;
}
int GetHasEnoughGoldToResearch(object oPC, int nSpellDC)
{
int nCost = nSpellDC * GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER);
if (GetHasGPToSpend(oPC, nCost))
return TRUE;
return FALSE;
}
int GetHasEnoughExperienceToResearch(object oPC, int nSpellDC)
{
int nXPCost = nSpellDC * GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER) / GetPRCSwitch(PRC_EPIC_XP_FRACTION);
if (GetHasXPToSpend(oPC, nXPCost))
return TRUE;
return FALSE;
}
int GetHasRequiredFeatsForResearch(object oPC, int nReq1, int nReq2 = 0, int nReq3 = 0, int nReq4 = 0,
int nSeed1 = 0, int nSeed2 = 0, int nSeed3 = 0, int nSeed4 = 0, int nSeed5 = 0)
{
if(DEBUG)
{
DoDebug("Requirement #1: " + IntToString(nReq1));
DoDebug("Requirement #2: " + IntToString(nReq2));
DoDebug("Requirement #3: " + IntToString(nReq3));
DoDebug("Requirement #4: " + IntToString(nReq4));
DoDebug("Seed #1: " + IntToString(nSeed1));
DoDebug("Seed #2: " + IntToString(nSeed2));
DoDebug("Seed #3: " + IntToString(nSeed3));
DoDebug("Seed #4: " + IntToString(nSeed4));
DoDebug("Seed #4: " + IntToString(nSeed5));
}
if ((GetHasFeat(nReq1, oPC) || nReq1 == 0)
&& (GetHasFeat(nReq2, oPC) || nReq2 == 0)
&& (GetHasFeat(nReq3, oPC) || nReq3 == 0)
&& (GetHasFeat(nReq4, oPC) || nReq4 == 0)
&& (GetHasEpicSeedKnown(nSeed1, oPC) || nSeed1 == -1)
&& (GetHasEpicSeedKnown(nSeed2, oPC) || nSeed2 == -1)
&& (GetHasEpicSeedKnown(nSeed3, oPC) || nSeed3 == -1)
&& (GetHasEpicSeedKnown(nSeed4, oPC) || nSeed4 == -1)
&& (GetHasEpicSeedKnown(nSeed5, oPC) || nSeed5 == -1))
{
return TRUE;
}
return FALSE;
}
int GetResearchResult(object oPC, int nSpellDC)
{
int nCheck = GetSpellcraftCheck(oPC);
SendMessageToPC(oPC, "Your spellcraft check was a " +
IntToString(nCheck) + ", against a researching DC of " +
IntToString(nSpellDC));
if (nCheck >= nSpellDC)
{
SendMessageToPC(oPC, MES_SPELLCRAFT_CHECK_PASS);
return TRUE;
}
else
{
SendMessageToPC(oPC, MES_SPELLCRAFT_CHECK_FAIL);
return FALSE;
}
}
void TakeResourcesFromPC(object oPC, int nSpellDC, int nSuccess)
{
if (nSuccess != TRUE)
{
int nGold = nSpellDC *
GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER) / GetPRCSwitch(PRC_EPIC_FAILURE_FRACTION_GOLD);
SpendGP(oPC, nGold);
}
else
{
int nGold = nSpellDC * GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER);
SpendGP(oPC, nGold);
int nXP = nSpellDC * GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER) / GetPRCSwitch(PRC_EPIC_XP_FRACTION);
SpendXP(oPC, nXP);
}
}
int GetCanCastSpell(object oPC, int nEpicSpell)
{
int nSpellDC = GetDCForSpell(nEpicSpell);
string sChool = GetSchoolForSpell(nEpicSpell);
int nSpellXP =GetCastXPForSpell(nEpicSpell);
// Adjust the DC to account for Spell Foci feats.
nSpellDC -= GetDCSchoolFocusAdjustment(oPC, sChool);
int nCheck = GetSpellcraftCheck(oPC);
// Does oPC already know it
if (!GetHasEpicSpellKnown(nEpicSpell, oPC))
{
return FALSE;
}
if (!(GetSpellSlots(oPC) >= 1))
{ // No? Cancel spell, then.
SendMessageToPC(oPC, MES_CANNOT_CAST_SLOTS);
return FALSE;
}
if (GetPRCSwitch(PRC_EPIC_XP_COSTS) == TRUE)
{
// Does oPC have the needed XP available to cast the spell?
if (!GetHasXPToSpend(oPC, nSpellXP))
{ // No? Cancel spell, then.
SendMessageToPC(oPC, MES_CANNOT_CAST_XP);
return FALSE;
}
}
// Does oPC pass the Spellcraft check for the spell's casting?
if (!(nCheck >= nSpellDC))
{ // No?
SendMessageToPC(oPC, MES_SPELLCRAFT_CHECK_FAIL);
SendMessageToPC(oPC,
IntToString(nCheck) + " against a DC of " + IntToString(nSpellDC));
// Failing a Spellcraft check still costs a spell slot, so decrement...
DecrementSpellSlots(oPC);
return FALSE;
}
// If the answer is YES to all three, cast the spell!
SendMessageToPC(oPC, MES_SPELLCRAFT_CHECK_PASS);
SendMessageToPC(oPC,
IntToString(nCheck) + " against a DC of " + IntToString(nSpellDC));
SpendXP(oPC, nSpellXP); // Only spends the XP on a successful casting.
DecrementSpellSlots(oPC);
return TRUE;
}
void GiveFeat(object oPC, int nFeatIP)
{
object oSkin = GetPCSkin(oPC);
if (oSkin != OBJECT_INVALID)
IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(nFeatIP), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
void TakeFeat(object oPC, int nFeatIP)
{
object oSkin = GetPCSkin(oPC);
itemproperty ipX = GetFirstItemProperty(oSkin);
while (GetIsItemPropertyValid(ipX))
{
if (GetItemPropertyType(ipX) == ITEM_PROPERTY_BONUS_FEAT)
{
if(GetItemPropertySubType(ipX) == nFeatIP)
{
RemoveItemProperty(oSkin, ipX);
break;
}
}
ipX = GetNextItemProperty(oSkin);
}
}
int GetCastableFeatCount(object oPC)
{
int nX = 0;
int i = 0;
int nFeat = GetFeatForSpell(i);
while(nFeat != 0)
{
//test for the castable feat
if(GetHasFeat(nFeat, oPC))
nX += 1;
i++;
nFeat = GetFeatForSpell(i);
}
return nX;
}
void PenalizeSpellSlotForCaster(object oCaster)
{
int nMod = GetLocalInt(oCaster, "nSpellSlotPenalty");
SetLocalInt(oCaster, "nSpellSlotPenalty", nMod + 1);
SendMessageToPC(oCaster, MES_CONTINGENCIES_YES1);
SendMessageToPC(oCaster, MES_CONTINGENCIES_YES2);
SendMessageToPC(oCaster, "Your epic spell slot limit is now " +
IntToString(GetEpicSpellSlotLimit(oCaster)) + ".");
}
void RestoreSpellSlotForCaster(object oCaster)
{
int nMod = GetLocalInt(oCaster, "nSpellSlotPenalty");
if (nMod > 0) SetLocalInt(oCaster, "nSpellSlotPenalty", nMod - 1);
SendMessageToPC(oCaster, "Your epic spell slot limit is now " +
IntToString(GetEpicSpellSlotLimit(oCaster)) + ".");
}
void DoSpellResearch(object oCaster, int nSpellDC, int nSpellIP, string sSchool, object oBook)
{
float fDelay = 2.0;
string sCutScript;
int nResult = GetResearchResult(oCaster, nSpellDC);
if (PLAY_RESEARCH_CUTS == TRUE)
{
if (sSchool == "A") sCutScript = SCHOOL_A;
if (sSchool == "C") sCutScript = SCHOOL_C;
if (sSchool == "D") sCutScript = SCHOOL_D;
if (sSchool == "E") sCutScript = SCHOOL_E;
if (sSchool == "I") sCutScript = SCHOOL_I;
if (sSchool == "N") sCutScript = SCHOOL_N;
if (sSchool == "T") sCutScript = SCHOOL_T;
if (sSchool == "V") sCutScript = SCHOOL_V;
ExecuteScript(sCutScript, oCaster);
fDelay = 10.0;
}
DelayCommand(fDelay, TakeResourcesFromPC(oCaster, nSpellDC, nResult));
if (nResult == TRUE)
{
DelayCommand(fDelay, SendMessageToPC(oCaster, GetName(oCaster) + " " + MES_RESEARCH_SUCCESS));
//DelayCommand(fDelay, GiveFeat(oCaster, nSpellIP));
DelayCommand(fDelay, SetEpicSpellKnown(nSpellIP, oCaster, TRUE));
DelayCommand(fDelay, DestroyObject(oBook));
//research time
//1 day per 50,000GP +1
int nDays = (nSpellDC * GetPRCSwitch(PRC_EPIC_GOLD_MULTIPLIER))/50000;
nDays++;
float fSeconds = HoursToSeconds(24*nDays);
AdvanceTimeForPlayer(oCaster, fSeconds);
}
else
{
DelayCommand(fDelay, SendMessageToPC(oCaster, GetName(oCaster) + " " + MES_RESEARCH_FAILURE));
}
}
void UnequipAnyImmunityItems(object oTarget, int nImmType)
{
object oItem;
int nX;
for (nX = 0; nX <= 13; nX++) // Does not include creature items in search.
{
oItem = GetItemInSlot(nX, oTarget);
// Debug.
//SendMessageToPC(oTarget, "Checking slot " + IntToString(nX));
if (oItem != OBJECT_INVALID)
{
// Debug.
//SendMessageToPC(oTarget, "Valid item.");
itemproperty ipX = GetFirstItemProperty(oItem);
while (GetIsItemPropertyValid(ipX))
{
// Debug.
//SendMessageToPC(oTarget, "Valid ip");
if (GetItemPropertySubType(ipX) == nImmType)
{
// Debug.
//SendMessageToPC(oTarget, "ip match!!");
SendMessageToPC(oTarget, GetName(oItem) +
" cannot be equipped at this time.");
AssignCommand(oTarget, ClearAllActions());
AssignCommand(oTarget, ActionUnequipItem(oItem));
break;
}
else
ipX = GetNextItemProperty(oItem);
}
}
}
}
int GetTotalCastingLevel(object oCaster)
{
int iBestArcane = GetLevelByTypeArcaneFeats();
int iBestDivine = GetLevelByTypeDivineFeats();
int iBest = (iBestDivine > iBestArcane) ? iBestDivine : iBestArcane;
//SendMessageToPC(oCaster, "Epic casting at level " + IntToString(iBest));
return iBest;
}
int GetDCSchoolFocusAdjustment(object oPC, string sChool)
{
int nNewDC = 0;
if (sChool == "A") // Abjuration spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ABJURATION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ABJURATION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_ABJURATION, oPC)) nNewDC = 2;
}
if (sChool == "C") // Conjuration spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_CONJURATION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_CONJURATION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_CONJURATION, oPC)) nNewDC = 2;
}
if (sChool == "D") // Divination spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_DIVINATION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_DIVINIATION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_DIVINATION, oPC)) nNewDC = 2;
}
if (sChool == "E") // Enchantment spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ENCHANTMENT, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ENCHANTMENT, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_ENCHANTMENT, oPC)) nNewDC = 2;
}
if (sChool == "V") // Evocation spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_EVOCATION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_EVOCATION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_EVOCATION, oPC)) nNewDC = 2;
}
if (sChool == "I") // Illusion spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ILLUSION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ILLUSION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_ILLUSION, oPC)) nNewDC = 2;
}
if (sChool == "N") // Necromancy spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_NECROMANCY, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_NECROMANCY, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_NECROMANCY, oPC)) nNewDC = 2;
}
if (sChool == "T") // Transmutation spell?
{
if (GetHasFeat(FEAT_EPIC_SPELL_FOCUS_TRANSMUTATION, oPC)) nNewDC = 6;
else if (GetHasFeat(FEAT_GREATER_SPELL_FOCUS_TRANSMUTATION, oPC)) nNewDC = 4;
else if (GetHasFeat(FEAT_SPELL_FOCUS_TRANSMUTATION, oPC)) nNewDC = 2;
}
return nNewDC;
}
int GetEpicSpellSaveDC(object oCaster = OBJECT_SELF, object oTarget = OBJECT_INVALID, int nSpellID = -1)
{
int iDiv = GetPrCAdjustedCasterLevelByType(TYPE_DIVINE, oCaster); // ie. wisdom determines DC
int iWiz = GetPrCAdjustedCasterLevel(CLASS_TYPE_WIZARD, oCaster); // int determines DC
int iWMa = GetPrCAdjustedCasterLevel(CLASS_TYPE_WARMAGE, oCaster); // cha determines DC
int iDNc = GetPrCAdjustedCasterLevel(CLASS_TYPE_DREAD_NECROMANCER, oCaster); // cha determines DC
int iSor = GetPrCAdjustedCasterLevel(CLASS_TYPE_SORCERER, oCaster); // cha determines DC
int iWit = GetPrCAdjustedCasterLevel(CLASS_TYPE_WITCH, oCaster); // wis determines DC
int iArc = GetPrCAdjustedCasterLevel(CLASS_TYPE_ARCHIVIST, oCaster); // int determines DC
int iBeg = GetPrCAdjustedCasterLevel(CLASS_TYPE_BEGUILER, oCaster); // int determines DC
int iTpl = GetPrCAdjustedCasterLevel(CLASS_TYPE_TEMPLAR, oCaster); // cha determines DC
int iBest = 0;
int iAbility;
if(nSpellID == -1)
nSpellID = PRCGetSpellId();
if (iArc > iBest) { iAbility = ABILITY_INTELLIGENCE; iBest = iWit; }
if (iTpl > iBest) { iAbility = ABILITY_CHARISMA; iBest = iTpl; }
if (iWiz > iBest) { iAbility = ABILITY_INTELLIGENCE; iBest = iWiz; }
if (iWMa > iBest) { iAbility = ABILITY_CHARISMA; iBest = iWMa; }
if (iDNc > iBest) { iAbility = ABILITY_CHARISMA; iBest = iDNc; }
if (iSor > iBest) { iAbility = ABILITY_CHARISMA; iBest = iSor; }
if (iWit > iBest) { iAbility = ABILITY_WISDOM; iBest = iWit; }
if (iBeg > iBest) { iAbility = ABILITY_INTELLIGENCE; iBest = iBeg; }
if (iDiv > iBest) { iAbility = ABILITY_WISDOM; iBest = iDiv; }
int nDC;
if (iBest) nDC = 20 + GetAbilityModifier(iAbility, oCaster);
else nDC = 20; // DC = 20 if the epic spell is cast some other way.
nDC += GetDCSchoolFocusAdjustment(oCaster, Get2DACache("spells", "school", nSpellID));
nDC += GetChangesToSaveDC(oTarget, oCaster, nSpellID, GetSpellSchool(nSpellID));
return nDC;
}
// Test main
//void main(){}