//::///////////////////////////////////////////////
//:: Tome of Battle include: Initiating
//:: tob_inc_move
//::///////////////////////////////////////////////
/** @file
    Defines structures and functions for handling
    initiating a maneuver

    @author Stratovarius
    @date   Created - 2007.3.20
    @thanks to Ornedan for his work on Psionics upon which this is based.
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////


//////////////////////////////////////////////////
/*                 Constants                    */
//////////////////////////////////////////////////

const string TOB_DEBUG_IGNORE_CONSTRAINTS = "TOB_DEBUG_IGNORE_CONSTRAINTS";

/**
 * The variable in which the maneuver token is stored. If no token exists,
 * the variable is set to point at the initiator itself. That way OBJECT_INVALID
 * means the variable is unitialised.
 */
const string PRC_MANEVEUR_TOKEN_VAR  = "PRC_ManeuverToken";
const string PRC_MANEVEUR_TOKEN_NAME = "PRC_MOVETOKEN";
const float  PRC_MANEVEUR_HB_DELAY   = 0.5f;


//////////////////////////////////////////////////
/*                 Structures                   */
//////////////////////////////////////////////////

/**
 * A structure that contains common data used during maneuver.
 */
struct maneuver{
    /* Generic stuff */
    /// The creature Truespeaking the Maneuver
    object oInitiator;
    /// Whether the maneuver is successful or not
    int bCanManeuver;
    /// The creature's initiator level in regards to this maneuver
    int nInitiatorLevel;
    /// The maneuver's spell ID
    int nMoveId;
};

//////////////////////////////////////////////////
/*             Function prototypes              */
//////////////////////////////////////////////////

/**
 * Determines if the maneuver that is currently being attempted to be TrueSpoken
 * can in fact be truespoken. Determines metamaneuvers used.
 *
 * @param oInitiator  A creature attempting to truespeak a maneuver at this moment.
 * @param oTarget       The target of the maneuver, if any. For pure Area of Effect.
 *                      maneuvers, this should be OBJECT_INVALID. Otherwise the main
 *                      target of the maneuver as returned by PRCGetSpellTargetObject().
 *
 * @return              A maneuver structure that contains the data about whether
 *                      the maneuver was successfully initiated and some other
 *                      commonly used data, like the PC's initiator level for this maneuver.
 */
struct maneuver EvaluateManeuver(object oInitiator, object oTarget = OBJECT_INVALID, int bTOBAbility = FALSE);

/**
 * Causes OBJECT_SELF to use the given maneuver.
 *
 * @param nManeuver         The index of the maneuver to use in spells.2da or an UTTER_*
 * @param nClass         The index of the class to use the maneuver as in classes.2da or a CLASS_TYPE_*
 * @param nLevelOverride An optional override to normal initiator level.
 *                       Default: 0, which means the parameter is ignored.
 */
void UseManeuver(int nManeuver, int nClass, int nLevelOverride = 0);

/**
 * A debugging function. Takes a maneuver structure and
 * makes a string describing the contents.
 *
 * @param move A set of maneuver data
 * @return      A string describing the contents of move
 */
string DebugManeuver2Str(struct maneuver move);

/**
 * Stores a maneuver structure as a set of local variables. If
 * a structure was already stored with the same name on the same object,
 * it is overwritten.
 *
 * @param oObject The object on which to store the structure
 * @param sName   The name under which to store the structure
 * @param move   The maneuver structure to store
 */
void SetLocalManeuver(object oObject, string sName, struct maneuver move);

/**
 * Retrieves a previously stored maneuver structure. If no structure is stored
 * by the given name, the structure returned is empty.
 *
 * @param oObject The object from which to retrieve the structure
 * @param sName   The name under which the structure is stored
 * @return        The structure built from local variables stored on oObject under sName
 */
struct maneuver GetLocalManeuver(object oObject, string sName);

/**
 * Deletes a stored maneuver structure.
 *
 * @param oObject The object on which the structure is stored
 * @param sName   The name under which the structure is stored
 */
void DeleteLocalManeuver(object oObject, string sName);

/**
 * Checks whether the maneuver is a class ability
 *
 * @param nMoveId The SpellID
 *
 * @return        TRUE if it is a class ability, FALSE otherwise
 */
int GetIsTOBAbility(int nMoveId);

