Files
PRC8/nwn/nwnprc/trunk/newspellbook/tob_feats.nss
Jaysyn904 5e9986829f 2025/10/30 Update
Improved Trip / Disarm should be Champion of Corellon bonus feats.
Crinti Shadow Marauders don't get weapon proficiencies.
Epic Dragon Shaman is 21st level.
JPM was missing epic arcane bonus feats.
Karsites & Silverbrows can enter Crinti Shadow Maarauder.
Drunken Rage can allow entry into Frostrager.
Knight of the Sacred Seal was missing FEATOR prereq for Weapon Focus: Shortsword.
Two-Weapon Defense is a general feat.
Tweaked Echoblade enchantment cost.
Added base class equpiment packages more inline with PnP & the actual package descriptions (@Cypher).
Added a modified packages.2da to support the above.
Updated Dynamic Conversation tokens as to greatly lessen the chance of conflicting with module dialogues.
Added weapon proficiencies to FeatToIprop().
Added pnp essentia scaling support for meldshaper levels over 40.
Added GetProficiencyFeatOfWeaponType().
Added GetHasSwashbucklerWeapon().
Added GetHasCorellonWeapon().
Fixed spelling for IP_CONST_FEAT_WEAPON_PROFICIENCY_NUNCHAKU.
Fixed PsyRogue's Enhanced Sneak Attack scaling.
Eldrtich Doom shouldn't target non-hostiles.
Fixed Hellfire Warlock fire resistance to work with other sources of fire resistance.
Fixed text feedback for Island in Time.
Added some DEBUG for Shadow Blade.
prc_2da_cache creature should no longer be accidently targetable, causing faction issues.
Added a PnP cat creature, for the hell of it.  Tibitz is Dragon Magizine, unfortunately.
Updated text tokens for Astral Construct convos.
Updated text tokens for soulknife's mindblade convos.
If you save vs certain fear effects, they fail to work on you for 24 hours, from that source.  (Form of Doom, Dragon Fear)
Fixed Prismatic Sphere VFX bug (@Syrophir)
Fixed Banishment bug on all Prismatic spells.
Bralani Eldarin were missing Low-Light Vision.
Fixed Lips of Rapture bug.
Prelimiary work to making Favoured Soul's Deity's Weapon closer to PnP.
Fixed Firey Burst bug.  I think.

Updated notes.
Updated PRC8 Manual.
2025-10-30 19:04:58 -04:00

923 lines
44 KiB
Plaintext

