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.
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
|
|
}
|
|
} |