//////////////////////////////////////////////////
/*                  Includes                    */
//////////////////////////////////////////////////

#include "tob_inc_martlore"
#include "tob_inc_recovery"

//////////////////////////////////////////////////
/*             Internal functions               */
//////////////////////////////////////////////////

/** Internal function.
 * Deletes maneuver-related local variables.
 *
 * @param oInitiator The creature currently initiating a maneuver
 */
void _CleanManeuverVariables(object oInitiator)
{
    DeleteLocalInt(oInitiator, PRC_INITIATING_CLASS);
    DeleteLocalInt(oInitiator, PRC_MANEUVER_LEVEL);
    DeleteLocalInt(oInitiator, "PCIsInitiating");
}

/** Internal function.
 * Determines whether a maneuver token exists. If one does, returns it.
 *
 * @param oInitiator A creature whose maneuver token to get
 * @return            The maneuver token if it exists, OBJECT_INVALID otherwise.
 */
object _GetManeuverToken(object oInitiator)
{
    object oMoveToken = GetLocalObject(oInitiator, PRC_MANEVEUR_TOKEN_VAR);

    // If the token object is no longer valid, set the variable to point at initiator
    if(!GetIsObjectValid(oMoveToken))
    {
        oMoveToken = oInitiator;
        SetLocalObject(oInitiator, PRC_MANEVEUR_TOKEN_VAR, oMoveToken);
    }


    // Check if there is no token
    if(oMoveToken == oInitiator)
        oMoveToken = OBJECT_INVALID;

    return oMoveToken;
}

/** Internal function.
 * Destroys the given maneuver token and sets the creature's maneuver token variable
 * to point at itself.
 *
 * @param oInitiator The initiator whose token to destroy
 * @param oMoveToken    The token to destroy
 */
void _DestroyManeuverToken(object oInitiator, object oMoveToken)
{
    DestroyObject(oMoveToken);
    if(DEBUG) DoDebug("_DestroyManeuverToken(): Destroying Token");
    SetLocalObject(oInitiator, PRC_MANEVEUR_TOKEN_VAR, oInitiator);
}

/** Internal function.
 * Destroys the previous maneuver token, if any, and creates a new one.
 *
 * @param oInitiator A creature for whom to create a maneuver token
 * @return            The newly created token
 */
object _CreateManeuverToken(object oInitiator)
{
    object oMoveToken = _GetManeuverToken(oInitiator);
    object oStore   = GetObjectByTag("PRC_MANIFTOKEN_STORE"); //GetPCSkin(oInitiator);

    // Delete any previous tokens
    if(GetIsObjectValid(oMoveToken))
        _DestroyManeuverToken(oInitiator, oMoveToken);

    // Create new token and store a reference to it
    oMoveToken = CreateItemOnObject(PRC_MANEVEUR_TOKEN_NAME, oStore);
    SetLocalObject(oInitiator, PRC_MANEVEUR_TOKEN_VAR, oMoveToken);

    Assert(GetIsObjectValid(oMoveToken), "GetIsObjectValid(oMoveToken)", "ERROR: Unable to create maneuver token! Store object: " + DebugObject2Str(oStore), "true_inc_Utter", "_CreateManeuverToken()");

    return oMoveToken;
}

/** Internal function.
 * Determines whether the given initiator is doing something that would
 * interrupt initiating a maneuver or affected by an effect that would do
 * the same.
 *
 * @param oInitiator A creature on which _ManeuverHB() is running
 * @return            TRUE if the creature can continue initiating,
 *                    FALSE otherwise
 */
int _ManeuverStateCheck(object oInitiator)
{
    if(GetIsDead(oInitiator)) return FALSE;
    int nAction = GetCurrentAction(oInitiator);
    // If the current action is not among those that could either be used to truespeak the maneuver or movement, the maneuver fails
    if(!(nAction || ACTION_CASTSPELL     || nAction == ACTION_INVALID      ||
         nAction || ACTION_ITEMCASTSPELL || nAction == ACTION_MOVETOPOINT  ||
         nAction || ACTION_USEOBJECT     || nAction == ACTION_WAIT
       ) )
        return FALSE;

    // Affected by something that prevents one from initiating
    effect eTest = GetFirstEffect(oInitiator);
    int nEType;
    while(GetIsEffectValid(eTest))
    {
        nEType = GetEffectType(eTest);
        if(nEType == EFFECT_TYPE_CUTSCENE_PARALYZE ||
           nEType == EFFECT_TYPE_DAZED             ||
           nEType == EFFECT_TYPE_PARALYZE          ||
           nEType == EFFECT_TYPE_PETRIFY           ||
           nEType == EFFECT_TYPE_SLEEP             ||
           nEType == EFFECT_TYPE_STUNNED
           )
            return FALSE;

        // Get next effect
        eTest = GetNextEffect(oInitiator);
    }

    return TRUE;
}

