Fixed issue that was preventing certain character builds from replenishing epic spell slots. Updated release archive.
858 lines
30 KiB
Plaintext
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(){}
|