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.
1313 lines
50 KiB
Plaintext
1313 lines
50 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Psionics include: Psionic Core Files
|
|
//:: psi_inc_core
|
|
//::///////////////////////////////////////////////
|
|
/** @file
|
|
Core functions removed from
|
|
|
|
psi_inc_psifunc
|
|
psi_inc_focus (depreciated)
|
|
|
|
as they are required by many of the other psi groups
|
|
|
|
@author Ornedan/ElgarL
|
|
@date Created - 2005.11.10/23.07.2010
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:://////////////////////////////////////////////
|
|
|
|
//:: Updated for .35 by Jaysyn 2023/03/10
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Constants */
|
|
//////////////////////////////////////////////////
|
|
|
|
// Included here to provide the values for the constants below
|
|
#include "prc_class_const"
|
|
|
|
const int POWER_LIST_PSION = CLASS_TYPE_PSION;
|
|
const int POWER_LIST_WILDER = CLASS_TYPE_WILDER;
|
|
const int POWER_LIST_PSYWAR = CLASS_TYPE_PSYWAR;
|
|
const int POWER_LIST_PSYROG = CLASS_TYPE_PSYCHIC_ROGUE;
|
|
const int POWER_LIST_FIST_OF_ZUOKEN = CLASS_TYPE_FIST_OF_ZUOKEN;
|
|
const int POWER_LIST_WARMIND = CLASS_TYPE_WARMIND;
|
|
|
|
#include "psi_inc_const"
|
|
|
|
//:: Test Main
|
|
//void main (){}
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function prototypes */
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Attempts to use psionic focus. If the creature was focused, it
|
|
* loses the focus. If it has Epic Psionic Focus feats, it will
|
|
* be able to use the focus for a number of times equal to the
|
|
* number of those feats it has during the next 0.5s
|
|
*
|
|
* @param oUser Creature expending it's psionic focus
|
|
* @return TRUE if the creature was psionically focus or had
|
|
* Epic Psionic Focus uses remaining. FALSE otherwise.
|
|
*/
|
|
int UsePsionicFocus(object oUser = OBJECT_SELF);
|
|
|
|
/**
|
|
* Sets psionic focus active and triggers feats dependant
|
|
* on it.
|
|
*
|
|
* Feats currently keyed to activity of psionic focus:
|
|
* Psionic Dodge
|
|
* Speed of Thought
|
|
*
|
|
* @param oGainee Creature gaining psionic focus.
|
|
*/
|
|
void GainPsionicFocus(object oGainee = OBJECT_SELF);
|
|
|
|
/**
|
|
* Gets the number of psionic focus uses the creature has available
|
|
* to it at this moment. If the creature is psionically focused,
|
|
* the number equal to GetPsionicFocusUsesPerExpenditure(), otherwise
|
|
* it is however many focus uses the creature still has remaining of
|
|
* that number.
|
|
*
|
|
* @param oCreature Creaute whose psionic focus use count to evaluate
|
|
* @return The total number of times UsePsionicFocus() will
|
|
* return TRUE if called at this moment.
|
|
*/
|
|
int GetPsionicFocusesAvailable(object oCreature = OBJECT_SELF);
|
|
|
|
/**
|
|
* Calculates the number of times a creature may use it's psionic focus when expending it.
|
|
* Base is 1.
|
|
* In addition, 1 more use for each Epic Psionic Focus feat the creature has.
|
|
*
|
|
* @param oCreature Creaute whose psionic focus use count to evaluate
|
|
* @return The total number of times UsePsionicFocus() will return
|
|
* TRUE for a single expending of psionic focus.
|
|
*/
|
|
int GetPsionicFocusUsesPerExpenditure(object oCreature = OBJECT_SELF);
|
|
|
|
/**
|
|
* Sets the given creature's psionic focus off and deactivates all feats keyed to it.
|
|
*
|
|
* @param oLoser Creature losing it's psionic focus
|
|
*/
|
|
void LosePsionicFocus(object oLoser = OBJECT_SELF);
|
|
|
|
/**
|
|
* Checks whether the given creature is psionically focused.
|
|
*
|
|
* @param oCreature Creature whose psionic focus's state to examine
|
|
* @return TRUE if the creature is psionically focused, FALSE
|
|
* otherwise.
|
|
*/
|
|
int GetIsPsionicallyFocused(object oCreature = OBJECT_SELF);
|
|
|
|
/**
|
|
* Determines the number of feats that would use psionic focus
|
|
* when triggered the given creature has active.
|
|
*
|
|
* Currently accounts for:
|
|
* Talented
|
|
* Power Specialization
|
|
* Power Penetration
|
|
* Psionic Endowment
|
|
* Chain Power
|
|
* Empower Power
|
|
* Extend Power
|
|
* Maximize Power
|
|
* Split Psionic Ray
|
|
* Twin Power
|
|
* Widen Power
|
|
* Quicken Power
|
|
*
|
|
* @param oCreature Creature whose feats to examine
|
|
* @return How many of the listed feats are active
|
|
*/
|
|
int GetPsionicFocusUsingFeatsActive(object oCreature = OBJECT_SELF);
|
|
|
|
/**
|
|
* Calculates the DC of the power being currently manifested.
|
|
* Base value is 10 + power level + ability modifier in manifesting stat
|
|
*
|
|
* WARNING: Return value is not defined when a power is not being manifested.
|
|
*
|
|
*/
|
|
int GetManifesterDC(object oManifester = OBJECT_SELF);
|
|
|
|
/**
|
|
* Determines the spell school matching a discipline according to the
|
|
* standard transparency rules.
|
|
* Disciplines which have no matching spell school are matched with
|
|
* SPELL_SCHOOL_GENERAL.
|
|
*
|
|
* @param nDiscipline Discipline to find matching spell school for
|
|
* @return SPELL_SCHOOL_* of the match
|
|
*/
|
|
int DisciplineToSpellSchool(int nDiscipline);
|
|
|
|
/**
|
|
* Determines the discipline matching a spell school according to the
|
|
* standard transparency rules.
|
|
* Spell schools that have no matching disciplines are matched with
|
|
* DISCIPLINE_NONE.
|
|
*
|
|
* @param nSpellSchool Spell schools to find matching discipline for
|
|
* @return DISCIPLINE_* of the match
|
|
*/
|
|
int SpellSchoolToDiscipline(int nSpellSchool);
|
|
|
|
/**
|
|
* Determines the discipline of a power, using the School column of spells.2da.
|
|
*
|
|
* @param nSpellID The spellID of the power to determine the discipline of
|
|
* @return DISCIPLINE_* constant. DISCIPLINE_NONE if the power's
|
|
* School designation does not match any of the discipline's.
|
|
*/
|
|
int GetPowerDiscipline(int nSpellID);
|
|
|
|
/**
|
|
* Determines whether a given power is a power of the Telepahty discipline.
|
|
*
|
|
* @param nSpellID The spells.2da row of the power. If left to default,
|
|
* PRCGetSpellId() is used.
|
|
* @return TRUE if the power's discipline is Telepathy, FALSE otherwise
|
|
*/
|
|
int GetIsTelepathyPower(int nSpellID = -1);
|
|
|
|
/**
|
|
* Checks whether the PC possesses the feats the given feat has as it's
|
|
* prerequisites. Possession of a feat is checked using GetHasFeat().
|
|
*
|
|
*
|
|
* @param nFeat The feat for which determine the possession of prerequisites
|
|
* @param oPC The creature whose feats to check
|
|
* @return TRUE if the PC possesses the prerequisite feats AND does not
|
|
* already posses nFeat, FALSE otherwise.
|
|
*/
|
|
int CheckPowerPrereqs(int nFeat, object oPC);
|
|
|
|
/**
|
|
* Determines the manifester's level in regards to manifester checks to overcome
|
|
* spell resistance.
|
|
*
|
|
* WARNING: Return value is not defined when a power is not being manifested.
|
|
*
|
|
* @param oManifester A creature manifesting a power at the moment
|
|
* @return The creature's manifester level, adjusted to account for
|
|
* modifiers that affect spell resistance checks.
|
|
*/
|
|
int GetPsiPenetration(object oManifester = OBJECT_SELF);
|
|
|
|
/**
|
|
* Determines whether a given creature possesses the Psionic subtype.
|
|
* Ways of possessing the subtype:
|
|
* - Being of a naturally psionic race
|
|
* - Having class levels in a psionic class
|
|
* - Possessing the Wild Talent feat
|
|
*
|
|
* @param oCreature Creature to test
|
|
* @return TRUE if the creature is psionic, FALSE otherwise.
|
|
*/
|
|
int GetIsPsionicCharacter(object oCreature);
|
|
|
|
/**
|
|
* Creates the creature weapon for powers like Bite of the Wolf and Claws of the
|
|
* Beast. If a creature weapon of the correct type is already present, it is
|
|
* used instead of a new one.
|
|
*
|
|
* Preserving existing weapons may cause problems, if so, make the function instead delete the old object - Ornedan
|
|
*
|
|
* @param oCreature Creatue whose creature weapons to mess with.
|
|
* @param sResRef Resref of the creature weapon. Assumed to be one of the
|
|
* PRC creature weapons, so this considered to is also be
|
|
* the tag.
|
|
* @param nIventorySlot Inventory slot where the creature weapon is to be equipped.
|
|
* @param fDuration If a new weapon is created, it will be destroyed after
|
|
* this duration.
|
|
*
|
|
* @return The newly created creature weapon. Or an existing weapon,
|
|
* if there was one.
|
|
*/
|
|
object GetPsionicCreatureWeapon(object oCreature, string sResRef, int nInventorySlot, float fDuration);
|
|
|
|
/**
|
|
* Applies modifications to a power's damage that depend on some property
|
|
* of the target.
|
|
* Currently accounts for:
|
|
* - Mental Resistance
|
|
* - Greater Power Specialization
|
|
* - Intellect Fortress
|
|
*
|
|
* @param oTarget A creature being dealt damage by a power
|
|
* @param oManifester The creature manifesting the damaging power
|
|
* @param nDamage The amount of damage the creature would be dealt
|
|
*
|
|
* @param bIsHitPointDamage Is the damage HP damage or something else?
|
|
* @param bIsEnergyDamage Is the damage caused by energy or something else? Only relevant if the damage is HP damage.
|
|
*
|
|
* @return The amount of damage, modified by oTarget's abilities
|
|
*/
|
|
int GetTargetSpecificChangesToDamage(object oTarget, object oManifester, int nDamage,
|
|
int bIsHitPointDamage = TRUE, int bIsEnergyDamage = FALSE);
|
|
|
|
/**
|
|
* Gets the manifester level adjustment from the Practiced Manifester feats.
|
|
*
|
|
* @param oManifester The creature to check
|
|
* @param iManifestingClass The CLASS_TYPE* that the power was cast by.
|
|
* @param iManifestingLevels The manifester level for the power calculated so far
|
|
* ie. BEFORE Practiced Manifester.
|
|
*/
|
|
int PracticedManifesting(object oManifester, int iManifestingClass, int iManifestingLevels);
|
|
|
|
/**
|
|
* Determines the given creature's manifester level. If a class is specified,
|
|
* then returns the manifester level for that class. Otherwise, returns
|
|
* the manifester level for the currently active manifestation.
|
|
*
|
|
* @param oManifester The creature whose manifester level to determine
|
|
* @param nSpecificClass The class to determine the creature's manifester
|
|
* level in.
|
|
* DEFAULT: CLASS_TYPE_INVALID, which means the creature's
|
|
* manifester level in regards to an ongoing manifestation
|
|
* is determined instead.
|
|
* @param nMaxPowerLevel For learning powers. Practiced Manifester is breaking things otherwise.
|
|
* @return The manifester level
|
|
*/
|
|
int GetManifesterLevel(object oManifester, int nSpecificClass = CLASS_TYPE_INVALID, int nMaxPowerLevel = FALSE);
|
|
|
|
/**
|
|
* Determines the given creature's highest undmodified manifester level among it's
|
|
* manifesting classes.
|
|
*
|
|
* @param oCreature Creature whose highest manifester level to determine
|
|
* @return The highest unmodified manifester level the creature can have
|
|
*/
|
|
int GetHighestManifesterLevel(object oCreature);
|
|
|
|
/**
|
|
* Gets the level of the power being currently manifested.
|
|
* WARNING: Return value is not defined when a power is not being manifested.
|
|
*
|
|
* @param oManifester The creature currently manifesting a power
|
|
* @return The level of the power being manifested
|
|
*/
|
|
int GetPowerLevel(object oManifester);
|
|
|
|
/**
|
|
* Determines a creature's ability score in the manifesting ability of a given
|
|
* class.
|
|
*
|
|
* @param oManifester Creature whose ability score to get
|
|
* @param nClass CLASS_TYPE_* constant of a manifesting class
|
|
*/
|
|
int GetAbilityScoreOfClass(object oManifester, int nClass);
|
|
|
|
/**
|
|
* Determines from what class's power list the currently being manifested
|
|
* power is manifested from.
|
|
*
|
|
* @param oManifester A creature manifesting a power at this moment
|
|
* @return CLASS_TYPE_* constant of the class
|
|
*/
|
|
int GetManifestingClass(object oManifester = OBJECT_SELF);
|
|
|
|
/**
|
|
* Determines the manifesting ability of a class.
|
|
*
|
|
* @param nClass CLASS_TYPE_* constant of the class to determine the manifesting stat of
|
|
* @return ABILITY_* of the manifesting stat. ABILITY_CHARISMA for non-manifester
|
|
* classes.
|
|
*/
|
|
int GetAbilityOfClass(int nClass);
|
|
|
|
/**
|
|
* Determines which of the character's classes is their highest or first psionic
|
|
* manifesting class, if any. This is the one which gains manifester level raise
|
|
* benefits from prestige classes.
|
|
*
|
|
* @param oCreature Creature whose classes to test
|
|
* @return CLASS_TYPE_* of the first psionic manifesting class,
|
|
* CLASS_TYPE_INVALID if the creature does not posses any.
|
|
*/
|
|
int GetPrimaryPsionicClass(object oCreature = OBJECT_SELF);
|
|
|
|
/**
|
|
* Calculates how many manifester levels are gained by a given creature from
|
|
* it's levels in prestige classes.
|
|
*
|
|
* @param oCreature Creature to calculate added manifester levels for
|
|
* @return The number of manifester levels gained
|
|
*/
|
|
int GetPsionicPRCLevels(object oCreature);
|
|
|
|
/**
|
|
* Determines the position of a creature's first psionic manifesting class, if any.
|
|
*
|
|
* @param oCreature Creature whose classes to test
|
|
* @return The position of the first psionic class {1, 2, 3} or 0 if
|
|
* the creature possesses no levels in psionic classes.
|
|
*/
|
|
int GetFirstPsionicClassPosition(object oCreature = OBJECT_SELF);
|
|
|
|
/**
|
|
* Determines whether a given class is a psionic class or not. A psionic
|
|
* class is defined as one that gives base manifesting.
|
|
*
|
|
* @param nClass CLASS_TYPE_* of the class to test
|
|
* @return TRUE if the class is a psionic class, FALSE otherwise
|
|
*/
|
|
int GetIsPsionicClass(int nClass);
|
|
|
|
/**
|
|
* Gets the amount of manifester levels the given creature is Wild Surging by.
|
|
*
|
|
* @param oManifester The creature to test
|
|
* @return The number of manifester levels added by Wild Surge. 0 if
|
|
* Wild Surge is not active.
|
|
*/
|
|
int GetWildSurge(object oManifester);
|
|
|
|
/**
|
|
* Gets the highest power level the creature should know
|
|
*
|
|
* @param oManifester The creature to test
|
|
* @return Power level.
|
|
*/
|
|
int GetMaxPowerLevel(object oManifester);
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Includes */
|
|
//////////////////////////////////////////////////
|
|
|
|
#include "prc_inc_unarmed"
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Global Structures */
|
|
//////////////////////////////////////////////////
|
|
|
|
// These are used in psi_inc_psifunc and psi_inc_augment
|
|
|
|
/**
|
|
* A structure that contains common data used during power manifestation.
|
|
*/
|
|
struct manifestation{
|
|
/* Generic stuff */
|
|
/// The creature manifesting the power
|
|
object oManifester;
|
|
/// Whether the manifestation is successfull or not
|
|
int bCanManifest;
|
|
/// How much Power Points the manifestation costs
|
|
int nPPCost;
|
|
/// How many psionic focus uses the manifester would have remaining at a particular point in the manifestation
|
|
int nPsiFocUsesRemain;
|
|
/// The creature's manifester level in regards to this power
|
|
int nManifesterLevel;
|
|
/// The power's spell ID
|
|
int nSpellID;
|
|
|
|
/* Augmentation */
|
|
/// How many times the first augmentation option of the power is used
|
|
int nTimesAugOptUsed_1;
|
|
/// How many times the second augmentation option of the power is used
|
|
int nTimesAugOptUsed_2;
|
|
/// How many times the third augmentation option of the power is used
|
|
int nTimesAugOptUsed_3;
|
|
/// How many times the fourth augmentation option of the power is used
|
|
int nTimesAugOptUsed_4;
|
|
/// How many times the fifth augmentation option of the power is used
|
|
int nTimesAugOptUsed_5;
|
|
/// How many times the PP used for augmentation triggered the generic augmentation of the power
|
|
int nTimesGenericAugUsed;
|
|
|
|
/* Metapsionics */
|
|
/// Whether Chain Power was used with this manifestation
|
|
int bChain;
|
|
/// Whether Empower Power was used with this manifestation
|
|
int bEmpower;
|
|
/// Whether Extend Power was used with this manifestation
|
|
int bExtend;
|
|
/// Whether Maximize Power was used with this manifestation
|
|
int bMaximize;
|
|
/// Whether Split Psionic Ray was used with this manifestation
|
|
int bSplit;
|
|
/// Whether Twin Power was used with this manifestation
|
|
int bTwin;
|
|
/// Whether Widen Power was used with this manifestation
|
|
int bWiden;
|
|
/// Whether Quicken Power was used with this manifestation
|
|
int bQuicken;
|
|
};
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function definitions */
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/* Begin PSI FOCUS */
|
|
//////////////////////////////////////////////////////
|
|
|
|
int UsePsionicFocus(object oUser = OBJECT_SELF)
|
|
{
|
|
int bToReturn = FALSE;
|
|
// This does not expend your psionic focus, but rather the item's
|
|
if (GetLocalInt(oUser, "SimpleBow_Focus"))
|
|
{
|
|
DeleteLocalInt(oUser, "SimpleBow_Focus");
|
|
return TRUE;
|
|
}
|
|
// Next, check if we have focus on
|
|
else if(GetLocalInt(oUser, PSIONIC_FOCUS))
|
|
{
|
|
SetLocalInt(oUser, "PsionicFocusUses", GetPsionicFocusUsesPerExpenditure(oUser) - 1);
|
|
DelayCommand(0.5f, DeleteLocalInt(oUser, "PsionicFocusUses"));
|
|
SendMessageToPCByStrRef(oUser, 16826414); // "You have used your Psionic Focus"
|
|
|
|
bToReturn = TRUE;
|
|
}
|
|
// We don't. Check if there are uses remaining
|
|
else if(GetLocalInt(oUser, "PsionicFocusUses"))
|
|
{
|
|
SetLocalInt(oUser, "PsionicFocusUses", GetLocalInt(oUser, "PsionicFocusUses") - 1);
|
|
|
|
bToReturn = TRUE;
|
|
}
|
|
|
|
// Lose focus if it was used
|
|
if(bToReturn) LosePsionicFocus(oUser);
|
|
|
|
return bToReturn;
|
|
}
|
|
|
|
void GainPsionicFocus(object oGainee = OBJECT_SELF)
|
|
{
|
|
SetLocalInt(oGainee, PSIONIC_FOCUS, TRUE);
|
|
|
|
// Speed Of Thought
|
|
if(GetHasFeat(FEAT_SPEED_OF_THOUGHT, oGainee))
|
|
{
|
|
// Check for heavy armor before adding the bonus now
|
|
if(GetBaseAC(GetItemInSlot(INVENTORY_SLOT_CHEST, oGainee)) < 6)
|
|
AssignCommand(oGainee, ActionCastSpellAtObject(SPELL_FEAT_SPEED_OF_THOUGHT_BONUS, oGainee, METAMAGIC_NONE, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
|
|
|
|
// Schedule a script to remove the bonus should they equip heavy armor
|
|
AddEventScript(oGainee, EVENT_ONPLAYEREQUIPITEM, "psi_spdfthgt_oeq", TRUE, FALSE);
|
|
// Schedule another script to add the bonus back if the unequip the armor
|
|
AddEventScript(oGainee, EVENT_ONPLAYERUNEQUIPITEM, "psi_spdfthgt_ueq", TRUE, FALSE);
|
|
}
|
|
// Psionic Dodge
|
|
if(GetHasFeat(FEAT_PSIONIC_DODGE, oGainee))
|
|
SetCompositeBonus(GetPCSkin(oGainee), "PsionicDodge", 1, ITEM_PROPERTY_AC_BONUS);
|
|
|
|
//Strength of Two - Kalashtar racial feat
|
|
if(GetHasFeat(FEAT_STRENGTH_OF_TWO, oGainee))
|
|
{
|
|
SetCompositeBonus(GetPCSkin(oGainee), "StrengthOfTwo", 1, ITEM_PROPERTY_SAVING_THROW_BONUS, SAVING_THROW_WILL);
|
|
}
|
|
// Danger Sense abilities for Psychic Rogue
|
|
if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oGainee) >= 5)
|
|
ExecuteScript("psi_psyrog_dngr", oGainee);
|
|
if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oGainee) >= 7) // Uncanny Dodge
|
|
IPSafeAddItemProperty(GetPCSkin(oGainee), PRCItemPropertyBonusFeat(IP_CONST_FEAT_UNCANNY_DODGE1), HoursToSeconds(24), X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oGainee) >= 9) // Improved Uncanny Dodge
|
|
IPSafeAddItemProperty(GetPCSkin(oGainee), PRCItemPropertyBonusFeat(IP_CONST_FEAT_UNCANNY_DODGE2), HoursToSeconds(24), X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
if(GetHasFeat(FEAT_PSY_SNEAK_ATTACK_1d6, oGainee))
|
|
{
|
|
int nPsySneak = 1;
|
|
if(GetHasFeat(FEAT_PSY_SNEAK_ATTACK_2d6, oGainee))
|
|
nPsySneak += 2;
|
|
if(GetHasFeat(FEAT_PSY_SNEAK_ATTACK_3d6, oGainee))
|
|
nPsySneak += 3;
|
|
|
|
SetLocalInt(oGainee, "PsyRogueSneak",nPsySneak);
|
|
DelayCommand(0.1, ExecuteScript("prc_sneak_att", oGainee));
|
|
}
|
|
}
|
|
|
|
int GetPsionicFocusesAvailable(object oCreature = OBJECT_SELF)
|
|
{
|
|
// If the creature has a psionic focus active, return the maximum
|
|
if(GetLocalInt(oCreature, PSIONIC_FOCUS))
|
|
return GetPsionicFocusUsesPerExpenditure(oCreature);
|
|
// Otherwise, return the amount currently remaining
|
|
else
|
|
return GetLocalInt(oCreature, "PsionicFocusUses");
|
|
}
|
|
|
|
int GetPsionicFocusUsesPerExpenditure(object oCreature = OBJECT_SELF)
|
|
{
|
|
int nFocusUses = 1;
|
|
int i;
|
|
for(i = FEAT_EPIC_PSIONIC_FOCUS_1; i <= FEAT_EPIC_PSIONIC_FOCUS_10; i++)
|
|
if(GetHasFeat(i, oCreature)) nFocusUses++;
|
|
|
|
return nFocusUses;
|
|
}
|
|
|
|
void LosePsionicFocus(object oLoser = OBJECT_SELF)
|
|
{
|
|
// Only remove focus if it's present
|
|
if(GetLocalInt(oLoser, PSIONIC_FOCUS))
|
|
{
|
|
SetLocalInt(oLoser, PSIONIC_FOCUS, FALSE);
|
|
|
|
// Loss of Speed of Thought effects
|
|
PRCRemoveSpellEffects(SPELL_FEAT_SPEED_OF_THOUGHT_BONUS, oLoser, oLoser);
|
|
RemoveEventScript(oLoser, EVENT_ONPLAYEREQUIPITEM, "psi_spdfthgt_oeq", TRUE);
|
|
RemoveEventScript(oLoser, EVENT_ONPLAYERUNEQUIPITEM, "psi_spdfthgt_ueq", TRUE);
|
|
// Loss of Psionic Dodge effects
|
|
SetCompositeBonus(GetPCSkin(oLoser), "PsionicDodge", 0, ITEM_PROPERTY_AC_BONUS);
|
|
// Loss of Strength of Two effects
|
|
SetCompositeBonus(GetPCSkin(oLoser), "StrengthOfTwo", 0, ITEM_PROPERTY_SAVING_THROW_BONUS, SAVING_THROW_WILL);
|
|
|
|
if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oLoser) >= 5)
|
|
PRCRemoveSpellEffects(POWER_DANGERSENSE, oLoser, oLoser);
|
|
if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oLoser) >= 7)
|
|
RemoveItemProperty(GetPCSkin(oLoser), ItemPropertyBonusFeat(IP_CONST_FEAT_UNCANNY_DODGE1));
|
|
if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oLoser) >= 9)
|
|
RemoveItemProperty(GetPCSkin(oLoser), ItemPropertyBonusFeat(IP_CONST_FEAT_UNCANNY_DODGE2));
|
|
|
|
// Inform oLoser about the event
|
|
FloatingTextStrRefOnCreature(16826415, oLoser, FALSE); // "You have lost your Psionic Focus"
|
|
if(GetHasFeat(FEAT_PSY_SNEAK_ATTACK_1d6, oLoser))
|
|
{
|
|
DeleteLocalInt(oLoser, "PsyRogueSneak");
|
|
DelayCommand(0.1, ExecuteScript("prc_sneak_att", oLoser));
|
|
}
|
|
}
|
|
}
|
|
|
|
int GetIsPsionicallyFocused(object oCreature = OBJECT_SELF)
|
|
{
|
|
return GetLocalInt(oCreature, PSIONIC_FOCUS);
|
|
}
|
|
|
|
int GetPsionicFocusUsingFeatsActive(object oCreature = OBJECT_SELF)
|
|
{
|
|
int nFeats;
|
|
|
|
if(GetLocalInt(oCreature, "TalentedActive")) nFeats++;
|
|
if(GetLocalInt(oCreature, "PowerSpecializationActive")) nFeats++;
|
|
if(GetLocalInt(oCreature, "PowerPenetrationActive")) nFeats++;
|
|
if(GetLocalInt(oCreature, "PsionicEndowmentActive")) nFeats++;
|
|
|
|
if(GetLocalInt(oCreature, METAPSIONIC_CHAIN_VAR)) nFeats++;
|
|
if(GetLocalInt(oCreature, METAPSIONIC_EMPOWER_VAR)) nFeats++;
|
|
if(GetLocalInt(oCreature, METAPSIONIC_EXTEND_VAR)) nFeats++;
|
|
if(GetLocalInt(oCreature, METAPSIONIC_MAXIMIZE_VAR)) nFeats++;
|
|
if(GetLocalInt(oCreature, METAPSIONIC_SPLIT_VAR)) nFeats++;
|
|
if(GetLocalInt(oCreature, METAPSIONIC_TWIN_VAR)) nFeats++;
|
|
if(GetLocalInt(oCreature, METAPSIONIC_WIDEN_VAR)) nFeats++;
|
|
if(GetLocalInt(oCreature, METAPSIONIC_QUICKEN_VAR)) nFeats++;
|
|
|
|
return nFeats;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////
|
|
/* END PSI FOCUS */
|
|
//////////////////////////////////////////////////////
|
|
|
|
int GetManifesterDC(object oManifester = OBJECT_SELF)
|
|
{
|
|
int nClass = GetManifestingClass(oManifester);
|
|
int nDC = 10;
|
|
nDC += GetPowerLevel(oManifester);
|
|
nDC += GetAbilityModifier(GetAbilityOfClass(nClass), oManifester);
|
|
|
|
// Stuff that applies only to powers, not psi-like abilities goes inside
|
|
if(!GetLocalInt(oManifester, PRC_IS_PSILIKE))
|
|
{
|
|
if (GetLocalInt(oManifester, "PsionicEndowmentActive") == TRUE && UsePsionicFocus(oManifester))
|
|
{
|
|
nDC += GetHasFeat(FEAT_GREATER_PSIONIC_ENDOWMENT, oManifester) ? 4 : 2;
|
|
}
|
|
}
|
|
|
|
// Needed to do some adjustments here.
|
|
object oTarget = PRCGetSpellTargetObject();
|
|
int nPower = PRCGetSpellId();
|
|
|
|
// Other DC adjustments
|
|
// Soul Manifester
|
|
nDC += Soulcaster(oManifester, PRCGetSpellId());
|
|
// Charming Veil meld
|
|
if(GetHasSpellEffect(MELD_CHARMING_VEIL, oManifester) && (GetIsOfSubschool(nPower, SUBSCHOOL_CHARM) || GetIsOfSubschool(nPower, SUBSCHOOL_COMPULSION))) nDC += GetEssentiaInvested(oManifester, MELD_CHARMING_VEIL)+1;
|
|
// Soul Eater
|
|
nDC += (GetLocalInt(oManifester, "PRC_SoulEater_HasDrained") && GetLevelByClass(CLASS_TYPE_SOUL_EATER, oManifester) >= 10) ? 2 : 0;
|
|
// Closed Mind
|
|
if(GetHasFeat(FEAT_CLOSED_MIND, oTarget)) nDC -= 2;
|
|
// Strong Mind
|
|
if(GetHasFeat(FEAT_STRONG_MIND, oTarget)) nDC -= 3;
|
|
// Fist of Dal Quor
|
|
if(GetLevelByClass(CLASS_TYPE_FIST_DAL_QUOR, oTarget) >= 4) nDC -= 2;
|
|
|
|
return nDC;
|
|
}
|
|
|
|
int DisciplineToSpellSchool(int nDiscipline)
|
|
{
|
|
int nSpellSchool = SPELL_SCHOOL_GENERAL;
|
|
|
|
switch(nDiscipline)
|
|
{
|
|
case DISCIPLINE_CLAIRSENTIENCE: nSpellSchool = SPELL_SCHOOL_DIVINATION; break;
|
|
case DISCIPLINE_METACREATIVITY: nSpellSchool = SPELL_SCHOOL_CONJURATION; break;
|
|
case DISCIPLINE_PSYCHOKINESIS: nSpellSchool = SPELL_SCHOOL_EVOCATION; break;
|
|
case DISCIPLINE_PSYCHOMETABOLISM: nSpellSchool = SPELL_SCHOOL_TRANSMUTATION; break;
|
|
case DISCIPLINE_TELEPATHY: nSpellSchool = SPELL_SCHOOL_ENCHANTMENT; break;
|
|
|
|
default: nSpellSchool = SPELL_SCHOOL_GENERAL; break;
|
|
}
|
|
|
|
return nSpellSchool;
|
|
}
|
|
|
|
int SpellSchoolToDiscipline(int nSpellSchool)
|
|
{
|
|
int nDiscipline = DISCIPLINE_NONE;
|
|
|
|
switch(nSpellSchool)
|
|
{
|
|
case SPELL_SCHOOL_GENERAL: nDiscipline = DISCIPLINE_NONE; break;
|
|
case SPELL_SCHOOL_ABJURATION: nDiscipline = DISCIPLINE_NONE; break;
|
|
case SPELL_SCHOOL_CONJURATION: nDiscipline = DISCIPLINE_METACREATIVITY; break;
|
|
case SPELL_SCHOOL_DIVINATION: nDiscipline = DISCIPLINE_CLAIRSENTIENCE; break;
|
|
case SPELL_SCHOOL_ENCHANTMENT: nDiscipline = DISCIPLINE_TELEPATHY; break;
|
|
case SPELL_SCHOOL_EVOCATION: nDiscipline = DISCIPLINE_PSYCHOKINESIS; break;
|
|
case SPELL_SCHOOL_ILLUSION: nDiscipline = DISCIPLINE_NONE; break;
|
|
case SPELL_SCHOOL_NECROMANCY: nDiscipline = DISCIPLINE_NONE; break;
|
|
case SPELL_SCHOOL_TRANSMUTATION: nDiscipline = DISCIPLINE_PSYCHOMETABOLISM; break;
|
|
|
|
default: nDiscipline = DISCIPLINE_NONE;
|
|
}
|
|
|
|
return nDiscipline;
|
|
}
|
|
|
|
int GetPowerDiscipline(int nSpellID)
|
|
{
|
|
string sSpellSchool = Get2DACache("spells", "School", nSpellID);//lookup_spell_school(nSpellID);
|
|
int nDiscipline;
|
|
|
|
if (sSpellSchool == "A") nDiscipline = DISCIPLINE_NONE;
|
|
else if (sSpellSchool == "C") nDiscipline = DISCIPLINE_METACREATIVITY;
|
|
else if (sSpellSchool == "D") nDiscipline = DISCIPLINE_CLAIRSENTIENCE;
|
|
else if (sSpellSchool == "E") nDiscipline = DISCIPLINE_TELEPATHY;
|
|
else if (sSpellSchool == "V") nDiscipline = DISCIPLINE_PSYCHOKINESIS;
|
|
else if (sSpellSchool == "I") nDiscipline = DISCIPLINE_NONE;
|
|
else if (sSpellSchool == "N") nDiscipline = DISCIPLINE_NONE;
|
|
else if (sSpellSchool == "T") nDiscipline = DISCIPLINE_PSYCHOMETABOLISM;
|
|
else if (sSpellSchool == "G") nDiscipline = DISCIPLINE_PSYCHOPORTATION;
|
|
|
|
return nDiscipline;
|
|
}
|
|
|
|
int GetIsTelepathyPower(int nSpellID = -1)
|
|
{
|
|
if(nSpellID == -1) nSpellID = PRCGetSpellId();
|
|
|
|
return GetPowerDiscipline(nSpellID) == DISCIPLINE_TELEPATHY;
|
|
}
|
|
|
|
int CheckPowerPrereqs(int nFeat, object oPC)
|
|
{
|
|
// Having the power already automatically disqualifies one from taking it again
|
|
if(GetHasFeat(nFeat, oPC))
|
|
return FALSE;
|
|
// We assume that the 2da is correctly formatted, and as such, a prereq slot only contains
|
|
// data if the previous slots in order also contains data.
|
|
// ie, no PREREQFEAT2 if PREREQFEAT1 is empty
|
|
if(Get2DACache("feat", "PREREQFEAT1", nFeat) != "")
|
|
{
|
|
if(!GetHasFeat(StringToInt(Get2DACache("feat", "PREREQFEAT1", nFeat)), oPC))
|
|
return FALSE;
|
|
if(Get2DACache("feat", "PREREQFEAT2", nFeat) != ""
|
|
&& !GetHasFeat(StringToInt(Get2DACache("feat", "PREREQFEAT2", nFeat)), oPC))
|
|
return FALSE;
|
|
}
|
|
|
|
if(Get2DACache("feat", "OrReqFeat0", nFeat) != "")
|
|
{
|
|
if(!GetHasFeat(StringToInt(Get2DACache("feat", "OrReqFeat0", nFeat)), oPC))
|
|
return FALSE;
|
|
if(Get2DACache("feat", "OrReqFeat1", nFeat) != "")
|
|
{
|
|
if(!GetHasFeat(StringToInt(Get2DACache("feat", "OrReqFeat1", nFeat)), oPC))
|
|
return FALSE;
|
|
if(Get2DACache("feat", "OrReqFeat2", nFeat) != "")
|
|
{
|
|
if(!GetHasFeat(StringToInt(Get2DACache("feat", "OrReqFeat2", nFeat)), oPC))
|
|
return FALSE;
|
|
if(Get2DACache("feat", "OrReqFeat3", nFeat) != "")
|
|
{
|
|
if(!GetHasFeat(StringToInt(Get2DACache("feat", "OrReqFeat3", nFeat)), oPC))
|
|
return FALSE;
|
|
if(Get2DACache("feat", "OrReqFeat4", nFeat) != "")
|
|
{
|
|
if(!GetHasFeat(StringToInt(Get2DACache("feat", "OrReqFeat4", nFeat)), oPC))
|
|
return FALSE;
|
|
} } } } }
|
|
|
|
//if youve reached this far then return TRUE
|
|
return TRUE;
|
|
}
|
|
|
|
int GetPsiPenetration(object oManifester = OBJECT_SELF)
|
|
{
|
|
int nPen = GetManifesterLevel(oManifester);
|
|
|
|
// The stuff inside applies only to normal manifestation, not psi-like abilities
|
|
if(!GetLocalInt(oManifester, PRC_IS_PSILIKE))
|
|
{
|
|
// Check for Power Pen feats being used
|
|
if(GetLocalInt(oManifester, "PowerPenetrationActive") == TRUE && UsePsionicFocus(oManifester))
|
|
{
|
|
nPen += GetHasFeat(FEAT_GREATER_POWER_PENETRATION, oManifester) ? 8 : 4;
|
|
}
|
|
}
|
|
|
|
return nPen;
|
|
}
|
|
|
|
int GetIsPsionicCharacter(object oCreature)
|
|
{
|
|
return !!(GetLevelByClass(CLASS_TYPE_PSION, oCreature) ||
|
|
GetLevelByClass(CLASS_TYPE_PSYWAR, oCreature) ||
|
|
GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oCreature) ||
|
|
GetLevelByClass(CLASS_TYPE_WILDER, oCreature) ||
|
|
GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN, oCreature) ||
|
|
GetLevelByClass(CLASS_TYPE_WARMIND, oCreature) ||
|
|
GetHasFeat(FEAT_WILD_TALENT, oCreature) ||
|
|
GetHasFeat(FEAT_KALASHTAR_PP, oCreature) ||
|
|
GetHasFeat(FEAT_NATPSIONIC_1, oCreature) ||
|
|
GetHasFeat(FEAT_NATPSIONIC_2, oCreature) ||
|
|
GetHasFeat(FEAT_NATPSIONIC_3, oCreature)
|
|
// Racial psionicity signifying feats go here
|
|
);
|
|
}
|
|
|
|
void LocalCleanExtraFists(object oCreature)
|
|
{
|
|
int iIsCWeap, iIsEquip;
|
|
|
|
object oClean = GetFirstItemInInventory(oCreature);
|
|
|
|
while (GetIsObjectValid(oClean))
|
|
{
|
|
iIsCWeap = GetIsPRCCreatureWeapon(oClean);
|
|
|
|
iIsEquip = oClean == GetItemInSlot(INVENTORY_SLOT_CWEAPON_L) ||
|
|
oClean == GetItemInSlot(INVENTORY_SLOT_CWEAPON_R) ||
|
|
oClean == GetItemInSlot(INVENTORY_SLOT_CWEAPON_B);
|
|
|
|
if (iIsCWeap && !iIsEquip)
|
|
{
|
|
DestroyObject(oClean);
|
|
}
|
|
|
|
oClean = GetNextItemInInventory(oCreature);
|
|
}
|
|
}
|
|
object GetPsionicCreatureWeapon(object oCreature, string sResRef, int nInventorySlot, float fDuration)
|
|
{
|
|
int bCreatedWeapon = FALSE;
|
|
object oCWeapon = GetItemInSlot(nInventorySlot, oCreature);
|
|
|
|
RemoveUnarmedAttackEffects(oCreature);
|
|
// Make sure they can actually equip them
|
|
UnarmedFeats(oCreature);
|
|
|
|
// Determine if a creature weapon of the proper type already exists in the slot
|
|
if(!GetIsObjectValid(oCWeapon) ||
|
|
GetStringUpperCase(GetTag(oCWeapon)) != GetStringUpperCase(sResRef) // Hack: The resref's and tags of the PRC creature weapons are the same
|
|
)
|
|
{
|
|
if (GetHasItem(oCreature, sResRef))
|
|
{
|
|
oCWeapon = GetItemPossessedBy(oCreature, sResRef);
|
|
SetIdentified(oCWeapon, TRUE);
|
|
//AssignCommand(oCreature, ActionEquipItem(oCWeapon, INVENTORY_SLOT_CWEAPON_L));
|
|
ForceEquip(oCreature, oCWeapon, nInventorySlot);
|
|
}
|
|
else
|
|
{
|
|
oCWeapon = CreateItemOnObject(sResRef, oCreature);
|
|
SetIdentified(oCWeapon, TRUE);
|
|
//AssignCommand(oCreature, ActionEquipItem(oCWeapon, INVENTORY_SLOT_CWEAPON_L));
|
|
ForceEquip(oCreature, oCWeapon, nInventorySlot);
|
|
bCreatedWeapon = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
// Clean up the mess of extra fists made on taking first level.
|
|
DelayCommand(6.0f, LocalCleanExtraFists(oCreature));
|
|
|
|
// Weapon finesse or intuitive attack?
|
|
SetLocalInt(oCreature, "UsingCreature", TRUE);
|
|
ExecuteScript("prc_intuiatk", oCreature);
|
|
DelayCommand(1.0f, DeleteLocalInt(oCreature, "UsingCreature"));
|
|
|
|
// Add OnHitCast: Unique if necessary
|
|
if(GetHasFeat(FEAT_REND, oCreature))
|
|
IPSafeAddItemProperty(oCWeapon, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
|
|
// This adds creature weapon finesse
|
|
ApplyUnarmedAttackEffects(oCreature);
|
|
|
|
// Destroy the weapon if it was created by this function
|
|
if(bCreatedWeapon)
|
|
DestroyObject(oCWeapon, (fDuration + 6.0));
|
|
|
|
return oCWeapon;
|
|
}
|
|
|
|
int GetTargetSpecificChangesToDamage(object oTarget, object oManifester, int nDamage,
|
|
int bIsHitPointDamage = TRUE, int bIsEnergyDamage = FALSE)
|
|
{
|
|
// Greater Power Specialization - +2 damage on all HP-damaging powers when target is within 30ft
|
|
if(bIsHitPointDamage &&
|
|
GetHasFeat(FEAT_GREATER_POWER_SPECIALIZATION, oManifester) &&
|
|
GetDistanceBetween(oTarget, oManifester) <= FeetToMeters(30.0f)
|
|
)
|
|
nDamage += 2;
|
|
// Intellect Fortress - Halve damage dealt by powers that allow PR. Goes before DR (-like) reductions
|
|
if(GetLocalInt(oTarget, "PRC_Power_IntellectFortress_Active") &&
|
|
Get2DACache("spells", "ItemImmunity", PRCGetSpellId()) == "1"
|
|
)
|
|
nDamage /= 2;
|
|
// Mental Resistance - 3 damage less for all non-energy damage and ability damage
|
|
if(GetHasFeat(FEAT_MENTAL_RESISTANCE, oTarget) && !bIsEnergyDamage)
|
|
nDamage -= 3;
|
|
|
|
// Reasonable return values only
|
|
if(nDamage < 0) nDamage = 0;
|
|
|
|
if (GetIsMeldBound(oManifester, MELD_PSYCHIC_FOCUS) == CHAKRA_THROAT && nDamage > 0 && !GetLocalInt(oManifester, "PsychicFocusMeld") && bIsHitPointDamage)
|
|
{
|
|
SetLocalInt(oManifester, "PsychicFocusMeld", TRUE);
|
|
DelayCommand(6.0, DeleteLocalInt(oManifester, "PsychicFocusMeld"));
|
|
int nClass = GetMeldShapedClass(oManifester, MELD_PSYCHIC_FOCUS);
|
|
int nDC = GetMeldshaperDC(oManifester, nClass, MELD_PSYCHIC_FOCUS);
|
|
if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NONE))
|
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectDazed(), oTarget, 6.0);
|
|
}
|
|
|
|
return nDamage;
|
|
}
|
|
|
|
int PracticedManifesting(object oManifester, int iManifestingClass, int iManifestingLevels)
|
|
{
|
|
int nFeat;
|
|
int iAdjustment = GetHitDice(oManifester) - iManifestingLevels;
|
|
iAdjustment = iAdjustment > 4 ? 4 : iAdjustment < 0 ? 0 : iAdjustment;
|
|
|
|
switch(iManifestingClass)
|
|
{
|
|
case CLASS_TYPE_PSION: nFeat = FEAT_PRACTICED_MANIFESTER_PSION; break;
|
|
case CLASS_TYPE_PSYWAR: nFeat = FEAT_PRACTICED_MANIFESTER_PSYWAR; break;
|
|
case CLASS_TYPE_PSYCHIC_ROGUE: nFeat = FEAT_PRACTICED_MANIFESTER_PSYROG; break;
|
|
case CLASS_TYPE_WILDER: nFeat = FEAT_PRACTICED_MANIFESTER_WILDER; break;
|
|
case CLASS_TYPE_WARMIND: nFeat = FEAT_PRACTICED_MANIFESTER_WARMIND; break;
|
|
case CLASS_TYPE_FIST_OF_ZUOKEN: nFeat = FEAT_PRACTICED_MANIFESTER_FIST_OF_ZUOKEN; break;
|
|
default: nFeat = -1;
|
|
}
|
|
|
|
if(GetHasFeat(nFeat, oManifester))
|
|
return iAdjustment;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int GetManifesterLevel(object oManifester, int nSpecificClass = CLASS_TYPE_INVALID, int nMaxPowerLevel = FALSE)
|
|
{
|
|
int nLevel;
|
|
int nAdjust = GetLocalInt(oManifester, PRC_CASTERLEVEL_ADJUSTMENT);
|
|
nAdjust -= GetLocalInt(oManifester, "WoLManifPenalty");
|
|
|
|
// The function user needs to know the character's manifester level in a specific class
|
|
// instead of whatever the character last manifested a power as
|
|
if(nSpecificClass != CLASS_TYPE_INVALID)
|
|
{
|
|
if(GetIsPsionicClass(nSpecificClass))
|
|
{
|
|
nLevel = GetLevelByClass(nSpecificClass, oManifester);
|
|
// Add levels from +ML PrCs only for the first manifesting class
|
|
if(nSpecificClass == GetPrimaryPsionicClass(oManifester))
|
|
nLevel += GetPsionicPRCLevels(oManifester);
|
|
|
|
// Psionic vestiges are tucked in here to override things.
|
|
// This assumes that there will never be a psion with this spell effect manifesting things
|
|
if (nSpecificClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_ARETE, oManifester) && !nMaxPowerLevel)
|
|
{
|
|
nLevel = GetLocalInt(oManifester, "AretePsion");
|
|
nMaxPowerLevel = TRUE;
|
|
}
|
|
if (nSpecificClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_THETRIAD, oManifester) && !nMaxPowerLevel)
|
|
{
|
|
nLevel = GetLocalInt(oManifester, "TheTriadPsion");
|
|
nMaxPowerLevel = TRUE;
|
|
}
|
|
if (nSpecificClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_ABYSM, oManifester) && !nMaxPowerLevel)
|
|
{
|
|
nLevel = GetLocalInt(oManifester, "AbysmPsion");
|
|
nMaxPowerLevel = TRUE;
|
|
}
|
|
|
|
// This is for learning powers, we need to ignore some adjustments
|
|
if (nMaxPowerLevel) return nLevel;
|
|
|
|
nLevel += PracticedManifesting(oManifester, nSpecificClass, nLevel); //gotta be the last one
|
|
|
|
return nLevel + nAdjust;
|
|
}
|
|
// A character's manifester level gained from non-manifesting classes is always a nice, round zero
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// Item Spells
|
|
if(GetItemPossessor(GetSpellCastItem()) == oManifester)
|
|
{
|
|
if(DEBUG) SendMessageToPC(oManifester, "Item casting at level " + IntToString(GetCasterLevel(oManifester)));
|
|
|
|
return GetCasterLevel(oManifester) + nAdjust;
|
|
}
|
|
|
|
// For when you want to assign the caster level.
|
|
else if(GetLocalInt(oManifester, PRC_CASTERLEVEL_OVERRIDE) != 0)
|
|
{
|
|
if(DEBUG) SendMessageToPC(oManifester, "Forced-level manifesting at level " + IntToString(GetCasterLevel(oManifester)));
|
|
|
|
DelayCommand(1.0, DeleteLocalInt(oManifester, PRC_CASTERLEVEL_OVERRIDE));
|
|
nLevel = GetLocalInt(oManifester, PRC_CASTERLEVEL_OVERRIDE);
|
|
}
|
|
else if(GetManifestingClass(oManifester) != CLASS_TYPE_INVALID)
|
|
{
|
|
//Gets the manifesting class
|
|
int nManifestingClass = GetManifestingClass(oManifester);
|
|
// if(DEBUG) DoDebug("Manifesting class: " + IntToString(nManifestingClass), oManifester);
|
|
nLevel = GetLevelByClass(nManifestingClass, oManifester);
|
|
// Add levels from +ML PrCs only for the first manifesting class
|
|
nLevel += nManifestingClass == GetPrimaryPsionicClass(oManifester) ? GetPsionicPRCLevels(oManifester) : 0;
|
|
|
|
// Psionic vestiges are tucked in here to override things.
|
|
// This assumes that there will never be a psion with this spell effect manifesting things
|
|
if (nManifestingClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_ARETE, oManifester) && !nMaxPowerLevel)
|
|
{
|
|
nLevel = GetLocalInt(oManifester, "AretePsion");
|
|
nMaxPowerLevel = TRUE;
|
|
}
|
|
if (nManifestingClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_THETRIAD, oManifester) && !nMaxPowerLevel)
|
|
{
|
|
nLevel = GetLocalInt(oManifester, "TheTriadPsion");
|
|
nMaxPowerLevel = TRUE;
|
|
}
|
|
if (nManifestingClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_ABYSM, oManifester) && !nMaxPowerLevel)
|
|
{
|
|
nLevel = GetLocalInt(oManifester, "AbysmPsion");
|
|
nMaxPowerLevel = TRUE;
|
|
}
|
|
|
|
// This is for learning powers, we need to ignore some adjustments
|
|
if (nMaxPowerLevel) return nLevel;
|
|
|
|
nLevel += PracticedManifesting(oManifester, nManifestingClass, nLevel); //gotta be the last one
|
|
// if(DEBUG) DoDebug("Level gotten via GetLevelByClass: " + IntToString(nLevel), oManifester);
|
|
}
|
|
|
|
// If you have a primary psionic class and no manifester level yet, get levels based on that
|
|
if (GetPrimaryPsionicClass(oManifester) && nLevel == 0)
|
|
{
|
|
int nClass = GetPrimaryPsionicClass(oManifester);
|
|
nLevel = GetLevelByClass(nClass, oManifester);
|
|
nLevel += GetPsionicPRCLevels(oManifester);
|
|
nLevel += PracticedManifesting(oManifester, nClass, nLevel); //gotta be the last one
|
|
}
|
|
|
|
// If everything else fails, you are not a manifester
|
|
if(nLevel == 0)
|
|
{
|
|
if(DEBUG) DoDebug("Failed to get manifester level for creature " + DebugObject2Str(oManifester) + ", using first class slot");
|
|
//else WriteTimestampedLogEntry("Failed to get manifester level for creature " + DebugObject2Str(oManifester) + ", using first class slot");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// The bonuses inside only apply to normal manifestation
|
|
if(!GetLocalInt(oManifester, PRC_IS_PSILIKE))
|
|
{
|
|
//Adding wild surge
|
|
int nSurge = GetWildSurge(oManifester);
|
|
if (nSurge > 0) nLevel += nSurge;
|
|
|
|
// Adding overchannel
|
|
int nOverchannel = GetLocalInt(oManifester, PRC_OVERCHANNEL);
|
|
if(nOverchannel > 0) nLevel += nOverchannel;
|
|
|
|
// Adding Soul Manifester
|
|
nLevel += Soulcaster(oManifester, PRCGetSpellId());
|
|
}
|
|
|
|
nLevel += nAdjust;
|
|
|
|
// This spam is technically no longer necessary once the manifester level getting mechanism has been confirmed to work
|
|
// if(DEBUG) FloatingTextStringOnCreature("Manifester Level: " + IntToString(nLevel), oManifester, FALSE);
|
|
|
|
return nLevel;
|
|
}
|
|
|
|
int GetHighestManifesterLevel(object oCreature)
|
|
{
|
|
int n = 0;
|
|
int nHighest;
|
|
int nTemp;
|
|
|
|
while(n <= 8)
|
|
{
|
|
if(GetClassByPosition(n, oCreature) != CLASS_TYPE_INVALID)
|
|
{
|
|
nTemp = GetManifesterLevel(oCreature, GetClassByPosition(n, oCreature));
|
|
|
|
if(nTemp > nHighest)
|
|
nHighest = nTemp;
|
|
}
|
|
n++;
|
|
|
|
}
|
|
|
|
return nHighest;
|
|
}
|
|
|
|
/* int GetHighestManifesterLevel(object oCreature)
|
|
{
|
|
return max(max(GetClassByPosition(1, oCreature) != CLASS_TYPE_INVALID ? GetManifesterLevel(oCreature, GetClassByPosition(1, oCreature)) : 0,
|
|
GetClassByPosition(2, oCreature) != CLASS_TYPE_INVALID ? GetManifesterLevel(oCreature, GetClassByPosition(2, oCreature)) : 0
|
|
),
|
|
GetClassByPosition(3, oCreature) != CLASS_TYPE_INVALID ? GetManifesterLevel(oCreature, GetClassByPosition(3, oCreature)) : 0
|
|
);
|
|
} */
|
|
|
|
int GetPowerLevel(object oManifester)
|
|
{
|
|
return GetLocalInt(oManifester, PRC_POWER_LEVEL);
|
|
}
|
|
|
|
int GetAbilityScoreOfClass(object oManifester, int nClass)
|
|
{
|
|
return GetAbilityScore(oManifester, GetAbilityOfClass(nClass));
|
|
}
|
|
|
|
int GetManifestingClass(object oManifester = OBJECT_SELF)
|
|
{
|
|
return GetLocalInt(oManifester, PRC_MANIFESTING_CLASS) - 1;
|
|
}
|
|
|
|
int GetAbilityOfClass(int nClass)
|
|
{
|
|
switch(nClass)
|
|
{
|
|
case CLASS_TYPE_DIAMOND_DRAGON:
|
|
case CLASS_TYPE_PSION:
|
|
case CLASS_TYPE_PSYCHIC_ROGUE:
|
|
return ABILITY_INTELLIGENCE;
|
|
case CLASS_TYPE_PSYWAR:
|
|
case CLASS_TYPE_FIST_OF_ZUOKEN:
|
|
case CLASS_TYPE_WARMIND:
|
|
return ABILITY_WISDOM;
|
|
case CLASS_TYPE_WILDER:
|
|
return ABILITY_CHARISMA;
|
|
}
|
|
|
|
// If there's no class, it's racial. Use Charisma
|
|
return ABILITY_CHARISMA;
|
|
}
|
|
|
|
int GetPrimaryPsionicClass(object oCreature = OBJECT_SELF)
|
|
{
|
|
int nClass;
|
|
|
|
if(GetPRCSwitch(PRC_CASTERLEVEL_FIRST_CLASS_RULE))
|
|
{
|
|
int iPsionicPos = GetFirstPsionicClassPosition(oCreature);
|
|
if (!iPsionicPos) return CLASS_TYPE_INVALID; // no Psionic casting class
|
|
|
|
nClass = GetClassByPosition(iPsionicPos, oCreature);
|
|
}
|
|
else
|
|
{
|
|
int nClassLvl;
|
|
int nClass1, nClass2, nClass3, nClass4, nClass5, nClass6, nClass7, nClass8;
|
|
int nClass1Lvl, nClass2Lvl, nClass3Lvl, nClass4Lvl, nClass5Lvl, nClass6Lvl, nClass7Lvl, nClass8Lvl;
|
|
|
|
nClass1 = GetClassByPosition(1, oCreature);
|
|
nClass2 = GetClassByPosition(2, oCreature);
|
|
nClass3 = GetClassByPosition(3, oCreature);
|
|
nClass4 = GetClassByPosition(4, oCreature);
|
|
nClass5 = GetClassByPosition(5, oCreature);
|
|
nClass6 = GetClassByPosition(6, oCreature);
|
|
nClass7 = GetClassByPosition(7, oCreature);
|
|
nClass8 = GetClassByPosition(8, oCreature);
|
|
|
|
if(GetIsPsionicClass(nClass1)) nClass1Lvl = GetLevelByClass(nClass1, oCreature);
|
|
if(GetIsPsionicClass(nClass2)) nClass2Lvl = GetLevelByClass(nClass2, oCreature);
|
|
if(GetIsPsionicClass(nClass3)) nClass3Lvl = GetLevelByClass(nClass3, oCreature);
|
|
if(GetIsPsionicClass(nClass4)) nClass4Lvl = GetLevelByClass(nClass4, oCreature);
|
|
if(GetIsPsionicClass(nClass5)) nClass5Lvl = GetLevelByClass(nClass5, oCreature);
|
|
if(GetIsPsionicClass(nClass6)) nClass6Lvl = GetLevelByClass(nClass6, oCreature);
|
|
if(GetIsPsionicClass(nClass7)) nClass7Lvl = GetLevelByClass(nClass7, oCreature);
|
|
if(GetIsPsionicClass(nClass8)) nClass8Lvl = GetLevelByClass(nClass8, oCreature);
|
|
|
|
|
|
nClass = nClass1;
|
|
nClassLvl = nClass1Lvl;
|
|
|
|
if(nClass2Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass2;
|
|
nClassLvl = nClass2Lvl;
|
|
}
|
|
if(nClass3Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass3;
|
|
nClassLvl = nClass3Lvl;
|
|
}
|
|
if(nClass4Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass4;
|
|
nClassLvl = nClass4Lvl;
|
|
}
|
|
if(nClass5Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass5;
|
|
nClassLvl = nClass5Lvl;
|
|
}
|
|
if(nClass6Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass6;
|
|
nClassLvl = nClass6Lvl;
|
|
}
|
|
if(nClass7Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass7;
|
|
nClassLvl = nClass7Lvl;
|
|
}
|
|
if(nClass8Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass8;
|
|
nClassLvl = nClass8Lvl;
|
|
}
|
|
|
|
if(nClassLvl == 0)
|
|
nClass = CLASS_TYPE_INVALID;
|
|
}
|
|
|
|
return nClass;
|
|
}
|
|
|
|
//:: [PRC .35] This needs to be updated for marker feats.
|
|
int GetPsionicPRCLevels(object oCreature)
|
|
{
|
|
int nLevel = 0;
|
|
|
|
// Cerebremancer and Psychic Theurge add manifester levels on each level
|
|
nLevel += GetLevelByClass(CLASS_TYPE_CEREBREMANCER, oCreature);
|
|
nLevel += GetLevelByClass(CLASS_TYPE_PSYCHIC_THEURGE, oCreature);
|
|
if (GetFirstPsionicClassPosition(oCreature)) nLevel += GetLevelByClass(CLASS_TYPE_SOULCASTER, oCreature);
|
|
|
|
// No manifester level boost at level 1 and 10 for Thrallherd
|
|
if(GetLevelByClass(CLASS_TYPE_THRALLHERD, oCreature))
|
|
{
|
|
nLevel += GetLevelByClass(CLASS_TYPE_THRALLHERD, oCreature) - 1;
|
|
if(GetLevelByClass(CLASS_TYPE_THRALLHERD, oCreature) >= 10) nLevel -= 1;
|
|
}
|
|
// No manifester level boost at levels 2, 5 and 8 for Shadow Mind
|
|
if(GetLevelByClass(CLASS_TYPE_SHADOWMIND, oCreature))
|
|
{
|
|
nLevel += GetLevelByClass(CLASS_TYPE_SHADOWMIND, oCreature);
|
|
if(GetLevelByClass(CLASS_TYPE_SHADOWMIND, oCreature) >= 2) nLevel -= 1;
|
|
if(GetLevelByClass(CLASS_TYPE_SHADOWMIND, oCreature) >= 5) nLevel -= 1;
|
|
if(GetLevelByClass(CLASS_TYPE_SHADOWMIND, oCreature) >= 8) nLevel -= 1;
|
|
}
|
|
// No manifester level boost at level 1 and 6 for Iron Mind
|
|
if(GetLevelByClass(CLASS_TYPE_IRONMIND, oCreature))
|
|
{
|
|
nLevel += GetLevelByClass(CLASS_TYPE_IRONMIND, oCreature) - 1;
|
|
if(GetLevelByClass(CLASS_TYPE_IRONMIND, oCreature) >= 6) nLevel -= 1;
|
|
}
|
|
// No manifester level boost at level 1 and 6 for Diamond Dragon
|
|
if(GetLevelByClass(CLASS_TYPE_DIAMOND_DRAGON, oCreature))
|
|
{
|
|
nLevel += GetLevelByClass(CLASS_TYPE_DIAMOND_DRAGON, oCreature) - 1;
|
|
if(GetLevelByClass(CLASS_TYPE_DIAMOND_DRAGON, oCreature) >= 6) nLevel -= 1;
|
|
}
|
|
// No manifester level boost at level 1 for Sanctified Mind
|
|
if(GetLevelByClass(CLASS_TYPE_SANCTIFIED_MIND, oCreature))
|
|
{
|
|
nLevel += GetLevelByClass(CLASS_TYPE_SANCTIFIED_MIND, oCreature) - 1;
|
|
}
|
|
|
|
return nLevel;
|
|
}
|
|
|
|
int GetFirstPsionicClassPosition(object oCreature = OBJECT_SELF)
|
|
{
|
|
if (GetIsPsionicClass(GetClassByPosition(1, oCreature)))
|
|
return 1;
|
|
if (GetIsPsionicClass(GetClassByPosition(2, oCreature)))
|
|
return 2;
|
|
if (GetIsPsionicClass(GetClassByPosition(3, oCreature)))
|
|
return 3;
|
|
if (GetIsPsionicClass(GetClassByPosition(4, oCreature)))
|
|
return 4;
|
|
if (GetIsPsionicClass(GetClassByPosition(5, oCreature)))
|
|
return 5;
|
|
if (GetIsPsionicClass(GetClassByPosition(6, oCreature)))
|
|
return 6;
|
|
if (GetIsPsionicClass(GetClassByPosition(7, oCreature)))
|
|
return 7;
|
|
if (GetIsPsionicClass(GetClassByPosition(8, oCreature)))
|
|
return 8;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int GetIsPsionicClass(int nClass)
|
|
{
|
|
return (nClass==CLASS_TYPE_PSION
|
|
|| nClass==CLASS_TYPE_PSYWAR
|
|
|| nClass==CLASS_TYPE_PSYCHIC_ROGUE
|
|
|| nClass==CLASS_TYPE_WILDER
|
|
|| nClass==CLASS_TYPE_FIST_OF_ZUOKEN
|
|
|| nClass==CLASS_TYPE_WARMIND
|
|
);
|
|
}
|
|
|
|
int GetWildSurge(object oManifester)
|
|
{
|
|
int nWildSurge = GetLocalInt(oManifester, PRC_IS_PSILIKE) ?
|
|
0 : // Wild Surge does not apply to psi-like abilities
|
|
GetLocalInt(oManifester, PRC_WILD_SURGE);
|
|
|
|
if(DEBUG) DoDebug("GetWildSurge():\n"
|
|
+ "oManifester = " + DebugObject2Str(oManifester) + "\n"
|
|
+ "nWildSurge = " + IntToString(nWildSurge) + "\n"
|
|
);
|
|
|
|
return nWildSurge;
|
|
}
|
|
|
|
int GetMaxPowerLevel(object oManifester)
|
|
{
|
|
int nClass = GetPrimaryPsionicClass(oManifester);
|
|
string sFile = GetAMSKnownFileName(nClass);
|
|
int nLevel = GetHighestManifesterLevel(oManifester);
|
|
int nMax = StringToInt(Get2DACache(sFile, "MaxPowerLevel", nLevel));
|
|
if (DEBUG) DoDebug("GetMaxPowerLevel is "+IntToString(nMax));
|
|
return nMax;
|
|
} |