/** Internal function.
 * Runs while the given creature is initiating. If they move, take other actions
 * that would cause them to interrupt initiating the maneuver or are affected by an
 * effect that would cause such interruption, deletes the maneuver token.
 * Stops if such condition occurs or something else destroys the token.
 *
 * @param oInitiator A creature initiating a maneuver
 * @param lInitiator The location where the initiator was when starting the maneuver
 * @param oMoveToken    The maneuver token that controls the ongoing maneuver
 */
void _ManeuverHB(object oInitiator, location lInitiator, object oMoveToken)
{
    float fDistance;
    if(DEBUG) DoDebug("_ManeuverHB() running:\n"
                    + "oInitiator = " + DebugObject2Str(oInitiator) + "\n"
                    + "lInitiator = " + DebugLocation2Str(lInitiator) + "\n"
                    + "oMoveToken = " + DebugObject2Str(oMoveToken) + "\n"
                    + "Distance between maneuver start location and current location: " + FloatToString(GetDistanceBetweenLocations(lInitiator, GetLocation(oInitiator))) + "\n"
                      );
    if(GetIsObjectValid(oMoveToken))
    {
        // Continuance check
        fDistance = GetDistanceBetweenLocations(lInitiator, GetLocation(oInitiator));
        if(fDistance > 2.0f || fDistance < 0.0 || // Allow some variance in the location to account for dodging and random fidgeting
           !_ManeuverStateCheck(oInitiator)                                       // Action and effect check
           )
        {
            if(DEBUG) DoDebug("_ManeuverHB(): initiator moved or lost concentration, destroying token");
            _DestroyManeuverToken(oInitiator, oMoveToken);

            // Inform initiator
            FloatingTextStringOnCreature("You have lost concentration on the maneuver you were attempting to initiate!", oInitiator, FALSE);
        }
        // Schedule next HB
        else
            DelayCommand(PRC_MANEVEUR_HB_DELAY, _ManeuverHB(oInitiator, lInitiator, oMoveToken));
    }
}

/** Internal function.
 * Checks if the initiator is in range to use the maneuver they are trying to use.
 * If not, queues commands to make the initiator to run into range.
 *
 * @param oInitiator A creature initiating a maneuver
 * @param nManeuver      SpellID of the maneuver being initiated
 * @param lTarget     The target location or the location of the target object
 */
void _ManeuverRangeCheck(object oInitiator, int nManeuver, location lTarget)
{
    float fDistance   = GetDistanceBetweenLocations(GetLocation(oInitiator), lTarget);
    float fRangeLimit;
    string sRange     = Get2DACache("spells", "Range", nManeuver);

    // Personal range maneuvers are always in range
    if(sRange == "P")
        return;
    // Ranges according to the CCG spells.2da page
    else if(sRange == "T")
        fRangeLimit = 2.25f;
    else if(sRange == "S")
        fRangeLimit = 8.0f;
    else if(sRange == "M")
        fRangeLimit = 20.0f;
    else if(sRange == "L")
        fRangeLimit = 40.0f;

    // See if we are out of range
    if(fDistance > fRangeLimit)
    {
        // Create waypoint for the movement
        object oWP = CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", lTarget);

        // Move into range, with a bit of fudge-factor
        //ActionMoveToObject(oWP, TRUE, fRangeLimit - 0.15f);

        // CleanUp
        ActionDoCommand(DestroyObject(oWP));

        // CleanUp, paranoia
        AssignCommand(oWP, ActionDoCommand(DestroyObject(oWP, 60.0f)));
    }
}

