//:://///////////////////////////////////////////// //:: 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 */ //::////////////////////////////////////////////// //::////////////////////////////////////////////// ////////////////////////////////////////////////// /* 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" ////////////////////////////////////////////////// /* 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) { 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; int nClass1Lvl, nClass2Lvl, nClass3Lvl; nClass1 = GetClassByPosition(1, oCreature); nClass2 = GetClassByPosition(2, oCreature); nClass3 = GetClassByPosition(3, oCreature); if(GetIsPsionicClass(nClass1)) nClass1Lvl = GetLevelByClass(nClass1, oCreature); if(GetIsPsionicClass(nClass2)) nClass2Lvl = GetLevelByClass(nClass2, oCreature); if(GetIsPsionicClass(nClass3)) nClass3Lvl = GetLevelByClass(nClass3, oCreature); nClass = nClass1; nClassLvl = nClass1Lvl; if(nClass2Lvl > nClassLvl) { nClass = nClass2; nClassLvl = nClass2Lvl; } if(nClass3Lvl > nClassLvl) { nClass = nClass3; nClassLvl = nClass3Lvl; } if(nClassLvl == 0) nClass = CLASS_TYPE_INVALID; } return nClass; } 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; 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; }