Further file organization
Further file organization
This commit is contained in:
733
nwn/nwnprc/trunk/scripts/prc_onhitcast.nss
Normal file
733
nwn/nwnprc/trunk/scripts/prc_onhitcast.nss
Normal file
@@ -0,0 +1,733 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: User Defined OnHitCastSpell code
|
||||
//:: prc_onhitcast
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
This file holds all the OnHitCastSpell events
|
||||
used by PRC.
|
||||
It was created to replace x2_s3_onhitcast so that
|
||||
it wouldn't override module-specific onhitcast events.
|
||||
|
||||
Add your own entries after the previous ones. Try to
|
||||
keep variable scope as little as possible. ie, no top-
|
||||
level variables if you just can avoid it.
|
||||
If your entry is long (over 20 lines), consider placing
|
||||
the guts of it outside the main to improve readability
|
||||
for the rest of us :D
|
||||
|
||||
|
||||
Please remember to comment your entry.
|
||||
At least mention what class ability / spell / whatever
|
||||
it is part of.
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Various people
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "psi_inc_onhit"
|
||||
#include "inc_rend"
|
||||
#include "psi_inc_ac_const"
|
||||
#include "prc_inc_onhit"
|
||||
#include "tob_inc_tobfunc"
|
||||
#include "prc_inc_sp_tch"
|
||||
|
||||
void SetRancorVar(object oPC);
|
||||
void SetImprovedRicochetVar(object oPC);
|
||||
void DoImprovedRicochet(object oPC, object oTarget);
|
||||
|
||||
object GetProperTarget(object oPC, object oTarget)
|
||||
{
|
||||
location lTarget = GetLocation(oPC);
|
||||
// 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 != oPC && // Not you.
|
||||
GetIsEnemy(oPC, oAreaTarget) && // Enemies only, please
|
||||
GetIsInMeleeRange(oPC, oAreaTarget)) // They must be in melee range
|
||||
{
|
||||
return oAreaTarget;
|
||||
}
|
||||
//Select the next target within the spell shape.
|
||||
oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
}
|
||||
|
||||
return oTarget;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oSpellOrigin = OBJECT_SELF; // On a weapon: The one wielding the weapon. On an armor: The one wearing an armor
|
||||
|
||||
// Call the normal OnHitCastSpell: Unique script
|
||||
if (DEBUG) DoDebug("prc_onhitcast: entered, executing normal onhitcastspell unique power script x2_s3_onhitcast for "+GetName(oSpellOrigin));
|
||||
ExecuteScript("x2_s3_onhitcast", oSpellOrigin);
|
||||
|
||||
// motu99: setting a local int, so that onhitcast impact spell scripts can find out, whether they were called from prc_onhitcast
|
||||
// or from somewhere else (presumably the aurora engine). This local int will be deleted just before we exit prc_onhitcast
|
||||
// Note that any scripts that are called by a DelayCommand (or AssignCommand) from prc_onhitcast will not find this local int
|
||||
SetLocalInt(oSpellOrigin, "prc_ohc", TRUE);
|
||||
|
||||
object oSpellTarget = PRCGetSpellTargetObject(oSpellOrigin); // On a weapon: The one being hit. On an armor: The one hitting the armor
|
||||
|
||||
// Make sure you don't hit yourself. Some idiot didn't check that.
|
||||
if (oSpellOrigin == oSpellTarget)
|
||||
oSpellTarget = GetProperTarget(oSpellOrigin, oSpellTarget);
|
||||
|
||||
// motu99: replacing call to Bioware's GetSpellCastItem with new PRC wrapper function
|
||||
// will ensure that we retrieve a valid item when we are called from scripted combat (prc_inc_combat) or
|
||||
object oItem = PRCGetSpellCastItem(oSpellOrigin); // The item casting triggering this spellscript
|
||||
int iItemBaseType = GetBaseItemType(oItem);
|
||||
|
||||
|
||||
// DEBUG code, remove
|
||||
if (DEBUG)
|
||||
{
|
||||
if(!GetIsOnHitCastSpell(oSpellTarget, oItem, oSpellOrigin))
|
||||
DoDebug("prc_onhitcast: Warning, the currently running instance of prc_onhitcast was not recognized as an onhitcastspell");
|
||||
}
|
||||
// DEBUG code, remove
|
||||
|
||||
if (DEBUG) DoDebug("prc_onhitcast: now executing prc specific routines with item = "+ GetName(oItem)+", target = "+GetName(oSpellTarget)+", caller = "+GetName(oSpellOrigin)+", item type = "+IntToString(iItemBaseType));
|
||||
|
||||
// int nBArcher; // Blood Archer level
|
||||
int nFoeHunter = GetLevelByClass(CLASS_TYPE_FOE_HUNTER, oSpellOrigin); // Foe Hunter Level
|
||||
//int bItemIsWeapon;
|
||||
|
||||
//nBArcher = GetLevelByClass(CLASS_TYPE_BLARCHER, oSpellOrigin);
|
||||
|
||||
//// Swashbuckler Weakening and Wounding Criticals
|
||||
if(GetHasFeat(INSIGHTFUL_STRIKE, oSpellOrigin))
|
||||
ExecuteScript("prc_swashweak", oSpellOrigin);
|
||||
|
||||
//// Champion of Corellon damage healing for sneak/critical immune creatures
|
||||
if(GetHasFeat(FEAT_COC_ELEGANT_STRIKE, oSpellOrigin))
|
||||
ExecuteScript("prc_coc_heal", oSpellOrigin);
|
||||
|
||||
//// Stormlord Shocking & Thundering Spear
|
||||
|
||||
if(GetHasFeat(FEAT_THUNDER_WEAPON, oSpellOrigin))
|
||||
ExecuteScript("ft_shockweap", oSpellOrigin);
|
||||
|
||||
if(GetHasSpellEffect(TEMPUS_ENCHANT_WEAPON, oItem))
|
||||
{
|
||||
int nRace = MyPRCGetRacialType(oSpellTarget);
|
||||
if((GetLocalInt(oSpellOrigin, "WeapEchant1") == TEMPUS_ABILITY_VICIOUS &&
|
||||
nRace == GetLocalInt(oSpellOrigin,"WeapEchantRace1")) ||
|
||||
(GetLocalInt(oSpellOrigin,"WeapEchant2")==TEMPUS_ABILITY_VICIOUS &&
|
||||
nRace == GetLocalInt(oSpellOrigin,"WeapEchantRace2")) ||
|
||||
(GetLocalInt(oSpellOrigin,"WeapEchant3")==TEMPUS_ABILITY_VICIOUS &&
|
||||
nRace == GetLocalInt(oSpellOrigin,"WeapEchantRace3"))
|
||||
)
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectDamage(d6()),oSpellOrigin);
|
||||
}
|
||||
|
||||
if (GetIsPC(oSpellOrigin))
|
||||
SetLocalInt(oSpellOrigin,"DmgDealt",GetTotalDamageDealt());
|
||||
|
||||
/// Vassal of Bahamut Dragonwrack
|
||||
if(GetLevelByClass(CLASS_TYPE_VASSAL, oSpellOrigin) > 3)
|
||||
{
|
||||
if (iItemBaseType == BASE_ITEM_ARMOR)
|
||||
ExecuteScript("prc_vb_dw_armor", oSpellOrigin);
|
||||
else
|
||||
ExecuteScript("prc_vb_dw_weap", oSpellOrigin);
|
||||
}
|
||||
/* /// Blood Archer Acidic Blood
|
||||
if (nBArcher >= 2)
|
||||
{
|
||||
if(iItemBaseType == BASE_ITEM_ARMOR)
|
||||
ExecuteScript("prc_bldarch_ab", oSpellOrigin);
|
||||
}
|
||||
|
||||
// Blood Archer Poison Blood
|
||||
if (nBArcher > 0 && iItemBaseType != BASE_ITEM_ARMOR)
|
||||
{
|
||||
// poison number based on archer level
|
||||
// gives proper DC for poison
|
||||
int iPoison = 104 + nBArcher;
|
||||
effect ePoison = EffectPoison(iPoison);
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, ePoison, oSpellTarget);
|
||||
}*/
|
||||
|
||||
// Frenzied Berserker Auto Frenzy
|
||||
if(iItemBaseType == BASE_ITEM_ARMOR && GetHasFeat(FEAT_FRENZY, oSpellOrigin))
|
||||
{
|
||||
if(!GetHasFeatEffect(FEAT_FRENZY, oSpellOrigin))
|
||||
{
|
||||
DelayCommand(0.01, ExecuteScript("prc_fb_auto_fre", oSpellOrigin) );
|
||||
}
|
||||
else if(GetCurrentHitPoints(oSpellOrigin) == 1 && GetHasFeat(FEAT_DEATHLESS_FRENZY, oSpellOrigin))
|
||||
{
|
||||
DelayCommand(0.01, ExecuteScript("prc_fb_deathless", oSpellOrigin) );
|
||||
}
|
||||
}
|
||||
|
||||
// Warsling Sniper Improved Ricochet
|
||||
if (iItemBaseType == BASE_ITEM_BULLET
|
||||
&& GetLevelByClass(CLASS_TYPE_HALFLING_WARSLINGER, oSpellOrigin) > 5
|
||||
&& GetLocalInt(oSpellOrigin, "CanRicochet") != 2)
|
||||
{
|
||||
// Deactivates Ability
|
||||
SetLocalInt(oSpellOrigin, "CanRicochet", 2);
|
||||
|
||||
DoImprovedRicochet(oSpellOrigin, oSpellTarget);
|
||||
|
||||
// Prevents the heartbeat script from running multiple times
|
||||
if(GetLocalInt(oSpellOrigin, "ImpRicochetVarRunning") != 1)
|
||||
{
|
||||
DelayCommand(6.0, SetImprovedRicochetVar(oSpellOrigin) );
|
||||
SetLocalInt(oSpellOrigin, "ImpRicochetVarRunning", 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Warchief Devoted Bodyguards
|
||||
if(iItemBaseType == BASE_ITEM_ARMOR && GetLevelByClass(CLASS_TYPE_WARCHIEF, oSpellOrigin) > 7)
|
||||
{
|
||||
// Warchief must make a reflex save
|
||||
if(!GetLocalInt(oSpellOrigin, "WarChiefDelay"))
|
||||
{
|
||||
// Done this way for formatting reasons in game
|
||||
if(ReflexSave(oSpellOrigin, 15))
|
||||
DelayCommand(0.01, ExecuteScript("prc_wchf_bodygrd", oSpellOrigin));
|
||||
|
||||
// He can only do this once a round, so put a limit on it
|
||||
SetLocalInt(oSpellOrigin, "WarChiefDelay", TRUE);
|
||||
DelayCommand(6.0, DeleteLocalInt(oSpellOrigin, "WarChiefDelay"));
|
||||
}
|
||||
}
|
||||
|
||||
// Foe Hunter Damage Resistance
|
||||
if(iItemBaseType == BASE_ITEM_ARMOR && nFoeHunter > 1)
|
||||
{
|
||||
DelayCommand(0.01, ExecuteScript("prc_fh_dr",oSpellOrigin) );
|
||||
}
|
||||
|
||||
// Foe Hunter Rancor Attack
|
||||
if(iItemBaseType != BASE_ITEM_ARMOR && nFoeHunter > 0)
|
||||
{
|
||||
if( GetLocalInt(oSpellOrigin, "PRC_CanUseRancor") != 2
|
||||
&& GetLocalInt(oSpellOrigin, "HatedFoe") == MyPRCGetRacialType(oSpellTarget) )
|
||||
{
|
||||
int iFHLevel = GetLevelByClass(CLASS_TYPE_FOE_HUNTER, oSpellOrigin);
|
||||
int iRancorDice = FloatToInt( (( iFHLevel + 1.0 ) /2) );
|
||||
|
||||
int iDamage = d6(iRancorDice);
|
||||
int iDamType = GetWeaponDamageType(oItem);
|
||||
int iDamPower = GetDamagePowerConstant(oItem, oSpellTarget, oSpellOrigin);
|
||||
|
||||
effect eDam = EffectDamage(iDamage, iDamType, iDamPower);
|
||||
|
||||
string sMess = "*Rancor Attack*";
|
||||
FloatingTextStringOnCreature(sMess, oSpellOrigin, FALSE);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oSpellTarget);
|
||||
|
||||
// Deactivates Ability
|
||||
SetLocalInt(oSpellOrigin, "PRC_CanUseRancor", 2);
|
||||
|
||||
// Prevents the heartbeat script from running multiple times
|
||||
if(GetLocalInt(oSpellOrigin, "PRC_RancorVarRunning") != 1)
|
||||
{
|
||||
DelayCommand(6.0, SetRancorVar(oSpellOrigin) );
|
||||
SetLocalInt(oSpellOrigin, "PRC_RancorVarRunning", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Creatures with a necrotic cyst take +1d6 damage from natural attacks of undead
|
||||
if(GetHasNecroticCyst(oSpellOrigin) && iItemBaseType == BASE_ITEM_ARMOR)
|
||||
{
|
||||
//if enemy is undead
|
||||
if(MyPRCGetRacialType(oSpellTarget) == RACIAL_TYPE_UNDEAD)
|
||||
{
|
||||
//and unarmed
|
||||
if (!GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oSpellTarget)) &&
|
||||
!GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oSpellTarget)))
|
||||
|
||||
{
|
||||
effect eDam = EffectDamage(d6(1), DAMAGE_TYPE_MAGICAL);
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oSpellOrigin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////
|
||||
//////////////// PSIONICS //////////////////////////
|
||||
//////////////////////////////////////////////////*/
|
||||
|
||||
// SweepingStrike OnHit
|
||||
if(iItemBaseType != BASE_ITEM_ARMOR && GetLocalInt(oItem, "SweepingStrike"))
|
||||
{
|
||||
SweepingStrike(oSpellOrigin, oSpellTarget);
|
||||
}
|
||||
|
||||
// Mind Stab OnHit
|
||||
if(iItemBaseType != BASE_ITEM_ARMOR && GetLocalInt(oSpellOrigin, "ShadowMindStab") && !GetLocalInt(oSpellOrigin, "MindStabDelay"))
|
||||
{
|
||||
//FloatingTextStringOnCreature("MindStab Stage 1", oSpellOrigin, FALSE);
|
||||
// Only works when able to sneak attack a target
|
||||
if (GetCanSneakAttack(oSpellTarget, oSpellOrigin))
|
||||
{
|
||||
//FloatingTextStringOnCreature("MindStab Stage 2", oSpellOrigin, FALSE);
|
||||
MindStab(oSpellOrigin, oSpellTarget);
|
||||
// Only once per round
|
||||
SetLocalInt(oSpellOrigin, "MindStabDelay", TRUE);
|
||||
DelayCommand(6.0, DeleteLocalInt(oSpellOrigin, "MindStabDelay"));
|
||||
}
|
||||
}
|
||||
|
||||
// Astral Construct's Poison Touch special ability
|
||||
if(GetLocalInt(oSpellOrigin, ASTRAL_CONSTRUCT_POISON_TOUCH))
|
||||
{
|
||||
ExecuteScript("psi_ast_con_ptch", oSpellOrigin);
|
||||
}
|
||||
|
||||
// Pyrokineticist bonus damage
|
||||
int nPyroLevel = GetLevelByClass(CLASS_TYPE_PYROKINETICIST, oSpellOrigin);
|
||||
if(nPyroLevel)
|
||||
{
|
||||
int iElement = GetPersistantLocalInt(oSpellOrigin, "PyroDamageType");
|
||||
int nDam1 = 0;
|
||||
int nDam2 = 0;
|
||||
int nDam = 0;
|
||||
int nDice = 0;
|
||||
|
||||
if(iItemBaseType == BASE_ITEM_ARMOR)
|
||||
{ //Nimbus Onhit
|
||||
if(nPyroLevel >= 5 && GetHasSpellEffect(SPELL_NIMBUS, oSpellOrigin))
|
||||
{
|
||||
nDice = 2;
|
||||
nDam = (iElement == DAMAGE_TYPE_SONIC) ? d4(nDice) : d6(nDice); //reduced damage dice
|
||||
if((iElement == DAMAGE_TYPE_COLD) || (iElement == DAMAGE_TYPE_ELECTRICAL) || (iElement == DAMAGE_TYPE_ACID))
|
||||
nDam = max(nDice, nDam - nDice); //minimum of 1 per die
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //Assume unarmed/weapon damage
|
||||
if(nPyroLevel >= 2)
|
||||
{
|
||||
nDice = (GetLevelByClass(CLASS_TYPE_PYROKINETICIST, oSpellOrigin) >= 8) ? 4 : 2;
|
||||
nDam1 = (iElement == DAMAGE_TYPE_SONIC) ? d4(nDice) : d6(nDice); //reduced damage dice
|
||||
if((iElement == DAMAGE_TYPE_COLD) || (iElement == DAMAGE_TYPE_ELECTRICAL) || (iElement == DAMAGE_TYPE_ACID))
|
||||
nDam1 = max(nDice, nDam1 - nDice); //minimum of 1 per die
|
||||
}
|
||||
if(GetTag(oItem) == "PRC_PYRO_LASH_WHIP")
|
||||
{ //Extra damage from whip
|
||||
nDam2 += (iElement == DAMAGE_TYPE_SONIC) ? d6(1) : d8(1); //reduced damage dice
|
||||
if((iElement == DAMAGE_TYPE_COLD) || (iElement == DAMAGE_TYPE_ELECTRICAL) || (iElement == DAMAGE_TYPE_ACID))
|
||||
nDam2 = max(1, nDam2 - 1); //minimum of 1
|
||||
}
|
||||
nDam = nDam1 + nDam2;
|
||||
}
|
||||
if(nDam > 0)
|
||||
{
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDam, iElement), oSpellTarget);
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(GetPersistantLocalInt(oSpellOrigin, "PyroImpactVFX")), oSpellTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////
|
||||
//////////////// END PSIONICS //////////////////////
|
||||
//////////////////////////////////////////////////*/
|
||||
|
||||
/*//////////////////////////////////////////////////
|
||||
//////////////// Blade Magic ///////////////////////
|
||||
//////////////////////////////////////////////////*/
|
||||
|
||||
// Martial Spirit
|
||||
if(GetHasSpellEffect(MOVE_DS_MARTIAL_SPIRIT, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR && GetObjectType(oSpellTarget) == OBJECT_TYPE_CREATURE && !GetIsDead(oSpellTarget))
|
||||
{
|
||||
object oHealTarget = GetCrusaderHealTarget(oSpellOrigin, 30.0);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(2), oHealTarget);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HEALING_L_LAW), oHealTarget);
|
||||
}
|
||||
|
||||
// Blood in the Water
|
||||
if(GetHasSpellEffect(MOVE_TC_BLOOD_WATER, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR && !GetIsImmune(oSpellTarget, IMMUNITY_TYPE_CRITICAL_HIT))
|
||||
{
|
||||
// Fake critical hit check
|
||||
if(d20() >= GetWeaponCriticalRange(oSpellOrigin, oItem))
|
||||
{
|
||||
effect eBuff = EffectLinkEffects(EffectAttackIncrease(1), EffectDamageIncrease(DAMAGE_BONUS_1, DAMAGE_TYPE_SLASHING));
|
||||
DelayCommand(0.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBuff, oSpellOrigin, TurnsToSeconds(1)));
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_BLOOD_CRT_YELLOW_HEAD), oSpellOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
// Fire Riposte
|
||||
if(GetHasSpellEffect(MOVE_DW_FIRE_RIPOSTE, oSpellOrigin) && GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
|
||||
{
|
||||
int nTouchAttack = PRCDoMeleeTouchAttack(oSpellTarget);
|
||||
if(nTouchAttack > 0)
|
||||
{
|
||||
// Apply the damage and VFX
|
||||
ApplyTouchAttackDamage(oSpellOrigin, oSpellTarget, nTouchAttack, d6(4), DAMAGE_TYPE_FIRE);
|
||||
effect eVis = EffectVisualEffect(VFX_COM_HIT_FIRE);
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oSpellTarget);
|
||||
FloatingTextStringOnCreature("Fire Riposte Hit", oSpellOrigin, FALSE);
|
||||
// Clean up
|
||||
PRCRemoveSpellEffects(MOVE_DW_FIRE_RIPOSTE, oSpellOrigin, oSpellOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
// Holocaust Cloak
|
||||
if(GetHasSpellEffect(MOVE_DW_HOLOCAUST_CLOAK, oSpellOrigin) && GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
|
||||
{
|
||||
if(GetIsInMeleeRange(oSpellOrigin, oSpellTarget))
|
||||
{
|
||||
// Apply the damage and VFX
|
||||
effect eVis = EffectVisualEffect(VFX_COM_HIT_FIRE);
|
||||
effect eDam = EffectDamage(5, DAMAGE_TYPE_FIRE);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oSpellTarget);
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oSpellTarget);
|
||||
FloatingTextStringOnCreature("Holocaust Cloak Hit", oSpellOrigin, FALSE);
|
||||
}
|
||||
}
|
||||
// Defensive Rebuke
|
||||
if(GetHasSpellEffect(MOVE_DS_DEFENSIVE_REBUKE, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
|
||||
{
|
||||
SetLocalObject(oSpellTarget, "DefensiveRebuke", oSpellOrigin);
|
||||
DelayCommand(3.0, ExecuteScript("tob_dvsp_defrbka", oSpellTarget));
|
||||
}
|
||||
// Defensive Rebuke
|
||||
if(GetHasSpellEffect(MOVE_DM_PEARL_BLACK_DOUBT, oSpellOrigin) && GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
|
||||
{
|
||||
// Will reset to 0.
|
||||
DeleteLocalInt(oSpellOrigin, "PearlOfBlackDoubtBonus");
|
||||
}
|
||||
// Tactics of the Wolf
|
||||
if(GetHasSpellEffect(MOVE_WR_TACTICS_WOLF, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
|
||||
{
|
||||
if (GetIsFlanked(oSpellTarget, oSpellOrigin))
|
||||
{
|
||||
int nWolfDam = GetLocalInt(oSpellOrigin, "TacticsWolf");
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nWolfDam), oSpellTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// Aura of Triumph
|
||||
if(GetHasSpellEffect(MOVE_DS_AURA_TRIUMPH, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
|
||||
{
|
||||
// Heal both
|
||||
object oHealTarget = GetLocalObject(oSpellOrigin, "DSTriumph");
|
||||
// Must be within 10 feet
|
||||
if (10.0 >= FeetToMeters(GetDistanceBetween(oSpellOrigin, oSpellOrigin)))
|
||||
{
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(4), oHealTarget);
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HEALING_L_LAW), oHealTarget);
|
||||
}
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(4), oSpellOrigin);
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HEALING_L_LAW), oSpellOrigin);
|
||||
}
|
||||
|
||||
// Immortal Fortitude
|
||||
if(GetHasSpellEffect(MOVE_DS_IMMORTAL_FORTITUDE, oSpellOrigin) && GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
|
||||
{
|
||||
// He's immortal, so now we run a script to see if he should/would have died (Saving, etc)
|
||||
if(GetCurrentHitPoints(oSpellOrigin) == 1)
|
||||
{
|
||||
DelayCommand(0.01, ExecuteScript("tob_dvsp_imfrtoh", oSpellOrigin));
|
||||
}
|
||||
}
|
||||
// Immortal Fortitude
|
||||
if(GetHasSpellEffect(MOVE_WR_CLARION_CALL, oSpellOrigin) && GetBaseItemType(oItem) != BASE_ITEM_ARMOR)
|
||||
{
|
||||
// Check to see if the target is dead, triggers each time
|
||||
if(GetIsDead(oSpellTarget))
|
||||
{
|
||||
location lTarget = GetLocation(oSpellOrigin);
|
||||
object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0), lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
while(GetIsObjectValid(oAreaTarget))
|
||||
{
|
||||
if(GetIsFriend(oAreaTarget, oSpellOrigin))
|
||||
{
|
||||
// Apply extra attack for one round
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectModifyAttacks(1)), oAreaTarget, 6.0);
|
||||
}
|
||||
oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0), lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////
|
||||
//////////////// End Blade Magic ///////////////////
|
||||
//////////////////////////////////////////////////*/
|
||||
|
||||
if(iItemBaseType != BASE_ITEM_ARMOR && GetLocalInt(oSpellOrigin,"doarcstrike"))
|
||||
{
|
||||
int nDice = GetLocalInt(oSpellOrigin,"curentspell");
|
||||
int nDamage = d4(nDice);
|
||||
effect eDam = EffectDamage(nDamage);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT,eDam,oSpellTarget);
|
||||
}
|
||||
|
||||
//spellsword & arcane archer
|
||||
//will also fire for other OnHit:UniquePower items that have a SpellSequencer property (such as Duskblade)
|
||||
if(GetLocalInt(oItem, "X2_L_NUMCHANNELTRIGGERS"))
|
||||
{
|
||||
if (DEBUG) DoDebug("prc_onhitcast: Triggering Sequencer Discharge");
|
||||
SetLocalObject(oSpellOrigin, "ChannelSpellTarget", oSpellTarget);
|
||||
ExecuteScript("x2_s3_sequencer", oSpellOrigin);
|
||||
}
|
||||
|
||||
// Handle Rend. Creature weapon damage + 1.5x STR bonus.
|
||||
// Only happens when attacking with a creature weapon
|
||||
if(GetIsCreatureWeaponType(iItemBaseType) && (GetHasFeat(FEAT_REND, oSpellOrigin) || GetLevelByClass(CLASS_TYPE_BLACK_BLOOD_CULTIST, oSpellOrigin) >= 6))
|
||||
{
|
||||
DoRend(oSpellTarget, oSpellOrigin, oItem);
|
||||
}
|
||||
|
||||
// Handle Frostrager Rend. 2d8 damage + 1.5x STR bonus.
|
||||
// Only happens when attacking with a creature weapon
|
||||
if(GetIsCreatureWeaponType(iItemBaseType) && (GetLevelByClass(CLASS_TYPE_FROSTRAGER, oSpellOrigin) > 4))
|
||||
{
|
||||
DoFrostRend(oSpellTarget, oSpellOrigin, oItem);
|
||||
}
|
||||
|
||||
// Handle Spine Rend. 2d6 damage + 1.5x STR bonus.
|
||||
// Only happens when attacking with a skarn spine
|
||||
if(GetTag(oItem) == "skarn_spine" && (GetLevelByClass(CLASS_TYPE_SPINEMELD_WARRIOR, oSpellOrigin) >= 5))
|
||||
{
|
||||
DoSpineRend(oSpellTarget, oSpellOrigin, oItem);
|
||||
}
|
||||
|
||||
// now cycle through all onhitcast spells on the item
|
||||
// we must exclude unique power (which is associated with prc_onhitcast), because otherwise we would get infinite recursions
|
||||
// it is of utmost importance to devise a *safe* way to cycle through all onhitcast spells on the item. The safe way is provided
|
||||
// by the function ApplyAllOnHitCastSpellsOnItemExcludingSubType defined in prc_inc_spells
|
||||
|
||||
// There are two ways to call this function: Either with all necessary parameters passed explicitly to the function
|
||||
// or with no parameters passed to the function (in this case default values are used, which also works, at least in prc_onhitcast)
|
||||
|
||||
// VERSION 1:
|
||||
// generally it is more efficient to call ApplyAllOnHitCastSpellsOnItemExcludingSubType by explicitly passing the parameters to the function
|
||||
// this will set up the overrides in the PRC-wrappers for the spell information functions, which generally is much faster
|
||||
// ApplyAllOnHitCastSpellsOnItemExcludingSubType(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, oSpellTarget, oItem, oSpellOrigin);
|
||||
|
||||
// VERSION 2:
|
||||
// motu99: It might be safer to call this only with defaults in order disallow overrides being set.
|
||||
// (they could have been set beforehand, though - in fact they *are* if we were called from prc_inc_combat)
|
||||
// VERSION 2 has also been tested to work; however, if Bioware changes its implementation the code below is more likely to break
|
||||
ApplyAllOnHitCastSpellsOnItemExcludingSubType(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER);
|
||||
|
||||
// ONLY FOR TESTING
|
||||
// if(GetPRCSwitch(PRC_TIMESTOP_LOCAL)) CastSpellAtLocation(SPELL_FIREBALL, GetLocation(oSpellTarget) /*, METAMAGIC_ANY, GetLevelByTypeArcane(oSpellOrigin), CLASS_TYPE_WIZARD */);
|
||||
// if(GetPRCSwitch(PRC_PNP_TRUESEEING)) CastSpellAtObject(SPELL_FIREBALL, oSpellTarget /*, METAMAGIC_ANY, GetLevelByTypeArcane(oSpellOrigin), CLASS_TYPE_WIZARD */);
|
||||
/*
|
||||
// motu99: This is the old (unsafe) way to cycle through the onhitcast spells.
|
||||
// This method fails, whenever one of the called impact spell script cycles through the item properties of the SpellCastItem on its own
|
||||
// (or calls a function that cycles through the item properties - such as PRCGetMetaMagicFeat)
|
||||
// The safe way to do things is to use the functions ApplyAllOnHitCastSpells* to be found in prc_inc_spells
|
||||
// Left the piece of code here as an example and a warning, how perfectly reasonable code can break without the fault of the scripter
|
||||
// Such an "error" can easily happen to any of us. It is quite difficult to spot an error, caused by nested loops
|
||||
// over item properties in *different* scripts. Runtime behavior is erratic. If you are lucky, you get an
|
||||
// infinite recursion (then you will notice that something is wrong). If you are not lucky, the loop will just skip over
|
||||
// some item properties. And this simply because you put a completely harmless looking function like PRCGetMetaMagicFeat
|
||||
// into your Spell script. How could you possibly know that you just broke your script, because of an unsafe implementation
|
||||
// in a *different* script (here: prc_onhitcast)? You might not even know, that this different scripts exists.
|
||||
|
||||
//handle other OnHit:CastSpell properties
|
||||
DoDebug("prc_onhitcast: now doing other OnHitCastSpell properties on item = "+GetName(oItem));
|
||||
itemproperty ipTest = GetFirstItemProperty(oItem);
|
||||
while(GetIsItemPropertyValid(ipTest))
|
||||
{
|
||||
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_ONHITCASTSPELL)
|
||||
{
|
||||
int nIPSpell = GetItemPropertySubType(ipTest);
|
||||
if(nIPSpell == 125)
|
||||
{
|
||||
ipTest = GetNextItemProperty(oItem);
|
||||
continue; //abort if its OnHit:CastSpell:UniquePower otherwise it would TMI.
|
||||
}
|
||||
int nSpell = StringToInt(Get2DACache("iprp_onhitspell", "SpellIndex", nIPSpell));
|
||||
// int nLevel = GetItemPropertyCostTableValue(ipTest);
|
||||
string sScript = Get2DACache("spells", "ImpactScript", nSpell);
|
||||
DoDebug("prc_onhitcast: Now executing Impact spell script "+sScript);
|
||||
// motu99: Never execute complicated scripts within an GetFirst* / GetNext* loop !!!
|
||||
// The code will break, whenever the script does a loop over item properties (or effects) on its own
|
||||
// rather store all found scripts in a local array, and execute the scripts in a separate loop
|
||||
ExecuteScript(sScript,oSpellOrigin);
|
||||
}
|
||||
ipTest = GetNextItemProperty(oItem);
|
||||
}
|
||||
*/
|
||||
|
||||
/*//////////////////////////////////////////////////
|
||||
/////////////////// SPELLFIRE ////////////////////
|
||||
//////////////////////////////////////////////////*/
|
||||
|
||||
int nSpellfire = GetLevelByClass(CLASS_TYPE_SPELLFIRE, oSpellOrigin);
|
||||
if(nSpellfire && (iItemBaseType == BASE_ITEM_ARMOR))
|
||||
{
|
||||
int nStored = GetPersistantLocalInt(oSpellOrigin, "SpellfireLevelStored");
|
||||
int nCON = GetAbilityScore(oSpellOrigin, ABILITY_CONSTITUTION);
|
||||
int nFlare = 0;
|
||||
int bFlare = FALSE;
|
||||
if(nStored > 4 * nCON)
|
||||
{
|
||||
nFlare = d6(2);
|
||||
bFlare = TRUE;
|
||||
}
|
||||
else if(nStored > 3 * nCON)
|
||||
{
|
||||
nFlare = d6();
|
||||
bFlare = TRUE;
|
||||
}
|
||||
else if(nStored > 2 * nCON)
|
||||
nFlare = d4();
|
||||
else if(nStored > nCON)
|
||||
nFlare = 1;
|
||||
if(nFlare)
|
||||
{
|
||||
nStored -= nFlare;
|
||||
if(nStored < 0) nStored = 0;
|
||||
SetPersistantLocalInt(oSpellOrigin, "SpellfireLevelStored", nStored);
|
||||
}
|
||||
if(bFlare)
|
||||
{
|
||||
int nDC = 10 + nFlare;
|
||||
location lTarget = GetLocation(oSpellOrigin);
|
||||
object oFlareTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
while(GetIsObjectValid(oFlareTarget))
|
||||
{
|
||||
if(spellsIsTarget(oFlareTarget, SPELL_TARGET_STANDARDHOSTILE, oSpellOrigin))
|
||||
{
|
||||
if(!PRCDoResistSpell(oSpellOrigin, oFlareTarget, nSpellfire))
|
||||
{
|
||||
if (PRCMySavingThrow(SAVING_THROW_FORT, oFlareTarget, nDC))
|
||||
{
|
||||
if (GetHasMettle(oFlareTarget, SAVING_THROW_FORT))
|
||||
// This script does nothing if it has Mettle, bail
|
||||
return;
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FLAME_S), oFlareTarget);
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectDazzle(), oFlareTarget, 60.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
oFlareTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
}
|
||||
}
|
||||
if(GetLocalInt(oSpellOrigin, "SpellfireCrown")) //melts non-magical melee weapons
|
||||
{ //can't really get which weapon hit you, so...
|
||||
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oSpellTarget);
|
||||
if(GetIsObjectValid(oWeapon))
|
||||
{
|
||||
if(IPGetIsMeleeWeapon(oWeapon) && !GetIsMagicItem(oWeapon))
|
||||
{
|
||||
DestroyObject(oWeapon);
|
||||
FloatingTextStringOnCreature("*Your weapon has melted!*", oSpellTarget);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oSpellTarget);
|
||||
if(GetIsObjectValid(oWeapon))
|
||||
{
|
||||
if(IPGetIsMeleeWeapon(oWeapon) && !GetIsMagicItem(oWeapon))
|
||||
{
|
||||
DestroyObject(oWeapon);
|
||||
FloatingTextStringOnCreature("*Your weapon has melted!*", oSpellTarget);
|
||||
}
|
||||
}
|
||||
else //You're putting your arms and legs through something that melts weapons?
|
||||
{ //Silly monk/brawler/fool with molten weapons!
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d20()), oSpellTarget);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d20(), DAMAGE_TYPE_FIRE), oSpellTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////
|
||||
////////////////// END SPELLFIRE ///////////////////
|
||||
//////////////////////////////////////////////////*/
|
||||
|
||||
// Handle poisoned weapons
|
||||
/*
|
||||
if(GetLocalInt(oItem, "pois_wpn_uses"))
|
||||
{
|
||||
ExecuteScript("poison_wpn_onhit", OBJECT_SELF);
|
||||
}
|
||||
*/
|
||||
// Execute scripts hooked to this event for the player triggering it
|
||||
if (DEBUG) DoDebug("prc_onhitcast: executing all scripts hooked to onhit events of attacker and item");
|
||||
ExecuteAllScriptsHookedToEvent(oSpellOrigin, EVENT_ONHIT);
|
||||
ExecuteAllScriptsHookedToEvent(oItem, EVENT_ITEM_ONHIT);
|
||||
|
||||
DeleteLocalInt(oSpellOrigin, "prc_ohc");
|
||||
|
||||
}
|
||||
|
||||
void SetRancorVar(object oPC)
|
||||
{
|
||||
// Turn Rancor on
|
||||
SetLocalInt(oPC, "PRC_CanUseRancor", 1);
|
||||
//FloatingTextStringOnCreature("Rancor Attack Possible", oPC, FALSE);
|
||||
|
||||
int iMain = GetMainHandAttacks(oPC);
|
||||
float fDelay = 6.0 / IntToFloat(iMain);
|
||||
|
||||
// Turn Rancor off after one attack is made
|
||||
DelayCommand(fDelay, SetLocalInt(oPC, "PRC_CanUseRancor", 2));
|
||||
//DelayCommand((fDelay + 0.01), FloatingTextStringOnCreature("Rancor Attack Not Possible", oPC, FALSE));
|
||||
|
||||
// Call again if the character is still in combat.
|
||||
// this allows the ability to keep running even if the
|
||||
// player does not score a rancor hit during the allotted time
|
||||
if( PRCGetIsFighting() )
|
||||
{
|
||||
DelayCommand(6.0, SetRancorVar(oPC) );
|
||||
}
|
||||
else
|
||||
{
|
||||
DelayCommand(2.0, SetLocalInt(oPC, "PRC_CanUseRancor", 1));
|
||||
DelayCommand(2.1, SetLocalInt(oPC, "PRC_RancorVarRunning", 2));
|
||||
//DelayCommand(2.2, FloatingTextStringOnCreature("Rancor Enabled After Combat", oPC, FALSE));
|
||||
}
|
||||
}
|
||||
|
||||
void DoImprovedRicochet(object oPC, object oTarget)
|
||||
{
|
||||
int nTargetsLeft = 1;
|
||||
effect eVis = EffectVisualEffect(VFX_IMP_DUST_EXPLOSION);
|
||||
|
||||
location lTarget = GetLocation(oTarget);
|
||||
//Declare the spell shape, size and the location. Capture the first target object in the shape.
|
||||
object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
|
||||
//Cycle through the targets within the spell shape until you run out of targets.
|
||||
while (GetIsObjectValid(oAreaTarget) && nTargetsLeft > 0)
|
||||
{
|
||||
if (spellsIsTarget(oAreaTarget, SPELL_TARGET_SELECTIVEHOSTILE, OBJECT_SELF) && oAreaTarget != OBJECT_SELF && oAreaTarget != oTarget)
|
||||
{
|
||||
PerformAttack(oAreaTarget, oPC, eVis, 0.0, -2, 0, 0, "*Improved Ricochet Hit*", "*Improved Ricochet Missed*");
|
||||
// Use up a target slot only if we actually did something to it
|
||||
nTargetsLeft -= 1;
|
||||
}
|
||||
|
||||
//Select the next target within the spell shape.
|
||||
oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
}
|
||||
}
|
||||
|
||||
void SetImprovedRicochetVar(object oPC)
|
||||
{
|
||||
// Turn Retort on
|
||||
SetLocalInt(oPC, "CanRicochet", 1);
|
||||
|
||||
// Turn Retort off after one attack is made
|
||||
DelayCommand(0.01, SetLocalInt(oPC, "CanRicochet", 0));
|
||||
|
||||
// Call again if the character is still in combat.
|
||||
// this allows the ability to keep running even if the
|
||||
// player does not score a retort hit during the allotted time
|
||||
if( PRCGetIsFighting() )
|
||||
{
|
||||
DelayCommand(6.0, SetImprovedRicochetVar(oPC));
|
||||
}
|
||||
else
|
||||
{
|
||||
DelayCommand(2.0, SetLocalInt(oPC, "CanRicochet", 1));
|
||||
DelayCommand(2.1, SetLocalInt(oPC, "ImpRicochetVarRunning", 2));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user