/** Internal function.
 * Assigns the fakecast command that is used to display the conjuration VFX when using an maneuver.
 * Separated from UseManeuver() due to a bug with ActionFakeCastSpellAtObject(), which requires
 * use of ClearAllActions() to work around.
 * The problem is that if the target is an item on the ground, if the actor is out of spell
 * range when doing the fakecast, they will run on top of the item instead of to the edge of
 * the spell range. This only happens if there was a "real action" in the actor's action queue
 * immediately prior to the fakecast.
 */
void _AssignUseManeuverFakeCastCommands(object oInitiator, object oTarget, location lTarget, int nSpellID)
{
    // Nuke actions to prevent the fakecast action from bugging
    ClearAllActions();

    if(GetIsObjectValid(oTarget))
        ActionCastFakeSpellAtObject(nSpellID, oTarget, PROJECTILE_PATH_TYPE_DEFAULT);
    else
        ActionCastFakeSpellAtLocation(nSpellID, lTarget, PROJECTILE_PATH_TYPE_DEFAULT);
}


/** Internal function.
 * Places the cheatcasting of the real maneuver into the initiator's action queue.
 */
void _UseManeuverAux(object oInitiator, object oMoveToken, int nSpellId,
                  object oTarget, location lTarget,
                  int nManeuver, int nClass, int nLevelOverride)
{
    if(DEBUG) DoDebug("_UseManeuverAux() running:\n"
                    + "oInitiator = " + DebugObject2Str(oInitiator) + "\n"
                    + "oMoveToken = " + DebugObject2Str(oMoveToken) + "\n"
                    + "nSpellId = " + IntToString(nSpellId) + "\n"
                    + "oTarget = " + DebugObject2Str(oTarget) + "\n"
                    + "lTarget = " + DebugLocation2Str(lTarget) + "\n"
                    + "nManeuver = " + IntToString(nManeuver) + "\n"
                    + "nClass = " + IntToString(nClass) + "\n"
                    + "nLevelOverride = " + IntToString(nLevelOverride) + "\n"
                      );

    // Make sure nothing has interrupted this maneuver
    if(GetIsObjectValid(oMoveToken))
    {
        if(DEBUG) DoDebug("_UseManeuverAux(): Token was valid, queueing actual maneuver");
        // Set the class to maneuver as
        SetLocalInt(oInitiator, PRC_INITIATING_CLASS, nClass + 1);

        // Set the maneuver's level
        SetLocalInt(oInitiator, PRC_MANEUVER_LEVEL, StringToInt(lookup_spell_innate(nSpellId)));

        if(nLevelOverride != 0)
            AssignCommand(oInitiator, ActionDoCommand(SetLocalInt(oInitiator, PRC_CASTERLEVEL_OVERRIDE, nLevelOverride)));
        if(GetIsObjectValid(oTarget))
            AssignCommand(oInitiator, ActionCastSpellAtObject(nManeuver, oTarget, METAMAGIC_NONE, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
        else
            AssignCommand(oInitiator, ActionCastSpellAtLocation(nManeuver, lTarget, METAMAGIC_NONE, TRUE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
        if(nLevelOverride != 0)
            AssignCommand(oInitiator, ActionDoCommand(DeleteLocalInt(oInitiator, PRC_CASTERLEVEL_OVERRIDE)));

        // Begins the Crusader Granting Maneuver process
        if (nClass == CLASS_TYPE_CRUSADER)
        {
            BeginCrusaderGranting(oInitiator);
            //if(DEBUG) DoDebug("_UseManeuverAux(): BeginCrusaderGranting");
        }
        
        SetLocalInt(oInitiator, "PCIsInitiating", TRUE);
        // Destroy the maneuver token for this maneuver
        _DestroyManeuverToken(oInitiator, oMoveToken);
    }
}

int _GetIsManeuverWeaponAppropriate(object oInitiator)
{
    object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator);
    // If the initiator is empty handed, unarmed strikes are good
    if (!GetIsObjectValid(oItem)) return TRUE;
    // If melee weapon, all good.
    if (IPGetIsMeleeWeapon(oItem)) return TRUE;
    // Add other legal items in here, like Bloodstorm Blade throwing

    // If one of the other's hasn't tripped, fail here
    return FALSE;
}

void _StanceSpecificChecks(object oInitiator, int nMoveId)
{
    int nStanceToKeep = -1;
    if (GetLevelByClass(CLASS_TYPE_WARBLADE, oInitiator) >= 20)
    {
        nStanceToKeep = GetHasActiveStance(oInitiator);
    }
    if (GetLevelByClass(CLASS_TYPE_DEEPSTONE_SENTINEL, oInitiator) >= 3 &&
        GetHasSpellEffect(MOVE_MOUNTAIN_FORTRESS, oInitiator) &&
        GetDisciplineByManeuver(nMoveId) == DISCIPLINE_STONE_DRAGON)
    {
        nStanceToKeep = GetHasActiveStance(oInitiator);
    }
    // Master of Nine can keep two stances active for 2 rounds per class level.
    if (GetLevelByClass(CLASS_TYPE_MASTER_OF_NINE, oInitiator) >= 3 && GetLocalInt(oInitiator, "MoNDualStance"))
    {
        nStanceToKeep = GetHasActiveStance(oInitiator);
        float fDelay = 12.0 * GetLevelByClass(CLASS_TYPE_MASTER_OF_NINE, oInitiator);
        // Clean up the stance when the timer runs out
        DelayCommand(fDelay, ClearStances(oInitiator, -1));
        DeleteLocalInt(oInitiator, "MoNDualStance");
    }

    //if(DEBUG) DoDebug("tob_inc_move: ClearStances");
    if(nStanceToKeep == nMoveId)
        nStanceToKeep = -1;
    // Can only have one stance active, except for a level 20+ Warblade
    ClearStances(oInitiator, nStanceToKeep);

    // Mark current stance as atcive
    MarkStanceActive(oInitiator, nMoveId);
}

//////////////////////////////////////////////////
/*             Function definitions             */
//////////////////////////////////////////////////

struct maneuver EvaluateManeuver(object oInitiator, object oTarget = OBJECT_INVALID, int bTOBAbility = FALSE)
{
    /* Get some data */
    // initiator-related stuff
    int nInitiatorLevel  = GetInitiatorLevel(oInitiator);
    int nManeuverLevel   = GetManeuverLevel(oInitiator);
    int nClass           = GetInitiatingClass(oInitiator);

    /* Initialise the maneuver structure */
    struct maneuver move;
    move.oInitiator      = oInitiator;
    move.bCanManeuver    = TRUE; // Assume successfull maneuver by default
    move.nInitiatorLevel = nInitiatorLevel;
    move.nMoveId         = PRCGetSpellId();

    //if(DEBUG) DoDebug("move.bCanManeuver: " + IntToString(move.bCanManeuver));
    // Skip doing anything if something has prevented a successful maneuver already by this point
    if(/*move.bCanManeuver && */bTOBAbility == FALSE) // set up identification later
    {
        // If you're this far in, you always succeed, there are very few checks.
        // Deletes any active stances, and allows a Warblade 20 to have his two stances active.
        /* GC - TMI is being caused from GetIsStance being run on the swordsage. Let's not run it twice.*/
        if (GetIsStance(move.nMoveId)) _StanceSpecificChecks(oInitiator, move.nMoveId);
        else ExpendManeuver(move.oInitiator, nClass, move.nMoveId);
        // Allows the Master of Nine to Counter Stance.
        if(GetManeuverType(move.nMoveId) == MANEUVER_TYPE_COUNTER
        && GetLevelByClass(CLASS_TYPE_MASTER_OF_NINE, oInitiator) >= 4)
        {
            SetLocalInt(oInitiator, "MoNCounterStance", TRUE);
            DelayCommand(6.0, DeleteLocalInt(oInitiator, "MoNCounterStance"));
        }
        //if(DEBUG) DoDebug("tob_inc_move: _StanceSpecificChecks");
        // Expend the Maneuver until recovered
        //if (!GetIsStance(move.nMoveId)) ExpendManeuver(move.oInitiator, nClass, move.nMoveId);
        //if(DEBUG) DoDebug("tob_inc_move: ExpendManeuver");
        // Do Martial Lore data
        IdentifyManeuver(move.oInitiator, move.nMoveId);
        //if(DEBUG) DoDebug("tob_inc_move: IdentifyManeuver");
        IdentifyDiscipline(move.oInitiator);
        //if(DEBUG) DoDebug("tob_inc_move: IdentifyDiscipline");

    }//end if

    if(DEBUG) DoDebug("EvaluateManeuver(): Final result:\n" + DebugManeuver2Str(move));

    // Initiate maneuver-related variable CleanUp
    DelayCommand(0.5f, _CleanManeuverVariables(oInitiator));

    return move;
}

void UseManeuver(int nManeuver, int nClass, int nLevelOverride = 0)
{
    object oInitiator  = OBJECT_SELF;
    object oSkin       = GetPCSkin(oInitiator);
    object oTarget     = PRCGetSpellTargetObject();
    object oMoveToken;
    location lTarget   = PRCGetSpellTargetLocation();
    int nSpellID       = PRCGetSpellId();
    
    // Divine Surge Greater hardcoding to fix radial issue
    // Yes it's deliberate that it's both
    if (nSpellID == 15840 || nSpellID == 16051 || nSpellID == 16262)
    {
        nManeuver = MOVE_DS_GREATER_DIVINE_SURGE;
        nSpellID  = MOVE_DS_GREATER_DIVINE_SURGE;
    }    
    
	// Hardcoding to make Reth Dekala maneuvers work without forcing a massive redo of everything        
	if (nSpellID == 19331) nManeuver = MOVE_DS_MARTIAL_SPIRIT;        
	else if (nSpellID == 19332) nManeuver = MOVE_DS_THICKET_BLADES;
	else if (nSpellID == 19333) nManeuver = MOVE_DS_DAUNTING_STRIKE;
	else if (nSpellID == 19334) nManeuver = MOVE_TC_DEATH_FROM_ABOVE;
	else if (nSpellID == 19335) nManeuver = MOVE_IH_DISARMING_STRIKE;
	else if (nSpellID == 19336) nManeuver = MOVE_DS_ENTANGLING_BLADE;
	else if (nSpellID == 19337) nManeuver = MOVE_IH_WALL_BLADES;    
    
    if (DEBUG) DoDebug(GetName(oInitiator)+" initiating "+IntToString(nManeuver)+" on "+GetName(oTarget));
    
    float fDistance = MetersToFeet(GetDistanceBetweenLocations(GetLocation(oInitiator), GetLocation(oTarget)));
    float fDelay = FeetToMeters(fDistance)/10;
    
    // Moved the checks here, so they don't use an action.  

    // Don't hit yourself, dumbass    
    if (Get2DACache("feat", "TARGETSELF", GetClassFeatFromPower(nManeuver, nClass)) != "1" && oInitiator == oTarget && nSpellID != 19331 && nSpellID != 19332 && nSpellID != 19337)
    {
        //if(DEBUG) DoDebug("tob_inc_move: _GetTargetSelfStrike");
        FloatingTextStringOnCreature("You cannot target yourself with this maneuver.", oInitiator, FALSE);
        return;    
    }
    // If the weapon is not appropriate, fail.
    if (!_GetIsManeuverWeaponAppropriate(oInitiator))
    {
        //if(DEBUG) DoDebug("tob_inc_move: _GetIsManeuverWeaponAppropriate");
        FloatingTextStringOnCreature("You do not have an appropriate weapon to initiate this maneuver.", oInitiator, FALSE);
        return;
    }
    // If the maneuver is not readied, fail.
    // Stances don't need to be readied
    if (!GetIsManeuverReadied(oInitiator, nClass, nManeuver) && !GetIsStance(nManeuver) && !GetIsTOBAbility(nManeuver))
    {
        //if(DEBUG) DoDebug("tob_inc_move: GetIsManeuverReadied");
        FloatingTextStringOnCreature(GetManeuverName(nManeuver) + " is not readied.", oInitiator, FALSE);
        return;
    }
    // If the maneuver is expended, fail.
    if (GetIsManeuverExpended(oInitiator, nClass, nManeuver) && !GetIsTOBAbility(nManeuver))
    {
        //if(DEBUG) DoDebug("tob_inc_move: GetIsManeuverExpended");
        FloatingTextStringOnCreature(GetManeuverName(nManeuver) + " is already expended.", oInitiator, FALSE);
        return;
    }
    // If the PC is in a Warblade recovery round, fail
    if (GetIsWarbladeRecoveryRound(oInitiator))
    {
        //if(DEBUG) DoDebug("tob_inc_move: GetIsWarbladeRecoveryRound");
        FloatingTextStringOnCreature(GetName(oInitiator) + " is recovering Warblade maneuvers.", oInitiator, FALSE);
        return;
    }
    // Is the maneuver granted, and is the class a Crusader
    if (nClass == CLASS_TYPE_CRUSADER && !GetIsManeuverGranted(oInitiator, nManeuver) && !GetIsStance(nManeuver) && !GetIsTOBAbility(nManeuver))
    {
        //if(DEBUG) DoDebug("tob_inc_move: GetIsManeuverGranted");
        FloatingTextStringOnCreature(GetManeuverName(nManeuver) + " is not a granted maneuver.", oInitiator, FALSE);
        return;
    }    

    // These maneuvers don't have a delay otherwise, because the distance is always 0    
    if (Get2DACache("feat", "TARGETSELF", GetClassFeatFromPower(nManeuver, nClass)) == "1" && GetManeuverType(nManeuver) == MANEUVER_TYPE_STRIKE)
        fDelay = 3.0;

    // Dual Boost check
    if(GetManeuverType(nManeuver) == MANEUVER_TYPE_BOOST // If the maneuver is a boost
    && GetLocalInt(oInitiator, "SSDualBoost"))           // And the initiator can Dual boost.
    {
        // Set the maneuver time to 0 to skip VFX
        DeleteLocalInt(oInitiator, "SSDualBoost");
        fDelay = 0.0;
    }
    // Stance of Alacrity check
    // Only works on Counters, not Boosts
    else if(GetManeuverType(nManeuver) == MANEUVER_TYPE_COUNTER // If the maneuver is counter
    && GetHasSpellEffect(MOVE_DM_STANCE_ALACRITY, oInitiator))  // And the initiator has the stance
    {
        // Set the maneuver time to 0 to skip VFX
        fDelay = 0.0;
    }
    else if((Get2DACache("feat", "Constant", GetClassFeatFromPower(nManeuver, nClass)) == "SWIFT_ACTION" // Normally swift action maneuvers check
    || GetManeuverType(nManeuver) == MANEUVER_TYPE_BOOST
    || GetManeuverType(nManeuver) == MANEUVER_TYPE_COUNTER
    || GetManeuverType(nManeuver) == MANEUVER_TYPE_STANCE) // The maneuver is swift action to use
    && GetLocalInt(oInitiator, "RKVDivineImpetus")                                               // And the initiator can take a swift action now
       )
    {
        fDelay = 0.0;
        DeleteLocalInt(oInitiator, "RKVDivineImpetus");
    }
    else if(GetManeuverType(nManeuver) == MANEUVER_TYPE_STANCE && // The maneuver is a stance
       GetLocalInt(oInitiator, "MoNCounterStance")                                                          // Has used a counter already this round
       )
    {
        fDelay = 0.0;
        DeleteLocalInt(oInitiator, "MoNCounterStance");
    }
    else if((Get2DACache("feat", "Constant", GetClassFeatFromPower(nManeuver, nClass)) == "SWIFT_ACTION" // Normally swift action maneuvers check
    || GetManeuverType(nManeuver) == MANEUVER_TYPE_BOOST
    || GetManeuverType(nManeuver) == MANEUVER_TYPE_COUNTER
    || GetManeuverType(nManeuver) == MANEUVER_TYPE_STANCE)) // The maneuver is swift action to use
    {
        if (TakeSwiftAction(oInitiator)) // And the initiator can take a swift action now
            fDelay = 0.0;
        else
            return;
    }
    
    if (nManeuver == MOVE_DW_BURNING_BRAND)
        fDelay = FeetToMeters(fDistance*2)/10; // Because of how it has to be implemented.

    if(DEBUG) DoDebug("UseManeuver(): initiator is " + DebugObject2Str(oInitiator) + "\n"
                    + "nManeuver = " + IntToString(nManeuver) + "\n"
                    + "nClass = " + IntToString(nClass) + "\n"
                    + "nLevelOverride = " + IntToString(nLevelOverride) + "\n"
                    + "maneuver duration = " + FloatToString(fDelay) + "ms \n"
                    //+ "Token exists = " + DebugBool2String(GetIsObjectValid(oMoveToken))
                      );

    // Create the maneuver token. Deletes any old tokens and cancels corresponding maneuvers as a side effect
    oMoveToken = _CreateManeuverToken(oInitiator);

    /// @todo Hook to the initiator's OnDamaged event for the concentration checks to avoid losing the maneuver

    // Nuke action queue to prevent cheating with creative maneuver stacking.
    // Probably not necessary anymore - Ornedan
    if(DEBUG) SendMessageToPC(oInitiator, "Clearing all actions in preparation for second stage of the maneuver.");
    ClearAllActions();

    // If out of range, move to range
    _ManeuverRangeCheck(oInitiator, nManeuver, GetIsObjectValid(oTarget) ? GetLocation(oTarget) : lTarget);

    // Start the maneuver monitor HB
    DelayCommand(fDelay, ActionDoCommand(_ManeuverHB(oInitiator, GetLocation(oInitiator), oMoveToken)));
    if(DEBUG) DoDebug("Starting _ManeuverHB");

    // Assuming the spell isn't used as a swift action, fakecast for visuals
    if(fDelay > 0.0)
    {
        // Hack. Workaround of a bug with the fakecast actions. See function comment for details
        ActionDoCommand(_AssignUseManeuverFakeCastCommands(oInitiator, oTarget, lTarget, nSpellID));
        if(DEBUG) DoDebug("Starting _AssignUseManeuverFakeCastCommands");
    }

    if(DEBUG) DoDebug("Starting _UseManeuverAux");
    // Action queue the function that will cheatcast the actual maneuver
    DelayCommand(fDelay, AssignCommand(oInitiator, ActionDoCommand(_UseManeuverAux(oInitiator, oMoveToken, nSpellID, oTarget, lTarget, nManeuver, nClass, nLevelOverride))));
}

string DebugManeuver2Str(struct maneuver move)
{
    string sRet;

    sRet += "oInitiator = " + DebugObject2Str(move.oInitiator) + "\n";
    sRet += "bCanManeuver = " + DebugBool2String(move.bCanManeuver) + "\n";
    sRet += "nInitiatorLevel = "  + IntToString(move.nInitiatorLevel);

    return sRet;
}

void SetLocalManeuver(object oObject, string sName, struct maneuver move)
{
    //SetLocal (oObject, sName + "_", );
    SetLocalObject(oObject, sName + "_oInitiator", move.oInitiator);

    SetLocalInt(oObject, sName + "_bCanManeuver",      move.bCanManeuver);
    SetLocalInt(oObject, sName + "_nInitiatorLevel",   move.nInitiatorLevel);
    SetLocalInt(oObject, sName + "_nSpellID",          move.nMoveId);
}

struct maneuver GetLocalManeuver(object oObject, string sName)
{
    struct maneuver move;
    move.oInitiator = GetLocalObject(oObject, sName + "_oInitiator");

    move.bCanManeuver      = GetLocalInt(oObject, sName + "_bCanManeuver");
    move.nInitiatorLevel  = GetLocalInt(oObject, sName + "_nInitiatorLevel");
    move.nMoveId          = GetLocalInt(oObject, sName + "_nSpellID");

    return move;
}

void DeleteLocalManeuver(object oObject, string sName)
{
    DeleteLocalObject(oObject, sName + "_oInitiator");

    DeleteLocalInt(oObject, sName + "_bCanManeuver");
    DeleteLocalInt(oObject, sName + "_nInitiatorLevel");
    DeleteLocalInt(oObject, sName + "_nSpellID");
}

void ManeuverDebugIgnoreConstraints(object oInitiator)
{
    SetLocalInt(oInitiator, TOB_DEBUG_IGNORE_CONSTRAINTS, TRUE);
    DelayCommand(0.0f, DeleteLocalInt(oInitiator, TOB_DEBUG_IGNORE_CONSTRAINTS));
}

int GetIsTOBAbility(int nMoveId)
{
    // Shadow Sun Ninja and Eternal Blade class abilities
    if(nMoveId == 19320 ||
       nMoveId == 19321 ||
       nMoveId == 19322 ||
       nMoveId == 19323 ||
       nMoveId == 19324 ||
       nMoveId == 19325 ||
       nMoveId == 19326 ||
       nMoveId == 19316 ||
       nMoveId == 19315 ||
       nMoveId == 19314 ||
       nMoveId == 19317 ||
       nMoveId == 19318 ||
       nMoveId == 19319)
        return TRUE;

    return FALSE;
}

// Test main
//void main(){}
