Further file organization
Further file organization
This commit is contained in:
261
nwn/nwnprc/trunk/scripts/prc_sleat_edrain.nss
Normal file
261
nwn/nwnprc/trunk/scripts/prc_sleat_edrain.nss
Normal file
@@ -0,0 +1,261 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Soul Eater: Energy Drain
|
||||
//:: prc_sleat_edrain
|
||||
//:://////////////////////////////////////////////
|
||||
/** @file
|
||||
Implements all of the Soul Eater's Energy Drain
|
||||
-related abilities.
|
||||
|
||||
Energy Drain (Su): A soul eater gains the ability to drain energy, bestowing
|
||||
negative levels upon it's victims. Beginning at 1st level, the touch of a
|
||||
soul eater bestows one negative level on it's target. At 7th level, the
|
||||
soul eater bestows two negative levels with a touch.
|
||||
|
||||
Soul Strength (Su): When a 2nd-level soul eater uses it's energy drain
|
||||
ability, it gains a +4 bonus to Strenth for 24 hours.
|
||||
|
||||
Soul Enhancement (Su): When a 4th-level soul eater uses it's energy drain
|
||||
ability, it gains a +2 enhancement bonus on all saving throws and skill
|
||||
checks for 24 hours.
|
||||
|
||||
Soul Endurance (Su): When a 5nd-level soul eater uses it's energy drain
|
||||
ability, it gains a +4 bonus to Constitution for 24 hours.
|
||||
|
||||
Soul Radiance (Su): If a 6th-level soul eater completely drains a creature
|
||||
of energy, it may adopt the creature's soul radiance, taking the victim's
|
||||
form, appearance, and abilities for 24 hours.
|
||||
|
||||
Soul Agility (Su): When a 8th-level soul eater uses it's energy drain
|
||||
ability, it gains a +4 bonus to Dexterity for 24 hours.
|
||||
|
||||
Soul Slave (Su): If a 9th-level soul eater completely drains a creature of
|
||||
energy, the victim becomes a wight under the command of the soul eater.
|
||||
|
||||
Soul Power (Su): After a 10th-level soul eater has drained energy, all
|
||||
spell-like and supernatural abilities gain a +2 profane bonus to their
|
||||
saving throw DC for 24 hours. Further, it may use it's Soul Blast ability
|
||||
up to two times instead of one during that 24-hour period.
|
||||
|
||||
@date Modified - 04.12.2006
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "prc_inc_sp_tch"
|
||||
#include "prc_inc_shifting"
|
||||
#include "prc_spell_const"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function prototypes */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void DoEnergyDrain(object oEater, object oTarget, int nDamage);
|
||||
void DoDeathDependent(object oEater, object oTarget, string sResRef, string sName);
|
||||
void LevelUpWight(int nTargetLevel, object oCreature);
|
||||
void IncrementMarker(object oEater);
|
||||
void DecrementMarker(object oEater);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function definitions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void main()
|
||||
{
|
||||
object oEater = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
object oItem = PRCGetSpellCastItem();
|
||||
effect eImpact = EffectVisualEffect(VFX_IMP_REDUCE_ABILITY_SCORE);
|
||||
int nDrain = GetLevelByClass(CLASS_TYPE_SOUL_EATER, oEater) < 7 ? 1 : 2;
|
||||
|
||||
// Sanity check - can't affect self or dead stuff. Also, check PvP limits
|
||||
if(oTarget == oEater ||
|
||||
GetIsDead(oTarget) ||
|
||||
!spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oEater)
|
||||
)
|
||||
return;
|
||||
|
||||
// Let the target's AI know about hostile action
|
||||
SignalEvent(oTarget, EventSpellCastAt(oEater, PRCGetSpellId(), TRUE));
|
||||
|
||||
int bHit = FALSE;
|
||||
if (GetIsObjectValid(oItem))
|
||||
{
|
||||
//If happening due to an On Hit Cast Spell: skip the touch attack (we've already touched when we hit)
|
||||
//Have to use local variable on the item because GetSpellCastItem() can return valid object from
|
||||
//previously cast spells that are not this spell at all.
|
||||
//TODO: Is there a better way to do this?
|
||||
bHit = GetLocalInt(oItem, "PRC_SOULEATER_ONHIT_ENERGYDRAIN");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Melee touch attack to actually do anything
|
||||
bHit = PRCDoMeleeTouchAttack(oTarget, TRUE, oEater);
|
||||
}
|
||||
|
||||
if(bHit)
|
||||
{
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oTarget);
|
||||
DoEnergyDrain(oEater, oTarget, nDrain);
|
||||
}
|
||||
}
|
||||
|
||||
void DoEnergyDrain(object oEater, object oTarget,int nDamage)
|
||||
{
|
||||
// Immunity prevents anything from actually happening
|
||||
if(!GetIsImmune(oTarget, IMMUNITY_TYPE_NEGATIVE_LEVEL))
|
||||
{
|
||||
// Apply the actual drain
|
||||
effect eDrain = SupernaturalEffect(EffectNegativeLevel(nDamage));
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDrain, oTarget);
|
||||
|
||||
// Update marker
|
||||
IncrementMarker(oEater);
|
||||
DelayCommand(HoursToSeconds(24), DecrementMarker(oEater));
|
||||
|
||||
|
||||
/// Soul X side effects
|
||||
// Clear out old effects
|
||||
PRCRemoveSpellEffects(PRCGetSpellId(), oEater, oEater);
|
||||
|
||||
// Generate new effects
|
||||
int nClassLevel = GetLevelByClass(CLASS_TYPE_SOUL_EATER, oEater);
|
||||
effect eSideEffect = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
|
||||
|
||||
// Soul Strength
|
||||
if(nClassLevel >= 2)
|
||||
{
|
||||
eSideEffect = EffectLinkEffects(eSideEffect, EffectAbilityIncrease(ABILITY_STRENGTH, 4));
|
||||
}
|
||||
|
||||
// Soul Enchancement
|
||||
if(nClassLevel >= 4)
|
||||
{
|
||||
eSideEffect = EffectLinkEffects(eSideEffect, EffectSavingThrowIncrease(SAVING_THROW_TYPE_ALL, 2));
|
||||
eSideEffect = EffectLinkEffects(eSideEffect, EffectSkillIncrease(SKILL_ALL_SKILLS, 2));
|
||||
}
|
||||
|
||||
// Soul Endurance
|
||||
if(nClassLevel >= 5)
|
||||
{
|
||||
eSideEffect = EffectLinkEffects(eSideEffect, EffectAbilityIncrease(ABILITY_CONSTITUTION, 4));
|
||||
}
|
||||
|
||||
// Soul Agility
|
||||
if(nClassLevel >= 8)
|
||||
{
|
||||
eSideEffect = EffectLinkEffects(eSideEffect, EffectAbilityIncrease(ABILITY_DEXTERITY, 4));
|
||||
}
|
||||
|
||||
// Apply the gathered side effects. All the abilities are supernatural and last 24h
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,
|
||||
SupernaturalEffect(eSideEffect),
|
||||
oEater,
|
||||
HoursToSeconds(24)
|
||||
);
|
||||
|
||||
|
||||
// Soul Power
|
||||
// Rebalanced to give +2 to all DCs and just double Soul Blast uses, due to it not being sanely
|
||||
// possible to find out all use-limited abilities one may have
|
||||
if(nClassLevel >= 10)
|
||||
{
|
||||
// +2 DCs
|
||||
// Handled based on "PRC_SoulEater_HasDrained" and class level in the relevant places
|
||||
|
||||
// 2x special abilities uses
|
||||
//IncrementRemainingFeatUses(oEater, FEAT_SLEAT_SBLAST); // Handled via 2da instead
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Soul Radiance and Soul Slave work only if the target was killed.
|
||||
// And death by level loss only gets calculated once the script has terminated.
|
||||
// Therefore, delay by 0.0
|
||||
DelayCommand(0.0f, DoDeathDependent(oEater, oTarget, GetResRef(oTarget), GetName(oTarget)));
|
||||
}
|
||||
else
|
||||
FloatingTextStrRefOnCreature(16832115, oEater, FALSE); // "Target is immune to negative levels"
|
||||
}
|
||||
|
||||
void DoDeathDependent(object oEater, object oTarget, string sResRef, string sName)
|
||||
{
|
||||
// For anything to happen here, the target needs to be dead. And if it is, due to having only been delayed by 0
|
||||
// we know that the only reason for it's death can have been level drain
|
||||
if(GetIsDead(oTarget))
|
||||
{
|
||||
// Soul Radiance
|
||||
if(GetLevelByClass(CLASS_TYPE_SOUL_EATER, oEater) >= 6)
|
||||
{
|
||||
// If the user has toggled Soul Radiance active, use the shifting code to turn into the target
|
||||
if(GetLocalInt(oEater, "PRC_SoulEater_SoulRadianceActive"))
|
||||
{
|
||||
StoreCurrentAppearanceAsTrueAppearance(oEater, TRUE);
|
||||
ShiftIntoCreature(oEater, SHIFTER_TYPE_SOULEATER, oTarget, TRUE); // Gain special abilities
|
||||
//TODO: only if there are uses left
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Soul Slave
|
||||
if(GetLevelByClass(CLASS_TYPE_SOUL_EATER, oEater) >= 9)
|
||||
{
|
||||
int nMaxHenchmen = GetMaxHenchmen();
|
||||
int nNumSlaves = 0;
|
||||
int nMaxSlaves = GetPRCSwitch(PRC_SOUL_EATER_MAX_SLAVES);
|
||||
effect eSummon = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD);
|
||||
|
||||
// Special switch values handling
|
||||
if(nMaxSlaves == 0 ) nMaxSlaves = 4;
|
||||
if(nMaxSlaves == -1) nMaxSlaves = 0;
|
||||
|
||||
// Determine current number of slaves
|
||||
int i = 1;
|
||||
object oHench;
|
||||
do {
|
||||
oHench = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oEater, i++);
|
||||
if(GetResRef(oHench) == "soul_wight_test")
|
||||
nNumSlaves++;
|
||||
} while(GetIsObjectValid(oHench));
|
||||
|
||||
// If we can add more wights, do so. Spawn the wight with some VFX at the corpse's location
|
||||
if(nNumSlaves < nMaxSlaves)
|
||||
{
|
||||
location lSpawn = GetLocation(oTarget);
|
||||
|
||||
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eSummon, lSpawn);
|
||||
|
||||
object oSlave = CreateObject(OBJECT_TYPE_CREATURE, "soul_wight_test", lSpawn);
|
||||
if(GetIsObjectValid(oSlave))
|
||||
{
|
||||
SetMaxHenchmen(max(nMaxHenchmen, i)); // Temporarily set the number of max henchmen high enough that we can add another
|
||||
AddHenchman(oEater, oSlave);
|
||||
SetMaxHenchmen(nMaxHenchmen);
|
||||
|
||||
// Level up the wight a bit to make it usefull. Needs to be delayed a bit to let the object creation routines happen first
|
||||
DelayCommand(3.0f, LevelUpWight(GetHitDice(oEater) - 3, oSlave));
|
||||
}
|
||||
else if(DEBUG)
|
||||
DoDebug("prc_sleat_edrain: ERROR: Failed to create wight at location " + DebugLocation2Str(lSpawn));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelUpWight(int nTargetLevel, object oCreature)
|
||||
{
|
||||
int n;
|
||||
for(n = 1; n < nTargetLevel; n++)
|
||||
LevelUpHenchman(oCreature, CLASS_TYPE_INVALID, TRUE);
|
||||
}
|
||||
|
||||
void IncrementMarker(object oEater)
|
||||
{
|
||||
SetLocalInt(oEater, "PRC_SoulEater_HasDrained", GetLocalInt(oEater, "PRC_SoulEater_HasDrained") + 1);
|
||||
}
|
||||
|
||||
void DecrementMarker(object oEater)
|
||||
{
|
||||
SetLocalInt(oEater, "PRC_SoulEater_HasDrained", GetLocalInt(oEater, "PRC_SoulEater_HasDrained") - 1);
|
||||
}
|
Reference in New Issue
Block a user