Updated AMS marker feats. Removed arcane & divine marker feats. Updated Dread Necromancer for epic progression. Updated weapon baseitem models. Updated new weapons for crafting & npc equip. Updated prefix. Updated release archive.
922 lines
44 KiB
Plaintext
922 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);
|
|
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)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
else 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, 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, 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);
|
|
}
|
|
//FloatingTextStringOnCreature("Adding Shield Specialization bonus of "+IntToString(iTemp+1), oInitiator, FALSE);
|
|
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);
|
|
}
|
|
|
|
} |