PRC8/nwn/nwnprc/trunk/scripts/prc_reservefeat.nss
Jaysyn904 ea09e4db6f Really fixed Evard's on wands this time
Really fixed Evard's on wands this time.  Fixed Acidic Spatter in regards to Acid Fog being spell #0.
2024-11-08 19:02:23 -05:00

447 lines
15 KiB
Plaintext

//Reserve Feat Script
//prc_reservefeat
//by ebonfowl 5/5/2022
//Dedicated to Edgar, the real ebonfowl
//Lookup constants
//Domains
const string RESERVESPELL_DOMAIN_DESTRUCTION = "destruc";
const string RESERVESPELL_DOMAIN_DEATH = "dethdom";
const string RESERVESPELL_DOMAIN_WAR = "wardom";
//Descriptors
const string RESERVESPELL_DESCRIPTOR_ACID = "acid";
const string RESERVESPELL_DESCRIPTOR_AIR = "air";
const string RESERVESPELL_DESCRIPTOR_COLD = "cold";
const string RESERVESPELL_DESCRIPTOR_DARKNESS = "darknes";
const string RESERVESPELL_DESCRIPTOR_EARTH = "earth";
const string RESERVESPELL_DESCRIPTOR_ELECTRICITY = "electri";
const string RESERVESPELL_DESCRIPTOR_FIRE = "fire";
const string RESERVESPELL_DESCRIPTOR_FORCE = "force";
const string RESERVESPELL_DESCRIPTOR_GLAMER = "glamer";
const string RESERVESPELL_DESCRIPTOR_HEALING = "healing";
const string RESERVESPELL_DESCRIPTOR_LIGHT = "light";
const string RESERVESPELL_DESCRIPTOR_POLYMORPH = "polymor";
const string RESERVESPELL_DESCRIPTOR_SONIC = "sonic";
const string RESERVESPELL_DESCRIPTOR_SUMMONING = "summon";
const string RESERVESPELL_DESCRIPTOR_TELEPORTATION = "teleprt";
const string RESERVESPELL_DESCRIPTOR_WATER = "water";
//Schools
const string RESERVESPELL_SCHOOL_ABJURATION = "abjurat";
const string RESERVESPELL_SCHOOL_ENCHANTMENT = "enchant";
const string RESERVESPELL_SCHOOL_NECROMANCY = "necro";
//Includes
#include "prc_feat_const"
#include "prc_x2_itemprop"
#include "psi_inc_psifunc"
//ebonfowl: this function is not currently used, but I am leaving it in just in case
/*
int GetHighestSpellAvailable(object oPC)
{
//This will loop all the spells and return the highest level available to cast
string sFile = "prc_all"; //May need to rename
int i;
int nSpellID;
int nNewSpellLevel;
int nSpellLevel = 0;
string sSpellLabel;
for (i = 0; i < 500; i++) // Adjust max i to reflect something close to the highest row number in the 2das
{
nSpellID = StringToInt(Get2DACache(sFile, "SpellID", i));
sSpellLabel = Get2DACache(sFile, "Label", i);
if(sSpellLabel != "") // Non-blank row
{
if(PRCGetHasSpell(nSpellID, oPC))
{
nNewSpellLevel = StringToInt(Get2DACache(sFile, "Innate", i));
if (nNewSpellLevel > nSpellLevel) nSpellLevel = nNewSpellLevel;
}
}
}
return nSpellLevel;
}
*/
int GetHighestSpellAvailableBySchool(object oPC, string sSchool)
{
//This will loop all spells fpr a given school and return the highest level available to cast
string sFile = "prc_desc_" + sSchool;
int i;
int nSpellID;
int nNewSpellLevel;
int nSpellLevel = 0;
string sSpellLabel;
for (i = 0; i < 126; i++) // Adjust max i to reflect something close to the highest row number in the 2das
{
nSpellID = StringToInt(Get2DACache(sFile, "SpellID", i));
sSpellLabel = Get2DACache(sFile, "Label", i);
if(sSpellLabel != "") // Non-blank row
{
if(PRCGetHasSpell(nSpellID, oPC))
{
nNewSpellLevel = StringToInt(Get2DACache(sFile, "Innate", i));
if (nNewSpellLevel > nSpellLevel) nSpellLevel = nNewSpellLevel;
}
}
}
return nSpellLevel;
}
int GetHighestDomainSpellAvailable(object oPC, string sDomain) //This will loop all domain spells for a given domain and return the highest level available to cast
{
string sFile = "prc_desc_" + sDomain;
int i;
int nSpellID;
int nNewSpellLevel;
int nSpellLevel = 0;
string sSpellLabel;
for (i = 0; i < 12; i++) // Adjust max i to reflect something close to the highest row number in the 2das
{
nSpellID = StringToInt(Get2DACache(sFile, "SpellID", i));
sSpellLabel = Get2DACache(sFile, "Label", i);
if(sSpellLabel != "") // Non-blank row
{
if(PRCGetHasSpell(nSpellID, oPC))
{
nNewSpellLevel = StringToInt(Get2DACache(sFile, "Innate", i));
if (nNewSpellLevel > nSpellLevel) nSpellLevel = nNewSpellLevel;
}
}
}
return nSpellLevel;
}
int GetHighestSpellAvailableByDescriptor(object oPC, string sDescriptor)
{
//This will loop all spells fpr a given descriptor and return the highest level available to cast
string sFile = "prc_desc_" + sDescriptor;
int i;
int nSpellID;
int nNewSpellLevel;
int nSpellLevel = 0;
string sSpellLabel;
for (i = 0; i < 125; i++) // Adjust max i to reflect something close to the highest row number in the 2das
{
nSpellID = StringToInt(Get2DACache(sFile, "SpellID", i));
sSpellLabel = Get2DACache(sFile, "Label", i);
if(sSpellLabel != "") // Non-blank row
{
if(PRCGetHasSpell(nSpellID, oPC))
{
nNewSpellLevel = StringToInt(Get2DACache(sFile, "Innate", i));
if (nNewSpellLevel > nSpellLevel) nSpellLevel = nNewSpellLevel;
}
}
}
return nSpellLevel;
}
void UpdateReserveFeats(object oPC) //This will check for each reserve feat, call the function to set the bonus, then set the bonus
{
object oWeapon, oOffHand;
int nBonus;
int nDamage;
effect eEffect;
effect eCheckEffect;
string sTag;
//Holy Warrior
if (GetHasFeat(FEAT_HOLY_WARRIOR, oPC)) //Update constant when feat constant is made
{
nBonus = GetHighestDomainSpellAvailable(oPC, RESERVESPELL_DOMAIN_WAR);
nDamage = IPGetDamageBonusConstantFromNumber(nBonus);
oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
oOffHand = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
eEffect = EffectDamageIncrease(nDamage, DAMAGE_TYPE_SLASHING);
eEffect = TagEffect(eEffect, "HolyWarriorBonus");
eEffect = SupernaturalEffect(eEffect);
eCheckEffect = GetFirstEffect(oPC);
while (GetIsEffectValid(eCheckEffect))
{
if (GetEffectTag(eCheckEffect) == "HolyWarriorBonus")
{
RemoveEffect(oPC, eCheckEffect);
}
eCheckEffect = GetNextEffect(oPC);
}
if (IPGetIsMeleeWeapon(oWeapon) ||
IPGetIsMeleeWeapon(oOffHand) ||
GetWeaponRanged(oWeapon) ||
GetWeaponRanged(oOffHand))
{
if (nBonus > 3) ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEffect, oPC);
}
}
//Mystic Backlash
if (GetHasFeat(FEAT_MYSTIC_BACKLASH, oPC)) //Update constant when feat constant is made
{
nBonus = GetHighestSpellAvailableBySchool(oPC, RESERVESPELL_SCHOOL_ABJURATION);
DeleteLocalInt(oPC, "MysticBacklashBonus");
if (nBonus > 4) SetLocalInt(oPC, "MysticBacklashBonus", nBonus);
}
//Acidic Splatter
if(GetHasFeat(FEAT_ACIDIC_SPLATTER, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_ACID);
if((GetHasSpell(SPELL_ACID_FOG, oPC)) || (PRCGetIsRealSpellKnown(SPELL_ACID_FOG, oPC)))
{
nBonus = 6;
}
DeleteLocalInt(oPC, "AcidicSplatterBonus");
if (nBonus > 1) SetLocalInt(oPC, "AcidicSplatterBonus", nBonus);
}
//Fiery Burst
if(GetHasFeat(FEAT_FIERY_BURST, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_FIRE);
DeleteLocalInt(oPC, "FieryBurstBonus");
if (nBonus > 1) SetLocalInt(oPC, "FieryBurstBonus", nBonus);
}
//Storm Bolt
if(GetHasFeat(FEAT_STORM_BOLT, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_ELECTRICITY);
DeleteLocalInt(oPC, "StormBoltBonus");
if (nBonus > 2) SetLocalInt(oPC, "StormBoltBonus", nBonus);
}
//Winter's Blast
if(GetHasFeat(FEAT_WINTERS_BLAST, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_COLD);
DeleteLocalInt(oPC, "WintersBlastBonus");
if (nBonus > 1) SetLocalInt(oPC, "WintersBlastBonus", nBonus);
}
//Clap of Thunder
if(GetHasFeat(FEAT_CLAP_OF_THUNDER, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_SONIC);
DeleteLocalInt(oPC, "ClapOfThunderBonus");
if (nBonus > 2) SetLocalInt(oPC, "ClapOfThunderBonus", nBonus);
}
//Sickening Grasp
if (GetHasFeat(FEAT_SICKENING_GRASP, oPC)) //Update constant when feat constant is made
{
nBonus = GetHighestSpellAvailableBySchool(oPC, RESERVESPELL_SCHOOL_NECROMANCY);
DeleteLocalInt(oPC, "SickeningGraspBonus");
if (nBonus > 2) SetLocalInt(oPC, "SickeningGraspBonus", nBonus);
}
//Touch of Healing
if(GetHasFeat(FEAT_TOUCH_OF_HEALING, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_HEALING);
DeleteLocalInt(oPC, "TouchOfHealingBonus");
if (nBonus > 1) SetLocalInt(oPC, "TouchOfHealingBonus", nBonus);
}
//Dimensional Jaunt
if(GetHasFeat(FEAT_DIMENSIONAL_JAUNT, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_TELEPORTATION);
DeleteLocalInt(oPC, "DimensionalJauntBonus");
if (nBonus > 3) SetLocalInt(oPC, "DimensionalJauntBonus", nBonus);
}
//Clutch of Earth
if(GetHasFeat(FEAT_CLUTCH_OF_EARTH, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_EARTH);
DeleteLocalInt(oPC, "ClutchOfEarthBonus");
if (nBonus > 1) SetLocalInt(oPC, "ClutchOfEarthBonus", nBonus);
}
//Borne Aloft
if(GetHasFeat(FEAT_BORNE_ALOFT, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_AIR);
DeleteLocalInt(oPC, "BorneAloftBonus");
if (nBonus > 4) SetLocalInt(oPC, "BorneAloftBonus", nBonus);
}
//Protective Ward
if (GetHasFeat(FEAT_PROTECTIVE_WARD, oPC))
{
nBonus = GetHighestSpellAvailableBySchool(oPC, RESERVESPELL_SCHOOL_ABJURATION);
DeleteLocalInt(oPC, "ProtectiveWardBonus");
if (nBonus > 0) SetLocalInt(oPC, "ProtectiveWardBonus", nBonus);
}
//Shadow Veil
if(GetHasFeat(FEAT_SHADOW_VEIL, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_DARKNESS);
DeleteLocalInt(oPC, "ShadowVeilBonus");
if (nBonus > 1) SetLocalInt(oPC, "ShadowVeilBonus", nBonus);
}
//Sunlight Eyes
if(GetHasFeat(FEAT_SUNLIGHT_EYES, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_LIGHT);
DeleteLocalInt(oPC, "SunlightEyesBonus");
if (nBonus > 1) SetLocalInt(oPC, "SunlightEyesBonus", nBonus);
}
//Touch of Distraction
if (GetHasFeat(FEAT_TOUCH_OF_DISTRACTION, oPC))
{
nBonus = GetHighestSpellAvailableBySchool(oPC, RESERVESPELL_SCHOOL_ENCHANTMENT);
DeleteLocalInt(oPC, "TouchOfDistractionBonus");
if (nBonus > 2) SetLocalInt(oPC, "TouchOfDistractionBonus", nBonus);
}
//Umbral Shroud
if(GetHasFeat(FEAT_UMBRAL_SHROUD, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_DARKNESS);
DeleteLocalInt(oPC, "UmbralShroudBonus");
if (nBonus > 2) SetLocalInt(oPC, "UmbralShroudBonus", nBonus);
}
//Charnel Miasma
if(GetHasFeat(FEAT_CHARNEL_MIASMA, oPC))
{
nBonus = GetHighestDomainSpellAvailable(oPC, RESERVESPELL_DOMAIN_DEATH);
DeleteLocalInt(oPC, "CharnelMiasmaBonus");
if (nBonus > 1) SetLocalInt(oPC, "CharnelMiasmaBonus", nBonus);
}
//Drowning Glance
if(GetHasFeat(FEAT_DROWNING_GLANCE, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_WATER);
DeleteLocalInt(oPC, "DrowningGlanceBonus");
if (nBonus > 3) SetLocalInt(oPC, "DrowningGlanceBonus", nBonus);
}
//Invisible Needle
if(GetHasFeat(FEAT_INVISIBLE_NEEDLE, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_FORCE);
DeleteLocalInt(oPC, "InvisibleNeedleBonus");
if (nBonus > 2) SetLocalInt(oPC, "InvisibleNeedleBonus", nBonus);
}
//Summon Elemental
if(GetHasFeat(FEAT_SUMMON_ELEMENTAL, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_SUMMONING);
DeleteLocalInt(oPC, "SummonElementalBonus");
if (nBonus > 3) SetLocalInt(oPC, "SummonElementalBonus", nBonus);
}
//Dimensional Reach
if(GetHasFeat(FEAT_DIMENSIONAL_REACH, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_SUMMONING);
DeleteLocalInt(oPC, "DimensionalReachBonus");
if (nBonus > 2) SetLocalInt(oPC, "DimensionalReachBonus", nBonus);
}
//Hurricane Breath
if(GetHasFeat(FEAT_HURRICANE_BREATH, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_AIR);
DeleteLocalInt(oPC, "HurricaneBreathBonus");
if (nBonus > 1) SetLocalInt(oPC, "HurricaneBreathBonus", nBonus);
}
//Minor Shapeshift
if(GetHasFeat(FEAT_MINOR_SHAPESHIFT, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_POLYMORPH);
DeleteLocalInt(oPC, "MinorShapeshiftBonus");
if (nBonus > 3) SetLocalInt(oPC, "MinorShapeshiftBonus", nBonus);
}
//Face-Changer
if(GetHasFeat(FEAT_FACECHANGER, oPC))
{
nBonus = GetHighestSpellAvailableByDescriptor(oPC, RESERVESPELL_DESCRIPTOR_GLAMER);
DeleteLocalInt(oPC, "FaceChangerBonus");
if (nBonus > 2) SetLocalInt(oPC, "FaceChangerBonus", nBonus);
}
}
void main()
{
object oPC = OBJECT_SELF;
if(!GetLocalInt(oPC, "ReserveFeatsRunning"))
{
SetLocalInt(oPC, "ReserveFeatsRunning", TRUE);
//Hook this script into event system so it runs on hooked events
AddEventScript(oPC, EVENT_ONACTIVATEITEM, "prc_reservefeat", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONACQUIREITEM, "prc_reservefeat", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONCLIENTENTER, "prc_reservefeat", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONCLIENTLEAVE, "prc_reservefeat", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONPLAYERLEVELDOWN, "prc_reservefeat", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONPLAYERLEVELUP, "prc_reservefeat", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONPLAYERRESPAWN, "prc_reservefeat", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONPLAYEREQUIPITEM, "prc_reservefeat", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONPLAYERUNEQUIPITEM, "prc_reservefeat", TRUE, FALSE);
AddEventScript(oPC, EVENT_ONUNAQUIREITEM, "prc_reservefeat", TRUE, FALSE);
//Update the feat bonuses
UpdateReserveFeats(oPC);
}
else
{
UpdateReserveFeats(oPC);
}
}