Files
PRC8/nwn/nwnprc/trunk/spells/nw_s2_turndead.nss
Jaysyn904 88ed27dd37 Marrusalts are large creatures
Marrusalts are large creatures.  Updated Vow of Poverty to function more like Pen & Paper.  (@fencas) Updated release archive.
2025-01-21 07:40:49 -05:00

278 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//::///////////////////////////////////////////////
//:: Turn Undead
//:: NW_S2_TurnDead
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Checks domain powers and class to determine
the proper turning abilities of the casting
character.
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Nov 2, 2001
//:: Updated On: Jul 15, 2003 - Georg Zoeller
//:://////////////////////////////////////////////
/*
308 - turn undead
1726 - Turn_Scaleykind
1727 - Turn_Slime
1728 - Turn_Spider
1729 - Turn_Plant
1730 - Turn_Air
1731 - Turn_Earth
1732 - Turn_Fire
1733 - Turn_Water
1734 - Turn_Blightspawned
2259 - turn outsider
3497 - Turn cold
*/
#include "prc_inc_clsfunc"
#include "prc_inc_domain"
#include "prc_inc_turning"
#include "prc_inc_factotum"
void main()
{
int nTurnType = GetSpellId();
if(nTurnType == VESTIGE_TENEBROUS_TURN)
{
if(!BindAbilCooldown(OBJECT_SELF, GetSpellId(), VESTIGE_TENEBROUS)) return;
nTurnType = SPELL_TURN_UNDEAD;
}
if(nTurnType == SPELL_OPPORTUNISTIC_PIETY_TURN)
{
if (!ExpendInspiration(OBJECT_SELF, 1))
{
IncrementRemainingFeatUses(OBJECT_SELF, FEAT_OPPORTUNISTIC_PIETY_TURN);
return;
}
// We know we can cast it now
nTurnType = SPELL_TURN_UNDEAD;
DecrementRemainingFeatUses(OBJECT_SELF, FEAT_OPPORTUNISTIC_PIETY_HEAL);
}
// Because Turn Undead/Outsider isn't from a domain, skip this check
if(nTurnType != SPELL_TURN_UNDEAD && nTurnType != SPELL_TURN_OUTSIDER)
{
// Used by the uses per day check code for bonus domains
if(!DecrementDomainUses(GetTurningDomain(nTurnType), OBJECT_SELF))
return;
}
int bUndeadMastery = GetHasFeat(FEAT_UNDEAD_MASTERY);
//casters level for turning
int nLevel = GetTurningClassLevel(OBJECT_SELF, nTurnType);
int nCommandLevel = bUndeadMastery ? nLevel * 10 : nLevel;
//check alignment - we will need that later
int nAlign = GetAlignmentGoodEvil(OBJECT_SELF);
//casters charisma modifier
int nChaMod = GetTurningCharismaMod(nTurnType);
//key values for turning
int nTurningTotalHD = d6(2) + nLevel + nChaMod;
int nTurningCheck = d20() + nChaMod;
if(nTurnType == SPELL_TURN_UNDEAD) // Hallow spell, +4 for turning, -4 for commanding undead
{
if (nAlign == ALIGNMENT_EVIL && GetLocalInt(OBJECT_SELF, "HallowTurn")) nTurningCheck -= 4;
else if (GetLocalInt(OBJECT_SELF, "HallowTurn")) nTurningCheck += 4;
}
int nTurningMaxHD = GetTurningCheckResult(nLevel, nTurningCheck);
//these stack but dont multiply
//so use a bonus amount and then add that on later
//apply maximize turning
//+100% if good
if((GetHasFeat(FEAT_MAXIMIZE_TURNING) && nAlign == ALIGNMENT_GOOD)
|| GetLocalInt(OBJECT_SELF,"vMaximizeNextTurn"))
{
nTurningTotalHD += nTurningTotalHD;
DeleteLocalInt(OBJECT_SELF,"vMaximizeNextTurn");
DecrementRemainingFeatUses(OBJECT_SELF, FEAT_ML_MAXIMIZE_TURNING);
}
//apply empowered turning
//+50%
//only if maximize doesnt apply
else if(GetHasFeat(FEAT_EMPOWER_TURNING))
nTurningTotalHD += nTurningTotalHD/2;
// Evil clerics rebuke, not turn, and have a different VFX
effect eImpactVis = nAlign == ALIGNMENT_EVIL ? EffectVisualEffect(VFX_FNF_LOS_EVIL_30):
EffectVisualEffect(VFX_FNF_LOS_HOLY_30);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpactVis, GetLocation(OBJECT_SELF));
//zone of animation effect
//"You can use a rebuke or command undead attempt to animate
//corpses within range of your rebuke or command attempt.
//You animate a total number of HD of undead equal to the
//number of undead that would be commanded by your result
//(though you cant animate more undead than there are available
//corpses within range). You cant animate more undead with
//any single attempt than the maximum number you can command
//(including any undead already under your command). These
//undead are automatically under your command, though your
//normal limit of commanded undead still applies. If the
//corpses are relatively fresh, the animated undead are zombies.
//Otherwise, they are skeletons."
//currently implemented ignoring corpses & what the corpses are of.
if(GetLocalInt(OBJECT_SELF, "UsingZoneOfAnimation"))
{
//Undead Mastery multiplies total HD by 10
int bUndeadMastery = GetHasFeat(FEAT_UNDEAD_MASTERY);
if(bUndeadMastery)
nLevel *= 10;
//keep creating stuff
int nCommandedTotalHD = GetCommandedTotalHD(nTurnType, bUndeadMastery);
while(nCommandedTotalHD < nTurningTotalHD)
{
//skeletal blackguard
string sResRef = "x2_s_bguard_18";
object oCreated = CreateObject(OBJECT_TYPE_CREATURE, sResRef, GetLocation(OBJECT_SELF));
int nTargetHD = GetHitDiceForTurning(oCreated, nTurnType, RACIAL_TYPE_UNDEAD);
if(nCommandedTotalHD + nTargetHD <= nLevel)
{
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD), GetLocation(oCreated));
DoCommand(oCreated);
CorpseCrafter(OBJECT_SELF, oCreated);
nCommandedTotalHD += nTargetHD;
}
//cant be commanded, clean it up
else
DestroyObject(oCreated);
}
//send feedback
FloatingTextStringOnCreature("Currently commanding "+IntToString(nCommandedTotalHD)+"HD out of "+IntToString(nLevel)+"HD.", OBJECT_SELF, FALSE);
return;
}
FloatingTextStringOnCreature("You are turning "+IntToString(nTurningTotalHD)+"HD of creatures whose HD is equal or less than "+IntToString(nTurningMaxHD), OBJECT_SELF, FALSE);
int bDisplayCommandMessage = -1;
int nCommandedTotalHD = GetCommandedTotalHD(nTurnType, bUndeadMastery);
int nHDCount, nTurnOrRebuke, nTargetHD, nTargetRace;
int i = 1;
object oTest = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, OBJECT_SELF, i);
if (GetEssentiaInvestedFeat(OBJECT_SELF, FEAT_AZURE_TURNING) && nTurnType == SPELL_TURN_UNDEAD)
{
while(GetIsObjectValid(oTest) && GetDistanceToObject(oTest) < 20.0)
{
nTargetRace = MyPRCGetRacialType(oTest);
if(nTargetRace == RACIAL_TYPE_UNDEAD && nTurningMaxHD >= GetHitDiceForTurning(oTest, nTurnType, nTargetRace))
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d8(GetEssentiaInvestedFeat(OBJECT_SELF, FEAT_AZURE_TURNING)), DAMAGE_TYPE_DIVINE), oTest);
}
//move to next test
i++;
oTest = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, OBJECT_SELF, i);
}
}
i = 1;
oTest = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, OBJECT_SELF, i);
while(GetIsObjectValid(oTest) && nHDCount < nTurningTotalHD && GetDistanceToObject(oTest) < 20.0)//20 m = 60 ft
{
nTargetRace = MyPRCGetRacialType(oTest);
nTurnOrRebuke = GetIsTurnOrRebuke(oTest, nTurnType, nTargetRace);
if(nTurnOrRebuke)
{
int nTargetHD = GetHitDiceForTurning(oTest, nTurnType, nTargetRace);
if(nTargetHD <= nTurningMaxHD && nHDCount+nTargetHD <= nTurningTotalHD)
{
nHDCount += nTargetHD;
//signal the event
SignalEvent(oTest, EventSpellCastAt(OBJECT_SELF, nTurnType));
//sun domain
//destroys instead of turn/rebuke/command
//useable once per day only
if(GetLocalInt(OBJECT_SELF, "UsingSunDomain"))
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_SUNSTRIKE), oTest);
//Do not destroy until this script finishes, otherwise GetNearestCreature() will not work correctly
DelayCommand(0.0, DoDestroy(oTest));
}
else
{
if(nTurnOrRebuke == ACTION_TURN)
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_SUNSTRIKE), oTest);
//if half of level, destroy
//otherwise turn
if(nTargetHD < nLevel/2)
DelayCommand(0.0, DoDestroy(oTest));
else
DoTurn(oTest);
}
else
{
bDisplayCommandMessage = TRUE;
//if half of level, command
//otherwise rebuke
if(nTargetHD < nLevel/2)
{
//undead mastery only applies to undead
//so non-undead have thier HD multiplied by 10
if(nTargetRace != RACIAL_TYPE_UNDEAD && bUndeadMastery)
nTargetHD *= 10;
if(nCommandedTotalHD + nTargetHD <= nCommandLevel)
{
nCommandedTotalHD += nTargetHD;
DoCommand(oTest);
}
//not enough commanding power left
//rebuke instead
else
DoRebuke(oTest);
}
else
DoRebuke(oTest);
}
}
// Check for Exalted Turning
// take 3d6 damage if they do
// Only works on undead
if(nAlign == ALIGNMENT_GOOD
&& nTargetRace == RACIAL_TYPE_UNDEAD
&& (GetHasFeat(FEAT_EXALTED_TURNING)) || GetPersistantLocalInt(OBJECT_SELF, "VoPFeat"+IntToString(FEAT_EXALTED_TURNING)))
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6(3), DAMAGE_TYPE_DIVINE), oTest);
}
//Check for Holy Fire
if(GetHasSpellEffect(SPELL_HOLY_FIRE, oTest))
{
int nFire = nTurningMaxHD / 2;
int nHoly = nTurningMaxHD - nFire;
effect eDam = EffectLinkEffects(EffectDamage(DAMAGE_TYPE_DIVINE, nHoly), EffectDamage(DAMAGE_TYPE_FIRE, nFire));
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTest);
}
}
}
//move to next test
i++;
oTest = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, OBJECT_SELF, i);
}
if(bDisplayCommandMessage)
FloatingTextStringOnCreature("Currently commanding "+IntToString(nCommandedTotalHD)+"HD out of "+IntToString(nCommandLevel)+"HD.", OBJECT_SELF, FALSE);
}