#include "xstp_inc_jump"
//#include "jump_include"

int TargetHasRequiredRing(object oTarget)
{
    object oLeftRing = GetItemInSlot(INVENTORY_SLOT_LEFTRING, oTarget);
    object oRightRing = GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oTarget);

    if (GetTag(oLeftRing) == "I_CAS_SLUTSNATCHER" || GetTag(oRightRing) == "I_CAS_SLUTSNATCHER")
    {
        return TRUE;
    }
    return FALSE;
}


void SpeakStringDelayed(object oTarget, string sString)
{
    ActionSpeakString(sString);
}


void JumpTarget(object oTarget, object oUser, float fFraction)
{
    location lIntermediate = GetIntermediateLocation(oTarget, oUser, fFraction);
    AssignCommand(oTarget, ActionJumpToLocation(lIntermediate));
}

// Custom function to move the target towards the activator



// Function to cycle the paralysis effect and jump
void CycleParalysisAndJump(object oTarget, object oUser, int nCycles, float fFraction)

{
    if (nCycles > 0)
    {
        // Apply the paralysis effect
        effect eImmobilize = EffectCutsceneImmobilize();
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmobilize, oTarget, 6.0);

        // Schedule to remove the paralysis effect and then jump
        DelayCommand(6.0, RemoveEffect(oTarget, eImmobilize));
        DelayCommand(6.0, JumpTarget(oTarget, oUser, fFraction));

        // Schedule the next cycle
        DelayCommand(7.0, CycleParalysisAndJump(oTarget, oUser, nCycles - 1, fFraction));
    }
}

int CheckValidErf(string sPrefix)
{
    if (sPrefix == "cac" ||
    sPrefix == "hvh" || 
    sPrefix == "mds" || 
    sPrefix == "poe" ||
    sPrefix == "scd" ||
    sPrefix == "ggd" ||
    sPrefix == "bhm")
    return FALSE;
    
    else return TRUE;
}

// Custom function to calculate the difference between two vectors
vector VectorDifference(vector v1, vector v2)
{
    return Vector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}

// Custom function to normalize a vector
vector VectorNormalize(vector v)
{
    float fMagnitude = sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
    if (fMagnitude == 0.0)
        return Vector(0.0, 0.0, 0.0);
    
    return Vector(v.x / fMagnitude, v.y / fMagnitude, v.z / fMagnitude);
}

void GradualPullTowardsActivator(object oTarget, object oActivator, int nCycle, float fTotalDistance)
{
    if (nCycle <= 0) return;

    float fFraction = 0.25 * (4 - nCycle); // Fraction of the total distance for this cycle
    float fDistanceToMove = fFraction * fTotalDistance; // Distance to move in this cycle

    vector vTargetPos = GetPosition(oTarget);
    vector vActivatorPos = GetPosition(oActivator);

    vector vDirection = VectorNormalize(VectorDifference(vActivatorPos, vTargetPos));
    vector vNewPos = Vector(
        vTargetPos.x + vDirection.x * fDistanceToMove,
        vTargetPos.y + vDirection.y * fDistanceToMove,
        vTargetPos.z + vDirection.z * fDistanceToMove
    );

    location lNewTargetLocation = Location(GetArea(oTarget), vNewPos, GetFacing(oTarget));
    AssignCommand(oTarget, ActionJumpToLocation(lNewTargetLocation));

    DelayCommand(6.0, GradualPullTowardsActivator(oTarget, oActivator, nCycle - 1, fTotalDistance));
}



void main()
{
    object oItem = GetEventParamObject(0);
    object oTarget = GetEventParamObject(1);
    object oUser = GetEventParamObject(2);
    
    // Retrieve the area object where the user is located
    object oArea = GetArea(oUser);

    // Check if XS_NO_JUMP_TOOL is set in this area
    int nNoJumpTool = GetLocalInt(oArea, "XS_NO_JUMP_TOOL");
    if (nNoJumpTool == 1)
    {
        SendMessageToPC(oUser, "The jump tool cannot be used in this area.");
        return;
    }
    
    // Check if the area is from a valid ERF
    string sPrefix = GetResRefErfPrefix(GetResRef(oArea));
    if (!CheckValidErf(sPrefix))
    {
        SendMessageToPC(oUser, "Jumpers can't be used in epic dungeons!");
        return;
    }

    // Check if the target has the required ring
    if (!TargetHasRequiredRing(oTarget))
    {
        SendMessageToPC(oUser, "Target does not have the required item equipped in either ring slot.");
        return;
    }

    // Check distance between user and target
    if(GetDistanceBetween(oUser, oTarget) > 20.0)
    {
        SendMessageToPC(oUser, "The target is too far away.");
        return;
    }

    // Apply visual effects
    effect eBeam = EffectBeam(VFX_BEAM_CHAIN, oUser, BODY_NODE_CHEST);
    effect eEntangleVFX = EffectVisualEffect(VFX_DUR_ENTANGLE);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBeam, oTarget, 24.0);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEntangleVFX, oTarget, 24.0);

    // Immobilize the target
    effect eImmobilize = EffectCutsceneImmobilize();
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmobilize, oTarget, 24.0);

    // Command the target to speak
    AssignCommand(oTarget, SpeakStringDelayed(oTarget, "I am immobilized and being pulled!"));

    // Start the process of moving the target towards the activator
    float fTotalDistance = GetDistanceBetween(oTarget, oUser);
    GradualPullTowardsActivator(oTarget, oUser, 4, fTotalDistance);
}
