Added Martial Stalker feat. Fixed Ninja not getting level based AC. Updated Release archive.
2047 lines
89 KiB
Plaintext
2047 lines
89 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: [PRC Feat Router]
|
|
//:: [prc_inc_function.nss]
|
|
//:://////////////////////////////////////////////
|
|
//:: This file serves as a hub for the various
|
|
//:: PRC passive feat functions. If you need to
|
|
//:: add passive feats for a new PRC, link them here.
|
|
//::
|
|
//:: This file also contains a few multi-purpose
|
|
//:: PRC functions that need to be included in several
|
|
//:: places, ON DIFFERENT PRCS. Make local include files
|
|
//:: for any functions you use ONLY on ONE PRC.
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Aaon Graywolf
|
|
//:: Created On: Dec 19, 2003
|
|
//:://////////////////////////////////////////////
|
|
|
|
//:: Updated for 8 class slots by Jaysyn 2024/02/05
|
|
|
|
//--------------------------------------------------------------------------
|
|
// This is the "event" that is called to re-evalutate PRC bonuses. Currently
|
|
// it is fired by OnEquip, OnUnequip and OnLevel. If you want to move any
|
|
// classes into this event, just copy the format below. Basically, this function
|
|
// is meant to keep the code looking nice and clean by routing each class's
|
|
// feats to their own self-contained script
|
|
//--------------------------------------------------------------------------
|
|
|
|
//:: Test Void
|
|
//void main (){}
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Constants */
|
|
//////////////////////////////////////////////////
|
|
|
|
const int TEMPLATE_SLA_START = 16304;
|
|
const int TEMPLATE_SLA_END = 16400;
|
|
|
|
const string PRC_ScrubPCSkin_Generation = "PRC_ScrubPCSkin_Generation";
|
|
const string PRC_EvalPRCFeats_Generation = "PRC_EvalPRCFeats_Generation";
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function prototypes */
|
|
//////////////////////////////////////////////////
|
|
|
|
void EvalPRCFeats(object oPC);
|
|
|
|
int BlastInfidelOrFaithHeal(object oCaster, object oTarget, int iEnergyType, int iDisplayFeedback);
|
|
|
|
void ScrubPCSkin(object oPC, object oSkin);
|
|
|
|
void DeletePRCLocalInts(object oSkin);
|
|
|
|
void DelayedAddIPFeats(int nExpectedGeneration, object oPC);
|
|
|
|
void DelayedReApplyUnhealableAbilityDamage(int nExpectedGeneration, object oPC);
|
|
|
|
int nbWeaponFocus(object oPC);
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Includes */
|
|
//////////////////////////////////////////////////
|
|
|
|
// Minimalist includes
|
|
#include "prc_inc_util"
|
|
#include "prc_inc_spells"
|
|
#include "prc_inc_stunfist"
|
|
#include "inc_nwnx_funcs"
|
|
#include "prc_template_con"
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function definitions */
|
|
//////////////////////////////////////////////////
|
|
|
|
void DeleteCharacterData(object oPC)
|
|
{
|
|
DeletePersistantLocalString(oPC, "PRC_Class_Script1");
|
|
DeletePersistantLocalString(oPC, "PRC_Class_Script2");
|
|
DeletePersistantLocalString(oPC, "PRC_Class_Script3");
|
|
DeletePersistantLocalString(oPC, "PRC_Class_Script4");
|
|
DeletePersistantLocalString(oPC, "PRC_Class_Script5");
|
|
DeletePersistantLocalString(oPC, "PRC_Class_Script6");
|
|
DeletePersistantLocalString(oPC, "PRC_Class_Script7");
|
|
DeletePersistantLocalString(oPC, "PRC_Class_Script8");
|
|
DeletePersistantLocalInt(oPC, "PRC_Class_Data");
|
|
}
|
|
|
|
void SetupCharacterData(object oPC)
|
|
{
|
|
// iData format:
|
|
// 0x01 - run alternate magic system setup
|
|
// 0x02 - add new metamagic feats for spontaneous casters
|
|
// 0x04 - run reduced arcane spell failure check
|
|
// use bitwise to combine flags
|
|
|
|
int i, iData, iShifting;
|
|
for(i = 1; i <= 8; i++)
|
|
{
|
|
int nClassType = GetClassByPosition(i, oPC);
|
|
if(nClassType != CLASS_TYPE_INVALID)
|
|
{
|
|
string sScript;
|
|
switch(nClassType)
|
|
{
|
|
case CLASS_TYPE_ABJURANT_CHAMPION: sScript = "prc_abchamp"; break;
|
|
case CLASS_TYPE_ACOLYTE: sScript = "prc_acolyte"; break;
|
|
case CLASS_TYPE_ALIENIST: sScript = "prc_alienist"; break;
|
|
case CLASS_TYPE_ARCANE_DUELIST: sScript = "prc_arcduel"; break;
|
|
case CLASS_TYPE_ARCHIVIST: sScript = "prc_archivist"; iData |= 0x01; break;
|
|
case CLASS_TYPE_ASSASSIN: iData |= 0x03; break;
|
|
case CLASS_TYPE_BAELNORN: sScript = "prc_baelnorn"; break;
|
|
case CLASS_TYPE_BARD: iData |= 0x07; break;
|
|
case CLASS_TYPE_BATTLESMITH: sScript = "prc_battlesmith"; break;
|
|
case CLASS_TYPE_BEGUILER: iData |= 0x03; break;
|
|
case CLASS_TYPE_BINDER: sScript = "bnd_binder"; break;
|
|
case CLASS_TYPE_BFZ: sScript = "prc_bfz"; break;
|
|
case CLASS_TYPE_BLACK_BLOOD_CULTIST: sScript = "prc_bbc"; break;
|
|
case CLASS_TYPE_BLACKGUARD: sScript = "prc_blackguard"; break;
|
|
case CLASS_TYPE_BLADESINGER: sScript = "prc_bladesinger"; iData |= 0x04; break;
|
|
case CLASS_TYPE_BLIGHTLORD: sScript = "prc_blightlord"; break;
|
|
case CLASS_TYPE_BLOODCLAW_MASTER: sScript = "tob_bloodclaw"; break;
|
|
case CLASS_TYPE_BONDED_SUMMONNER: sScript = "prc_bondedsumm"; break;
|
|
case CLASS_TYPE_CELEBRANT_SHARESS: iData |= 0x03; break;
|
|
case CLASS_TYPE_CHILD_OF_NIGHT: sScript = "shd_childnight"; break;
|
|
case CLASS_TYPE_COC: sScript = "prc_coc"; break;
|
|
case CLASS_TYPE_COMBAT_MEDIC: sScript = "prc_cbtmed"; break;
|
|
case CLASS_TYPE_CONTEMPLATIVE: sScript = "prc_contemplate"; break;
|
|
case CLASS_TYPE_CRUSADER: sScript = "tob_crusader"; iData |= 0x01; break;
|
|
case CLASS_TYPE_CULTIST_SHATTERED_PEAK: sScript = "prc_shatterdpeak"; break;
|
|
case CLASS_TYPE_CW_SAMURAI: sScript = "prc_cwsamurai"; break;
|
|
case CLASS_TYPE_DEEPSTONE_SENTINEL: sScript = "tob_deepstone"; break;
|
|
case CLASS_TYPE_DIAMOND_DRAGON: sScript = "psi_diadra"; break;
|
|
case CLASS_TYPE_DISC_BAALZEBUL: sScript = "prc_baalzebul"; break;
|
|
case CLASS_TYPE_DISCIPLE_OF_ASMODEUS: sScript = "prc_discasmodeus"; break;
|
|
case CLASS_TYPE_DISCIPLE_OF_MEPH: sScript = "prc_discmeph"; break;
|
|
case CLASS_TYPE_DISPATER: sScript = "prc_dispater"; break;
|
|
case CLASS_TYPE_DRAGON_DEVOTEE: sScript = "prc_dragdev"; break;
|
|
case CLASS_TYPE_DRAGON_DISCIPLE: sScript = "prc_dradis"; break;
|
|
case CLASS_TYPE_DRAGON_SHAMAN: sScript = "prc_dragonshaman"; break;
|
|
case CLASS_TYPE_DRAGONFIRE_ADEPT: sScript = "inv_drgnfireadpt"; iData |= 0x01; break;
|
|
case CLASS_TYPE_DREAD_NECROMANCER: sScript = "prc_dreadnecro"; iData |= 0x03; break;
|
|
case CLASS_TYPE_DRUID: iShifting = TRUE; break;
|
|
case CLASS_TYPE_DRUNKEN_MASTER: sScript = "prc_drunk"; break;
|
|
case CLASS_TYPE_DUELIST: sScript = "prc_duelist"; break;
|
|
case CLASS_TYPE_DUSKBLADE: sScript = "prc_duskblade"; iData |= 0x03; break;
|
|
case CLASS_TYPE_ENLIGHTENEDFIST: sScript = "prc_enlfis"; break;
|
|
case CLASS_TYPE_ELEMENTAL_SAVANT: sScript = "prc_elemsavant"; break;
|
|
case CLASS_TYPE_ETERNAL_BLADE: sScript = "tob_eternalblade"; break;
|
|
case CLASS_TYPE_FACTOTUM: sScript = "prc_factotum"; break;
|
|
case CLASS_TYPE_FAVOURED_SOUL: sScript = "prc_favouredsoul"; iData |= 0x03; break;
|
|
case CLASS_TYPE_FIST_OF_ZUOKEN: sScript = "psi_zuoken"; iData |= 0x01; break;
|
|
case CLASS_TYPE_FOCHLUCAN_LYRIST: sScript = "prc_fochlyr"; break;
|
|
case CLASS_TYPE_FOE_HUNTER: sScript = "prc_foe_hntr"; break;
|
|
case CLASS_TYPE_FORESTMASTER: sScript = "prc_forestmaster"; break;
|
|
case CLASS_TYPE_FORSAKER: sScript = "prc_forsaker"; break;
|
|
case CLASS_TYPE_FRE_BERSERKER: sScript = "prc_frebzk"; break;
|
|
case CLASS_TYPE_FROSTRAGER: sScript = "prc_frostrager"; break;
|
|
case CLASS_TYPE_FROST_MAGE: sScript = "prc_frostmage"; break;
|
|
case CLASS_TYPE_HALFLING_WARSLINGER: sScript = "prc_warsling"; break;
|
|
case CLASS_TYPE_HARPER: iData |= 0x03; break;
|
|
case CLASS_TYPE_HEARTWARDER: sScript = "prc_heartwarder"; break;
|
|
case CLASS_TYPE_HENSHIN_MYSTIC: sScript = "prc_henshin"; break;
|
|
case CLASS_TYPE_HEXBLADE: iData |= 0x03; break;
|
|
case CLASS_TYPE_HEXTOR: sScript = "prc_hextor"; break;
|
|
case CLASS_TYPE_IAIJUTSU_MASTER: sScript = "prc_iaijutsu_mst"; break;
|
|
case CLASS_TYPE_INCARNATE: sScript = "moi_incarnate"; break;
|
|
case CLASS_TYPE_INCARNUM_BLADE: sScript = "moi_iblade"; break;
|
|
case CLASS_TYPE_INITIATE_DRACONIC: sScript = "prc_initdraconic"; break;
|
|
case CLASS_TYPE_IRONMIND: sScript = "psi_ironmind"; break;
|
|
case CLASS_TYPE_IRONSOUL_FORGEMASTER: sScript = "moi_ironsoul"; break;
|
|
case CLASS_TYPE_JADE_PHOENIX_MAGE: sScript = "tob_jadephoenix"; break;
|
|
case CLASS_TYPE_JUDICATOR: sScript = "prc_judicator"; break;
|
|
case CLASS_TYPE_JUSTICEWW: iData |= 0x03; break;
|
|
case CLASS_TYPE_KNIGHT: sScript = "prc_knight"; break;
|
|
case CLASS_TYPE_KNIGHT_CHALICE: sScript = "prc_knghtch"; break;
|
|
case CLASS_TYPE_KNIGHT_WEAVE: iData |= 0x03; break;
|
|
case CLASS_TYPE_KNIGHT_SACRED_SEAL: sScript = "bnd_kss"; break;
|
|
case CLASS_TYPE_LASHER: sScript = "prc_lasher"; break;
|
|
case CLASS_TYPE_LEGENDARY_DREADNOUGHT: sScript = "prc_legendread"; break;
|
|
case CLASS_TYPE_LICH: sScript = "pnp_lich_level"; break;
|
|
case CLASS_TYPE_MAGEKILLER: sScript = "prc_magekill"; break;
|
|
case CLASS_TYPE_MASTER_HARPER: sScript = "prc_masterh"; break;
|
|
case CLASS_TYPE_MASTER_OF_NINE: sScript = "tob_masterofnine"; break;
|
|
case CLASS_TYPE_MASTER_OF_SHADOW: sScript = "shd_mastershadow"; break;
|
|
case CLASS_TYPE_MIGHTY_CONTENDER_KORD: sScript = "prc_contendkord"; break;
|
|
case CLASS_TYPE_MORNINGLORD: sScript = "prc_morninglord"; break;
|
|
case CLASS_TYPE_NIGHTSHADE: sScript = "prc_nightshade"; break;
|
|
case CLASS_TYPE_NINJA: sScript = "prc_ninjca"; break;
|
|
case CLASS_TYPE_OLLAM: sScript = "prc_ollam"; break;
|
|
case CLASS_TYPE_OOZEMASTER: sScript = "prc_oozemstr"; break;
|
|
case CLASS_TYPE_ORDER_BOW_INITIATE: sScript = "prc_ootbi"; break;
|
|
case CLASS_TYPE_PEERLESS: sScript = "prc_peerless"; break;
|
|
case CLASS_TYPE_PNP_SHIFTER : iShifting = TRUE; break;
|
|
case CLASS_TYPE_PRC_EYE_OF_GRUUMSH: sScript = "prc_eog"; break;
|
|
case CLASS_TYPE_PSION: iData |= 0x01; break;
|
|
case CLASS_TYPE_PSYWAR: iData |= 0x01; break;
|
|
case CLASS_TYPE_PSYCHIC_ROGUE: sScript = "psi_psyrogue"; iData |= 0x01; break;
|
|
case CLASS_TYPE_PYROKINETICIST: sScript = "psi_pyro"; break;
|
|
case CLASS_TYPE_RAGE_MAGE: iData |= 0x04; break;
|
|
case CLASS_TYPE_REAPING_MAULER : sScript = "prc_reapmauler"; break;
|
|
case CLASS_TYPE_RUBY_VINDICATOR: sScript = "tob_rubyknight"; break;
|
|
case CLASS_TYPE_RUNESCARRED: sScript = "prc_runescarred"; break;
|
|
case CLASS_TYPE_SACREDFIST: sScript = "prc_sacredfist"; break;
|
|
case CLASS_TYPE_SANCTIFIED_MIND: sScript = "psi_sancmind"; break;
|
|
case CLASS_TYPE_SAPPHIRE_HIERARCH: sScript = "moi_sapphire"; break;
|
|
case CLASS_TYPE_SCOUT: sScript = "prc_scout"; break;
|
|
case CLASS_TYPE_SERENE_GUARDIAN: sScript = "prc_sereneguard"; break;
|
|
case CLASS_TYPE_SHADOW_ADEPT: sScript = "prc_shadowadept"; break;
|
|
case CLASS_TYPE_SHADOWCASTER: sScript = "shd_shadowcaster"; iData |= 0x01; break;
|
|
case CLASS_TYPE_SHADOWSMITH: iData |= 0x01; break;
|
|
case CLASS_TYPE_SHADOW_SUN_NINJA: sScript = "tob_shadowsun"; break;
|
|
case CLASS_TYPE_SHADOWBLADE: sScript = "prc_sb_shdstlth"; break;
|
|
case CLASS_TYPE_SHADOWMIND: sScript = "psi_shadowmind"; break;
|
|
case CLASS_TYPE_SHADOWBANE_STALKER: sScript = "prc_shadstalker"; break;
|
|
case CLASS_TYPE_SHADOW_THIEF_AMN: sScript = "prc_amn"; break;
|
|
case CLASS_TYPE_SHAMAN: sScript = "prc_shaman"; break;
|
|
case CLASS_TYPE_SHINING_BLADE: sScript = "prc_sbheir"; break;
|
|
case CLASS_TYPE_SHOU: sScript = "prc_shou"; break;
|
|
case CLASS_TYPE_SKULLCLAN_HUNTER: sScript = "prc_skullclan"; break;
|
|
case CLASS_TYPE_SLAYER_OF_DOMIEL: sScript = "prc_slayerdomiel"; break;
|
|
case CLASS_TYPE_SOHEI: sScript = "prc_sohei"; break;
|
|
case CLASS_TYPE_SOLDIER_OF_LIGHT: sScript = "prc_soldoflight"; break;
|
|
case CLASS_TYPE_SORCERER: iData |= 0x03; break;
|
|
case CLASS_TYPE_SOULBORN: sScript = "moi_soulborn"; break;
|
|
case CLASS_TYPE_SOUL_EATER: iShifting = TRUE; break;
|
|
case CLASS_TYPE_SOULKNIFE: sScript = "psi_sk_clseval"; break;
|
|
case CLASS_TYPE_SPELLSWORD: sScript = "prc_spellswd"; iData |= 0x04; break;
|
|
case CLASS_TYPE_SPINEMELD_WARRIOR: sScript = "moi_spinemeld"; break;
|
|
case CLASS_TYPE_STORMLORD: sScript = "prc_stormlord"; break;
|
|
case CLASS_TYPE_SUBLIME_CHORD: sScript = "prc_schord"; iData |= 0x03; break;
|
|
case CLASS_TYPE_SUEL_ARCHANAMACH: iData |= 0x03; break;
|
|
case CLASS_TYPE_SWASHBUCKLER: sScript = "prc_swashbuckler"; break;
|
|
case CLASS_TYPE_SWIFT_WING: sScript = "prc_swiftwing"; break;
|
|
case CLASS_TYPE_SWORDSAGE: sScript = "tob_swordsage"; iData |= 0x01; break;
|
|
case CLASS_TYPE_TALON_OF_TIAMAT: sScript = "prc_talontiamat"; break;
|
|
case CLASS_TYPE_TEMPEST: sScript = "prc_tempest"; break;
|
|
case CLASS_TYPE_TEMPUS: sScript = "prc_battletempus"; break;
|
|
case CLASS_TYPE_TENEBROUS_APOSTATE: sScript = "bnd_tenebrous"; break;
|
|
case CLASS_TYPE_THAYAN_KNIGHT: sScript = "prc_thayknight"; break;
|
|
case CLASS_TYPE_THRALL_OF_GRAZZT_A: sScript = "tog"; break;
|
|
case CLASS_TYPE_THRALLHERD: sScript = "psi_thrallherd"; break;
|
|
case CLASS_TYPE_TOTEMIST: sScript = "moi_totemist"; break;
|
|
case CLASS_TYPE_TOTEM_RAGER: sScript = "moi_totemrager"; break;
|
|
case CLASS_TYPE_TRUENAMER: sScript = "true_truenamer"; iData |= 0x01; break;
|
|
case CLASS_TYPE_VASSAL: sScript = "prc_vassal"; break;
|
|
case CLASS_TYPE_VIGILANT: sScript = "prc_vigilant"; break;
|
|
case CLASS_TYPE_WARBLADE: sScript = "tob_warblade"; iData |= 0x01; break;
|
|
case CLASS_TYPE_WARCHIEF: sScript = "prc_warchief"; break;
|
|
case CLASS_TYPE_WARFORGED_JUGGERNAUT: sScript = "prc_juggernaut"; break;
|
|
case CLASS_TYPE_WARLOCK: sScript = "inv_warlock"; iData |= 0x01; break;
|
|
case CLASS_TYPE_WARMAGE: iData |= 0x03; break;
|
|
case CLASS_TYPE_WARMIND: sScript = "psi_warmind"; iData |= 0x01; break;
|
|
case CLASS_TYPE_WEREWOLF: sScript = "prc_werewolf"; break;
|
|
case CLASS_TYPE_WILDER: iData |= 0x01; break;
|
|
|
|
// Races that can cast spells
|
|
case CLASS_TYPE_DRAGON: iData |= 0x03; break;
|
|
case CLASS_TYPE_SHAPECHANGER: iData |= 0x03; break;
|
|
case CLASS_TYPE_OUTSIDER: iData |= 0x03; break;
|
|
case CLASS_TYPE_ABERRATION: iData |= 0x03; break;
|
|
case CLASS_TYPE_MONSTROUS: iData |= 0x03; break;
|
|
case CLASS_TYPE_FEY: iData |= 0x03; break;
|
|
}
|
|
if(sScript != "")
|
|
SetPersistantLocalString(oPC, "PRC_Class_Script"+IntToString(i), sScript);
|
|
}
|
|
if (DEBUG) DoDebug("SetupCharacterData Class: " + IntToString(nClassType));
|
|
if (DEBUG) DoDebug("SetupCharacterData Data: " + IntToString(iData));
|
|
}
|
|
if(iData)
|
|
SetPersistantLocalInt(oPC, "PRC_Class_Data", iData);
|
|
|
|
if(iShifting)
|
|
SetPersistantLocalInt(oPC, "PRC_UNI_SHIFT_SCRIPT", 1);
|
|
|
|
//Setup class info for onleveldown script
|
|
int nCharData = ((GetClassByPosition(8, oPC) & 0xFF) << 56) |
|
|
((GetClassByPosition(7, oPC) & 0xFF) << 48) |
|
|
((GetClassByPosition(6, oPC) & 0xFF) << 40) |
|
|
((GetClassByPosition(5, oPC) & 0xFF) << 32) |
|
|
((GetClassByPosition(4, oPC) & 0xFF) << 24) |
|
|
((GetClassByPosition(3, oPC) & 0xFF) << 16) |
|
|
((GetClassByPosition(2, oPC) & 0xFF) << 8) |
|
|
(GetClassByPosition(1, oPC) & 0xFF);
|
|
|
|
SetPersistantLocalInt(oPC, "PRC_Character_Data", nCharData);
|
|
}
|
|
|
|
void DelayedExecuteScript(int nExpectedGeneration, string sScriptName, object oPC)
|
|
{
|
|
if (nExpectedGeneration != GetLocalInt(oPC, PRC_EvalPRCFeats_Generation))
|
|
{
|
|
//Generation has changed, so don't apply the effect
|
|
return;
|
|
}
|
|
ExecuteScript(sScriptName, oPC);
|
|
}
|
|
|
|
void DelayedReApplyUnhealableAbilityDamage(int nExpectedGeneration, object oPC)
|
|
{
|
|
if (nExpectedGeneration != GetLocalInt(oPC, PRC_ScrubPCSkin_Generation))
|
|
{
|
|
//Generation has changed, so don't apply the effect
|
|
return;
|
|
}
|
|
ReApplyUnhealableAbilityDamage(oPC);
|
|
}
|
|
|
|
int ToBFeats(object oPC)
|
|
{
|
|
if(GetHasFeat(FEAT_SHADOW_BLADE, oPC) ||
|
|
GetHasFeat(FEAT_RAPID_ASSAULT, oPC) ||
|
|
GetHasFeat(FEAT_DESERT_WIND_DODGE, oPC) ||
|
|
GetHasFeat(FEAT_DESERT_FIRE, oPC) ||
|
|
GetHasFeat(FEAT_IRONHEART_AURA, oPC) ||
|
|
GetHasFeat(FEAT_SHADOW_TRICKSTER, oPC) ||
|
|
GetHasFeat(FEAT_WHITE_RAVEN_DEFENSE, oPC) ||
|
|
GetHasFeat(FEAT_DEVOTED_BULWARK, oPC) ||
|
|
GetHasFeat(FEAT_SNAP_KICK, oPC) ||
|
|
GetHasFeat(FEAT_THREE_MOUNTAINS, oPC) ||
|
|
GetHasFeat(FEAT_VAE_SCHOOL, oPC) ||
|
|
GetHasFeat(FEAT_INLINDL_SCHOOL, oPC) ||
|
|
GetHasFeat(FEAT_XANIQOS_SCHOOL, oPC) ||
|
|
GetHasFeat(FEAT_SHIELD_WALL, oPC) ||
|
|
GetHasFeat(FEAT_CROSSBOW_SNIPER, oPC) ||
|
|
GetHasFeat(FEAT_CRESCENT_MOON, oPC) ||
|
|
GetHasFeat(FEAT_QUICK_STAFF, oPC) ||
|
|
GetHasFeat(FEAT_BEAR_FANG, oPC) ||
|
|
GetHasFeat(FEAT_IMPROVED_RAPID_SHOT, oPC) ||
|
|
GetHasFeat(FEAT_DIRE_FLAIL_SMASH, oPC) ||
|
|
GetHasFeat(FEAT_SHIELD_SPECIALIZATION_LIGHT, oPC) ||
|
|
GetHasFeat(FEAT_SHIELD_SPECIALIZATION_HEAVY, oPC) ||
|
|
GetHasFeat(FEAT_FOCUSED_SHIELD, oPC) ||
|
|
GetHasFeat(FEAT_SHIELDMATE, oPC) ||
|
|
GetHasFeat(FEAT_IMPROVED_SHIELDMATE, oPC) ||
|
|
GetHasFeat(FEAT_SHIELDED_CASTING, oPC) ||
|
|
GetHasFeat(FEAT_BLADE_MEDITATION_DESERT_WIND , oPC) ||
|
|
GetHasFeat(FEAT_BLADE_MEDITATION_DEVOTED_SPIRIT, oPC) ||
|
|
GetHasFeat(FEAT_BLADE_MEDITATION_DIAMOND_MIND , oPC) ||
|
|
GetHasFeat(FEAT_BLADE_MEDITATION_IRON_HEART , oPC) ||
|
|
GetHasFeat(FEAT_BLADE_MEDITATION_SETTING_SUN , oPC) ||
|
|
GetHasFeat(FEAT_BLADE_MEDITATION_SHADOW_HAND , oPC) ||
|
|
GetHasFeat(FEAT_BLADE_MEDITATION_STONE_DRAGON , oPC) ||
|
|
GetHasFeat(FEAT_BLADE_MEDITATION_TIGER_CLAW , oPC) ||
|
|
GetHasFeat(FEAT_BLADE_MEDITATION_WHITE_RAVEN , oPC) ||
|
|
GetRacialType(oPC) == RACIAL_TYPE_RETH_DEKALA ||
|
|
GetRacialType(oPC) == RACIAL_TYPE_HADRIMOI)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void EvalPRCFeats(object oPC)
|
|
{
|
|
// Player is currently making character in ConvoCC
|
|
// don't run EvalPRCFeats() yet
|
|
if(oPC == GetLocalObject(GetModule(), "ccc_active_pc"))
|
|
return;
|
|
|
|
int nGeneration = PRC_NextGeneration(GetLocalInt(oPC, PRC_EvalPRCFeats_Generation));
|
|
if (DEBUG > 1) DoDebug("EvalPRCFeats Generation: " + IntToString(nGeneration));
|
|
SetLocalInt(oPC, PRC_EvalPRCFeats_Generation, nGeneration);
|
|
|
|
//permanent ability changes
|
|
if(GetPRCSwitch(PRC_NWNX_FUNCS))
|
|
ExecuteScript("prc_nwnx_funcs", oPC);
|
|
|
|
//Add IP Feats to the hide
|
|
DelayCommand(0.0f, DelayedAddIPFeats(nGeneration, oPC));
|
|
|
|
// If there is a bonus domain, it will always be in the first slot, so just check that.
|
|
// It also runs things that clerics with those domains need
|
|
if (GetPersistantLocalInt(oPC, "PRCBonusDomain1") > 0 || GetLevelByClass(CLASS_TYPE_CLERIC, oPC) || GetLevelByClass(CLASS_TYPE_SHAMAN, oPC))
|
|
DelayCommand(0.1f, ExecuteScript("prc_domain_skin", oPC));
|
|
|
|
// special add atk bonus equal to Enhancement
|
|
ExecuteScript("ft_sanctmartial", oPC);
|
|
|
|
//hook in the weapon size restrictions script
|
|
//ExecuteScript("prc_restwpnsize", oPC);
|
|
|
|
//Route the event to the appropriate class specific scripts
|
|
int i, iData;
|
|
string sScript;
|
|
for (i = 1; i <= 8; i++)
|
|
{
|
|
sScript = GetPersistantLocalString(oPC, "PRC_Class_Script"+IntToString(i));
|
|
if(sScript != "")
|
|
{
|
|
if (DEBUG) DoDebug("PRC_Class_Script: "+sScript);
|
|
ExecuteScript(sScript, oPC);
|
|
}
|
|
}
|
|
|
|
iData = GetPersistantLocalInt(oPC, "PRC_Class_Data");
|
|
|
|
// Handle alternate caster types gaining new stuff
|
|
if(iData & 0x01)
|
|
ExecuteScript("prc_amagsys_gain", oPC);
|
|
|
|
// Add ip feats for spontaneous casters using metamagic
|
|
if(iData & 0x02)
|
|
ExecuteScript("prc_metamagic", oPC);
|
|
|
|
// Handle classes with reduced arcane spell failure
|
|
if(iData & 0x04)
|
|
ExecuteScript("prc_reducedasf", oPC);
|
|
|
|
if(GetPersistantLocalInt(oPC, "PRC_UNI_SHIFT_SCRIPT"))
|
|
//Executing shifter-related stuff like this has these advantages:
|
|
//1) All races and classes that need it can get it without a different script needing to be created for each.
|
|
//2) PCs with shifter-related stuff from multiple classes or races don't run the same functions multiple times.
|
|
ExecuteScript("prc_uni_shift", oPC);
|
|
|
|
// Templates
|
|
//these go here so feats can be reused
|
|
ExecuteScript("prc_templates", oPC);
|
|
|
|
// Feats
|
|
//these are here so if templates add them the if check runs after the template was applied
|
|
ExecuteScript("prc_feats", oPC);
|
|
|
|
if (ToBFeats(oPC))
|
|
ExecuteScript("tob_feats", oPC);
|
|
|
|
if (GetIsIncarnumUser(oPC) || GetRacialType(oPC) == RACIAL_TYPE_JAEBRIN)
|
|
ExecuteScript("moi_events", oPC);
|
|
|
|
if (GetIsBinder(oPC))
|
|
ExecuteScript("bnd_events", oPC);
|
|
|
|
// check if character with crafting feat has appropriate base item in her inventory
|
|
// x - moved from prc_onhb_indiv.nss
|
|
if(GetPRCSwitch(PRC_CRAFTING_BASE_ITEMS))
|
|
DelayCommand(0.5f, ExecuteScript("prc_crftbaseitms", oPC));
|
|
|
|
// Add the teleport management feats.
|
|
// 2005.11.03: Now added to all base classes on 1st level - Ornedan
|
|
// ExecuteScript("prc_tp_mgmt_eval", oPC);
|
|
|
|
// Size changes. Removed due to double-dipping most size adjustments
|
|
//ExecuteScript("prc_size", oPC);
|
|
|
|
// Speed changes
|
|
// The local int is for when items are requipped too quickly and this script bugs out
|
|
if (!GetLocalInt(oPC, "PRCSpeedDelay"))
|
|
{
|
|
ExecuteScript("prc_speed", oPC);
|
|
SetLocalInt(oPC, "PRCSpeedDelay", TRUE);
|
|
DelayCommand(0.15, DeleteLocalInt(oPC, "PRCSpeedDelay"));
|
|
}
|
|
|
|
// ACP system
|
|
if((GetIsPC(oPC) &&
|
|
(GetPRCSwitch(PRC_ACP_MANUAL) ||
|
|
GetPRCSwitch(PRC_ACP_AUTOMATIC)
|
|
)
|
|
) ||
|
|
(!GetIsPC(oPC) &&
|
|
GetPRCSwitch(PRC_ACP_NPC_AUTOMATIC)
|
|
)
|
|
)
|
|
ExecuteScript("acp_auto", oPC);
|
|
|
|
// this is handled inside the PRC Options conversation now.
|
|
/* // Epic spells
|
|
if((GetCasterLvl(CLASS_TYPE_CLERIC, oPC) >= 21 ||
|
|
GetCasterLvl(CLASS_TYPE_DRUID, oPC) >= 21 ||
|
|
GetCasterLvl(CLASS_TYPE_SORCERER, oPC) >= 21 ||
|
|
GetCasterLvl(CLASS_TYPE_FAVOURED_SOUL, oPC) >= 21 ||
|
|
GetCasterLvl(CLASS_TYPE_HEALER, oPC) >= 21 ||
|
|
GetCasterLvl(CLASS_TYPE_WIZARD, oPC) >= 21
|
|
) &&
|
|
!GetHasFeat(FEAT_EPIC_SPELLCASTING_REST, oPC)
|
|
)
|
|
{
|
|
IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(IP_CONST_FEAT_EPIC_REST), 0.0f,
|
|
X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
}*/
|
|
|
|
// Miscellaneous
|
|
ExecuteScript("prc_sneak_att", oPC);
|
|
ExecuteScript("race_skin", oPC);
|
|
ExecuteScript("prc_mithral", oPC);
|
|
if(GetPRCSwitch(PRC_ENFORCE_RACIAL_APPEARANCE) && GetIsPC(oPC))
|
|
ExecuteScript("race_appear", oPC);
|
|
|
|
//Reserve Feats
|
|
if(!GetLocalInt(oPC, "ReserveFeatsRunning"))
|
|
{
|
|
if(GetHasFeat(FEAT_HOLY_WARRIOR, oPC) ||
|
|
GetHasFeat(FEAT_MYSTIC_BACKLASH, oPC) ||
|
|
GetHasFeat(FEAT_ACIDIC_SPLATTER, oPC) ||
|
|
GetHasFeat(FEAT_FIERY_BURST, oPC) ||
|
|
GetHasFeat(FEAT_STORM_BOLT, oPC) ||
|
|
GetHasFeat(FEAT_WINTERS_BLAST, oPC) ||
|
|
GetHasFeat(FEAT_CLAP_OF_THUNDER, oPC) ||
|
|
GetHasFeat(FEAT_SICKENING_GRASP, oPC) ||
|
|
GetHasFeat(FEAT_TOUCH_OF_HEALING, oPC) ||
|
|
GetHasFeat(FEAT_DIMENSIONAL_JAUNT, oPC) ||
|
|
GetHasFeat(FEAT_CLUTCH_OF_EARTH, oPC) ||
|
|
GetHasFeat(FEAT_BORNE_ALOFT, oPC) ||
|
|
GetHasFeat(FEAT_PROTECTIVE_WARD, oPC) ||
|
|
GetHasFeat(FEAT_SHADOW_VEIL, oPC) ||
|
|
GetHasFeat(FEAT_SUNLIGHT_EYES, oPC) ||
|
|
GetHasFeat(FEAT_TOUCH_OF_DISTRACTION, oPC) ||
|
|
GetHasFeat(FEAT_UMBRAL_SHROUD, oPC) ||
|
|
GetHasFeat(FEAT_CHARNEL_MIASMA, oPC) ||
|
|
GetHasFeat(FEAT_DROWNING_GLANCE, oPC) ||
|
|
GetHasFeat(FEAT_INVISIBLE_NEEDLE, oPC) ||
|
|
GetHasFeat(FEAT_SUMMON_ELEMENTAL, oPC) ||
|
|
GetHasFeat(FEAT_DIMENSIONAL_REACH, oPC) ||
|
|
GetHasFeat(FEAT_HURRICANE_BREATH, oPC) ||
|
|
GetHasFeat(FEAT_MINOR_SHAPESHIFT, oPC) ||
|
|
GetHasFeat(FEAT_FACECHANGER, oPC))
|
|
{
|
|
ExecuteScript("prc_reservefeat", oPC);
|
|
}
|
|
}
|
|
|
|
/*if(// Psionics
|
|
GetLevelByClass(CLASS_TYPE_PSION, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_WILDER, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_PSYWAR, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_WARMIND, oPC) ||
|
|
// New spellbooks
|
|
GetLevelByClass(CLASS_TYPE_BARD, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_SORCERER, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_FAVOURED_SOUL, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_MYSTIC, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_HEXBLADE, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_DUSKBLADE, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_WARMAGE, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER,oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_JUSTICEWW, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_WITCH, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_BEGUILER, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_HARPER, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_TEMPLAR, oPC) ||
|
|
// Truenaming
|
|
GetLevelByClass(CLASS_TYPE_TRUENAMER, oPC) ||
|
|
// Tome of Battle
|
|
GetLevelByClass(CLASS_TYPE_CRUSADER, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_SWORDSAGE, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_WARBLADE, oPC) ||
|
|
// Invocations
|
|
GetLevelByClass(CLASS_TYPE_DRAGONFIRE_ADEPT, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_WARLOCK, oPC) ||
|
|
// Racial casters
|
|
(GetLevelByClass(CLASS_TYPE_OUTSIDER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA)
|
|
)
|
|
{
|
|
DelayCommand(1.0, DelayedExecuteScript(nGeneration, "prc_amagsys_gain", oPC));
|
|
|
|
//add selectable metamagic feats for spontaneous spellcasters
|
|
ExecuteScript("prc_metamagic", oPC);
|
|
}*/
|
|
|
|
// Gathers all the calls to UnarmedFists & Feats to one place.
|
|
// Must be after all evaluationscripts that need said functions.
|
|
//if(GetLocalInt(oPC, "CALL_UNARMED_FEATS") || GetLocalInt(oPC, "CALL_UNARMED_FISTS")) // ExecuteScript() is pretty expensive, do not run it needlessly - 20060702, Ornedan
|
|
ExecuteScript("unarmed_caller", oPC);
|
|
|
|
// Gathers all the calls to SetBaseAttackBonus() to one place
|
|
// Must be after all evaluationscripts that need said function.
|
|
ExecuteScript("prc_bab_caller", oPC);
|
|
|
|
// Classes an invoker can take
|
|
if( GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_ACOLYTE, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_ANIMA_MAGE, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_ARCTRICK, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_BLOOD_MAGUS, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_DISCIPLE_OF_ASMODEUS, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_MAESTER, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_TALON_OF_TIAMAT, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_VIRTUOSO, oPC) ||
|
|
GetLevelByClass(CLASS_TYPE_WILD_MAGE, oPC))
|
|
{
|
|
//Arcane caster first class position, take arcane
|
|
if(GetFirstArcaneClassPosition(oPC) == 1)
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
//Invoker first class position. take invoker
|
|
else if(GetClassByPosition(1, oPC) == CLASS_TYPE_WARLOCK || GetClassByPosition(1, oPC) == CLASS_TYPE_DRAGONFIRE_ADEPT)
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
//Non arcane first class position, invoker second. Take invoker
|
|
else if(GetFirstArcaneClassPosition(oPC) ==0 && (GetClassByPosition(2, oPC) == CLASS_TYPE_WARLOCK || GetClassByPosition(2, oPC) == CLASS_TYPE_DRAGONFIRE_ADEPT))
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
//last class would be Non-invoker first class position, arcane second position. take arcane.
|
|
else
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
|
|
//:: Set arcane or invocation bonus caster levels
|
|
if ( GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oPC) > 0 &&
|
|
GetHasFeat(FEAT_ABCHAMP_NONE, oPC) )
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_ACOLYTE, oPC) > 0 &&
|
|
GetHasFeat(FEAT_AOTS_NONE, oPC) || GetHasFeat(FEAT_AOTS_MYSTERY_SHADOWCASTER, oPC) || GetHasFeat(FEAT_AOTS_MYSTERY_SHADOWSMITH, oPC))
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_ANIMA_MAGE, oPC) > 0 &&
|
|
GetHasFeat(FEAT_ANIMA_NONE, oPC) )
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_ARCTRICK, oPC) > 0 &&
|
|
GetHasFeat(FEAT_ARCTRICK_NONE, oPC) )
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_BLOOD_MAGUS, oPC) > 0 &&
|
|
GetHasFeat(FEAT_BLDMAGUS_NONE, oPC) )
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_DISCIPLE_OF_ASMODEUS, oPC) > 0 &&
|
|
GetHasFeat(FEAT_ASMODEUS_NONE, oPC) || GetHasFeat(FEAT_ASMODEUS_MYSTERY_SHADOWCASTER, oPC) || GetHasFeat(FEAT_ASMODEUS_MYSTERY_SHADOWSMITH, oPC))
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oPC) > 0 &&
|
|
GetHasFeat(FEAT_ENLIGHTENEDFIST_NONE, oPC) )
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_MAESTER, oPC) > 0 &&
|
|
GetHasFeat(FEAT_MAESTER_NONE, oPC) )
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_TALON_OF_TIAMAT, oPC) > 0 &&
|
|
GetHasFeat(FEAT_TIAMAT_NONE, oPC) || GetHasFeat(FEAT_TIAMAT_MYSTERY_SHADOWCASTER, oPC) || GetHasFeat(FEAT_TIAMAT_MYSTERY_SHADOWSMITH, oPC))
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oPC) > 0 &&
|
|
GetHasFeat(FEAT_UNSEEN_NONE, oPC) )
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_VIRTUOSO, oPC) > 0 &&
|
|
GetHasFeat(FEAT_VIRTUOSO_NONE, oPC) )
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
if ( GetLevelByClass(CLASS_TYPE_WILD_MAGE, oPC) > 0 &&
|
|
GetHasFeat(FEAT_WILDMAGE_NONE, oPC) )
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
}
|
|
|
|
/* //Arcane caster first class position, take arcane
|
|
if(GetFirstArcaneClassPosition(oPC) == 1)
|
|
SetLocalInt(oPC, "INV_Caster", 1);
|
|
//Invoker first class position. take invoker
|
|
else if(GetClassByPosition(1, oPC) == CLASS_TYPE_WARLOCK || GetClassByPosition(1, oPC) == CLASS_TYPE_DRAGONFIRE_ADEPT)
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
//Non arcane first class position, invoker second. Take invoker
|
|
else if(GetFirstArcaneClassPosition(oPC) ==0 && (GetClassByPosition(2, oPC) == CLASS_TYPE_WARLOCK || GetClassByPosition(2, oPC) == CLASS_TYPE_DRAGONFIRE_ADEPT))
|
|
SetLocalInt(oPC, "INV_Caster", 2);
|
|
//last class would be Non-invoker first class position, arcane second position. take arcane.
|
|
else
|
|
SetLocalInt(oPC, "INV_Caster", 1); */
|
|
}
|
|
}
|
|
|
|
void DelayedAddIPFeats(int nExpectedGeneration, object oPC)
|
|
{
|
|
if (nExpectedGeneration != GetLocalInt(oPC, PRC_EvalPRCFeats_Generation))
|
|
{
|
|
//Generation has changed, so don't apply the effect
|
|
return;
|
|
}
|
|
|
|
object oSkin = GetPCSkin(oPC);
|
|
|
|
//Horse menu
|
|
AddSkinFeat(FEAT_HORSE_MENU, 40, oSkin, oPC);
|
|
|
|
// Switch convo feat
|
|
//Now everyone gets it at level 1, but just to be on the safe side
|
|
AddSkinFeat(FEAT_OPTIONS_CONVERSATION, 229, oSkin, oPC);
|
|
|
|
//PnP familiars
|
|
if(GetHasFeat(FEAT_SUMMON_FAMILIAR, oPC) && GetPRCSwitch(PRC_PNP_FAMILIARS))
|
|
IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(IP_CONST_PNP_FAMILIAR), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING);
|
|
else if(!GetHasFeat(FEAT_SUMMON_FAMILIAR, oPC) || !GetPRCSwitch(PRC_PNP_FAMILIARS))
|
|
RemoveItemProperty(oSkin, ItemPropertyBonusFeat(IP_CONST_PNP_FAMILIAR));
|
|
|
|
//PnP Spell Schools
|
|
if(GetPRCSwitch(PRC_PNP_SPELL_SCHOOLS)
|
|
&& GetLevelByClass(CLASS_TYPE_WIZARD, oPC)
|
|
&& !GetIsPolyMorphedOrShifted(oPC)
|
|
&& !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_GENERAL, oPC)
|
|
&& !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_ABJURATION, oPC)
|
|
&& !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_CONJURATION, oPC)
|
|
&& !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_DIVINATION, oPC)
|
|
&& !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_ENCHANTMENT, oPC)
|
|
&& !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_EVOCATION, oPC)
|
|
&& !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_ILLUSION, oPC)
|
|
&& !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_NECROMANCY, oPC)
|
|
&& !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_TRANSMUTATION, oPC)
|
|
//&& !PRCGetHasEffect(EFFECT_TYPE_POLYMORPH, oPC) //so it doesnt pop up on polymorphing
|
|
//&& !GetLocalInt(oSkin, "nPCShifted") //so it doenst pop up on shifting
|
|
)
|
|
{
|
|
if(GetXP(oPC))// ConvoCC compatibility fix
|
|
ExecuteScript("prc_pnp_shcc_s", oPC);
|
|
}
|
|
|
|
/*//Arcane Archer old imbue arrow
|
|
if(GetLevelByClass(CLASS_TYPE_ARCANE_ARCHER, oPC) >= 2
|
|
&& !GetHasFeat(FEAT_PRESTIGE_IMBUE_ARROW, oPC)
|
|
&& GetPRCSwitch(PRC_PNP_SPELL_SCHOOLS))
|
|
{
|
|
//add the old feat to the hide
|
|
IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(IP_CONST_FEAT_FEAT_PRESTIGE_IMBUE_ARROW), 0.0f,
|
|
X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
|
}*/
|
|
|
|
//handle PnP sling switch
|
|
if(GetPRCSwitch(PRC_PNP_SLINGS))
|
|
{
|
|
if(GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC)) == BASE_ITEM_SLING)
|
|
IPSafeAddItemProperty(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC),
|
|
ItemPropertyMaxRangeStrengthMod(20),
|
|
999999.9);
|
|
}
|
|
}
|
|
|
|
void TemplateSLAs(object oPC)
|
|
{
|
|
int i;
|
|
for(i = TEMPLATE_SLA_START; i <= TEMPLATE_SLA_END; i++)
|
|
{
|
|
DeleteLocalInt(oPC, "TemplateSLA_"+IntToString(i));
|
|
}
|
|
}
|
|
|
|
void DeletePRCLocalInts(object oSkin)
|
|
{
|
|
// This will get rid of any SetCompositeAttackBonus LocalInts:
|
|
object oPC = GetItemPossessor(oSkin);
|
|
DeleteLocalInt(oPC, "CompositeAttackBonusR");
|
|
DeleteLocalInt(oPC, "CompositeAttackBonusL");
|
|
|
|
//Do not use DelayCommand for this--it's too dangerous:
|
|
//if SetCompositeAttackBonus is called at the wrong time the result will be incorrect.
|
|
DeleteNamedComposites(oPC, "PRC_ComAttBon");
|
|
|
|
// PRCGetClassByPosition and PRCGetLevelByPosition cleanup
|
|
// not needed now that GetClassByPosition() works for custom classes
|
|
// DeleteLocalInt(oPC, "PRC_ClassInPos1");
|
|
// DeleteLocalInt(oPC, "PRC_ClassInPos2");
|
|
// DeleteLocalInt(oPC, "PRC_ClassInPos3");
|
|
// DeleteLocalInt(oPC, "PRC_ClassLevelInPos1");
|
|
// DeleteLocalInt(oPC, "PRC_ClassLevelInPos2");
|
|
// DeleteLocalInt(oPC, "PRC_ClassLevelInPos3");
|
|
|
|
//persistant local token object cache
|
|
//looks like logging off then back on without the server rebooting breaks it
|
|
//I guess because the token gets a new ID, but the local still points to the old one
|
|
DeleteLocalObject(oPC, "PRC_HideTokenCache");
|
|
|
|
DeleteLocalInt(oSkin, "PRC_ArcaneSpellFailure");
|
|
|
|
DeleteLocalInt(oPC, "PRC_SwiftActionUsed");
|
|
DeleteLocalInt(oPC, "PRC_MoveActionUsed");
|
|
|
|
// In order to work with the PRC system we need to delete some locals for each
|
|
// PRC that has a hide
|
|
|
|
//Do not use DelayCommand for this--it's too dangerous:
|
|
//if SetCompositeBonus is called between the time EvalPRCFeats removes item properties
|
|
//and the time this delayed command is executed, the result will be incorrect.
|
|
//Since this error case actually happens frequently with any delay here, just don't do it.
|
|
DeleteNamedComposites(oSkin, "PRC_CBon");
|
|
|
|
if (DEBUG) DoDebug("Clearing class flags");
|
|
|
|
// Elemental Savants
|
|
DeleteLocalInt(oSkin,"ElemSavantResist");
|
|
DeleteLocalInt(oSkin,"ElemSavantPerfection");
|
|
DeleteLocalInt(oSkin,"ElemSavantImmMind");
|
|
DeleteLocalInt(oSkin,"ElemSavantImmParal");
|
|
DeleteLocalInt(oSkin,"ElemSavantImmSleep");
|
|
// HeartWarder
|
|
DeleteLocalInt(oSkin,"FeyType");
|
|
// OozeMaster
|
|
DeleteLocalInt(oSkin,"IndiscernibleCrit");
|
|
DeleteLocalInt(oSkin,"IndiscernibleBS");
|
|
DeleteLocalInt(oSkin,"OneOozeMind");
|
|
DeleteLocalInt(oSkin,"OneOozePoison");
|
|
// Storm lord
|
|
DeleteLocalInt(oSkin,"StormLResElec");
|
|
// Spell sword
|
|
DeleteLocalInt(oSkin,"SpellswordSFBonusNormal");
|
|
DeleteLocalInt(oSkin,"SpellswordSFBonusEpic");
|
|
// Acolyte of the skin
|
|
DeleteLocalInt(oSkin,"AcolyteSymbBonus");
|
|
DeleteLocalInt(oSkin,"AcolyteResistanceCold");
|
|
DeleteLocalInt(oSkin,"AcolyteResistanceFire");
|
|
DeleteLocalInt(oSkin,"AcolyteResistanceAcid");
|
|
DeleteLocalInt(oSkin,"AcolyteResistanceElectric");
|
|
// Battleguard of Tempus
|
|
DeleteLocalInt(oSkin,"FEAT_WEAP_TEMPUS");
|
|
// Bonded Summoner
|
|
DeleteLocalInt(oSkin,"BondResEle");
|
|
DeleteLocalInt(oSkin,"BondSubType");
|
|
// Disciple of Meph
|
|
DeleteLocalInt(oSkin,"DiscMephResist");
|
|
DeleteLocalInt(oSkin,"DiscMephGlove");
|
|
// Initiate of Draconic Mysteries
|
|
DeleteLocalInt(oSkin,"IniSR");
|
|
DeleteLocalInt(oSkin,"IniStunStrk");
|
|
// Man at Arms
|
|
DeleteLocalInt(oSkin,"ManArmsCore");
|
|
// Telflammar Shadowlord
|
|
DeleteLocalInt(oSkin,"ShaDiscorp");
|
|
// Vile Feats
|
|
DeleteLocalInt(oSkin,"DeformGaunt");
|
|
DeleteLocalInt(oSkin,"DeformObese");
|
|
// Sneak Attack
|
|
DeleteLocalInt(oSkin,"RogueSneakDice");
|
|
DeleteLocalInt(oSkin,"BlackguardSneakDice");
|
|
// Sacred Fist
|
|
DeleteLocalInt(oSkin,"SacFisMv");
|
|
// Minstrel
|
|
DeleteLocalInt(oSkin,"MinstrelSFBonus"); /// @todo Make ASF reduction compositable
|
|
// Nightshade
|
|
DeleteLocalInt(oSkin,"ImmuNSWeb");
|
|
DeleteLocalInt(oSkin,"ImmuNSPoison");
|
|
// Soldier of Light
|
|
DeleteLocalInt(oSkin,"ImmuPF");
|
|
// Ultimate Ranger
|
|
DeleteLocalInt(oSkin,"URImmu");
|
|
// Thayan Knight
|
|
DeleteLocalInt(oSkin,"ThayHorror");
|
|
DeleteLocalInt(oSkin,"ThayZulkFave");
|
|
DeleteLocalInt(oSkin,"ThayZulkChamp");
|
|
// Black Flame Zealot
|
|
DeleteLocalInt(oSkin,"BFZHeart");
|
|
// Henshin Mystic
|
|
DeleteLocalInt(oSkin,"Happo");
|
|
DeleteLocalInt(oSkin,"HMInvul");
|
|
//Blightlord
|
|
DeleteLocalInt(oSkin, "WntrHeart");
|
|
DeleteLocalInt(oSkin, "BlightBlood");
|
|
// Contemplative
|
|
DeleteLocalInt(oSkin, "ContempDisease");
|
|
DeleteLocalInt(oSkin, "ContempPoison");
|
|
DeleteLocalInt(oSkin, "ContemplativeDR");
|
|
DeleteLocalInt(oSkin, "ContemplativeSR");
|
|
// Dread Necromancer
|
|
DeleteLocalInt(oSkin, "DNDamageResist");
|
|
// Warsling Sniper
|
|
DeleteLocalInt(oPC, "CanRicochet");
|
|
// Blood Magus
|
|
DeleteLocalInt(oSkin, "ThickerThanWater");
|
|
|
|
// Feats
|
|
DeleteLocalInt(oPC, "ForceOfPersonalityWis");
|
|
DeleteLocalInt(oPC, "ForceOfPersonalityCha");
|
|
DeleteLocalInt(oPC, "InsightfulReflexesInt");
|
|
DeleteLocalInt(oPC, "InsightfulReflexesDex");
|
|
DeleteLocalInt(oSkin, "TactileTrapsmithSearchIncrease");
|
|
DeleteLocalInt(oSkin, "TactileTrapsmithDisableIncrease");
|
|
DeleteLocalInt(oSkin, "TactileTrapsmithSearchDecrease");
|
|
DeleteLocalInt(oSkin, "TactileTrapsmithDisableDecrease");
|
|
|
|
// Warmind
|
|
DeleteLocalInt(oSkin, "EnduringBody");
|
|
|
|
// Ironmind
|
|
DeleteLocalInt(oSkin, "IronMind_DR");
|
|
|
|
// Suel Archanamach
|
|
DeleteLocalInt(oSkin, "SuelArchanamachSpellFailure");
|
|
|
|
// Favoured Soul
|
|
DeleteLocalInt(oSkin, "FavouredSoulResistElementAcid");
|
|
DeleteLocalInt(oSkin, "FavouredSoulResistElementCold");
|
|
DeleteLocalInt(oSkin, "FavouredSoulResistElementElec");
|
|
DeleteLocalInt(oSkin, "FavouredSoulResistElementFire");
|
|
DeleteLocalInt(oSkin, "FavouredSoulResistElementSonic");
|
|
DeleteLocalInt(oSkin, "FavouredSoulDR");
|
|
|
|
// Domains
|
|
DeleteLocalInt(oSkin, "StormDomainPower");
|
|
|
|
// Skullclan Hunter
|
|
DeleteLocalInt(oSkin, "SkullClanFear");
|
|
DeleteLocalInt(oSkin, "SkullClanDisease");
|
|
DeleteLocalInt(oSkin, "SkullClanProtectionEvil");
|
|
DeleteLocalInt(oSkin, "SkullClanSwordLight");
|
|
DeleteLocalInt(oSkin, "SkullClanParalysis");
|
|
DeleteLocalInt(oSkin, "SkullClanAbilityDrain");
|
|
DeleteLocalInt(oSkin, "SkullClanLevelDrain");
|
|
|
|
// Sohei
|
|
DeleteLocalInt(oSkin, "SoheiDamageResist");
|
|
|
|
// Dragon Disciple
|
|
DeleteLocalInt(oPC, "DragonDiscipleBreathWeaponUses");
|
|
|
|
//Dragon Shaman
|
|
DeleteLocalInt(oPC, "DragonShamanTotem");
|
|
|
|
//Warblade
|
|
DeleteLocalInt(oSkin, "PRC_WEAPON_APTITUDE_APPLIED");
|
|
|
|
//Shifter(PnP)
|
|
DeleteLocalInt(oSkin, "PRC_SHIFTER_TEMPLATE_APPLIED");
|
|
|
|
DeleteLocalInt(oPC, "ScoutFreeMove");
|
|
DeleteLocalInt(oPC, "ScoutFastMove");
|
|
DeleteLocalInt(oPC, "ScoutBlindsight");
|
|
|
|
//Truenamer
|
|
// Called elsewhere now
|
|
/*int UtterID;
|
|
for(UtterID = 3526; UtterID <= 3639; UtterID++) // All utterances
|
|
DeleteLocalInt(oPC, "PRC_LawOfResistance" + IntToString(UtterID));
|
|
for(UtterID = 3418; UtterID <= 3431; UtterID++) // Syllable of Detachment to Word of Heaven, Greater
|
|
DeleteLocalInt(oPC, "PRC_LawOfResistance" + IntToString(UtterID));*/
|
|
|
|
//Invocations
|
|
DeleteLocalInt(oPC, "ChillingFogLock");
|
|
//Endure Exposure wearing off
|
|
array_delete(oPC, "BreathProtected");
|
|
DeleteLocalInt(oPC, "DragonWard");
|
|
|
|
//Scry on Familiar
|
|
DeleteLocalInt(oPC, "Scry_Familiar");
|
|
|
|
// Undead HD
|
|
DeleteLocalInt(oPC, "PRCUndeadHD");
|
|
DeleteLocalInt(oPC, "PRCUndeadFSPen");
|
|
|
|
//Template Spell-Like Abilities
|
|
DelayCommand(0.5f, TemplateSLAs(oPC));
|
|
|
|
// future PRCs Go below here
|
|
}
|
|
|
|
void ScrubPCSkin(object oPC, object oSkin)
|
|
{
|
|
int nGeneration = PRC_NextGeneration(GetLocalInt(oPC, PRC_ScrubPCSkin_Generation));
|
|
if (DEBUG > 1) DoDebug("ScrubPCSkin Generation: " + IntToString(nGeneration));
|
|
SetLocalInt(oPC, PRC_ScrubPCSkin_Generation, nGeneration);
|
|
|
|
int iCode = GetHasFeat(FEAT_SF_CODE,oPC);
|
|
int ipType, st;
|
|
if(!(/*GetIsPolyMorphedOrShifted(oPC) || */GetIsObjectValid(GetMaster(oPC))))
|
|
{
|
|
itemproperty ip = GetFirstItemProperty(oSkin);
|
|
while(GetIsItemPropertyValid(ip))
|
|
{
|
|
// Insert Logic here to determine if we spare a property
|
|
ipType = GetItemPropertyType(ip);
|
|
if(ipType == ITEM_PROPERTY_BONUS_FEAT)
|
|
{
|
|
// Check for specific Bonus Feats
|
|
// Reference iprp_feats.2da
|
|
st = GetItemPropertySubType(ip);
|
|
|
|
// Spare 400 through 570 and 398 -- epic spells & spell effects
|
|
//also spare the new spellbook feats (1000-12000 & 17701-24704
|
|
//also spare the psionic, trunaming, tob, invocation feats (12000-16000)
|
|
// spare template, tob stuff (16300-17700)
|
|
// changed by fluffyamoeba so that iprp weapon specialization, dev crit, epic weapon focus, epic weapon spec
|
|
// overwhelming crit and weapon of choice are no longer skipped.
|
|
if ((st < 400 || st > 570)
|
|
&& st != 102 //:: ACP Feats
|
|
&& st != 586 //:: ACP Feats
|
|
&& st != 587 //:: ACP Feats
|
|
&& st != 398
|
|
&& (st < 1000 || st > 13520)
|
|
//&& (st < 1000 || st > 13999)
|
|
//&& (st < 14501 || st > 15999)
|
|
&& (st < 16300 || st > 24704)
|
|
&& (st < 223 || st > 226) // draconic feats
|
|
&& (st < 229 || st > 249) // Pnp spellschool feats and PRC options feat (231-249 & 229)
|
|
&& st != 259 // 259 - psionic focus
|
|
&& (st < 141 || st > 200) // 141 - shadowmaster shades, 142-151 bonus domains casting feats, 152 - 200 bonus domain powers
|
|
&& st != 26000 // Bullybasher Giant Bearing
|
|
&& ( (st == IP_CONST_FEAT_PRC_POWER_ATTACK_QUICKS_RADIAL ||
|
|
st == IP_CONST_FEAT_POWER_ATTACK_SINGLE_RADIAL ||
|
|
st == IP_CONST_FEAT_POWER_ATTACK_FIVES_RADIAL) ? // Remove the PRC Power Attack radials if the character no longer has Power Attack
|
|
!GetHasFeat(FEAT_POWER_ATTACK, oPC) :
|
|
TRUE // If the feat is not relevant to this clause, always pass
|
|
)
|
|
)
|
|
RemoveItemProperty(oSkin, ip);
|
|
}
|
|
else if(ipType == ITEM_PROPERTY_BONUS_SPELL_SLOT_OF_LEVEL_N)
|
|
{
|
|
//bonus spellslots code here
|
|
//st = GetItemPropertySubType(ip);
|
|
RemoveItemProperty(oSkin, ip);
|
|
}
|
|
else
|
|
RemoveItemProperty(oSkin, ip);
|
|
|
|
// Get the next property
|
|
ip = GetNextItemProperty(oSkin);
|
|
}
|
|
}
|
|
if(iCode)
|
|
AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(381),oSkin);
|
|
|
|
// Schedule restoring the unhealable ability damage
|
|
DelayCommand(0.1f, DelayedReApplyUnhealableAbilityDamage(nGeneration, oPC));
|
|
|
|
// Remove all natural weapons too
|
|
// ClearNaturalWeapons(oPC);
|
|
// Done this way to remove prc_inc_natweap and prc_inc_combat from the include
|
|
// Should help with compile speeds and the like
|
|
//array_delete(oPC, "ARRAY_NAT_SEC_WEAP_RESREF");
|
|
//array_delete(oPC, "ARRAY_NAT_PRI_WEAP_RESREF");
|
|
//array_delete(oPC, "ARRAY_NAT_PRI_WEAP_ATTACKS");
|
|
}
|
|
|
|
int BlastInfidelOrFaithHeal(object oCaster, object oTarget, int iEnergyType, int iDisplayFeedback)
|
|
{
|
|
//Don't bother doing anything if iEnergyType isn't either positive/negative energy
|
|
if(iEnergyType != DAMAGE_TYPE_POSITIVE && iEnergyType != DAMAGE_TYPE_NEGATIVE)
|
|
return FALSE;
|
|
|
|
//If the target is undead and damage type is negative
|
|
//or if the target is living and damage type is positive
|
|
//then we're healing. Otherwise, we're harming.
|
|
int iTombTainted = GetHasFeat(FEAT_TOMB_TAINTED_SOUL, oTarget) && GetAlignmentGoodEvil(oTarget) != ALIGNMENT_GOOD;
|
|
int iHeal = ( iEnergyType == DAMAGE_TYPE_NEGATIVE && (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD || iTombTainted)) ||
|
|
( iEnergyType == DAMAGE_TYPE_POSITIVE && MyPRCGetRacialType(oTarget) != RACIAL_TYPE_UNDEAD && !iTombTainted);
|
|
int iRetVal = FALSE;
|
|
int iAlignDif = CompareAlignment(oCaster, oTarget);
|
|
string sFeedback = "";
|
|
|
|
if(iHeal){
|
|
if((GetHasFeat(FEAT_FAITH_HEALING, oCaster) && iAlignDif < 2)){
|
|
iRetVal = TRUE;
|
|
sFeedback = "Faith Healing";
|
|
}
|
|
}
|
|
else{
|
|
if((GetHasFeat(FEAT_BLAST_INFIDEL, oCaster) && iAlignDif >= 2)){
|
|
iRetVal = TRUE;
|
|
sFeedback = "Blast Infidel";
|
|
}
|
|
}
|
|
|
|
if(iDisplayFeedback) FloatingTextStringOnCreature(sFeedback, oCaster);
|
|
return iRetVal;
|
|
}
|
|
|
|
int GetShiftingFeats(object oPC)
|
|
{
|
|
int nNumFeats;
|
|
nNumFeats = GetHasFeat(FEAT_BEASTHIDE_ELITE, oPC)
|
|
+ GetHasFeat(FEAT_DREAMSIGHT_ELITE, oPC)
|
|
+ GetHasFeat(FEAT_GOREBRUTE_ELITE, oPC)
|
|
+ GetHasFeat(FEAT_LONGSTRIDE_ELITE, oPC)
|
|
+ GetHasFeat(FEAT_LONGTOOTH_ELITE, oPC)
|
|
+ GetHasFeat(FEAT_RAZORCLAW_ELITE, oPC)
|
|
+ GetHasFeat(FEAT_WILDHUNT_ELITE, oPC)
|
|
+ GetHasFeat(FEAT_EXTRA_SHIFTER_TRAIT, oPC)
|
|
+ GetHasFeat(FEAT_HEALING_FACTOR, oPC)
|
|
+ GetHasFeat(FEAT_SHIFTER_AGILITY, oPC)
|
|
+ GetHasFeat(FEAT_SHIFTER_DEFENSE, oPC)
|
|
+ GetHasFeat(FEAT_GREATER_SHIFTER_DEFENSE, oPC)
|
|
+ GetHasFeat(FEAT_SHIFTER_FEROCITY, oPC)
|
|
+ GetHasFeat(FEAT_SHIFTER_INSTINCTS, oPC)
|
|
+ GetHasFeat(FEAT_SHIFTER_SAVAGERY, oPC);
|
|
|
|
return nNumFeats;
|
|
}
|
|
|
|
//Including DelayedApplyEffectToObject here because it is often used in conjunction with EvalPRCFeats and I don't know a better place to put it
|
|
void DelayedApplyEffectToObject(int nExpectedGeneration, int nCurrentGeneration, int nDuration, effect eEffect, object oTarget, float fDuration)
|
|
{
|
|
if (nExpectedGeneration != nCurrentGeneration)
|
|
{
|
|
//Generation has changed, so don't apply the effect
|
|
return;
|
|
}
|
|
ApplyEffectToObject(nDuration, eEffect, oTarget, fDuration);
|
|
}
|
|
|
|
//Including DelayedApplyEffectToObject here because it is often used in conjunction with EvalPRCFeats and I don't know a better place to put it
|
|
void DelayApplyEffectToObject(float fDelay, string sGenerationName, int nDuration, effect eEffect, object oTarget, float fDuration = 0.0f)
|
|
{
|
|
/*
|
|
There are a couple of problems that can arise in code that removes and reapplies effects;
|
|
this function helps deal with those problems. One example of a typical place where these problems
|
|
frequently arise is in the class scripts called by the EvalPRCFeats function.
|
|
|
|
The first problem is that when code removes and immediately reapplies a series of effects,
|
|
some of those effects may not actually be reapplied. This is because the RemoveEffect() function
|
|
doesn't actually remove an effect, it marks it to be removed later--when the currently running
|
|
script finishes. If any of the effects we reapply matches one of the effects marked to be
|
|
removed, that reapplied effect will be removed when the currently running script finishes
|
|
and so will be unexpectedly missing. To illustrate:
|
|
1) We start with effect A and B.
|
|
2) The application function is called; it removes all effects and reapplies effects B and C.
|
|
3) The actual removal happens when the script ends: effect A and B are removed.
|
|
End result: we have only effect C instead of the expected B and C.
|
|
The solution to this is to reapply the effects later using DelayCommand().
|
|
|
|
This introduces a new problem. If the function that removes and reapplies the effects is called
|
|
multiple times quickly, it can queue up a series of delayed applications. This causes two problems:
|
|
if the data on which the effects are calculated changes, the earlier delayed applications can
|
|
apply effects that should no longer be used, but they are anyway because the delayed code doesn't
|
|
know this. To illustrate:
|
|
1) The application function is called; it removes all effects, schedules delayed application of effect A.
|
|
2) The application function is called again; it removes all effects, schedules delayed application of effect B.
|
|
3) Delayed application of effect A occurs.
|
|
4) Delayed application of effect B occurs.
|
|
End result: we have both effect A and B instead of the expected result, B alone.
|
|
Another problem is that we can end up with multiple copies of the same effect.
|
|
If this happens enough, it can cause "Effect List overflow" errors. Also, if the effect stacks
|
|
with itself, this gives a greater bonus or penalty than it should. To illustrate:
|
|
1) The application function is called; it removes all effects, schedules delayed application of effect C.
|
|
2) The application function is called; it removes all effects, schedules delayed application of effect C.
|
|
3) Delayed application of effect C occurs.
|
|
4) Delayed application of effect C occurs.
|
|
End result: we have effect C twice instead of just once.
|
|
The solution is to both these problems is for the application function to increment an integer each time it
|
|
is called and to pass this to the delayed application function. The delayed application actually happens only
|
|
if the generation when it runs is the same as the generation when it was scheduled. To illustrate:
|
|
1) We start with effect A and B applied.
|
|
2) The application function is called: it increments generation to 2, schedules delayed application of effect B and C.
|
|
3) The application function is called: it increments generation to 3, schedules delayed application of effect C.
|
|
4) The generation 2 delayed application function executes: it sees that the current generation is 3 and simply exits, doing nothing.
|
|
5) The generation 3 delayed application function executes: it sees that the current generation is 3, so it applies effect C.
|
|
End result: we have one copy of effect C, which is what we wanted.
|
|
*/
|
|
|
|
if (fDelay < 0.0f || GetStringLength(sGenerationName) == 0)
|
|
{
|
|
ApplyEffectToObject(nDuration, eEffect, oTarget, fDuration);
|
|
}
|
|
else
|
|
{
|
|
int nExpectedGeneration = GetLocalInt(oTarget, sGenerationName); //This gets the generation now
|
|
DelayCommand(
|
|
fDelay,
|
|
DelayedApplyEffectToObject(
|
|
nExpectedGeneration,
|
|
GetLocalInt(oTarget, sGenerationName), //This is delayed by the DelayCommand, so it gets the generation when DelayedApplyEffectToObject is actually executed
|
|
nDuration,
|
|
eEffect,
|
|
oTarget,
|
|
fDuration
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
//Including DelayedAddItemProperty here to keep it with DelayedApplyEffectToObject, though more properly it should probably be in inc_item_props.nss
|
|
void DelayedAddItemProperty(int nExpectedGeneration, int nCurrentGeneration, int nDurationType, itemproperty ipProperty, object oItem, float fDuration)
|
|
{
|
|
if (nExpectedGeneration != nCurrentGeneration)
|
|
{
|
|
//Generation has changed, so don't apply the effect
|
|
return;
|
|
}
|
|
AddItemProperty(nDurationType, ipProperty, oItem, fDuration);
|
|
}
|
|
|
|
//Including DelayAddItemProperty here to keep it with DelayApplyEffectToObject, though more properly it should probably be in inc_item_props.nss
|
|
void DelayAddItemProperty(float fDelay, object oGenerationHolder, string sGenerationName, int nDurationType, itemproperty ipProperty, object oItem, float fDuration = 0.0f)
|
|
{
|
|
/*
|
|
There are a couple of problems that can arise in code that removes and reapplies item properties;
|
|
this function helps deal with those problems. One example of a typical place where these problems
|
|
frequently arise is in the class scripts called by the EvalPRCFeats function.
|
|
|
|
The first problem is that when code removes and immediately reapplies a series of item properties,
|
|
some of those properties may not actually be reapplied. This is because the RemoveItemProperty() function
|
|
doesn't actually remove a property, it marks it to be removed later--when the currently running
|
|
script finishes. If any of the properties we reapply matches one of the properties marked to be
|
|
removed, that reapplied property will be removed when the currently running script finishes
|
|
and so will be unexpectedly missing. To illustrate:
|
|
1) We start with properties A and B.
|
|
2) The application function is called; it removes all properties and reapplies properties B and C.
|
|
3) The actual removal happens when the script ends: property A and B are removed.
|
|
End result: we have only property C instead of the expected B and C.
|
|
The solution to this is to reapply the properties later using DelayCommand().
|
|
|
|
This introduces a new problem. If the function that removes and reapplies the properties is called
|
|
multiple times quickly, it can queue up a series of delayed applications. This causes two problems:
|
|
if the data on which the properties are calculated changes, the earlier delayed applications can
|
|
apply properties that should no longer be used, but they are anyway because the delayed code doesn't
|
|
know this. To illustrate:
|
|
1) The application function is called; it removes all properties, schedules delayed application of property A.
|
|
2) The application function is called again; it removes all properties, schedules delayed application of property B.
|
|
3) Delayed application of property A occurs.
|
|
4) Delayed application of property B occurs.
|
|
End result: we have both property A and B instead of the expected result, B alone.
|
|
Another problem is that we can end up with multiple copies of the same property.
|
|
If this happens enough, it can cause "Effect List overflow" errors. Also, if the property stacks
|
|
with itself, this gives a greater bonus or penalty than it should. To illustrate:
|
|
1) The application function is called; it removes all properties, schedules delayed application of property C.
|
|
2) The application function is called; it removes all properties, schedules delayed application of property C.
|
|
3) Delayed application of property C occurs.
|
|
4) Delayed application of property C occurs.
|
|
End result: we have property C twice instead of just once.
|
|
The solution is to both these problems is for the application function to increment an integer each time it
|
|
is called and to pass this to the delayed application function. The delayed application actually happens only
|
|
if the generation when it runs is the same as the generation when it was scheduled. To illustrate:
|
|
1) We start with property A and B applied.
|
|
2) The application function is called: it increments generation to 2, schedules delayed application of property B and C.
|
|
3) The application function is called: it increments generation to 3, schedules delayed application of property C.
|
|
4) The generation 2 delayed application function executes: it sees that the current generation is 3 and simply exits, doing nothing.
|
|
5) The generation 3 delayed application function executes: it sees that the current generation is 3, so it applies property C.
|
|
End result: we have one copy of property C, which is what we wanted.
|
|
*/
|
|
|
|
if (fDelay < 0.0f || GetStringLength(sGenerationName) == 0)
|
|
{
|
|
AddItemProperty(nDurationType, ipProperty, oItem, fDuration);
|
|
}
|
|
else
|
|
{
|
|
int nExpectedGeneration = GetLocalInt(oGenerationHolder, sGenerationName); //This gets the generation now
|
|
DelayCommand(
|
|
fDelay,
|
|
DelayedAddItemProperty(
|
|
nExpectedGeneration,
|
|
GetLocalInt(oGenerationHolder, sGenerationName), //This is delayed by the DelayCommand, so it gets the generation when DelayedAddItemProperty is actually executed
|
|
nDurationType,
|
|
ipProperty,
|
|
oItem,
|
|
fDuration
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
void FeatUsePerDay(object oPC, int iFeat, int iAbiMod = ABILITY_CHARISMA, int iMod = 0, int iMin = 1)
|
|
{
|
|
if(!GetHasFeat(iFeat,oPC))
|
|
return;
|
|
|
|
int iAbi = GetAbilityModifier(iAbiMod, oPC);
|
|
iAbi = (iAbi > 0) ? iAbi : 0;
|
|
|
|
if (iAbiMod == -1) iAbi = 0;
|
|
iAbi += iMod;
|
|
|
|
if(iAbi < iMin)
|
|
iAbi = iMin;
|
|
|
|
while(GetHasFeat(iFeat, oPC))
|
|
DecrementRemainingFeatUses(oPC, iFeat);
|
|
|
|
while(iAbi)
|
|
{
|
|
IncrementRemainingFeatUses(oPC, iFeat);
|
|
iAbi--;
|
|
}
|
|
}
|
|
|
|
void DomainUses(object oPC)
|
|
{
|
|
int nUses;
|
|
if(!GetHasFeat(FEAT_BONUS_DOMAIN_STRENGTH, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_STRENGTH_DOMAIN_POWER))
|
|
{
|
|
nUses = GetLevelByClass(CLASS_TYPE_MIGHTY_CONTENDER_KORD, oPC) ? GetAbilityModifier(ABILITY_STRENGTH, oPC) : 1;
|
|
FeatUsePerDay(oPC, FEAT_STRENGTH_DOMAIN_POWER, -1, nUses);
|
|
}
|
|
if(GetHasFeat(FEAT_BONUS_DOMAIN_SUN, oPC) && GetLevelByClass(CLASS_TYPE_MYSTIC, oPC) && PRC_Funcs_GetFeatKnown(oPC, FEAT_SUN_DOMAIN_POWER))
|
|
{
|
|
nUses = GetHasFeat(FEAT_EXTRA_TURNING, oPC) ? 7 : 3;
|
|
FeatUsePerDay(oPC, FEAT_SUN_DOMAIN_POWER, ABILITY_CHARISMA, nUses);
|
|
}
|
|
else if(!GetHasFeat(FEAT_BONUS_DOMAIN_SUN, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_SUN_DOMAIN_POWER))
|
|
FeatUsePerDay(oPC, FEAT_SUN_DOMAIN_POWER, -1, 1);
|
|
|
|
if(!GetHasFeat(FEAT_BONUS_DOMAIN_BLIGHTBRINGER, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_DOMAIN_POWER_BLIGHTBRINGER))
|
|
FeatUsePerDay(oPC, FEAT_DOMAIN_POWER_BLIGHTBRINGER, ABILITY_CHARISMA, 3);
|
|
if(!GetHasFeat(FEAT_BONUS_DOMAIN_AIR, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_AIR_DOMAIN_POWER))
|
|
FeatUsePerDay(oPC, FEAT_AIR_DOMAIN_POWER, ABILITY_CHARISMA, 3);
|
|
if(!GetHasFeat(FEAT_BONUS_DOMAIN_EARTH, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_EARTH_DOMAIN_POWER))
|
|
FeatUsePerDay(oPC, FEAT_EARTH_DOMAIN_POWER, ABILITY_CHARISMA, 3);
|
|
if(!GetHasFeat(FEAT_BONUS_DOMAIN_FIRE, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_FIRE_DOMAIN_POWER))
|
|
FeatUsePerDay(oPC, FEAT_FIRE_DOMAIN_POWER, ABILITY_CHARISMA, 3);
|
|
if(!GetHasFeat(FEAT_BONUS_DOMAIN_WATER, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_WATER_DOMAIN_POWER))
|
|
FeatUsePerDay(oPC, FEAT_WATER_DOMAIN_POWER, ABILITY_CHARISMA, 3);
|
|
if(!GetHasFeat(FEAT_BONUS_DOMAIN_SLIME, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_DOMAIN_POWER_SLIME))
|
|
FeatUsePerDay(oPC, FEAT_DOMAIN_POWER_SLIME, ABILITY_CHARISMA, 3);
|
|
if(!GetHasFeat(FEAT_BONUS_DOMAIN_SPIDER, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_DOMAIN_POWER_SPIDER))
|
|
FeatUsePerDay(oPC, FEAT_DOMAIN_POWER_SPIDER, ABILITY_CHARISMA, 3);
|
|
if(!GetHasFeat(FEAT_BONUS_DOMAIN_SCALEYKIND, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_DOMAIN_POWER_SCALEYKIND))
|
|
FeatUsePerDay(oPC, FEAT_DOMAIN_POWER_SCALEYKIND, ABILITY_CHARISMA, 3);
|
|
if(!GetHasFeat(FEAT_BONUS_DOMAIN_PLANT, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_PLANT_DOMAIN_POWER))
|
|
FeatUsePerDay(oPC, FEAT_PLANT_DOMAIN_POWER, ABILITY_CHARISMA, 3);
|
|
}
|
|
|
|
void MephlingBreath(object oPC) //:: Mephlings
|
|
{
|
|
if(!GetHasFeat(FEAT_MEPHLING_BREATH, oPC))
|
|
return;
|
|
|
|
int nMephBreath = ((1 + GetHitDice(oPC)) / 4);
|
|
|
|
FeatUsePerDay(oPC, FEAT_MEPHLING_BREATH, -1, nMephBreath);
|
|
}
|
|
|
|
void FeatAlaghar(object oPC)
|
|
{
|
|
int iAlagharLevel = GetLevelByClass(CLASS_TYPE_ALAGHAR, oPC);
|
|
|
|
if (!iAlagharLevel) return;
|
|
|
|
int iClangStrike = iAlagharLevel/3;
|
|
int iClangMight = (iAlagharLevel - 1)/3;
|
|
int iRockburst = (iAlagharLevel + 2)/4;
|
|
|
|
FeatUsePerDay(oPC, FEAT_CLANGEDDINS_STRIKE, -1, iClangStrike);
|
|
FeatUsePerDay(oPC, FEAT_CLANGEDDINS_MIGHT, -1, iClangMight);
|
|
FeatUsePerDay(oPC, FEAT_ALAG_ROCKBURST, -1, iRockburst);
|
|
}
|
|
|
|
|
|
void FeatDiabolist(object oPC)
|
|
{
|
|
int Diabol = GetLevelByClass(CLASS_TYPE_DIABOLIST, oPC);
|
|
|
|
if (!Diabol) return;
|
|
|
|
int iUse = (Diabol + 3)/3;
|
|
|
|
FeatUsePerDay(oPC,FEAT_DIABOL_DIABOLISM_1,-1,iUse);
|
|
FeatUsePerDay(oPC,FEAT_DIABOL_DIABOLISM_2,-1,iUse);
|
|
FeatUsePerDay(oPC,FEAT_DIABOL_DIABOLISM_3,-1,iUse);
|
|
}
|
|
|
|
void FeatNinja (object oPC)
|
|
{
|
|
int iNinjaLevel = GetLevelByClass(CLASS_TYPE_NINJA, oPC);
|
|
// Ascetic Stalker
|
|
if (GetHasFeat(FEAT_ASCETIC_STALKER, oPC))
|
|
iNinjaLevel += GetLevelByClass(CLASS_TYPE_MONK, oPC);
|
|
|
|
// Martial Stalker
|
|
if (GetHasFeat(FEAT_MARTIAL_STALKER, oPC))
|
|
iNinjaLevel += GetLevelByClass(CLASS_TYPE_FIGHTER, oPC);
|
|
|
|
if (!iNinjaLevel) return;
|
|
|
|
int nUsesLeft = iNinjaLevel / 2;
|
|
if (nUsesLeft < 1)
|
|
nUsesLeft = 1;
|
|
|
|
// Expanded Ki Pool
|
|
if (GetHasFeat(FEAT_EXPANDED_KI_POOL, oPC)) nUsesLeft += 3;
|
|
|
|
FeatUsePerDay(oPC, FEAT_KI_POWER, ABILITY_WISDOM, nUsesLeft);
|
|
FeatUsePerDay(oPC, FEAT_GHOST_STEP, ABILITY_WISDOM, nUsesLeft);
|
|
FeatUsePerDay(oPC, FEAT_GHOST_STRIKE, ABILITY_WISDOM, nUsesLeft);
|
|
FeatUsePerDay(oPC, FEAT_GHOST_WALK, ABILITY_WISDOM, nUsesLeft);
|
|
FeatUsePerDay(oPC, FEAT_KI_DODGE, ABILITY_WISDOM, nUsesLeft);
|
|
|
|
SetLocalInt(oPC, "prc_ninja_ki", nUsesLeft);
|
|
}
|
|
|
|
void BarbarianRage(object oPC)
|
|
{
|
|
if(!GetHasFeat(FEAT_BARBARIAN_RAGE, oPC)) return;
|
|
|
|
int nUses = (GetLevelByClass(CLASS_TYPE_BARBARIAN, oPC) + GetLevelByClass(CLASS_TYPE_BLACK_BLOOD_CULTIST, oPC) + GetLevelByClass(CLASS_TYPE_PRC_EYE_OF_GRUUMSH, oPC)) / 4 + 1;
|
|
nUses += (GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oPC) + 2) / 5;
|
|
nUses += (GetLevelByClass(CLASS_TYPE_BATTLERAGER, oPC) + 1) / 2;
|
|
nUses += (GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC) + 2) / 4;
|
|
nUses += GetLevelByClass(CLASS_TYPE_RUNESCARRED, oPC) ? ((GetLevelByClass(CLASS_TYPE_RUNESCARRED, oPC) / 4) + 1) : 0;
|
|
nUses += (GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oPC) + 4) / 6;
|
|
|
|
if(GetHasFeat(FEAT_EXTRA_RAGE, oPC)) nUses += 2;
|
|
|
|
FeatUsePerDay(oPC, FEAT_BARBARIAN_RAGE, -1, nUses);
|
|
FeatUsePerDay(oPC, FEAT_GREATER_RAGE, -1, nUses);
|
|
|
|
if(GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oPC) > 0)
|
|
{
|
|
if(GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oPC) > 9)
|
|
nUses = 3;
|
|
else if(GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oPC) > 4)
|
|
nUses = 2;
|
|
else
|
|
nUses = 1;
|
|
|
|
FeatUsePerDay(oPC, FEAT_SPELL_RAGE, -1, nUses);
|
|
}
|
|
}
|
|
|
|
void BardSong(object oPC)
|
|
{
|
|
// This is used to set the number of bardic song uses per day, as bardic PrCs can increase it
|
|
// or other classes can grant it on their own
|
|
if(!GetHasFeat(FEAT_BARD_SONGS, oPC)) return;
|
|
|
|
int nTotal = GetLevelByClass(CLASS_TYPE_BARD, oPC);
|
|
nTotal += GetLevelByClass(CLASS_TYPE_DIRGESINGER, oPC);
|
|
nTotal += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oPC);
|
|
nTotal += GetLevelByClass(CLASS_TYPE_FOCHLUCAN_LYRIST, oPC);
|
|
nTotal += GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oPC) / 2;
|
|
|
|
if(GetHasFeat(FEAT_EXTRA_MUSIC, oPC)) nTotal += 4;
|
|
|
|
FeatUsePerDay(oPC, FEAT_BARD_SONGS, -1, nTotal);
|
|
}
|
|
|
|
void FeatVirtuoso(object oPC)
|
|
{
|
|
int iVirtuosoLevel = GetLevelByClass(CLASS_TYPE_VIRTUOSO, oPC);
|
|
if (!iVirtuosoLevel) return;
|
|
|
|
int nUses = GetLevelByClass(CLASS_TYPE_BARD, oPC) + iVirtuosoLevel;
|
|
if(GetHasFeat(FEAT_EXTRA_MUSIC, oPC)) nUses += 4;
|
|
SetPersistantLocalInt(oPC, "Virtuoso_Performance_Uses", nUses);
|
|
int nFeat;
|
|
for(nFeat = FEAT_VIRTUOSO_SUSTAINING_SONG; nFeat <= FEAT_VIRTUOSO_PERFORMANCE; nFeat++)
|
|
{
|
|
FeatUsePerDay(oPC, nFeat, -1, nUses);
|
|
}
|
|
}
|
|
|
|
void HexCurse(object oPC)
|
|
{
|
|
int iHexLevel = GetLevelByClass(CLASS_TYPE_HEXBLADE, oPC);
|
|
|
|
if (!iHexLevel) return;
|
|
|
|
//Hexblade's Curse
|
|
int nUses = (iHexLevel + 3) / 4; // every 4 levels get 1 more use
|
|
FeatUsePerDay(oPC, FEAT_HEXCURSE, ABILITY_CHARISMA, nUses);
|
|
|
|
//Swift Cast
|
|
if(iHexLevel > 13)
|
|
nUses = (iHexLevel + 2) / 4;
|
|
else if(iHexLevel > 10)
|
|
nUses = 3;
|
|
else if(iHexLevel > 7)
|
|
nUses = 2;
|
|
else if(iHexLevel > 5)
|
|
nUses = 1;
|
|
else
|
|
nUses = 0;
|
|
FeatUsePerDay(oPC, FEAT_SWIFT_CAST, -1, nUses);
|
|
}
|
|
|
|
void FeatShadowblade(object oPC)
|
|
{
|
|
int iShadowLevel = GetLevelByClass(CLASS_TYPE_SHADOWBLADE, oPC);
|
|
if (!iShadowLevel) return;
|
|
|
|
FeatUsePerDay(oPC, FEAT_UNERRING_STRIKE, -1, iShadowLevel);
|
|
FeatUsePerDay(oPC, FEAT_UNEXPECTED_STRIKE, -1, iShadowLevel);
|
|
FeatUsePerDay(oPC, FEAT_EPHEMERAL_WEAPON, -1, iShadowLevel);
|
|
FeatUsePerDay(oPC, FEAT_SHADOWY_STRIKE, -1, iShadowLevel);
|
|
FeatUsePerDay(oPC, FEAT_FAR_SHADOW, -1, iShadowLevel);
|
|
}
|
|
|
|
void FeatNoble(object oPC)
|
|
{
|
|
int iNobleLevel = GetLevelByClass(CLASS_TYPE_NOBLE, oPC);
|
|
if (!iNobleLevel) return;
|
|
|
|
int nBonus = 0;
|
|
if (iNobleLevel >= 17) nBonus = 5;
|
|
else if (iNobleLevel >= 13) nBonus = 4;
|
|
else if (iNobleLevel >= 9) nBonus = 3;
|
|
else if (iNobleLevel >= 5) nBonus = 2;
|
|
else if (iNobleLevel >= 2) nBonus = 1;
|
|
|
|
FeatUsePerDay(oPC, FEAT_NOBLE_CONFIDENCE, -1, nBonus);
|
|
|
|
nBonus = (iNobleLevel - 11) / 3 + 1;
|
|
|
|
FeatUsePerDay(oPC, FEAT_NOBLE_GREATNESS, -1, nBonus);
|
|
}
|
|
|
|
void DarkKnowledge(object oPC)
|
|
{
|
|
int iArchivistLevel = GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC);
|
|
if(!iArchivistLevel) return;
|
|
|
|
int nUses = (iArchivistLevel / 3) + 3;
|
|
FeatUsePerDay(oPC, FEAT_DK_TACTICS, -1, nUses);
|
|
FeatUsePerDay(oPC, FEAT_DK_PUISSANCE, -1, nUses);
|
|
FeatUsePerDay(oPC, FEAT_DK_FOE, -1, nUses);
|
|
FeatUsePerDay(oPC, FEAT_DK_DREADSECRET, -1, nUses);
|
|
FeatUsePerDay(oPC, FEAT_DK_FOREKNOWLEDGE, -1, nUses);
|
|
}
|
|
|
|
void FeatImbueArrow(object oPC)
|
|
{
|
|
if(GetPRCSwitch(PRC_USE_NEW_IMBUE_ARROW))
|
|
FeatUsePerDay(oPC, FEAT_PRESTIGE_IMBUE_ARROW, -1, 0, 0);
|
|
}
|
|
|
|
void DragonDisciple(object oPC)
|
|
{
|
|
if(!GetHasFeat(FEAT_DRAGON_DIS_BREATH, oPC))
|
|
return;
|
|
|
|
//Dragon Disciples that do not possess any breath weapon
|
|
if(GetHasFeat(FEAT_CHIANG_LUNG_DRAGON, oPC)
|
|
|| GetHasFeat(FEAT_PAN_LUNG_DRAGON, oPC)
|
|
|| GetHasFeat(FEAT_SHEN_LUNG_DRAGON, oPC)
|
|
|| GetHasFeat(FEAT_TUN_MI_LUNG_DRAGON, oPC)
|
|
|| GetHasFeat(FEAT_YU_LUNG_DRAGON, oPC))
|
|
DecrementRemainingFeatUses(oPC, FEAT_DRAGON_DIS_BREATH);
|
|
}
|
|
|
|
void Warlock(object oPC)
|
|
{
|
|
if(GetHasFeat(FEAT_FIENDISH_RESILIENCE, oPC))
|
|
{
|
|
//Add daily Uses of Fiendish Resilience for epic warlock
|
|
if(GetHasFeat(FEAT_EPIC_FIENDISH_RESILIENCE_I, oPC))
|
|
{
|
|
int nFeatAmt = 0;
|
|
int bDone = FALSE;
|
|
while(!bDone)
|
|
{
|
|
if(nFeatAmt >= 9)
|
|
bDone = TRUE;
|
|
else if(GetHasFeat(FEAT_EPIC_FIENDISH_RESILIENCE_II + nFeatAmt, oPC))
|
|
nFeatAmt++;
|
|
else
|
|
bDone = TRUE;
|
|
}
|
|
nFeatAmt++;
|
|
FeatUsePerDay(oPC, FEAT_FIENDISH_RESILIENCE, -1, nFeatAmt);
|
|
}
|
|
else
|
|
FeatUsePerDay(oPC, FEAT_FIENDISH_RESILIENCE, -1, 1);
|
|
}
|
|
|
|
//Hellfire infusion
|
|
int nCha = GetAbilityModifier(ABILITY_CHARISMA, oPC);
|
|
FeatUsePerDay(oPC, FEAT_HELLFIRE_INFUSION, -1, nCha);
|
|
|
|
//Eldritch Spellweave
|
|
nCha += 3;
|
|
FeatUsePerDay(oPC, FEAT_ELDRITCH_SPELLWEAVE, -1, nCha);
|
|
}
|
|
|
|
void KotMC(object oPC)
|
|
{
|
|
int iKotMCLevel = GetLevelByClass(CLASS_TYPE_KNIGHT_MIDDLECIRCLE, oPC);
|
|
if(!iKotMCLevel) return;
|
|
|
|
int nUses = iKotMCLevel / 3;
|
|
FeatUsePerDay(oPC, FEAT_KOTMC_TRUE_STRIKE, -1, nUses);
|
|
}
|
|
|
|
void Templar(object oPC)
|
|
{
|
|
if(!GetHasFeat(FEAT_SECULAR_AUTHORITY, oPC)) return;
|
|
|
|
int nTemplar = GetLevelByClass(CLASS_TYPE_TEMPLAR, oPC);
|
|
int nUses = nTemplar + ((GetHitDice(oPC) - nTemplar) / 4);
|
|
FeatUsePerDay(oPC, FEAT_SECULAR_AUTHORITY, -1, nUses);
|
|
}
|
|
|
|
void FeatRacial(object oPC)
|
|
{
|
|
//Shifter bonus shifting uses
|
|
int nRace = GetRacialType(oPC);
|
|
if(nRace == RACIAL_TYPE_SHIFTER)
|
|
{
|
|
int nShiftFeats = GetShiftingFeats(oPC);
|
|
int nBonusShiftUses = (nShiftFeats / 2) + 1;
|
|
FeatUsePerDay(oPC, FEAT_SHIFTER_SHIFTING, -1, nBonusShiftUses);
|
|
}
|
|
else if(nRace == RACIAL_TYPE_FORESTLORD_ELF)
|
|
{
|
|
int nUses = GetHitDice(oPC) / 5 + 1;
|
|
FeatUsePerDay(oPC, FEAT_FORESTLORD_TREEWALK, -1, nUses);
|
|
}
|
|
}
|
|
|
|
void CombatMedic(object oPC)
|
|
{
|
|
int iCombMed = GetLevelByClass(CLASS_TYPE_COMBAT_MEDIC, oPC);
|
|
if(!iCombMed) return;
|
|
|
|
FeatUsePerDay(oPC, FEAT_HEALING_KICKER_1, ABILITY_WISDOM, iCombMed);
|
|
FeatUsePerDay(oPC, FEAT_HEALING_KICKER_2, ABILITY_WISDOM, iCombMed);
|
|
FeatUsePerDay(oPC, FEAT_HEALING_KICKER_3, ABILITY_WISDOM, iCombMed);
|
|
}
|
|
|
|
void MasterOfShrouds(object oPC)
|
|
{
|
|
if(!GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oPC)) return;
|
|
|
|
FeatUsePerDay(oPC, FEAT_MOS_UNDEAD_1, ABILITY_CHARISMA, 3);
|
|
FeatUsePerDay(oPC, FEAT_MOS_UNDEAD_2, ABILITY_CHARISMA, 3);
|
|
FeatUsePerDay(oPC, FEAT_MOS_UNDEAD_3, ABILITY_CHARISMA, 3);
|
|
FeatUsePerDay(oPC, FEAT_MOS_UNDEAD_4, ABILITY_CHARISMA, 3);
|
|
}
|
|
|
|
void SLAUses(object oPC)
|
|
{
|
|
if(!GetHasFeat(FEAT_SPELL_LIKE_ABILITY_1, oPC)) return;
|
|
|
|
FeatUsePerDay(oPC, FEAT_SPELL_LIKE_ABILITY_1, -1, GetPersistantLocalInt(oPC, "PRC_SLA_Uses_1"));
|
|
FeatUsePerDay(oPC, FEAT_SPELL_LIKE_ABILITY_2, -1, GetPersistantLocalInt(oPC, "PRC_SLA_Uses_2"));
|
|
FeatUsePerDay(oPC, FEAT_SPELL_LIKE_ABILITY_3, -1, GetPersistantLocalInt(oPC, "PRC_SLA_Uses_3"));
|
|
FeatUsePerDay(oPC, FEAT_SPELL_LIKE_ABILITY_4, -1, GetPersistantLocalInt(oPC, "PRC_SLA_Uses_4"));
|
|
FeatUsePerDay(oPC, FEAT_SPELL_LIKE_ABILITY_5, -1, GetPersistantLocalInt(oPC, "PRC_SLA_Uses_5"));
|
|
}
|
|
|
|
void ShadowShieldUses(object oPC)
|
|
{
|
|
if(!GetHasFeat(FEAT_SA_SHIELDSHADOW, oPC)) return;
|
|
FeatUsePerDay(oPC, FEAT_SA_SHIELDSHADOW, -1, GetPrCAdjustedCasterLevelByType(TYPE_ARCANE, oPC));
|
|
}
|
|
|
|
void BlighterFeats(object oPC)
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_BLIGHTER, oPC);
|
|
if(0 >= nClass) return;
|
|
|
|
if (nClass == 3)
|
|
FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 1);
|
|
else if (nClass == 4)
|
|
FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 2);
|
|
else if (nClass == 5)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 2);
|
|
FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 1);
|
|
}
|
|
else if (nClass == 6)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 3);
|
|
FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 1);
|
|
}
|
|
else if (nClass == 7)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 3);
|
|
FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 2);
|
|
}
|
|
else if (nClass == 8)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 4);
|
|
FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 2);
|
|
}
|
|
else if (nClass == 9)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 4);
|
|
FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 3);
|
|
}
|
|
else
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 5);
|
|
FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 3);
|
|
}
|
|
}
|
|
|
|
void MysteryFeats(object oPC)
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_CHILD_OF_NIGHT, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
if (nClass >= 10)
|
|
FeatUsePerDay(oPC, FEAT_CLOAK_SHADOWS, -1, 2);
|
|
else if (nClass >= 6)
|
|
FeatUsePerDay(oPC, FEAT_CLOAK_SHADOWS, -1, 3);
|
|
else
|
|
FeatUsePerDay(oPC, FEAT_CLOAK_SHADOWS, -1, 1);
|
|
|
|
if (nClass >= 7)
|
|
FeatUsePerDay(oPC, FEAT_DANCING_SHADOWS, -1, 2);
|
|
else
|
|
FeatUsePerDay(oPC, FEAT_DANCING_SHADOWS, -1, 1);
|
|
}
|
|
nClass = GetLevelByClass(CLASS_TYPE_NOCTUMANCER, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
if (nClass >= 8)
|
|
FeatUsePerDay(oPC, FEAT_INNATE_COUNTERSPELL, -1, 3);
|
|
else if (nClass >= 5)
|
|
FeatUsePerDay(oPC, FEAT_INNATE_COUNTERSPELL, -1, 2);
|
|
else
|
|
FeatUsePerDay(oPC, FEAT_INNATE_COUNTERSPELL, -1, 1);
|
|
}
|
|
nClass = GetLevelByClass(CLASS_TYPE_SHADOWSMITH, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_TOUCH_SHADOW , -1, nClass);
|
|
FeatUsePerDay(oPC, FEAT_SHROUD_SHADOW , -1, nClass);
|
|
FeatUsePerDay(oPC, FEAT_SHADOW_CRAFT , -1, nClass/2);
|
|
FeatUsePerDay(oPC, FEAT_ARMOR_SHADOW , -1, nClass/2);
|
|
FeatUsePerDay(oPC, FEAT_ARMOR_SHADOW_Q, -1, nClass/2);
|
|
}
|
|
}
|
|
|
|
void WildMage(object oPC)
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_WILD_MAGE, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
if (nClass >= 8)
|
|
FeatUsePerDay(oPC, FEAT_WILD_MAGE_RANDOM_DEFLECTOR, -1, 2);
|
|
else if (nClass >= 5)
|
|
FeatUsePerDay(oPC, FEAT_WILD_MAGE_RANDOM_DEFLECTOR, -1, 3);
|
|
else
|
|
FeatUsePerDay(oPC, FEAT_WILD_MAGE_RANDOM_DEFLECTOR, -1, 1);
|
|
}
|
|
}
|
|
|
|
void Factotum(object oPC)
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_FACTOTUM, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
if (nClass >= 20)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_TURN, ABILITY_WISDOM, 0, 6);
|
|
FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_HEAL, ABILITY_WISDOM, 0, 6);
|
|
}
|
|
else if (nClass >= 15)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_TURN, ABILITY_WISDOM, 0, 5);
|
|
FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_HEAL, ABILITY_WISDOM, 0, 5);
|
|
}
|
|
else if (nClass >= 10)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_TURN, ABILITY_WISDOM, 0, 4);
|
|
FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_HEAL, ABILITY_WISDOM, 0, 4);
|
|
}
|
|
else
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_TURN, ABILITY_WISDOM, 0, 3);
|
|
FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_HEAL, ABILITY_WISDOM, 0, 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Sharess(object oPC)
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_CELEBRANT_SHARESS_FASCINATE , -1, 0, nClass);
|
|
FeatUsePerDay(oPC, FEAT_CELEBRANT_SHARESS_CONFUSE , -1, 0, nClass);
|
|
FeatUsePerDay(oPC, FEAT_CELEBRANT_SHARESS_DOMINATE , -1, 0, nClass);
|
|
}
|
|
}
|
|
|
|
void SoulbornDefense(object oPC)
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_SOULBORN, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
if (nClass >= 37)
|
|
FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 8);
|
|
else if (nClass >= 33)
|
|
FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 7);
|
|
else if (nClass >= 29)
|
|
FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 6);
|
|
else if (nClass >= 25)
|
|
FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 5);
|
|
else if (nClass >= 21)
|
|
FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 4);
|
|
else if (nClass >= 17)
|
|
FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 3);
|
|
else if (nClass >= 13)
|
|
FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 2);
|
|
else
|
|
FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 1);
|
|
}
|
|
}
|
|
|
|
void TotemistReshape(object oPC)
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_TOTEMIST, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
if (nClass >= 40)
|
|
FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 9);
|
|
else if (nClass >= 36)
|
|
FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 8);
|
|
else if (nClass >= 32)
|
|
FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 7);
|
|
else if (nClass >= 28)
|
|
FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 6);
|
|
else if (nClass >= 24)
|
|
FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 5);
|
|
else if (nClass >= 20)
|
|
FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 4);
|
|
else if (nClass >= 16)
|
|
FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 3);
|
|
else if (nClass >= 12)
|
|
FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 2);
|
|
else
|
|
FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 1);
|
|
}
|
|
}
|
|
|
|
void CWSamurai(object oPC)
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_CW_SAMURAI, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
if (nClass >= 17)
|
|
FeatUsePerDay(oPC, FEAT_KIAI_SMITE, -1, 0, 4);
|
|
else if (nClass >= 12)
|
|
FeatUsePerDay(oPC, FEAT_KIAI_SMITE, -1, 0, 3);
|
|
else if (nClass >= 7)
|
|
FeatUsePerDay(oPC, FEAT_KIAI_SMITE, -1, 0, 2);
|
|
else
|
|
FeatUsePerDay(oPC, FEAT_KIAI_SMITE, -1, 0, 1);
|
|
}
|
|
}
|
|
|
|
void CrusaderSmite(object oPC)
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_CRUSADER, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
if (nClass >= 18)
|
|
FeatUsePerDay(oPC, FEAT_CRUSADER_SMITE, -1, 0, 2);
|
|
else
|
|
FeatUsePerDay(oPC, FEAT_CRUSADER_SMITE, -1, 0, 1);
|
|
}
|
|
}
|
|
|
|
void AnimaMage(object oPC)
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_ANIMA_MAGE, oPC);
|
|
if(nClass > 0)
|
|
{
|
|
if (nClass >= 9)
|
|
FeatUsePerDay(oPC, FEAT_ANIMA_VESTIGE_METAMAGIC, -1, 0, 3);
|
|
else if (nClass >= 7)
|
|
FeatUsePerDay(oPC, FEAT_ANIMA_VESTIGE_METAMAGIC, -1, 0, 2);
|
|
else
|
|
FeatUsePerDay(oPC, FEAT_ANIMA_VESTIGE_METAMAGIC, -1, 0, 1);
|
|
}
|
|
}
|
|
|
|
void FeatSpecialUsePerDay(object oPC)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_WWOC_WIDEN_SPELL, ABILITY_CHARISMA, GetLevelByClass(CLASS_TYPE_WAR_WIZARD_OF_CORMYR, oPC));
|
|
FeatUsePerDay(oPC, FEAT_FIST_DAL_QUOR_STUNNING_STRIKE, -1, GetLevelByClass(CLASS_TYPE_FIST_DAL_QUOR, oPC));
|
|
FeatUsePerDay(oPC, FEAT_AD_FALSE_KEENNESS, -1, GetLevelByClass(CLASS_TYPE_ARCANE_DUELIST, oPC));
|
|
FeatUsePerDay(oPC, FEAT_LASHER_STUNNING_SNAP, -1, GetLevelByClass(CLASS_TYPE_LASHER, oPC));
|
|
FeatUsePerDay(oPC, FEAT_AD_BLUR, -1, GetLevelByClass(CLASS_TYPE_ARCANE_DUELIST, oPC));
|
|
FeatUsePerDay(oPC, FEAT_SHADOW_RIDE, -1, GetLevelByClass(CLASS_TYPE_CRINTI_SHADOW_MARAUDER, oPC));
|
|
FeatUsePerDay(oPC, FEAT_SHADOWJUMP, -1, GetLevelByClass(CLASS_TYPE_SHADOWLORD, oPC));
|
|
FeatUsePerDay(oPC, FEAT_SHADOWBANE_SMITE, -1, (GetLevelByClass(CLASS_TYPE_SHADOWBANE_INQUISITOR, oPC)+2)/4);
|
|
FeatUsePerDay(oPC, FEAT_INCARNUM_RADIANCE, -1, (GetLevelByClass(CLASS_TYPE_INCARNATE, oPC)+2)/5);
|
|
FeatUsePerDay(oPC, FEAT_RAPID_MELDSHAPING, -1, (GetLevelByClass(CLASS_TYPE_INCARNATE, oPC)+1)/6);
|
|
FeatUsePerDay(oPC, FEAT_SMITE_OPPOSITION, -1, (GetLevelByClass(CLASS_TYPE_SOULBORN, oPC)+5)/5);
|
|
FeatUsePerDay(oPC, FEAT_SMITE_CHAOS, -1, (GetLevelByClass(CLASS_TYPE_SAPPHIRE_HIERARCH, oPC)+2)/3);
|
|
FeatUsePerDay(oPC, FEAT_INCANDESCENT_OVERLOAD, -1, (GetLevelByClass(CLASS_TYPE_INCANDESCENT_CHAMPION, oPC)-1)/3);
|
|
FeatUsePerDay(oPC, FEAT_NECROCARNATE_SOULSHIELD, -1, GetLevelByClass(CLASS_TYPE_NECROCARNATE, oPC)/2);
|
|
FeatUsePerDay(oPC, FEAT_SCION_DANTALION_SCHOLARSHIP, -1, GetLevelByClass(CLASS_TYPE_SCION_DANTALION, oPC));
|
|
FeatUsePerDay(oPC, FEAT_SMITE_GOOD_ALIGN, -1, (GetLevelByClass(CLASS_TYPE_FISTRAZIEL, oPC)+1)/2);
|
|
FeatUsePerDay(oPC, FEAT_FIST_OF_IRON, ABILITY_WISDOM, 3);
|
|
FeatUsePerDay(oPC, FEAT_SMITE_UNDEAD, ABILITY_CHARISMA, 3);
|
|
FeatUsePerDay(oPC, FEAT_COC_WRATH, ABILITY_CHARISMA, 3);
|
|
FeatUsePerDay(oPC, FEAT_KILLOREN_ASPECT_D, ABILITY_CHARISMA);
|
|
FeatUsePerDay(oPC, FEAT_AVENGING_STRIKE, ABILITY_CHARISMA, 0, 1);
|
|
FeatUsePerDay(oPC, FEAT_INCARNUM_BLADE_REBIND, ABILITY_CONSTITUTION, 1);
|
|
FeatUsePerDay(oPC, FEAT_WITCHBORN_INTEGUMENT, ABILITY_CONSTITUTION, 1);
|
|
FeatUsePerDay(oPC, FEAT_LIPS_RAPTUR);
|
|
FeatUsePerDay(oPC, FEAT_COMMAND_SPIDERS, ABILITY_CHARISMA, 3);
|
|
FeatUsePerDay(oPC, FEAT_FM_FOREST_DOMINION, ABILITY_CHARISMA, 3);
|
|
FeatDiabolist(oPC);
|
|
FeatAlaghar(oPC);
|
|
ShadowShieldUses(oPC);
|
|
CombatMedic(oPC);
|
|
FeatNinja(oPC);
|
|
FeatNoble(oPC);
|
|
MasterOfShrouds(oPC);
|
|
HexCurse(oPC);
|
|
FeatRacial(oPC);
|
|
FeatShadowblade(oPC);
|
|
SoulbornDefense(oPC);
|
|
|
|
int nDread = GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oPC);
|
|
if (nDread >= 1)
|
|
{//:: Enervating Touch
|
|
if (nDread >= 17)
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_DN_ENERVATING_TOUCH, -1, nDread);
|
|
}
|
|
else
|
|
{
|
|
FeatUsePerDay(oPC, FEAT_DN_ENERVATING_TOUCH, -1, nDread/2);
|
|
}
|
|
}
|
|
|
|
if (nDread >= 3)
|
|
{//:: Negative Energy Burst
|
|
int NegBurstUses = 0;
|
|
|
|
if (nDread >= 8)
|
|
{
|
|
// Gains 1 more daily use of Negative Energy Burst every 5 levels after 3rd
|
|
int additionalUses = (nDread - 3) / 5;
|
|
NegBurstUses += 1 + additionalUses;
|
|
FeatUsePerDay(oPC, FEAT_DN_NEG_NRG_BURST, -1, NegBurstUses);
|
|
}
|
|
else if (nDread >= 3)
|
|
{
|
|
// Dread Necromancer gains 1 use at level 3
|
|
NegBurstUses += 1;
|
|
FeatUsePerDay(oPC, FEAT_DN_NEG_NRG_BURST, -1, NegBurstUses);
|
|
}
|
|
}
|
|
if (nDread >= 7)
|
|
{//:: Scabrous Touch
|
|
int ScabUses = 0;
|
|
|
|
// Gains 1 more daily use every 5 levels after 21
|
|
if (nDread >= 26)
|
|
{
|
|
int additionalUses = (nDread - 21) / 5;
|
|
ScabUses += 4 + additionalUses;
|
|
FeatUsePerDay(oPC, FEAT_DN_SCABROUS_TOUCH, -1, ScabUses);
|
|
}
|
|
// Epic Dread Necromancer gains 1 more daily use at level 21
|
|
else if (nDread >= 21)
|
|
{
|
|
ScabUses += 4;
|
|
FeatUsePerDay(oPC, FEAT_DN_SCABROUS_TOUCH, -1, ScabUses);
|
|
}
|
|
else if (nDread >= 16)
|
|
{
|
|
ScabUses += 3;
|
|
FeatUsePerDay(oPC, FEAT_DN_SCABROUS_TOUCH, -1, ScabUses);
|
|
}
|
|
else if (nDread >= 11)
|
|
{
|
|
ScabUses += 2;
|
|
FeatUsePerDay(oPC, FEAT_DN_SCABROUS_TOUCH, -1, ScabUses);
|
|
}
|
|
|
|
else
|
|
{
|
|
ScabUses += 1;
|
|
FeatUsePerDay(oPC, FEAT_DN_SCABROUS_TOUCH, -1, ScabUses);
|
|
}
|
|
}
|
|
|
|
SLAUses(oPC);
|
|
DomainUses(oPC);
|
|
BardSong(oPC);
|
|
BarbarianRage(oPC);
|
|
FeatVirtuoso(oPC);
|
|
ResetExtraStunfistUses(oPC);
|
|
DarkKnowledge(oPC);
|
|
FeatImbueArrow(oPC);
|
|
DragonDisciple(oPC);
|
|
Warlock(oPC);
|
|
KotMC(oPC);
|
|
Templar(oPC);
|
|
BlighterFeats(oPC);
|
|
MysteryFeats(oPC);
|
|
WildMage(oPC);
|
|
Factotum(oPC);
|
|
Sharess(oPC);
|
|
TotemistReshape(oPC);
|
|
CWSamurai(oPC);
|
|
CrusaderSmite(oPC);
|
|
AnimaMage(oPC);
|
|
MephlingBreath(oPC);
|
|
}
|
|
|