//::///////////////////////////////////////////////
//:: Tome of Battle feats
//:: tob_feats
//::///////////////////////////////////////////////
/** @file
Does all ToB feats that require event scripting.
@author Stratovarius
@date Created - 2018.9.22
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
#include "tob_inc_tobfunc"
#include "psi_inc_psifunc"
#include "prc_inc_combmove"
#include "x0_i0_modes"
//////////////////////////////////////////////////
/* Feat Functions */
//////////////////////////////////////////////////
// Called on Heartbeat
void ShadowBlade(object oInitiator)
{
// Needs an active Shadow Hands stance
int nStance = GetHasActiveStance(oInitiator);
int nDisc = GetDisciplineByManeuver(nStance);
int nDex = GetAbilityModifier(ABILITY_DEXTERITY, oInitiator);
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator);
int nWeap = GetIsDisciplineWeapon(oWeapon, DISCIPLINE_SHADOW_HAND);
// Must be a shadow hand weapon while a stance is active
if (nDisc == DISCIPLINE_SHADOW_HAND && nWeap)
{
int nDamageType = GetWeaponDamageType(oWeapon);
if(DEBUG) DoDebug("tob_feats >> ShadowBlade(): " + IntToString(nDex) +": extra points of "+IntToString(nDamageType)+" Damage.");
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectDamageIncrease(IPGetDamageBonusConstantFromNumber(nDex), nDamageType)), oInitiator, 6.0);
SetLocalInt(oInitiator, "ShadowBladeDam", nDex);
DelayCommand(6.0, DeleteLocalInt(oInitiator, "ShadowBladeDam"));
}
}
// Called on Heartbeat
void RapidAssault(object oInitiator)
{
int nCombat = GetIsInCombat(oInitiator);
int nLast = GetLocalInt(oInitiator, "RapidAssault");
// Must must be in combat this round but not last round
if (nCombat == TRUE && nLast == FALSE)
{
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator);
int nDamageType = GetWeaponDamageType(oWeapon);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectDamageIncrease(DAMAGE_BONUS_1d6, nDamageType)), oInitiator, 6.0);
}
SetLocalInt(oInitiator, "RapidAssault", nCombat);
}
// Called on heartbeat
void DesertWindDodge(object oInitiator)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectACIncrease(1, AC_DODGE_BONUS)), oInitiator, 6.0);
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator);
int nWeap = GetIsDisciplineWeapon(oWeapon, DISCIPLINE_DESERT_WIND);
if (nWeap)
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectDamageIncrease(DAMAGE_BONUS_1, DAMAGE_TYPE_FIRE)), oInitiator, 6.0);
}
// Called on heartbeat
void DesertFire(object oInitiator)
{
SetLocalInt(oInitiator, "DesertFire", TRUE);
DelayCommand(5.9, DeleteLocalInt(oInitiator, "DesertFire"));
}
// Called on heartbeat
void DesertWind(object oInitiator)
{
// Check to see if the WP is valid
string sWPTag = "PRC_DWDWP_" + GetName(oInitiator);
object oTestWP = GetWaypointByTag(sWPTag);
if (!GetIsObjectValid(oTestWP))
{
// Create waypoint for the movement
CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oInitiator), FALSE, sWPTag);
if(DEBUG) DoDebug("tob_feats: Desert Wind Dodge WP for " + DebugObject2Str(oInitiator) + " didn't exist, creating. Tag: " + sWPTag);
}
else // We have a test waypoint, now to check the distance
{
// Distance moved in the last round
float fDist = GetDistanceBetween(oInitiator, oTestWP);
// Distance needed to move
float fCheck = FeetToMeters(10.0);
// Now clean up the WP and create a new one for next round's check
DestroyObject(oTestWP);
CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oInitiator), FALSE, sWPTag);
if(DEBUG) DoDebug("tob_feats: Moved enough: " + DebugBool2String(fDist >= fCheck));
// Moved the distance
if (fDist >= fCheck)
{
if(GetHasFeat(FEAT_DESERT_WIND_DODGE, oInitiator)) DesertWindDodge(oInitiator);
if(GetHasFeat(FEAT_DESERT_FIRE, oInitiator)) DesertFire(oInitiator);
}
}
}
// Called on False
void BladeMeditation(object oInitiator)
{
int nDisc = BladeMeditationFeat(oInitiator);
object oSkin = GetPCSkin(oInitiator);
int nSkill = GetDisciplineSkill(nDisc);
SetCompositeBonus(oSkin, "BladeMeditation", 2, ITEM_PROPERTY_SKILL_BONUS, nSkill);
}
// Called on Heartbeat
void IronheartAura(object oInitiator)
{
int nDisc = GetDisciplineByManeuver(GetHasActiveStance(oInitiator));
if (nDisc == DISCIPLINE_IRON_HEART)
{
location lTarget = GetLocation(oInitiator);
// Use the function to get the closest creature as a target
object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oAreaTarget))
{
if(oAreaTarget != oInitiator && // Not you
GetIsInMeleeRange(oInitiator, oAreaTarget) && // They must be in melee range
GetIsFriend(oAreaTarget, oInitiator)) // Only allies
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectSavingThrowIncrease(SAVING_THROW_ALL, 2, SAVING_THROW_TYPE_ALL)), oAreaTarget, 6.0);
}
//Select the next target within the spell shape.
oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE);
}
}
}
// Called on heartbeat
void ShadowTrickster(object oInitiator)
{
// Needs an active Shadow Hands stance
int nStance = GetHasActiveStance(oInitiator);
int nDisc = GetDisciplineByManeuver(nStance);
if (nDisc == DISCIPLINE_SHADOW_HAND)
{
SetLocalInt(oInitiator, "ShadowTrickster", TRUE);
}
else
DeleteLocalInt(oInitiator, "ShadowTrickster");
}
// Called on Heartbeat
void WhiteRavenDefense(object oInitiator)
{
int nDisc = GetDisciplineByManeuver(GetHasActiveStance(oInitiator));
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator);
int nWeap = GetIsDisciplineWeapon(oWeapon, DISCIPLINE_WHITE_RAVEN);
int nAlly = FALSE;
if (nDisc == DISCIPLINE_WHITE_RAVEN)
{
location lTarget = GetLocation(oInitiator);
// Use the function to get the closest creature as a target
object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oAreaTarget))
{
if(oAreaTarget != oInitiator && // Not you
GetIsInMeleeRange(oInitiator, oAreaTarget) && // They must be in melee range
GetIsFriend(oAreaTarget, oInitiator)) // Only allies
{
if (nWeap) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectACIncrease(1)), oAreaTarget, 6.0);
nAlly = TRUE;
}
//Select the next target within the spell shape.
oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE);
}
}
if (nAlly)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectACIncrease(1)), oInitiator, 6.0);
}
}
void DevotedBulwark(object oInitiator, object oTarget)
{
//only trigger if it was a melee weapon
if(GetIsInMeleeRange(oInitiator, oTarget))
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectACIncrease(1), oInitiator, 6.0f);
}
}
void SnapKick(object oInitiator, object oTarget)
{
if (GetLocalInt(oInitiator, "SnapKickDelay") == TRUE) return; //Once a round only
else
{
SetLocalInt(oInitiator, "SnapKickDelay", TRUE);
DelayCommand(6.0, DeleteLocalInt(oInitiator, "SnapKickDelay"));
}
object oWeap = GetItemInSlot(INVENTORY_SLOT_ARMS, oInitiator); // It's an unarmed attack, so we get the gloves
int nAttack = GetAttackRoll(oTarget, oInitiator, oWeap);
if (nAttack > 0) // We hit
{
FloatingTextStringOnCreature("Snap Kick Hit", oInitiator, FALSE);
int nCrit = FALSE;
if (nAttack == 2) nCrit = TRUE;
effect eDam = GetAttackDamage(oTarget, oInitiator, oWeap, GetWeaponBonusDamage(oWeap, oTarget), GetMagicalBonusDamage(oInitiator, oTarget), 1, 0, nCrit); //off-hand attack to get 1/2 strength bonus
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
}
else
FloatingTextStringOnCreature("Snap Kick Miss", oInitiator, FALSE);
}
void ThreeMountains(object oInitiator, object oTarget)
{
// Check for a first hit
int nHit = GetLocalInt(oTarget, "ThreeMountains");
if (!nHit)
{
SetLocalInt(oTarget, "ThreeMountains", TRUE);
DelayCommand(6.0, DeleteLocalInt(oTarget, "ThreeMountains"));
}
else // Hit them twice in six seconds
{
int nDC = 10 + GetHitDice(oInitiator)/2 + GetAbilityModifier(ABILITY_STRENGTH, oInitiator);
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NONE, oInitiator))
{
effect eLink = EffectLinkEffects(EffectSpellFailure(), EffectAttackDecrease(20));
SetBaseAttackBonus(1, oTarget);
effect eLink2 = EffectLinkEffects(EffectVisualEffect(VFX_IMP_DISEASE_S), EffectVisualEffect(VFX_IMP_REDUCE_ABILITY_SCORE_RED));
DelayCommand(6.0, RestoreBaseAttackBonus(oTarget));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oTarget, RoundsToSeconds(1));
ApplyEffectToObject(DURATION_TYPE_INSTANT, eLink2, oTarget);
}
DeleteLocalInt(oTarget, "ThreeMountains");
}
}
void VaeSchool(object oInitiator, object oTarget)
{
if (GetLocalInt(oInitiator, "VaeSchool") == TRUE) return; //Once a round only
else
{
SetLocalInt(oInitiator, "VaeSchool", TRUE);
DelayCommand(6.0, DeleteLocalInt(oInitiator, "VaeSchool"));
}
DoTrip(oInitiator, oTarget, 0, FALSE, FALSE, TRUE);
}
void InlindlSchool(object oInitiator)
{
if (GetIsLightWeapon(oInitiator) && GetLocalInt(oInitiator, "InlindlSchool"))
{
int nShield = GetItemACValue(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oInitiator));
effect eLink = EffectLinkEffects(EffectACDecrease(nShield), EffectAttackIncrease(nShield/2));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_ARMOR_OF_DARKNESS));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oInitiator, 6.0);
}
}
void XaniqosSchool(object oInitiator, object oTarget, object oItem, int nEvent)
{
int nType = GetBaseItemType(oItem);
/* if(nEvent == EVENT_ITEM_ONHIT) //:: handled in prc_onhitcast becuase it wasn't stacking w/ Skirmish
{
if(GetLocalInt(oInitiator, "XaniqosSchool") && IPGetIsProjectile(oItem)) // oItem is the ammo, since it's only applies to crossbows
{
effect eDam = EffectDamage(d6(), DAMAGE_TYPE_PIERCING);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
}
} */
if(nEvent == EVENT_ONPLAYEREQUIPITEM)
{
if (nType == BASE_ITEM_LIGHTCROSSBOW || nType == BASE_ITEM_HEAVYCROSSBOW)
{
object oAmmo = GetItemInSlot(INVENTORY_SLOT_BOLTS, oInitiator);
IPSafeAddItemProperty(oAmmo, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
AddEventScript(oAmmo, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
}
}
else if(nEvent == EVENT_ONPLAYERUNEQUIPITEM)
{
if (nType == BASE_ITEM_LIGHTCROSSBOW || nType == BASE_ITEM_HEAVYCROSSBOW)
{
object oAmmo = GetItemInSlot(INVENTORY_SLOT_BOLTS, oInitiator);
RemoveSpecificProperty(oAmmo, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", -1, DURATION_TYPE_TEMPORARY);
RemoveEventScript(oAmmo, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
}
}
else if(nEvent == EVENT_ONHEARTBEAT)
{
// Check to see if the WP is valid
string sWPTag = "XaniqosWP_" + GetName(oInitiator);
object oTestWP = GetWaypointByTag(sWPTag);
if (!GetIsObjectValid(oTestWP))
{
// Create waypoint for the movement
CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oInitiator), FALSE, sWPTag);
if(DEBUG) DoDebug("tob_feats: Xaniqos WP for " + DebugObject2Str(oInitiator) + " didn't exist, creating. Tag: " + sWPTag);
}
else // We have a test waypoint, now to check the distance
{
// Distance moved in the last round
float fDist = GetDistanceBetween(oInitiator, oTestWP);
// Distance needed to move
float fCheck = FeetToMeters(10.0);
// Now clean up the WP and create a new one for next round's check
DestroyObject(oTestWP);
CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oInitiator), FALSE, sWPTag);
if(DEBUG) DoDebug("tob_feats: Moved enough: " + DebugBool2String(fDist >= fCheck));
// Moved the distance
if (fDist >= fCheck)
{
// We have moved far enough
SetLocalInt(oInitiator, "XaniqosSchool", TRUE);
// Only lasts for a round
DelayCommand(6.0, DeleteLocalInt(oInitiator, "XaniqosSchool"));
}
}
}
}
void ShieldWall(object oInitiator)
{
int nBase = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oInitiator));
if (nBase == BASE_ITEM_SMALLSHIELD || nBase == BASE_ITEM_LARGESHIELD || nBase == BASE_ITEM_TOWERSHIELD)
{
location lTarget = GetLocation(oInitiator);
// Use the function to get the closest creature as a target
object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oAreaTarget))
{
if(oAreaTarget != oInitiator && // Not you
GetIsInMeleeRange(oInitiator, oAreaTarget) && // They must be in melee range
GetIsFriend(oAreaTarget, oInitiator)) // Only allies
{
int nBase2 = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oAreaTarget));
if (nBase2 == BASE_ITEM_SMALLSHIELD || nBase2 == BASE_ITEM_LARGESHIELD || nBase2 == BASE_ITEM_TOWERSHIELD) //Ally must have a shield
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectACIncrease(2, AC_SHIELD_ENCHANTMENT_BONUS)), oAreaTarget, 6.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectACIncrease(2, AC_SHIELD_ENCHANTMENT_BONUS)), oInitiator, 6.0);
}
}
//Select the next target within the spell shape.
oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE);
}
}
}
void CrossbowSniper(object oInitiator, object oItem, int nEvent)
{
int nType = GetBaseItemType(oItem);
int nDex = GetAbilityModifier(ABILITY_DEXTERITY, oInitiator);
if(nEvent == EVENT_ONPLAYEREQUIPITEM)
{
if ((nType == BASE_ITEM_LIGHTCROSSBOW && GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_CROSSBOW, oInitiator)) ||
(nType == BASE_ITEM_HEAVYCROSSBOW && GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_CROSSBOW, oInitiator)))
{
object oAmmo = GetItemInSlot(INVENTORY_SLOT_BOLTS, oInitiator);
IPSafeAddItemProperty(oAmmo, ItemPropertyDamageBonus(DAMAGE_TYPE_PIERCING, IPDamageConstant(nDex/2)), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
}
else if(nEvent == EVENT_ONPLAYERUNEQUIPITEM)
{
if ((nType == BASE_ITEM_LIGHTCROSSBOW && GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_CROSSBOW, oInitiator)) ||
(nType == BASE_ITEM_HEAVYCROSSBOW && GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_CROSSBOW, oInitiator)))
{
object oAmmo = GetItemInSlot(INVENTORY_SLOT_BOLTS, oInitiator);
RemoveSpecificProperty(oAmmo, ITEM_PROPERTY_DAMAGE_BONUS, DAMAGE_TYPE_PIERCING, IPDamageConstant(nDex/2), 1, "", -1, DURATION_TYPE_TEMPORARY);
}
}
}
void ExpeditiousDodge(object oInitiator)
{
// Check to see if the WP is valid
string sWPTag = "ExpeditiousWP_" + GetName(oInitiator);
object oTestWP = GetWaypointByTag(sWPTag);
if (!GetIsObjectValid(oTestWP))
{
// Create waypoint for the movement
CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oInitiator), FALSE, sWPTag);
if(DEBUG) DoDebug("tob_feats: Expeditious WP for " + DebugObject2Str(oInitiator) + " didn't exist, creating. Tag: " + sWPTag);
}
else // We have a test waypoint, now to check the distance
{
// Distance moved in the last round
float fDist = GetDistanceBetween(oInitiator, oTestWP);
// Distance needed to move
float fCheck = FeetToMeters(40.0);
// Now clean up the WP and create a new one for next round's check
DestroyObject(oTestWP);
CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oInitiator), FALSE, sWPTag);
if(DEBUG) DoDebug("tob_feats: Moved enough: " + DebugBool2String(fDist >= fCheck));
// Moved the distance
if (fDist >= fCheck)
{
// We have moved far enough
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectACIncrease(2, AC_DODGE_BONUS)), oInitiator, 6.0);
}
}
}
void CrescentMoon(object oInitiator, object oTarget)
{
int nRight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator));
int nLeft = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oInitiator));
if (nLeft == BASE_ITEM_DAGGER && (nRight == BASE_ITEM_SCIMITAR || nRight == BASE_ITEM_LONGSWORD || nRight == BASE_ITEM_BASTARDSWORD || nRight == BASE_ITEM_SHORTSWORD))
{
int nHits = GetLocalInt(oTarget, "CrescentMoon"); // Check hits
if (nHits == 2)
{
nHits = 0;
// Free disarm attempt, once a round, per target
if (!GetLocalInt(oTarget, "CrescentMoonDelay"))
{
DoDisarm(oInitiator, oTarget);
SetLocalInt(oTarget, "CrescentMoonDelay", TRUE);
DelayCommand(6.0, DeleteLocalInt(oTarget, "CrescentMoonDelay"));
}
}
else
nHits++;
SetLocalInt(oTarget, "CrescentMoon", nHits); // Store the hits
}
}
void QuickStaff(object oInitiator)
{
// Only applies when using expertise
if(GetModeActive(ACTION_MODE_EXPERTISE) || GetActionMode(oInitiator, ACTION_MODE_EXPERTISE) || GetLastAttackMode(oInitiator) == COMBAT_MODE_EXPERTISE ||
GetModeActive(ACTION_MODE_IMPROVED_EXPERTISE) || GetActionMode(oInitiator, ACTION_MODE_IMPROVED_EXPERTISE) || GetLastAttackMode(oInitiator) == COMBAT_MODE_IMPROVED_EXPERTISE)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectACIncrease(2), oInitiator, 6.0);
}
}
void BearFangGrapple(object oInitiator, object oTarget)
{
DoGrapple(oInitiator, oTarget, 0, FALSE, TRUE);
}
void BearFang(object oInitiator, object oTarget)
{
int nRight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator));
int nLeft = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oInitiator));
if (nLeft == BASE_ITEM_DAGGER && (nRight == BASE_ITEM_BATTLEAXE || nRight == BASE_ITEM_HANDAXE || nRight == BASE_ITEM_DWARVENWARAXE))
{
int nHits = GetLocalInt(oTarget, "BearFang"); // Check hits
if (nHits == 2)
{
SetLocalInt(oInitiator, "BearFangGrapple", TRUE);
ForceUnequip(oInitiator, GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator), INVENTORY_SLOT_RIGHTHAND);
DelayCommand(0.6, BearFangGrapple(oInitiator, oTarget));
DeleteLocalInt(oInitiator, "BearFang");
}
else
nHits++;
SetLocalInt(oTarget, "BearFang", nHits); // Store the hits
}
}
void BearFangHB(object oInitiator)
{
// Resets every round
DeleteLocalInt(oInitiator, "BearFang");
}
void ImprovedRapidShot(object oInitiator)
{
// Only applies when using Rapid Shot
if(GetModeActive(ACTION_MODE_RAPID_SHOT) || GetActionMode(oInitiator, ACTION_MODE_RAPID_SHOT) || GetLastAttackMode(oInitiator) == COMBAT_MODE_RAPID_SHOT)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAttackIncrease(2), oInitiator, 6.0);
}
}
void DireFlailSmash(object oInitiator, object oTarget)
{
// Check for a first hit
int nHit = GetLocalInt(oTarget, "DireFlailSmash");
if (!nHit)
{
SetLocalInt(oTarget, "DireFlailSmash", TRUE);
DelayCommand(6.0, DeleteLocalInt(oTarget, "DireFlailSmash"));
}
else // Hit them twice in six seconds
{
int nDC = 10 + GetHitDice(oInitiator)/2 + GetAbilityModifier(ABILITY_STRENGTH, oInitiator);
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NONE, oInitiator))
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectDazed()), oTarget, RoundsToSeconds(1));
}
DeleteLocalInt(oTarget, "DireFlailSmash");
}
}
void ShieldSpecialization(object oInitiator)
{
object oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oInitiator);
// Shield specialization
if((GetBaseItemType(oItem) == BASE_ITEM_SMALLSHIELD && GetHasFeat(FEAT_SHIELD_SPECIALIZATION_LIGHT, oInitiator)) || (GetBaseItemType(oItem) == BASE_ITEM_LARGESHIELD && GetHasFeat(FEAT_SHIELD_SPECIALIZATION_HEAVY, oInitiator)))
{
itemproperty ip = GetFirstItemProperty(oItem);
int iTemp;
while(GetIsItemPropertyValid(ip))
{
int iIpType = GetItemPropertyType(ip);
if (iIpType == ITEM_PROPERTY_AC_BONUS)
{
iTemp = GetItemPropertyCostTableValue(ip);
break;
}
ip = GetNextItemProperty(oItem);
}
if (DEBUG) DoDebug("Adding Shield Specialization bonus of "+IntToString(iTemp+1));
IPSafeAddItemProperty(oItem, ItemPropertyACBonus(iTemp+1), 5.95, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
}
}
void FocusedShield(object oInitiator)
{
object oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oInitiator);
int nBase = GetBaseItemType(oItem);
if ((nBase == BASE_ITEM_SMALLSHIELD || nBase == BASE_ITEM_LARGESHIELD || nBase == BASE_ITEM_TOWERSHIELD) && GetIsPsionicallyFocused(oInitiator))
{
itemproperty ip = GetFirstItemProperty(oItem);
int iTemp;
while(GetIsItemPropertyValid(ip))
{
int iIpType = GetItemPropertyType(ip);
if (iIpType == ITEM_PROPERTY_AC_BONUS)
{
iTemp = GetItemPropertyCostTableValue(ip);
break;
}
ip = GetNextItemProperty(oItem);
}
//FloatingTextStringOnCreature("Adding Focused Shield bonus of "+IntToString(iTemp+1), oInitiator, FALSE);
IPSafeAddItemProperty(oItem, ItemPropertyACBonus(iTemp+1), 5.95, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
}
}
void Shieldmate(object oInitiator)
{
// Have to be awake and aware to count
if (PRCGetHasEffect(EFFECT_TYPE_CONFUSED, oInitiator) || PRCGetHasEffect(EFFECT_TYPE_DOMINATED, oInitiator) || PRCGetHasEffect(EFFECT_TYPE_DAZED, oInitiator) ||
PRCGetHasEffect(EFFECT_TYPE_PETRIFY, oInitiator) || PRCGetHasEffect(EFFECT_TYPE_PARALYZE, oInitiator) || PRCGetHasEffect(EFFECT_TYPE_SLEEP, oInitiator) ||
PRCGetHasEffect(EFFECT_TYPE_STUNNED, oInitiator) || PRCGetHasEffect(EFFECT_TYPE_FRIGHTENED, oInitiator) || GetGrapple(oInitiator))
{
return;
}
int nBase = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oInitiator));
if (nBase == BASE_ITEM_SMALLSHIELD || nBase == BASE_ITEM_LARGESHIELD || nBase == BASE_ITEM_TOWERSHIELD)
{
location lTarget = GetLocation(oInitiator);
// Use the function to get the closest creature as a target
object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oAreaTarget))
{
if(oAreaTarget != oInitiator && // Not you
GetIsInMeleeRange(oInitiator, oAreaTarget) && // They must be in melee range
GetIsFriend(oAreaTarget, oInitiator)) // Only allies
{
int nBonus = 1;
if (nBase == BASE_ITEM_TOWERSHIELD) nBonus += 1;
if (GetHasFeat(FEAT_IMPROVED_SHIELDMATE, oInitiator)) nBonus += 1;
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectACIncrease(nBonus, AC_SHIELD_ENCHANTMENT_BONUS)), oAreaTarget, 6.0);
}
//Select the next target within the spell shape.
oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE);
}
}
}
void RethDekalaAura(object oInitiator)
{
location lTarget = GetLocation(oInitiator);
// Use the function to get the closest creature as a target
object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lTarget, TRUE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oAreaTarget))
{
if(oAreaTarget != oInitiator && // Not you. Hits everyone else though, even allies.
GetIsInMeleeRange(oInitiator, oAreaTarget)) // They must be in melee range
{
int nDamage = d6();
int nDC = 10 + GetHitDice(oInitiator)/2 + GetAbilityModifier(ABILITY_CONSTITUTION, oInitiator);
if(!PRCMySavingThrow(SAVING_THROW_FORT, oAreaTarget, nDC, SAVING_THROW_TYPE_NONE))
{
// Half fire, half acid
ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDamage(nDamage/2, DAMAGE_TYPE_FIRE)), oAreaTarget);
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FLAME_M), oAreaTarget);
// The +1 makes acid round up instead of round down, so you don't miss out on odd numbers
ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDamage((nDamage+1)/2, DAMAGE_TYPE_ACID)), oAreaTarget);
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_ACID_L), oAreaTarget);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(EffectSickened()), oAreaTarget, 6.0);
}
}
//Select the next target within the spell shape.
oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lTarget, TRUE, OBJECT_TYPE_CREATURE);
}
}
void HadrimoiPerfectSymmetry(object oInitiator)
{
int nSize = PRCGetCreatureSize(oInitiator);
object oSkin = GetPCSkin(oInitiator);
object oItemR = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator);
int nWeaponSizeR = GetWeaponSize(oItemR);
object oItemL = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oInitiator);
int nWeaponSizeL = GetWeaponSize(oItemL);
// is the size appropriate for a light weapon?
if (nWeaponSizeR < nSize && nWeaponSizeL < nSize)
{
SetLocalInt(oInitiator, "HadrimoiPerfectSymmetry", TRUE);
IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(IP_CONST_FEAT_AMBIDEXTROUS), 9999.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(IP_CONST_FEAT_TWO_WEAPON_FIGHTING), 9999.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
//int nBAB = GetBaseAttackBonus(oInitiator);
SetCompositeAttackBonus(oInitiator, "HadrimoiPerfectSymmetry", 2, ATTACK_BONUS_MISC);
/*object oWP = GetObjectToApplyNewEffect("WP_HadrimoiPerfectSymmetry", oInitiator, TRUE);
AssignCommand(oWP, ActionDoCommand(ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(EffectModifyAttacks(nAttackCount-1)), oInitiator)));*/
}
else
{
DeleteLocalInt(oInitiator, "HadrimoiPerfectSymmetry");
RemoveSpecificProperty(oSkin, ITEM_PROPERTY_BONUS_FEAT, IP_CONST_FEAT_AMBIDEXTROUS, -1, -1, "", -1, DURATION_TYPE_TEMPORARY);
RemoveSpecificProperty(oSkin, ITEM_PROPERTY_BONUS_FEAT, IP_CONST_FEAT_TWO_WEAPON_FIGHTING, -1, -1, "", -1, DURATION_TYPE_TEMPORARY);
SetCompositeAttackBonus(oInitiator, "HadrimoiPerfectSymmetry", 0, ATTACK_BONUS_MISC);
/*object oWP = GetObjectToApplyNewEffect("WP_HadrimoiPerfectSymmetry", oInitiator, TRUE);*/
}
}
//////////////////////////////////////////////////
/* Void Main and Event Triggers */
//////////////////////////////////////////////////
void main()
{
int nEvent = GetRunningEvent();
if(DEBUG) DoDebug("tob_feats running, event: " + IntToString(nEvent));
// Get the PC. This is event-dependent
object oInitiator;
switch(nEvent)
{
case EVENT_ITEM_ONHIT: oInitiator = OBJECT_SELF; break;
case EVENT_ONPLAYEREQUIPITEM: oInitiator = GetItemLastEquippedBy(); break;
case EVENT_ONPLAYERUNEQUIPITEM: oInitiator = GetItemLastUnequippedBy(); break;
case EVENT_ONHEARTBEAT: oInitiator = OBJECT_SELF; break;
default:
oInitiator = OBJECT_SELF;
}
object oItem;
object oSkin = GetPCSkin(oInitiator);
int nSnap = GetLocalInt(oInitiator, "SnapKick");
// We aren't being called from any event, instead from EvalPRCFeats
if(nEvent == FALSE)
{
if (BladeMeditationFeat(oInitiator) >= 1) BladeMeditation(oInitiator);
// Hook in the events
if(DEBUG) DoDebug("tob_feats: Adding eventhooks");
AddEventScript(oInitiator, EVENT_ONPLAYEREQUIPITEM, "tob_feats", TRUE, FALSE);
AddEventScript(oInitiator, EVENT_ONPLAYERUNEQUIPITEM, "tob_feats", TRUE, FALSE);
AddEventScript(oInitiator, EVENT_ONHEARTBEAT, "tob_feats", TRUE, FALSE);
}
else if(nEvent == EVENT_ITEM_ONHIT)
{
oItem = GetSpellCastItem();
object oTarget = PRCGetSpellTargetObject();
if(DEBUG) DoDebug("tob_feats: OnHit:\n"
+ "oInitiator = " + DebugObject2Str(oInitiator) + "\n"
+ "oItem = " + DebugObject2Str(oItem) + "\n"
+ "oTarget = " + DebugObject2Str(oTarget) + "\n"
);
if (GetHasFeat(FEAT_DEVOTED_BULWARK, oInitiator)) DevotedBulwark(oInitiator, oTarget);
if (nSnap == TRUE) SnapKick(oInitiator, oTarget);
if (GetHasFeat(FEAT_THREE_MOUNTAINS, oInitiator)) ThreeMountains(oInitiator, oTarget);
if (GetHasFeat(FEAT_VAE_SCHOOL, oInitiator) && GetCanSneakAttack(oTarget, oInitiator)) VaeSchool(oInitiator, oTarget);
if (GetHasFeat(FEAT_XANIQOS_SCHOOL, oInitiator)) XaniqosSchool(oInitiator, oTarget, oItem, nEvent);
if (GetHasFeat(FEAT_CRESCENT_MOON, oInitiator)) CrescentMoon(oInitiator, oTarget);
if (GetHasFeat(FEAT_BEAR_FANG, oInitiator)) BearFang(oInitiator, oTarget);
if (GetHasFeat(FEAT_DIRE_FLAIL_SMASH, oInitiator)) DireFlailSmash(oInitiator, oTarget);
}// end if - Running OnHit event
else if(nEvent == EVENT_ONPLAYEREQUIPITEM)
{
oInitiator = GetItemLastEquippedBy();
oItem = GetItemLastEquipped();
if(DEBUG) DoDebug("tob_feats - OnEquip\n"
+ "oInitiator = " + DebugObject2Str(oInitiator) + "\n"
+ "oItem = " + DebugObject2Str(oItem) + "\n"
);
// Armor checks
if(GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
{
if (GetHasFeat(FEAT_DEVOTED_BULWARK, oInitiator))
{
// Add eventhook to the armor
IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
AddEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
}
}
// Weapons for Three Mountains
if (GetHasFeat(FEAT_THREE_MOUNTAINS, oInitiator))
{
if (oItem == GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator) && (GetBaseItemType(oItem) == BASE_ITEM_MORNINGSTAR || GetBaseItemType(oItem) == BASE_ITEM_HEAVYFLAIL || GetBaseItemType(oItem) == BASE_ITEM_DIREMACE) || GetBaseItemType(oItem) == BASE_ITEM_HEAVY_MACE)
{
// Add eventhook to the weapon
IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
AddEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
}
}
// Weapons for Snap Kick
if (oItem == GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator) && IPGetIsMeleeWeapon(oItem) && nSnap == TRUE)
{
// Add eventhook to the weapon
IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
AddEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
}
// Weapons for Vae School
if (oItem == GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator) && GetBaseItemType(oItem) == BASE_ITEM_WHIP && GetHasFeat(FEAT_VAE_SCHOOL, oInitiator))
{
// Add eventhook to the weapon
IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
AddEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
}
if (GetHasFeat(FEAT_XANIQOS_SCHOOL, oInitiator)) XaniqosSchool(oInitiator, OBJECT_INVALID, oItem, nEvent);
if (GetHasFeat(FEAT_CROSSBOW_SNIPER, oInitiator)) CrossbowSniper(oInitiator, oItem, nEvent);
// Weapons for Crescent Moon
if (GetHasFeat(FEAT_CRESCENT_MOON, oInitiator))
{
if (GetBaseItemType(oItem) == BASE_ITEM_SCIMITAR || GetBaseItemType(oItem) == BASE_ITEM_LONGSWORD || GetBaseItemType(oItem) == BASE_ITEM_BASTARDSWORD || GetBaseItemType(oItem) == BASE_ITEM_DAGGER || GetBaseItemType(oItem) == BASE_ITEM_SHORTSWORD)
{
// Add eventhook to the weapon
IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
AddEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
}
}
// Weapons for Bear Fang
if (GetHasFeat(FEAT_BEAR_FANG, oInitiator))
{
if (GetBaseItemType(oItem) == BASE_ITEM_BATTLEAXE || GetBaseItemType(oItem) == BASE_ITEM_HANDAXE || GetBaseItemType(oItem) == BASE_ITEM_DWARVENWARAXE || GetBaseItemType(oItem) == BASE_ITEM_DAGGER)
{
// Add eventhook to the weapon
IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
AddEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
}
}
// Weapons for Dire Flail Smash
if (GetHasFeat(FEAT_DIRE_FLAIL_SMASH, oInitiator))
{
if (oItem == GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator) && GetBaseItemType(oItem) == BASE_ITEM_DIREMACE)
{
// Add eventhook to the weapon
IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
AddEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
}
}
if (GetHasFeat(FEAT_SHIELDED_CASTING, oInitiator))
{
int nBase = GetBaseItemType(oItem);
if (nBase == BASE_ITEM_SMALLSHIELD || nBase == BASE_ITEM_LARGESHIELD || nBase == BASE_ITEM_TOWERSHIELD)
{
IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(IP_CONST_IMP_CC), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
}
if (GetRacialType(oInitiator) == RACIAL_TYPE_RETH_DEKALA && GetIsWeapon(oItem))
{
IPSafeAddItemProperty(oItem, ItemPropertyAttackBonus(4), HoursToSeconds(24), X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
IPSafeAddItemProperty(oItem, ItemPropertyAttackPenalty(4), HoursToSeconds(24), X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
}
if (GetRacialType(oInitiator) == RACIAL_TYPE_HADRIMOI) HadrimoiPerfectSymmetry(oInitiator);
}
// We are called from the OnPlayerUnEquipItem eventhook. Remove OnHitCast: Unique Power from oInitiator's weapon
else if(nEvent == EVENT_ONPLAYERUNEQUIPITEM)
{
oInitiator = GetItemLastUnequippedBy();
oItem = GetItemLastUnequipped();
if(DEBUG) DoDebug("tob_feats - OnUnEquip\n"
+ "oInitiator = " + DebugObject2Str(oInitiator) + "\n"
+ "oItem = " + DebugObject2Str(oItem) + "\n"
);
// Only applies to armours
if(GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
{
// Add eventhook to the item
RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
// Remove the temporary OnHitCastSpell: Unique
RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", 1, DURATION_TYPE_TEMPORARY);
}
// Weapons for Snap Kick
if (IPGetIsMeleeWeapon(oItem) && nSnap)
{
// Remove eventhook to the item
RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
// Remove the temporary OnHitCastSpell: Unique
RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", 1, DURATION_TYPE_TEMPORARY);
}
// Weapons for Three Mountains
if (GetHasFeat(FEAT_THREE_MOUNTAINS, oInitiator))
{
if (GetBaseItemType(oItem) == BASE_ITEM_MORNINGSTAR || GetBaseItemType(oItem) == BASE_ITEM_HEAVYFLAIL || GetBaseItemType(oItem) == BASE_ITEM_DIREMACE || GetBaseItemType(oItem) == BASE_ITEM_HEAVY_MACE)
{
// Remove eventhook to the item
RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
// Remove the temporary OnHitCastSpell: Unique
RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", 1, DURATION_TYPE_TEMPORARY);
}
}
// Weapons for Vae School
if (GetBaseItemType(oItem) == BASE_ITEM_WHIP && GetHasFeat(FEAT_VAE_SCHOOL, oInitiator))
{
// Remove eventhook to the item
RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
// Remove the temporary OnHitCastSpell: Unique
RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", 1, DURATION_TYPE_TEMPORARY);
}
if (GetHasFeat(FEAT_XANIQOS_SCHOOL, oInitiator)) XaniqosSchool(oInitiator, OBJECT_INVALID, oItem, nEvent);
if (GetHasFeat(FEAT_CROSSBOW_SNIPER, oInitiator)) CrossbowSniper(oInitiator, oItem, nEvent);
// Weapons for Crescent Moon
if (GetHasFeat(FEAT_CRESCENT_MOON, oInitiator))
{
if (GetBaseItemType(oItem) == BASE_ITEM_SCIMITAR || GetBaseItemType(oItem) == BASE_ITEM_LONGSWORD || GetBaseItemType(oItem) == BASE_ITEM_BASTARDSWORD || GetBaseItemType(oItem) == BASE_ITEM_DAGGER || GetBaseItemType(oItem) == BASE_ITEM_SHORTSWORD)
{
// Remove eventhook to the item
RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
// Remove the temporary OnHitCastSpell: Unique
RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", 1, DURATION_TYPE_TEMPORARY);
}
}
// Weapons for Bear Fang
if (GetHasFeat(FEAT_BEAR_FANG, oInitiator))
{
if (GetBaseItemType(oItem) == BASE_ITEM_BATTLEAXE || GetBaseItemType(oItem) == BASE_ITEM_HANDAXE || GetBaseItemType(oItem) == BASE_ITEM_DWARVENWARAXE || GetBaseItemType(oItem) == BASE_ITEM_DAGGER)
{
// Remove eventhook to the item
RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
// Remove the temporary OnHitCastSpell: Unique
RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", 1, DURATION_TYPE_TEMPORARY);
}
}
// Weapons for Dire Flail Smash
if (GetHasFeat(FEAT_DIRE_FLAIL_SMASH, oInitiator))
{
if (GetBaseItemType(oItem) == BASE_ITEM_DIREMACE)
{
// Remove eventhook to the item
RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "tob_feats", TRUE, FALSE);
// Remove the temporary OnHitCastSpell: Unique
RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", 1, DURATION_TYPE_TEMPORARY);
}
}
if (GetHasFeat(FEAT_SHIELDED_CASTING, oInitiator))
{
// If you don't have a shield in your left hand, no benefit
int nBase = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oInitiator));
if (nBase != BASE_ITEM_SMALLSHIELD && nBase != BASE_ITEM_LARGESHIELD && nBase != BASE_ITEM_TOWERSHIELD)
{
RemoveSpecificProperty(oSkin, ITEM_PROPERTY_BONUS_FEAT, IP_CONST_IMP_CC);
}
}
if (GetRacialType(oInitiator) == RACIAL_TYPE_RETH_DEKALA && GetIsWeapon(oItem))
{
// Remove the attack bonus
RemoveSpecificProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS, -1, -1, 1, "", -1, DURATION_TYPE_TEMPORARY);
RemoveSpecificProperty(oItem, ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER, -1, -1, 1, "", -1, DURATION_TYPE_TEMPORARY);
}
if (GetRacialType(oInitiator) == RACIAL_TYPE_HADRIMOI) HadrimoiPerfectSymmetry(oInitiator);
}
else if(nEvent == EVENT_ONHEARTBEAT)
{
if(GetHasFeat(FEAT_SHADOW_BLADE, oInitiator)) ShadowBlade(oInitiator);
if(GetHasFeat(FEAT_RAPID_ASSAULT, oInitiator)) RapidAssault(oInitiator);
if(GetHasFeat(FEAT_DESERT_WIND_DODGE, oInitiator) || GetHasFeat(FEAT_DESERT_FIRE, oInitiator)) DesertWind(oInitiator);
if(GetHasFeat(FEAT_IRONHEART_AURA, oInitiator)) IronheartAura(oInitiator);
if(GetHasFeat(FEAT_SHADOW_TRICKSTER, oInitiator)) ShadowTrickster(oInitiator);
if(GetHasFeat(FEAT_WHITE_RAVEN_DEFENSE, oInitiator)) WhiteRavenDefense(oInitiator);
if(GetHasFeat(FEAT_INLINDL_SCHOOL, oInitiator)) InlindlSchool(oInitiator);
if(GetHasFeat(FEAT_XANIQOS_SCHOOL, oInitiator)) XaniqosSchool(oInitiator, OBJECT_INVALID, oItem, nEvent);
if(GetHasFeat(FEAT_EXPEDITIOUS_DODGE, oInitiator)) ExpeditiousDodge(oInitiator);
if(GetHasFeat(FEAT_SHIELD_WALL, oInitiator)) ShieldWall(oInitiator);
if(GetHasFeat(FEAT_QUICK_STAFF, oInitiator)) QuickStaff(oInitiator);
if(GetHasFeat(FEAT_IMPROVED_RAPID_SHOT, oInitiator)) ImprovedRapidShot(oInitiator);
if(GetHasFeat(FEAT_BEAR_FANG, oInitiator)) BearFangHB(oInitiator);
if(GetHasFeat(FEAT_SHIELD_SPECIALIZATION_LIGHT, oInitiator) || GetHasFeat(FEAT_SHIELD_SPECIALIZATION_HEAVY, oInitiator)) ShieldSpecialization(oInitiator);
if(GetHasFeat(FEAT_FOCUSED_SHIELD, oInitiator)) FocusedShield(oInitiator);
if(GetHasFeat(FEAT_SHIELDMATE, oInitiator)) Shieldmate(oInitiator);
if(GetRacialType(oInitiator) == RACIAL_TYPE_RETH_DEKALA) RethDekalaAura(oInitiator);
}
}