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.
115 lines
4.7 KiB
Plaintext
115 lines
4.7 KiB
Plaintext
/*
|
|
15/02/19 by Stratovarius
|
|
|
|
Dark Air
|
|
|
|
Initiate, Elemental Shadows
|
|
Level/School: 5th/Transmutation [Air]
|
|
|
|
Reaching out with your mind to the darkness attached to your soul, you infuse nature with shadow and compel it to do your will.
|
|
|
|
This mystery acts like the spell control wind, tossing creatures about and knocking them to the ground if they fail a reflex save.
|
|
*/
|
|
|
|
#include "shd_inc_shdfunc"
|
|
#include "shd_mysthook"
|
|
|
|
void DoRandomMove(object oTarget)
|
|
{
|
|
// Calculate the new location
|
|
object oArea = GetArea(oTarget);
|
|
float fDistance = FeetToMeters(10.0f * d4());
|
|
float fAngle = IntToFloat(Random(3600)) / 10.0;
|
|
float fFacing = IntToFloat(Random(3600)) / 10.0;
|
|
vector vOrigin = GetPosition(oTarget);
|
|
vector vAngle = AngleToVector(fAngle);
|
|
vector vTarget = vOrigin + (vAngle * fDistance);
|
|
|
|
// If there is blocking geometry on the way, determine where
|
|
if(!LineOfSightVector(vOrigin, vTarget))
|
|
{
|
|
float fEpsilon = 1.0f; // Search precision
|
|
float fLowerBound = 0.0f; // The lower search bound, initialise to 0
|
|
float fUpperBound = fDistance; // The upper search bound, initialise to the initial distance
|
|
fDistance = fDistance / 2; // The search position, set to middle of the range
|
|
|
|
do{
|
|
// Create test vector for this iteration
|
|
vTarget = vOrigin + (vAngle * fDistance);
|
|
|
|
// Determine which bound to move.
|
|
if(LineOfSightVector(vOrigin, vTarget))
|
|
fLowerBound = fDistance;
|
|
else
|
|
fUpperBound = fDistance;
|
|
|
|
// Get the new middle point
|
|
fDistance = (fUpperBound + fLowerBound) / 2;
|
|
}while(fabs(fUpperBound - fLowerBound) > fEpsilon);
|
|
}// end if - The location was blocked by geometry
|
|
|
|
// Create the final target vector
|
|
vTarget = vOrigin + (vAngle * fDistance);
|
|
|
|
// Move the target
|
|
int bCommandable = GetCommandable(oTarget);
|
|
location lTargetDestination = Location(oArea, vTarget, fFacing);
|
|
float fDelay = PRCGetRandomDelay();
|
|
|
|
// Set commandable if it isn't already
|
|
/* if(!bCommandable)
|
|
SetCommandable(TRUE, oTarget);*/
|
|
|
|
// Assign jump commands
|
|
AssignCommand(oTarget, ClearAllActions(TRUE));
|
|
AssignCommand(oTarget, JumpToLocation(lTargetDestination));
|
|
|
|
// Set commandability off it it was off in the beginning
|
|
/* if(!bCommandable)
|
|
AssignCommand(oTarget, ActionDoCommand(SetCommandable(FALSE, oTarget)));*/
|
|
/*DoDebug("DoRandomMove(): Jumping creature " + DebugObject2Str(oTarget) + "\n"
|
|
+ "Old location = " + DebugLocation2Str(GetLocation(oTarget)) + "\n"
|
|
+ "New location = " + DebugLocation2Str(lTargetDestination) + "\n"
|
|
+ "Commandability = " + DebugBool2String(bCommandable) + "\n"
|
|
);*/
|
|
// Do some VFX during the jump delay
|
|
DrawLineFromVectorToVector(DURATION_TYPE_INSTANT, VFX_IMP_WIND, oArea, vOrigin, vTarget, 0.0f,
|
|
FloatToInt(GetDistanceBetweenLocations(GetLocation(oTarget), lTargetDestination)), // One VFX every meter
|
|
fDelay
|
|
);
|
|
}
|
|
|
|
void main()
|
|
{
|
|
if(!ShadPreMystCastCode()) return;
|
|
|
|
object oShadow = OBJECT_SELF;
|
|
object oTarget = PRCGetSpellTargetObject();
|
|
location lTarget = PRCGetSpellTargetLocation();
|
|
struct mystery myst = EvaluateMystery(oShadow, oTarget, METASHADOW_NONE);
|
|
|
|
if(myst.bCanMyst)
|
|
{
|
|
//ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_STORM), lTarget);
|
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_TORNADO), lTarget);
|
|
oTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0f), lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
|
while(GetIsObjectValid(oTarget))
|
|
{
|
|
if(spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, oShadow))
|
|
{
|
|
// Let the AI know
|
|
PRCSignalSpellEvent(oTarget, TRUE, myst.nMystId, oShadow);
|
|
|
|
if (!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, GetShadowcasterDC(oShadow), SAVING_THROW_TYPE_SPELL))
|
|
{
|
|
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, 6.0, TRUE, myst.nMystId, myst.nShadowcasterLevel);
|
|
SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_PULSE_WIND), oTarget);
|
|
}// end if - Reflex save
|
|
DoRandomMove(oTarget);
|
|
}// end if - Difficulty check
|
|
|
|
// Get next target
|
|
oTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0f), lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
|
}// end while - Explosion target loop
|
|
}
|
|
} |