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.
989 lines
41 KiB
Plaintext
989 lines
41 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Breath Weapon Include
|
|
//:: prc_inc_breath
|
|
//::///////////////////////////////////////////////
|
|
/** @file
|
|
Centralizes handling for most breath weapons for
|
|
implementing Metabreath and the like.
|
|
|
|
@author Fox
|
|
@date Created - 2008.1.19
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:://////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Structures */
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* A structure that contains common data used during power manifestation.
|
|
*/
|
|
struct breath{
|
|
/* Generic stuff */
|
|
/// The creature breathing
|
|
object oDragon;
|
|
|
|
/* Basic info */
|
|
/// The shape of the breath
|
|
int bLine;
|
|
/// The size of the breath in feet
|
|
float fRange;
|
|
/// The element of the breath
|
|
int nDamageType;
|
|
/// Type of dice
|
|
int nDiceType;
|
|
/// Number of dice
|
|
int nDiceNumber;
|
|
/// The stat relavant for DC calculating
|
|
int nDCStat;
|
|
/// Any other DC mods, like class levels for DragDis
|
|
int nOtherDCMod;
|
|
/// Save type - needed in case of Fort Save
|
|
int nSaveUsed;
|
|
/// Rounds until next use
|
|
int nRoundsUntilRecharge;
|
|
|
|
/* Metabreath */
|
|
/// Number of rounds Clinging Breaths last
|
|
int nClinging;
|
|
/// Number of rounds Lingering Breaths last
|
|
int nLingering;
|
|
/// Whether Enlarge Breath was used
|
|
int bEnlarge;
|
|
/// How much the DC is increased by Heighten Breath - max of Con
|
|
int nHeighten;
|
|
/// Whether Maximize Breath was used
|
|
int bMaximize;
|
|
/// Whether Spreading Breath was used
|
|
int bSpread;
|
|
/// Whether Tempest Breath was used
|
|
int bTempest;
|
|
|
|
/* Breath Channeling */
|
|
/// Whether Entangling Exhalation was used
|
|
int bEntangling;
|
|
/// Whether Exhaled Barrier was used
|
|
int bBarrier;
|
|
/// Whether Exhaled Immunity was used
|
|
int bExhaleImmune;
|
|
|
|
|
|
/* Special Cases */
|
|
/// Special case referance number - used for things like Pyroclastic
|
|
int nOverrideSpecial;
|
|
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function prototypes */
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Creates the breath struct, taking metabreath and breath channeling into account.
|
|
*
|
|
* @param oDragon The creature breathing the breath weapon
|
|
* @param bLine True if breath is a line breath, false if a cone breath
|
|
* @param fRange The range of the breath weapon in feet.
|
|
* @param nDamageType The element of the breath weapon, if it has one.
|
|
* @param nDiceType The type of damage dice for the breath weapon.
|
|
* @param nDiceNumber The number of damage dice for the breath weapon.
|
|
* @param nDCStat The constant for the stat the breath weapon uses for DC
|
|
* calculation.
|
|
* @param nOtherDCMod Any other applicable modifications to the DC.
|
|
* e.g. Dragon Disciple levels.
|
|
* @param nOverrideSpecial Indicates any special case breath weapons, like the Pyroclastic's
|
|
* split damage or Shadow's negative level breath. Defaults to 0.
|
|
* @param nBaseRecharge The die size of the recharge "lock." Defaults to d4.
|
|
* @param nSaveUsed The constant to determine the save used. Defaults to Reflex.
|
|
* Diamond Dragon uses Fort saves for cold breath for example.
|
|
*
|
|
* @return Returns a struct that describes the breath being used, including
|
|
* applicable metabreath and breath channeling feats.
|
|
*/
|
|
struct breath CreateBreath(object oDragon, int bLine, float fRange, int nDamageType, int nDiceType, int nDiceNumber, int nDCStat, int nOtherDCMod, int nOverrideSpecial = 0, int nBaseRecharge = 4, int nSaveUsed = SAVING_THROW_REFLEX);
|
|
|
|
/**
|
|
* Applies the breath effect on the targeted location. Brought into the include since
|
|
* there is so much common code.
|
|
*
|
|
* @param BreathUsed A struct describing the details of the breath weapon
|
|
* @param lTargetArea The targeted location for the breath.
|
|
* @param bLinger Determines if this breath was applied by Lingering Breath metabreath.
|
|
* Defaults to FALSE.
|
|
* @param vSource The source of a Lingering breath. This does not matter except when
|
|
* bLinger is set to TRUE.
|
|
*
|
|
*/
|
|
void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = FALSE, float vSourceX = 0.0, float vSourceY = 0.0, float vSourceZ = 0.0);
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Includes */
|
|
//////////////////////////////////////////////////
|
|
|
|
#include "prc_alterations"
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Internal functions */
|
|
//////////////////////////////////////////////////
|
|
|
|
// Exhaled Immunity is different enough to break off on it's own, as it only
|
|
// applies to one creature, and nothing else happens.
|
|
void ExhaleImmunity(object oDragon, int nDamageType, location lTargetArea)
|
|
{
|
|
//since there's no "GetObjectAtLocation," grab a tiny AoE to find the creature
|
|
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 1.0, lTargetArea, TRUE,
|
|
OBJECT_TYPE_CREATURE, GetPosition(oDragon));
|
|
|
|
//make sure damage type is valid, default to fire for non-energy-damage-based breaths
|
|
int nImmuneType = DAMAGE_TYPE_FIRE;
|
|
|
|
if (nDamageType == DAMAGE_TYPE_ACID) nImmuneType = DAMAGE_TYPE_ACID;
|
|
else if (nDamageType == DAMAGE_TYPE_COLD) nImmuneType = DAMAGE_TYPE_COLD;
|
|
else if (nDamageType == DAMAGE_TYPE_SONIC) nImmuneType = DAMAGE_TYPE_SONIC;
|
|
else if (nDamageType == DAMAGE_TYPE_ELECTRICAL) nImmuneType = DAMAGE_TYPE_ELECTRICAL;
|
|
|
|
if((oTarget == OBJECT_INVALID) || (oTarget == oDragon))
|
|
{
|
|
SendMessageToPC(oDragon, "You must target another creature for Exhaled Immunity to work.");
|
|
return;
|
|
}
|
|
|
|
else
|
|
{
|
|
//Fire cast spell at event for the specified target
|
|
SignalEvent(oTarget, EventSpellCastAt(oDragon, GetSpellId(), FALSE));
|
|
//Determine effect delay
|
|
float fDelay = GetDistanceBetween(oDragon, oTarget)/20;
|
|
float fDuration = RoundsToSeconds(d4());
|
|
|
|
//set effects
|
|
effect eImmune = EffectDamageImmunityIncrease(nDamageType, 100);
|
|
effect eVis = EffectVisualEffect(VFX_IMP_ELEMENTAL_PROTECTION);
|
|
effect eVis2 = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
|
|
effect eLink = EffectLinkEffects(eImmune, eVis2);
|
|
|
|
//apply effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmune, oTarget, fDuration));
|
|
}
|
|
}
|
|
|
|
//fucntion to check for Adept breath
|
|
int IsAdeptBreath()
|
|
{
|
|
int nBreath = GetSpellId();
|
|
if(nBreath == BREATH_FIRE_CONE
|
|
|| nBreath == BREATH_FIRE_LINE
|
|
|| nBreath == BREATH_FROST_CONE
|
|
|| nBreath == BREATH_ELECTRIC_LINE
|
|
|| nBreath == BREATH_SICKENING_CONE
|
|
|| nBreath == BREATH_ACID_CONE
|
|
|| nBreath == BREATH_ACID_LINE
|
|
|| nBreath == BREATH_SLOW_CONE
|
|
|| nBreath == BREATH_WEAKENING_CONE
|
|
|| nBreath == BREATH_SLEEP_CONE
|
|
|| nBreath == BREATH_THUNDER_CONE
|
|
|| nBreath == BREATH_BAHAMUT_LINE
|
|
|| nBreath == BREATH_FORCE_LINE
|
|
|| nBreath == BREATH_PARALYZE_CONE
|
|
|| nBreath == BREATH_FIVEFOLD_TIAMAT)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
int IsBreathProtected(object oDragon, object oTarget)
|
|
{
|
|
int nBPIndex = 0;
|
|
while(array_get_object(oTarget, "BreathProtected", nBPIndex) != OBJECT_INVALID)
|
|
{
|
|
if(array_get_object(oTarget, "BreathProtected", nBPIndex) == oDragon)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
nBPIndex++;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function definitions */
|
|
//////////////////////////////////////////////////
|
|
|
|
struct breath CreateBreath(object oDragon, int bLine, float fRange, int nDamageType, int nDiceType, int nDiceNumber, int nDCStat, int nOtherDCMod, int nOverrideSpecial = 0, int nBaseRecharge = 4, int nSaveUsed = SAVING_THROW_REFLEX)
|
|
{
|
|
struct breath BreathUsed;
|
|
|
|
//gather base data
|
|
BreathUsed.oDragon = oDragon;
|
|
BreathUsed.bLine = bLine;
|
|
BreathUsed.fRange = fRange;
|
|
BreathUsed.nDamageType = nDamageType;
|
|
BreathUsed.nDiceType = nDiceType;
|
|
BreathUsed.nDiceNumber = nDiceNumber;
|
|
BreathUsed.nDCStat = nDCStat;
|
|
BreathUsed.nOtherDCMod = nOtherDCMod;
|
|
int nFinalRecharge;
|
|
switch(nBaseRecharge)
|
|
{
|
|
case 4:
|
|
nFinalRecharge = d4(); break;
|
|
case 1:
|
|
nFinalRecharge = 1; break;
|
|
default:
|
|
nFinalRecharge = 0; break;
|
|
}
|
|
BreathUsed.nRoundsUntilRecharge = nFinalRecharge;
|
|
BreathUsed.nSaveUsed = nSaveUsed;
|
|
BreathUsed.nOverrideSpecial = nOverrideSpecial;
|
|
|
|
//Energy Aura bonus checking
|
|
switch(nDamageType)
|
|
{
|
|
case DAMAGE_TYPE_ACID:
|
|
if(GetLocalInt(oDragon,"AcidEnergyAura"))
|
|
BreathUsed.nOtherDCMod += GetLocalInt(oDragon,"AcidEnergyAura");
|
|
break;
|
|
case DAMAGE_TYPE_COLD:
|
|
if(GetLocalInt(oDragon,"ColdEnergyAura"))
|
|
BreathUsed.nOtherDCMod += GetLocalInt(oDragon,"ColdEnergyAura");
|
|
break;
|
|
case DAMAGE_TYPE_ELECTRICAL:
|
|
if(GetLocalInt(oDragon,"ElecEnergyAura"))
|
|
BreathUsed.nOtherDCMod += GetLocalInt(oDragon,"ElecEnergyAura");
|
|
break;
|
|
case DAMAGE_TYPE_FIRE:
|
|
if(GetLocalInt(oDragon,"FireEnergyAura"))
|
|
BreathUsed.nOtherDCMod += GetLocalInt(oDragon,"FireEnergyAura");
|
|
}
|
|
|
|
/* Initialize metabreath/channeling tracking */
|
|
BreathUsed.nClinging = 0;
|
|
BreathUsed.nLingering = 0;
|
|
BreathUsed.bEnlarge = FALSE;
|
|
BreathUsed.nHeighten = 0;
|
|
BreathUsed.bMaximize = FALSE;
|
|
BreathUsed.bSpread = FALSE;
|
|
BreathUsed.bTempest = FALSE;
|
|
BreathUsed.bEntangling = FALSE;
|
|
BreathUsed.bBarrier = FALSE;
|
|
BreathUsed.bExhaleImmune = FALSE;
|
|
|
|
/* breath channeling */
|
|
|
|
// Whether Entangling Exhalation was used
|
|
if(GetLocalInt(oDragon, "EntangleBreath"))
|
|
BreathUsed.bEntangling = TRUE;
|
|
// Whether Exhaled Barrier was used
|
|
if(GetLocalInt(oDragon, "ExhaleBarrier"))
|
|
BreathUsed.bBarrier = TRUE;
|
|
// Whether Exhaled Immunity was used
|
|
if(GetLocalInt(oDragon, "ExhaleImmunity"))
|
|
BreathUsed.bExhaleImmune = TRUE;
|
|
|
|
//breath effect checks
|
|
|
|
//Cloud only works with 1 other effect applied
|
|
//this one handles combination with damage effects and enduring
|
|
if(GetLocalInt(oDragon, "AdeptCloudBreath")
|
|
&& !GetLocalInt(oDragon, "AdeptShapedBreath")
|
|
&& (GetSpellId() == BREATH_FIRE_CONE
|
|
|| GetSpellId() == BREATH_FROST_CONE
|
|
|| GetSpellId() == BREATH_SICKENING_CONE
|
|
|| GetSpellId() == BREATH_ACID_CONE
|
|
|| GetSpellId() == BREATH_SLOW_CONE
|
|
|| GetSpellId() == BREATH_WEAKENING_CONE
|
|
|| GetSpellId() == BREATH_SLEEP_CONE
|
|
|| GetSpellId() == BREATH_THUNDER_CONE
|
|
|| GetSpellId() == BREATH_PARALYZE_CONE))
|
|
{
|
|
BreathUsed.bSpread = TRUE;
|
|
}
|
|
//this one is Cloud + Shaped
|
|
if(GetLocalInt(oDragon, "AdeptCloudBreath")
|
|
&& GetLocalInt(oDragon, "AdeptShapedBreath")
|
|
&& !GetLocalInt(oDragon, "AdeptEnduringBreath")
|
|
&& GetSpellId() == BREATH_FIRE_CONE)
|
|
{
|
|
BreathUsed.bSpread = TRUE;
|
|
}
|
|
if(GetLocalInt(oDragon, "AdeptEnduringBreath")
|
|
&& !(GetLocalInt(oDragon, "AdeptCloudBreath") && GetLocalInt(oDragon, "AdeptShapedBreath"))
|
|
&& (GetSpellId() == BREATH_FIRE_CONE || GetSpellId() == BREATH_FIRE_LINE))
|
|
{
|
|
BreathUsed.nLingering = 1;
|
|
}
|
|
|
|
//breaths without recharge times can't use metabreath
|
|
if(BreathUsed.nRoundsUntilRecharge == 0)
|
|
return BreathUsed;
|
|
|
|
/* metabreath calculation*/
|
|
|
|
//Clinging breath - Main feat increments uses, secondary feat cancels.
|
|
if(GetLocalInt(oDragon, "ClingingBreath") > 0)
|
|
{
|
|
BreathUsed.nClinging = GetLocalInt(oDragon, "ClingingBreath");
|
|
BreathUsed.nRoundsUntilRecharge += BreathUsed.nClinging;
|
|
}
|
|
//Lingering breath - Main feat increments uses, secondary feat cancels.
|
|
if(GetLocalInt(oDragon, "LingeringBreath") > 0)
|
|
{
|
|
BreathUsed.nLingering = GetLocalInt(oDragon, "LingeringBreath");
|
|
BreathUsed.nRoundsUntilRecharge += (BreathUsed.nLingering * 2);
|
|
}
|
|
//Enlarge breath
|
|
if(GetLocalInt(oDragon, "EnlargeBreath"))
|
|
{
|
|
BreathUsed.bEnlarge = TRUE;
|
|
BreathUsed.nRoundsUntilRecharge += 1;
|
|
}
|
|
//Heighten breath - Feat increments uses, resets if incremented at max.
|
|
if(GetLocalInt(oDragon, "HeightenBreath") > 0)
|
|
{
|
|
BreathUsed.nHeighten = GetLocalInt(oDragon, "HeightenBreath");
|
|
BreathUsed.nRoundsUntilRecharge += BreathUsed.nHeighten;
|
|
}
|
|
//Maximize breath
|
|
if(GetLocalInt(oDragon, "MaximizeBreath"))
|
|
{
|
|
BreathUsed.bMaximize = TRUE;
|
|
BreathUsed.nRoundsUntilRecharge += 3;
|
|
}
|
|
//Shape breath
|
|
if(GetLocalInt(oDragon, "ShapeBreath"))
|
|
{
|
|
if(bLine) BreathUsed.bLine = FALSE;
|
|
else BreathUsed.bLine = TRUE;
|
|
BreathUsed.nRoundsUntilRecharge += 1;
|
|
}
|
|
//Spreading breath
|
|
if(GetLocalInt(oDragon, "SpreadingBreath"))
|
|
{
|
|
BreathUsed.bSpread = TRUE;
|
|
BreathUsed.nRoundsUntilRecharge += 2;
|
|
}
|
|
//Tempest breath
|
|
if(GetLocalInt(oDragon, "TempestBreath"))
|
|
{
|
|
BreathUsed.bTempest = TRUE;
|
|
BreathUsed.nRoundsUntilRecharge += 1;
|
|
}
|
|
//Recover Breath
|
|
if(GetHasFeat(FEAT_RECOVER_BREATH, oDragon)
|
|
&& (BreathUsed.nRoundsUntilRecharge > 1))
|
|
BreathUsed.nRoundsUntilRecharge += -1;
|
|
|
|
|
|
// Exhaled Barrier and Immunity don't apply Metabreath feats, so recharge time should be unaffected
|
|
if(BreathUsed.bBarrier || BreathUsed.bExhaleImmune)
|
|
BreathUsed.nRoundsUntilRecharge = nFinalRecharge;
|
|
|
|
return BreathUsed;
|
|
}
|
|
|
|
void ApplyBreath(struct breath BreathUsed, location lTargetArea, int bLinger = FALSE, float vSourceX = 0.0, float vSourceY = 0.0, float vSourceZ = 0.0)
|
|
{
|
|
//if using Exhaled Immunity, jump straight to it and ignore the rest
|
|
if(BreathUsed.bExhaleImmune)
|
|
{
|
|
ExhaleImmunity(BreathUsed.oDragon, BreathUsed.nDamageType, lTargetArea);
|
|
return;
|
|
}
|
|
|
|
//init variables
|
|
effect eBreath;
|
|
effect eVis;
|
|
float fDelay;
|
|
int nDamage = 0;
|
|
int nAdjustedDamage;
|
|
int nSaveDamageType = -1;
|
|
int nVisualType = -1;
|
|
int nEnergyAura = 0;
|
|
int bCanCling;
|
|
int nSaveDC;
|
|
int nShapedSpotsUsed = GetLocalInt(BreathUsed.oDragon, "AdeptShapedBreath") ? 0 : 4;
|
|
int nBreathShape = BreathUsed.bLine ? SHAPE_SPELLCYLINDER : SHAPE_SPELLCONE;
|
|
float fRange = FeetToMeters(BreathUsed.fRange);
|
|
int nKnockdownDC = 0;
|
|
vector vSource = Vector(vSourceX, vSourceY, vSourceZ);
|
|
vector vSourceOfBreath = bLinger ? vSource : GetPosition(BreathUsed.oDragon);
|
|
|
|
//Saving Throw setup
|
|
if (BreathUsed.nDCStat >= 10)
|
|
nSaveDC = BreathUsed.nDCStat;
|
|
else
|
|
nSaveDC = 10 + max(GetAbilityModifier(BreathUsed.nDCStat), 0) + BreathUsed.nOtherDCMod;
|
|
|
|
//Set up variables that depend on damage type
|
|
switch (BreathUsed.nDamageType)
|
|
{
|
|
case DAMAGE_TYPE_ACID:
|
|
nSaveDamageType = SAVING_THROW_TYPE_ACID;
|
|
nVisualType = VFX_IMP_ACID_S;
|
|
nEnergyAura = GetLocalInt(BreathUsed.oDragon, "AcidEnergyAura"); break;
|
|
|
|
case DAMAGE_TYPE_COLD:
|
|
nSaveDamageType = SAVING_THROW_TYPE_COLD;
|
|
nVisualType = VFX_IMP_FROST_S;
|
|
nEnergyAura = GetLocalInt(BreathUsed.oDragon, "ColdEnergyAura"); break;
|
|
|
|
case DAMAGE_TYPE_ELECTRICAL:
|
|
nSaveDamageType = SAVING_THROW_TYPE_ELECTRICITY;
|
|
nVisualType = VFX_IMP_LIGHTNING_S;
|
|
nEnergyAura = GetLocalInt(BreathUsed.oDragon, "ElecEnergyAura"); break;
|
|
|
|
case DAMAGE_TYPE_FIRE:
|
|
nSaveDamageType = SAVING_THROW_TYPE_FIRE;
|
|
nVisualType = VFX_IMP_FLAME_M;
|
|
nEnergyAura = GetLocalInt(BreathUsed.oDragon, "FireEnergyAura"); break;
|
|
|
|
case DAMAGE_TYPE_MAGICAL:
|
|
nSaveDamageType = SAVING_THROW_TYPE_NONE;
|
|
nVisualType = VFX_IMP_KNOCK; break;
|
|
|
|
case DAMAGE_TYPE_NEGATIVE:
|
|
nSaveDamageType = SAVING_THROW_TYPE_NEGATIVE;
|
|
nVisualType = VFX_IMP_NEGATIVE_ENERGY; break;
|
|
|
|
case DAMAGE_TYPE_POSITIVE:
|
|
nSaveDamageType = SAVING_THROW_TYPE_POSITIVE;
|
|
nVisualType = VFX_IMP_HOLY_AID; break;
|
|
|
|
case DAMAGE_TYPE_SONIC:
|
|
nSaveDamageType = SAVING_THROW_TYPE_SONIC;
|
|
nVisualType = VFX_IMP_SILENCE; break;
|
|
}
|
|
|
|
//apply Energy Draconic Aura bonus
|
|
if(nEnergyAura < 0) nEnergyAura = 0;
|
|
nSaveDC += nEnergyAura;
|
|
|
|
if(BreathUsed.nOverrideSpecial == BREATH_TOPAZ)
|
|
nVisualType = VFX_IMP_POISON_L;
|
|
|
|
if(BreathUsed.bBarrier)
|
|
{
|
|
//2d6 fire damage if the breath doesn't do damage
|
|
if(BreathUsed.nOverrideSpecial == BREATH_SHADOW
|
|
|| BreathUsed.nOverrideSpecial == BREATH_SLEEP
|
|
|| BreathUsed.nOverrideSpecial == BREATH_SLOW
|
|
|| BreathUsed.nOverrideSpecial == BREATH_PARALYZE
|
|
|| BreathUsed.nOverrideSpecial == BREATH_WEAKENING)
|
|
{
|
|
BreathUsed.nDiceType = 6;
|
|
BreathUsed.nDiceNumber = 2;
|
|
BreathUsed.nDamageType = DAMAGE_TYPE_FIRE;
|
|
}
|
|
|
|
//fire damage if damage isn't energy damage
|
|
if(BreathUsed.nDamageType == DAMAGE_TYPE_MAGICAL || BreathUsed.nDamageType == DAMAGE_TYPE_BLUDGEONING)
|
|
BreathUsed.nDamageType = DAMAGE_TYPE_FIRE;
|
|
|
|
//get the breath parameters and pass to the wall's scripts
|
|
SetLocalInt(BreathUsed.oDragon, "BarrierDiceType", BreathUsed.nDiceType);
|
|
SetLocalInt(BreathUsed.oDragon, "BarrierDiceNumber", BreathUsed.nDiceNumber);
|
|
SetLocalInt(BreathUsed.oDragon, "BarrierDamageType", BreathUsed.nDamageType);
|
|
|
|
//create the wall
|
|
effect eAOE = EffectAreaOfEffect(AOE_PER_WALLBREATH);
|
|
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAOE, lTargetArea, RoundsToSeconds(d4()));
|
|
|
|
//this overrides all other breath effects, so exit
|
|
return;
|
|
}
|
|
|
|
|
|
//roll damage
|
|
switch(BreathUsed.nDiceType)
|
|
{
|
|
case 4:
|
|
nDamage = d4(BreathUsed.nDiceNumber); break;
|
|
case 6:
|
|
nDamage = d6(BreathUsed.nDiceNumber); break;
|
|
case 8:
|
|
nDamage = d8(BreathUsed.nDiceNumber); break;
|
|
case 10:
|
|
nDamage = d10(BreathUsed.nDiceNumber); break;
|
|
}
|
|
if(DEBUG) DoDebug("prc_inc_breath: Rolling damage: " + IntToString(BreathUsed.nDiceNumber)
|
|
+ "d" + IntToString(BreathUsed.nDiceType) + "= " + IntToString(nDamage));
|
|
|
|
//Shadow breath does 1 neg level instead of damage
|
|
if(BreathUsed.nOverrideSpecial == BREATH_SHADOW)
|
|
nDamage = 1;
|
|
|
|
//adjust for metabreaths
|
|
if(BreathUsed.bEnlarge)
|
|
fRange = fRange * 1.5;
|
|
if(BreathUsed.nHeighten > 0)
|
|
nSaveDC += BreathUsed.nHeighten;
|
|
if(BreathUsed.bMaximize)
|
|
nDamage = BreathUsed.nDiceType * BreathUsed.nDiceNumber;
|
|
if(BreathUsed.bSpread)
|
|
{
|
|
fRange = PRCGetCreatureSize(BreathUsed.oDragon) * 5.0;
|
|
if(fRange < 1.0) fRange = 5.0;
|
|
fRange = FeetToMeters(fRange);
|
|
nBreathShape = SHAPE_SPHERE;
|
|
lTargetArea = GetLocation(BreathUsed.oDragon);
|
|
eVis = EffectVisualEffect(VFX_FNF_DRAGBREATHGROUND);
|
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lTargetArea);
|
|
}
|
|
|
|
//Lingering Breath's effects are 1/2 of normal when lingering
|
|
if(bLinger)
|
|
{
|
|
nDamage /= 2;
|
|
BreathUsed.nDiceNumber /= 2;
|
|
}
|
|
|
|
//DCs for Tempest Breath
|
|
switch(PRCGetCreatureSize(BreathUsed.oDragon))
|
|
{
|
|
case CREATURE_SIZE_LARGE:
|
|
nKnockdownDC = 15; break;
|
|
|
|
case CREATURE_SIZE_HUGE:
|
|
nKnockdownDC = 18; break;
|
|
|
|
case CREATURE_SIZE_GARGANTUAN:
|
|
nKnockdownDC = 20; break;
|
|
|
|
case CREATURE_SIZE_COLOSSAL:
|
|
nKnockdownDC = 30; break;
|
|
|
|
}
|
|
|
|
//adjust for breath channeling
|
|
if(BreathUsed.bEntangling)
|
|
nDamage = nDamage / 2;
|
|
|
|
/* Begin application */
|
|
int nObjectFilter = OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE;
|
|
//Adept's Breath of Bahamut does not affect objects
|
|
if(GetSpellId() == BREATH_BAHAMUT_LINE) nObjectFilter = OBJECT_TYPE_CREATURE;
|
|
|
|
//Get first target in spell area
|
|
object oTarget = GetFirstObjectInShape(nBreathShape, fRange, lTargetArea, TRUE, nObjectFilter, vSourceOfBreath);
|
|
if(DEBUG) DoDebug("prc_inc_breath: Target Name: " + GetName(oTarget));
|
|
while(GetIsObjectValid(oTarget))
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: Valid Target: " + GetName(oTarget));
|
|
if(oTarget != BreathUsed.oDragon && !IsBreathProtected(BreathUsed.oDragon, oTarget) && spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, BreathUsed.oDragon))
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: Not Self, Not Protected");
|
|
//Adjust the damage based on the Reflex Save, Evasion and Improved Evasion.
|
|
//Determine effect delay
|
|
fDelay = GetDistanceBetween(BreathUsed.oDragon, oTarget)/20;
|
|
|
|
//check for Shaped Breath effect
|
|
if(IsAdeptBreath() && (nShapedSpotsUsed < 4) && !GetIsReactionTypeHostile(oTarget) && GetLocalInt(BreathUsed.oDragon, "AdeptShapedBreath"))
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: Entering Shaped Breath. Slots used: " + IntToString(nShapedSpotsUsed));
|
|
nShapedSpotsUsed++;
|
|
}
|
|
|
|
//Adept's Sickening Breath breath effect
|
|
else if(BreathUsed.nOverrideSpecial == BREATH_SICKENING)
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: sickening breath attack");
|
|
|
|
//Fire cast spell at event for the specified target
|
|
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
|
|
|
|
//2 rounds on a failed save
|
|
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE))
|
|
{
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_POISON_L), oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSickened(), oTarget, 12.0));
|
|
}
|
|
//1 round otherwise
|
|
else
|
|
{
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_POISON_L), oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSickened(), oTarget, 6.0));
|
|
}
|
|
}
|
|
|
|
//Brass alternate breath - sleep
|
|
else if(BreathUsed.nOverrideSpecial == BREATH_SLEEP)
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: sleep breath attack");
|
|
//prepare effects
|
|
effect eBreath = EffectSleep();
|
|
effect eVis = EffectVisualEffect(VFX_IMP_SLEEP);
|
|
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
|
|
effect eLink = EffectLinkEffects(eBreath, eDur);
|
|
|
|
//get duration
|
|
int nSleepDuration = BreathUsed.nDiceNumber;
|
|
|
|
//Fire cast spell at event for the specified target
|
|
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
|
|
|
|
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE))
|
|
{
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nSleepDuration)));
|
|
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
|
|
}
|
|
}
|
|
|
|
//Copper alternate breath - slow
|
|
else if(BreathUsed.nOverrideSpecial == BREATH_SLOW)
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: slowing breath attack");
|
|
//prepare effects
|
|
effect eBreath = EffectSlow();
|
|
effect eVis = EffectVisualEffect(VFX_IMP_SLOW);
|
|
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
|
|
effect eLink = EffectLinkEffects(eBreath, eDur);
|
|
|
|
//get duration
|
|
int nSlowDuration = BreathUsed.nDiceNumber;
|
|
|
|
//Fire cast spell at event for the specified target
|
|
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
|
|
|
|
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE))
|
|
{
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nSlowDuration)));
|
|
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
|
|
}
|
|
//Adept breath effect still lasts for one round if save is made
|
|
else if(IsAdeptBreath())
|
|
{
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(1)));
|
|
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
|
|
}
|
|
}
|
|
|
|
//Gold alternate breath - drains strength
|
|
else if(BreathUsed.nOverrideSpecial == BREATH_WEAKENING)
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: weakening breath attack");
|
|
//Fire cast spell at event for the specified target
|
|
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
|
|
|
|
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE))
|
|
{
|
|
//Set Damage and VFX - Bioware Gold used VFX_IMP_REDUCE_ABILITY_SCORE originally
|
|
eVis = EffectVisualEffect(VFX_IMP_POISON_L);
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
|
//adept breath penalty only last 4 rounds on failure, gold breath has no duration
|
|
if(IsAdeptBreath())
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_STRENGTH, BreathUsed.nDiceNumber), oTarget, 24.0));
|
|
else
|
|
DelayCommand(fDelay, ApplyAbilityDamage(oTarget, ABILITY_STRENGTH, BreathUsed.nDiceNumber, DURATION_TYPE_PERMANENT, TRUE));
|
|
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
|
|
}
|
|
//Adept breath still happens for 2 rounds on successful save
|
|
else if(IsAdeptBreath())
|
|
{
|
|
//Set Damage and VFX - Bioware Gold used VFX_IMP_REDUCE_ABILITY_SCORE originally
|
|
eVis = EffectVisualEffect(VFX_IMP_POISON_L);
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectAbilityDecrease(ABILITY_STRENGTH, BreathUsed.nDiceNumber), oTarget, 12.0));
|
|
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
|
|
}
|
|
bCanCling = TRUE;
|
|
}
|
|
|
|
//Silver alternate breath - paralyze
|
|
else if(BreathUsed.nOverrideSpecial == BREATH_PARALYZE)
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: paralyzing breath attack");
|
|
//prepare effects
|
|
effect eBreath = EffectParalyze();
|
|
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
|
|
effect eDur2 = EffectVisualEffect(VFX_DUR_PARALYZE_HOLD);
|
|
effect eParal = EffectVisualEffect(VFX_DUR_PARALYZED);
|
|
|
|
effect eLink = EffectLinkEffects(eBreath, eDur);
|
|
eLink = EffectLinkEffects(eLink, eDur2);
|
|
eLink = EffectLinkEffects(eLink, eParal);
|
|
|
|
//get duration
|
|
int nParalDuration = BreathUsed.nDiceNumber;
|
|
|
|
//Fire cast spell at event for the specified target
|
|
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
|
|
|
|
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_NONE))
|
|
{
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nParalDuration)));
|
|
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
|
|
}
|
|
}
|
|
|
|
//Shadow Dragon breath - drains levels
|
|
else if(BreathUsed.nOverrideSpecial == BREATH_SHADOW)
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: shadow breath attack");
|
|
//Fire cast spell at event for the specified target
|
|
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
|
|
|
|
int nLevelDrain = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, SAVING_THROW_TYPE_NEGATIVE);
|
|
|
|
if (nLevelDrain > 0)
|
|
{
|
|
//Set Damage and VFX
|
|
eBreath = EffectNegativeLevel(nLevelDrain);
|
|
eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY);
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget));
|
|
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
|
|
}
|
|
}
|
|
|
|
//Swift Wing Breath of Life - Positive to Undead only, heals living creatures
|
|
else if(BreathUsed.nOverrideSpecial == BREATH_SWIFT_WING)
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: swift wing breath attack");
|
|
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD || (GetHasFeat(FEAT_TOMB_TAINTED_SOUL, oTarget) && GetAlignmentGoodEvil(oTarget) != ALIGNMENT_GOOD))
|
|
{
|
|
//Fire cast spell at event for the specified target
|
|
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
|
|
|
|
nAdjustedDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, SAVING_THROW_TYPE_POSITIVE);
|
|
|
|
if (nAdjustedDamage > 0)
|
|
{
|
|
//Set Damage and VFX
|
|
eBreath = EffectDamage(nAdjustedDamage, BreathUsed.nDamageType);
|
|
eVis = EffectVisualEffect(VFX_IMP_SUNSTRIKE);
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget));
|
|
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
|
|
bCanCling = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//normal damaging-type breath
|
|
else
|
|
{
|
|
//Fire cast spell at event for the specified target
|
|
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId()));
|
|
if(DEBUG) DoDebug("prc_inc_breath: normal breath attack");
|
|
|
|
if(BreathUsed.nSaveUsed == SAVING_THROW_FORT)
|
|
{
|
|
nAdjustedDamage = nDamage;
|
|
//make a fort save
|
|
if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, nSaveDamageType))
|
|
{
|
|
//Mettle is Evasion for Fort saves
|
|
if (GetHasMettle(oTarget, SAVING_THROW_FORT))
|
|
nAdjustedDamage = 0;
|
|
|
|
nAdjustedDamage /= 2;
|
|
}
|
|
}
|
|
else
|
|
nAdjustedDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, nSaveDamageType);
|
|
|
|
if (nAdjustedDamage > 0)
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: Damage > 0");
|
|
//Set Damage and VFX
|
|
if(BreathUsed.nOverrideSpecial == BREATH_PYROCLASTIC)
|
|
{
|
|
int chSaveth;
|
|
int chVisual;
|
|
int eleRoll;
|
|
|
|
int nNumDice = d2();
|
|
//Sets the random Element factor of the Chaos Dragons Breath Weapon.
|
|
//Affects damage, saving throw, and impact visual.
|
|
if (nNumDice==1)
|
|
{
|
|
chSaveth = SAVING_THROW_TYPE_SONIC;
|
|
chVisual = VFX_IMP_SILENCE;
|
|
}
|
|
else if (nNumDice==2)
|
|
{
|
|
chSaveth = SAVING_THROW_TYPE_FIRE;
|
|
chVisual = VFX_IMP_FLAME_M;
|
|
}
|
|
|
|
if(GetLocalInt(oTarget, "DragonWard"))
|
|
nAdjustedDamage -= 40;
|
|
|
|
effect eBreath1 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_FIRE);
|
|
effect eBreath2 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_SONIC);
|
|
eBreath = EffectLinkEffects(eBreath1, eBreath2);
|
|
eVis = EffectVisualEffect(chVisual);
|
|
}
|
|
else
|
|
{
|
|
if(GetLocalInt(oTarget, "DragonWard"))
|
|
nAdjustedDamage -= 20;
|
|
eBreath = EffectDamage(nAdjustedDamage, BreathUsed.nDamageType);
|
|
eVis = EffectVisualEffect(nVisualType);
|
|
}
|
|
//Apply the VFX impact and effects
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget));
|
|
SetLocalInt(oTarget, "AffectedByBreath", TRUE);
|
|
bCanCling = TRUE;
|
|
}
|
|
}
|
|
|
|
//Knockdown check for Tempest Breath
|
|
if(BreathUsed.bTempest && (PRCGetCreatureSize(BreathUsed.oDragon) > CREATURE_SIZE_MEDIUM))
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: tempest breath attack");
|
|
if(PRCGetCreatureSize(BreathUsed.oDragon) - PRCGetCreatureSize(oTarget) > 1)
|
|
{
|
|
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nKnockdownDC, SAVING_THROW_TYPE_NONE))
|
|
{
|
|
effect eWindblown = EffectKnockdown();
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eWindblown, oTarget, 6.0));
|
|
}
|
|
}
|
|
}
|
|
|
|
//Breath of Life healing
|
|
if(oTarget != BreathUsed.oDragon && BreathUsed.nOverrideSpecial == BREATH_SWIFT_WING && MyPRCGetRacialType(oTarget) != RACIAL_TYPE_UNDEAD && MyPRCGetRacialType(oTarget) != RACIAL_TYPE_CONSTRUCT
|
|
&& !(GetHasFeat(FEAT_TOMB_TAINTED_SOUL, oTarget) && GetAlignmentGoodEvil(oTarget) != ALIGNMENT_GOOD))
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: breath of life");
|
|
//Fire cast spell at event for the specified target
|
|
SignalEvent(oTarget, EventSpellCastAt(BreathUsed.oDragon, GetSpellId(), FALSE));
|
|
//Adjust the damage based on the Reflex Save, Evasion and Improved Evasion.
|
|
//Determine effect delay
|
|
fDelay = GetDistanceBetween(BreathUsed.oDragon, oTarget)/20;
|
|
int nHeal = BreathUsed.nDiceNumber;
|
|
|
|
//Warforged are only healed for half
|
|
if(GetIsWarforged(oTarget)) nHeal /= 2;
|
|
|
|
eBreath = EffectHeal(nHeal);
|
|
effect eHealVis = EffectVisualEffect(VFX_IMP_HEALING_S);
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget));
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eHealVis, oTarget));
|
|
}
|
|
|
|
//Entangling Exhalation
|
|
if(GetLocalInt(oTarget, "AffectedByBreath") && BreathUsed.bEntangling)
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: entangling breath attack");
|
|
effect eEntangled = EffectEntangle();
|
|
effect eEntangleVis = EffectVisualEffect(VFX_DUR_ENTANGLE);
|
|
eEntangled = EffectLinkEffects(eEntangled, eEntangleVis);
|
|
int nEntangleRounds = d4();
|
|
//only does damage if the original breath did damage
|
|
if(BreathUsed.nDamageType > 0)
|
|
{
|
|
effect eDamage = EffectDamage(d6(), BreathUsed.nDamageType);
|
|
switch(nEntangleRounds)
|
|
{
|
|
case 4:
|
|
DelayCommand(fDelay + RoundsToSeconds(4), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
|
|
case 3:
|
|
DelayCommand(fDelay + RoundsToSeconds(3), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
|
|
case 2:
|
|
DelayCommand(fDelay + RoundsToSeconds(2), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
|
|
case 1:
|
|
DelayCommand(fDelay + RoundsToSeconds(1), ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget)); break;
|
|
}
|
|
}
|
|
|
|
//but always entangles if the breath affects the target
|
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEntangled, oTarget, RoundsToSeconds(nEntangleRounds)));
|
|
}
|
|
|
|
DeleteLocalInt(oTarget, "AffectedByBreath");
|
|
|
|
//Clinging Breath check
|
|
if(BreathUsed.nClinging > 0 && bCanCling)
|
|
{
|
|
if(DEBUG) DoDebug("prc_inc_breath: clinging breath attack");
|
|
int nCount;
|
|
int AdjustedAbilityDamage = BreathUsed.nDiceNumber;
|
|
|
|
for(nCount = 0; nCount < BreathUsed.nClinging; nCount++)
|
|
{
|
|
float fNewDelay = RoundsToSeconds(nCount + 1);
|
|
if(BreathUsed.nOverrideSpecial == BREATH_WEAKENING)
|
|
{
|
|
AdjustedAbilityDamage /= 2;
|
|
DelayCommand(fNewDelay, ApplyAbilityDamage(oTarget, ABILITY_STRENGTH, BreathUsed.nDiceNumber, DURATION_TYPE_PERMANENT, TRUE));
|
|
if(AdjustedAbilityDamage = 1) nCount = BreathUsed.nClinging;
|
|
}
|
|
nAdjustedDamage /= 2;
|
|
if(BreathUsed.nOverrideSpecial == BREATH_PYROCLASTIC)
|
|
{
|
|
if(nAdjustedDamage < 3) nCount = BreathUsed.nClinging;
|
|
|
|
effect eBreath1 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_FIRE);
|
|
effect eBreath2 = EffectDamage(nAdjustedDamage/2, DAMAGE_TYPE_SONIC);
|
|
effect eAfterBreath = EffectLinkEffects(eBreath1, eBreath2);
|
|
DelayCommand(fNewDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eAfterBreath, oTarget));
|
|
}
|
|
else
|
|
{
|
|
if(nAdjustedDamage < 2) nCount = BreathUsed.nClinging;
|
|
effect eAfterBreath = EffectDamage(nAdjustedDamage, BreathUsed.nDamageType);
|
|
DelayCommand(fNewDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eAfterBreath, oTarget));
|
|
}
|
|
DelayCommand(fNewDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
|
}
|
|
}
|
|
}
|
|
|
|
//Get next target in spell area
|
|
if(DEBUG) DoDebug("prc_inc_breath: Next target");
|
|
oTarget = GetNextObjectInShape(nBreathShape, fRange, lTargetArea, TRUE, nObjectFilter, vSourceOfBreath);
|
|
}
|
|
|
|
//Lingering Breath check
|
|
if(BreathUsed.nLingering > 0)
|
|
{
|
|
int nCount;
|
|
int nLingerDuration = BreathUsed.nLingering;
|
|
BreathUsed.nLingering = 0;
|
|
BreathUsed.nClinging = 0;
|
|
vector vOrigin = GetPosition(BreathUsed.oDragon);
|
|
effect eGroundVis = EffectVisualEffect(VFX_FNF_DRAGBREATHGROUND);
|
|
|
|
for(nCount = 0; nCount < nLingerDuration; nCount++)
|
|
{
|
|
float fNewDelay = RoundsToSeconds(nCount + 1);
|
|
DelayCommand(fNewDelay, ApplyBreath(BreathUsed, lTargetArea, TRUE, vOrigin.x, vOrigin.y, vOrigin.z));
|
|
DelayCommand(fNewDelay, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eGroundVis, lTargetArea));
|
|
}
|
|
}
|
|
}
|
|
|
|
void PRCPlayDragonBattleCry()
|
|
{
|
|
if(d100() > 50)
|
|
{
|
|
PlayVoiceChat(VOICE_CHAT_BATTLECRY1);
|
|
}
|
|
else
|
|
{
|
|
PlayVoiceChat(VOICE_CHAT_BATTLECRY2);
|
|
}
|
|
}
|