Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
198 lines
8.5 KiB
Plaintext
198 lines
8.5 KiB
Plaintext
//:Ghost-Faced Killer Frightful Attack
|
|
//
|
|
//Power Attack must be active.
|
|
//The attack must be a Sudden Strike (Sneak Attack.)
|
|
//The victim makes a Will Save (DC 10 + GFK class level + GFK Cha modifier.)
|
|
//If the victim fails the save, the victim dies of fright.
|
|
//If the victim succeeds, the victim becomes shaken for 1 round per GFK class
|
|
//level.
|
|
//Victims immune to mind-affecting effects, immune to fear, or with more Hit
|
|
//Dice than the GFK's character level are immune to this frightful attack.
|
|
//All onlookers in a 30 foot radius who are not the victim, the GFK, or allies
|
|
//of the GFK must make a will save (DC 10 + GFK class level + GFK Cha modifier
|
|
//+ damage modifier of power attack.)
|
|
//If the onlooker succeeds the will save, no effect is applied.
|
|
//If the onlooker has less Hit Dice than the GFK class level + GFK Cha modifier,
|
|
//and fails the save, the onlooker becomes panicked for 1 round per GFK class
|
|
//level.
|
|
//If the onlooker has more Hit Dice than the GFK class level + GFK Cha modifier,
|
|
//and fails the save, the onlooker becomes shaken for 1 round per GFK class
|
|
//level.
|
|
|
|
#include "prc_inc_combat"
|
|
|
|
void DoFrightfulAttack(object oPC, object oTarget);
|
|
|
|
void DelayFrightfulAttackCheck(object oPC, object oTarget) {
|
|
if(GetIsDead(oTarget)) {
|
|
float fGFKSize = StringToFloat(Get2DACache("appearance","PREFATCKDIST",GetAppearanceType(oPC)));
|
|
object oNewTarget;
|
|
oNewTarget = MyFirstObjectInShape(SHAPE_SPHERE, fGFKSize, GetLocation(oPC), TRUE);
|
|
if ( GetIsObjectValid(oNewTarget) ) {
|
|
if ( oNewTarget == oPC ) {
|
|
oNewTarget = MyNextObjectInShape(SHAPE_SPHERE, fGFKSize, GetLocation(oPC), TRUE);
|
|
}
|
|
}
|
|
if ( GetIsObjectValid(oNewTarget) ) {
|
|
if ( oNewTarget != oPC ) {
|
|
if ( GetCanSneakAttack(oNewTarget,oPC)) {
|
|
DoFrightfulAttack(oPC, oNewTarget);
|
|
} else {
|
|
effect eEffect;
|
|
PerformAttack(oNewTarget,oPC,eEffect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DoFrightfulAttack(object oPC, object oTarget) {
|
|
|
|
//Does the GFK have frightful cleave yet?
|
|
int iGFKFrightfulCleave = GetHasFeat( FEAT_FRIGHTFUL_CLEAVE, oPC );
|
|
|
|
//What is the GFK class level?
|
|
int iGFKClassLevel = GetLevelByClass(CLASS_TYPE_GHOST_FACED_KILLER, oPC);
|
|
|
|
//What is the GFK character level?
|
|
int iGFKCharacterLevel = GetHitDice(oPC);
|
|
|
|
//What is the Cha modifier?
|
|
int iGFKCharModifier = GetAbilityModifier(ABILITY_CHARISMA, oPC);
|
|
|
|
//What is the Hit Dice of the target?
|
|
int iTargetHD = GetHitDice(oTarget);
|
|
|
|
//Can the GFK use a Sudden Strike? (sneak attack)
|
|
int iSuddenStrike = GetCanSneakAttack(oTarget, oPC);
|
|
if ( ! iSuddenStrike ) {
|
|
//Replace all of these with FloatingTextStrRefOnCreature() later.
|
|
FloatingTextStrRefOnCreature(16832361, oPC, FALSE);
|
|
//FloatingTextStringOnCreature("Frightful Attack must be a Sudden Strike (Sneak Attack).", oPC, FALSE);
|
|
IncrementRemainingFeatUses(oPC, FEAT_FRIGHTFUL_ATTACK);
|
|
}
|
|
|
|
//What level of Power Attack did the GFK use while making this attack?
|
|
//Not sure if this is correct.
|
|
int iDamageBonus = GetLocalInt(oPC, "PRC_PowerAttack_Level");
|
|
if ( GetActionMode(oPC, ACTION_MODE_POWER_ATTACK) ) {
|
|
iDamageBonus = 5;
|
|
}
|
|
if ( GetActionMode(oPC, ACTION_MODE_IMPROVED_POWER_ATTACK) ) {
|
|
iDamageBonus = 10;
|
|
}
|
|
if ( iDamageBonus <= 0 ) {
|
|
//Replace all of these with FloatingTextStrRefOnCreature() later.
|
|
FloatingTextStrRefOnCreature(16832362, oPC, FALSE);
|
|
//FloatingTextStringOnCreature("Power Attack must be active to use Frightful Attack.", oPC, FALSE);
|
|
IncrementRemainingFeatUses(oPC, FEAT_FRIGHTFUL_ATTACK);
|
|
}
|
|
|
|
|
|
//Is the target immune to mind-affecting effects?
|
|
int iTargetIMA = GetIsImmune(oTarget, IMMUNITY_TYPE_MIND_SPELLS, OBJECT_INVALID);
|
|
|
|
//Is the target immune to fear?
|
|
int iTargetIF = GetIsImmune(oTarget, IMMUNITY_TYPE_FEAR, OBJECT_INVALID);
|
|
|
|
if ( iSuddenStrike && iDamageBonus > 0 ) {
|
|
effect eEffect;
|
|
if ( ! iTargetIF && ! iTargetIMA ) {
|
|
if ( iTargetHD < iGFKCharacterLevel ) {
|
|
//We use PerformAttack from prc_inc_combat to make this easier
|
|
//eShaken = EffectShaken();
|
|
//eDeath = EffectDeath(TRUE,FALSE);
|
|
int iSave = PRCMySavingThrow( SAVING_THROW_WILL, oTarget, 10 + iGFKClassLevel + iGFKCharModifier, SAVING_THROW_TYPE_FEAR);
|
|
if ( iSave < 2 ) {
|
|
if ( iSave == 0 ) {
|
|
eEffect = EffectDeath(TRUE,FALSE);
|
|
}
|
|
else if (GetHasMettle(oTarget, SAVING_THROW_WILL)) // Ignores partial effects
|
|
{
|
|
eEffect = EffectVisualEffect(VFX_IMP_WILL_SAVING_THROW_USE);
|
|
}
|
|
else
|
|
{
|
|
eEffect = EffectShaken();
|
|
}
|
|
PerformAttack(oTarget, oPC, eEffect, IntToFloat(iGFKClassLevel));
|
|
} else {
|
|
//Should NEVER enter this code, but here for sanity
|
|
PerformAttack(oTarget, oPC, eEffect);
|
|
//Replace all of these with FloatingTextStrRefOnCreature() later.
|
|
FloatingTextStrRefOnCreature(16832363, oPC, FALSE);
|
|
//FloatingTextStringOnCreature("Failed Frightful Attack: Target is immune to fear.", oPC, FALSE);
|
|
}
|
|
} else {
|
|
PerformAttack(oTarget, oPC, eEffect);
|
|
//Replace all of these with FloatingTextStrRefOnCreature() later.
|
|
FloatingTextStrRefOnCreature(16832364, oPC, FALSE);
|
|
//FloatingTextStringOnCreature("Failed Frightful Attack: Target has too many Hit Dice.", oPC, FALSE);
|
|
}
|
|
} else {
|
|
PerformAttack(oTarget, oPC, eEffect);
|
|
//Replace all of these with FloatingTextStrRefOnCreature() later.
|
|
//16832365
|
|
//FloatingTextStringOnCreature("Failed Frightful Attack: Target must not be immune to sneak attacks, mind affecting effects, or fear.", oPC, FALSE);
|
|
FloatingTextStrRefOnCreature(16832365, oPC, FALSE);
|
|
}
|
|
//Frighten the onlookers.
|
|
|
|
//int nDamage;
|
|
effect eVis = EffectVisualEffect(VFX_IMP_FEAR_S);
|
|
effect eFearE = EffectFrightened();
|
|
effect eShakenE = EffectShaken();
|
|
effect eMind = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR);
|
|
effect eImpact = EffectVisualEffect(VFX_FNF_LOS_NORMAL_20);
|
|
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
|
|
float fDelay;
|
|
float fDuration = RoundsToSeconds( iGFKClassLevel );
|
|
//Link the fear and mind effects
|
|
effect eLink1 = EffectLinkEffects(eFearE, eMind);
|
|
effect eFear = EffectLinkEffects(eLink1, eDur);
|
|
effect eLink2 = EffectLinkEffects(eShakenE, eMind);
|
|
effect eShaken = EffectLinkEffects(eLink2, eDur);
|
|
|
|
//Apply Impact
|
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, GetSpellTargetLocation());
|
|
object oCurrentTarget;
|
|
//Get first target in the spell cone
|
|
oCurrentTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetSpellTargetLocation(), TRUE);
|
|
while(GetIsObjectValid(oCurrentTarget)) {
|
|
fDelay = PRCGetRandomDelay();
|
|
//The victim (oTarget) the Ghost-Faced Killer (oPC), and allies of the Ghost-Faced Killer are unaffected.
|
|
if((oCurrentTarget != oTarget) && (!GetIsFriend(oCurrentTarget, oPC)) && (oCurrentTarget != oPC)) {
|
|
//Make a will save
|
|
if(!PRCMySavingThrow(SAVING_THROW_WILL, oCurrentTarget, 10 + iGFKClassLevel + iGFKCharModifier + iDamageBonus, SAVING_THROW_TYPE_FEAR, OBJECT_SELF, fDelay)) {
|
|
//Apply the linked effects and the VFX impact
|
|
int iCurrentHD = GetHitDice( oCurrentTarget );
|
|
if ( iCurrentHD < ( iGFKClassLevel + iGFKCharModifier ) ) {
|
|
DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFear, oCurrentTarget, fDuration, TRUE, -1, -1));
|
|
} else {
|
|
DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShaken, oCurrentTarget, fDuration, TRUE, -1, -1));
|
|
}
|
|
}
|
|
}
|
|
//Get next target in the spell cone
|
|
oCurrentTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetSpellTargetLocation(), TRUE);
|
|
}
|
|
}
|
|
|
|
//delay this to see if we need to cleave
|
|
if(iGFKFrightfulCleave) {
|
|
DelayCommand(0.01, DelayFrightfulAttackCheck(oPC, oTarget));
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
object oPC = OBJECT_SELF;
|
|
object oTarget = PRCGetSpellTargetObject();
|
|
//Is the player trying to Frightful Attack himself?
|
|
if(oPC == oTarget) {
|
|
IncrementRemainingFeatUses(oPC, FEAT_FRIGHTFUL_ATTACK);
|
|
return;
|
|
}
|
|
DoFrightfulAttack(oPC, oTarget);
|
|
}
|
|
|