//////////////////////////////////////////////
//	Author: Drammel							//
//	Date: 3/6/2009							//
//	Title: gui_execute_strike				//
//	Description: Enqueues strike maneuvers.	//
//////////////////////////////////////////////

#include "bot9s_inc_constants"
#include "bot9s_inc_maneuvers"
#include "bot9s_inc_misc"
#include "bot9s_inc_variables"
#include "bot9s_include"

void StrikeInRange(object oPC, object oTarget, float fRange, int nTarget, int nRow, int nLocation, float fPosX, float fPosY, float fPosZ)
{
	string sToB = GetFirstName(oPC) + "tob";
	object oToB = GetObjectByTag(sToB);
	
	location lPC = GetLocation(oPC);
	location lMelee = GetLocalLocation(oPC, "bot9s_pc_pos_strike");
	
	if ((lPC == lMelee) && (GetDistanceToObject(oTarget) <= (fRange + FeetToMeters(5.0f))))
	{
		if (nLocation == 1) // Object or Location as the target?
		{
			IndexManeuverPosition(nRow, fPosX, fPosY, fPosZ);
		}
		else if (IntToObject(nTarget) == OBJECT_INVALID)
		{
			return;
		}
		else IndexStrikeTarget(nRow, nTarget);

		SetLocalInt(oToB, "StrikeMoveStatus", 0);
		AssignCommand(oPC, SetStrike(nRow));
		ActionUseFeat(FEAT_STUDENT_OF_THE_SUBLIME_WAY, oPC);
	}
	
	if (GetLocalInt(oToB, "StrikeMoveStatus") == 1)
	{
		DelayCommand(0.3f, StrikeInRange(oPC, oTarget, fRange, nTarget, nRow, nLocation, fPosX, fPosY, fPosZ));
	}
}
		
void RunPCStrikePosition(object oPC)
{
	location lPC = GetLocation(oPC);
	string sToB = GetFirstName(oPC) + "tob";
	object oToB = GetObjectByTag(sToB);

	if (GetLocalInt(oToB, "StrikeMoveStatus") == 1)
	{
		SetLocalLocation(oPC, "bot9s_pc_pos_strike", lPC);
		DelayCommand(0.3f, RunPCStrikePosition(oPC));
	}
	else DeleteLocalLocation(oPC, "bot9s_pc_pos_strike");
}

void ChargeRules(object oPC, object oTarget, float fStart, float fRange, int nTarget, int nRow, int nLocation, float fPosX, float fPosY, float fPosZ)
{
	string sToB = GetFirstName(oPC) + "tob";
	object oToB = GetObjectByTag(sToB);
	string sManeuver = GetFirstName(oPC) + GetLocalString(oToB, "maneuvers_Script" + IntToString(nRow));
	object oManeuver = GetObjectByTag(sManeuver);
	int nSupressAoO = GetLocalInt(oManeuver, "SupressAoO");
	
	location lPC = GetLocation(oPC);
	location lCharge = GetLocalLocation(oPC, "bot9s_pc_pos_charge");
	vector vCharge = GetPositionFromLocation(lCharge);
	float fCharge = GetZ(vCharge);
	
	effect eSpeed = EffectMovementSpeedIncrease(99);
	effect eAC = EffectACDecrease(2);
	effect eCharge = EffectLinkEffects(eAC, eSpeed);
	eCharge = SupernaturalEffect(eCharge);

	float fDist;

	if (fRange > FeetToMeters(8.0f))
	{
		fDist = fRange; // A check for reach weapons.
	}
	else fDist = FeetToMeters(8.0f); // Max distance the engine still lets you make attacks at.

	if ((GetLocalInt(oToB, "ChargeStatus") == 1) && (lPC != lCharge) && (GetLocalInt(oToB, "ChargeSpeedCheck") == 0))
	{
		ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCharge, oPC, 6.0f);
		SetLocalInt(oToB, "ChargeSpeedCheck", 1);
	}

	if ((lPC == lCharge) && (GetDistanceToObject(oTarget) <= fDist))
	{
		if (nSupressAoO == 1)
		{
			if ((!IsInConversation(oPC)) || (GetNumCutsceneActionsPending() == 0))
			{
				ClearCombatOverrides(oPC);
			}
		}

		if (nLocation == 1) // Object or Location as the target?
		{
			IndexManeuverPosition(nRow, fPosX, fPosY, fPosZ);
		}
		else if (IntToObject(nTarget) == OBJECT_INVALID)
		{
			return;
		}
		else IndexStrikeTarget(nRow, nTarget);

		RemoveEffect(oPC, eCharge);
		DeleteLocalInt(oToB, "ChargeStatus");
		DeleteLocalInt(oToB, "ChargeSpeedCheck");
		AssignCommand(oPC, SetStrike(nRow));
		ActionUseFeat(FEAT_STUDENT_OF_THE_SUBLIME_WAY, oPC);
	}
	else if ((fCharge < fStart - 0.25f) || (fCharge > fStart + 0.25f)) //Accounts for small bumps that aren't technically what you'd call 'rough terrain'.
	{
		if (nSupressAoO == 1)
		{
			if ((!IsInConversation(oPC)) || (GetNumCutsceneActionsPending() == 0))
			{
				ClearCombatOverrides(oPC);
			}
		}

		if (CheckStanceChargeRules() == FALSE)
		{
			ActionForceMoveToLocation(GetLocation(oPC));
			RemoveEffect(oPC, eCharge);
			DeleteLocalInt(oToB, "ChargeStatus");
			DeleteLocalInt(oToB, "ChargeSpeedCheck");
			ClearAllActions();
			ClearStrikes();
			SendMessageToPC(oPC, "<color=red>You cannot charge over uneven terrain.</color>");
		}
	}
	
	if ((GetLocalInt(oToB, "ChargeStatus") == 1) && (lPC != lCharge))
	{
		DelayCommand(0.3f, ChargeRules(oPC, oTarget, fStart, fRange, nTarget, nRow, nLocation, fPosX, fPosY, fPosZ));
	}
	else SetLocalInt(oToB, "ChargeSpeedCheck", 0);
}

void RunPCChargePosition(object oPC)
{
	location lPC = GetLocation(oPC);
	string sToB = GetFirstName(oPC) + "tob";
	object oToB = GetObjectByTag(sToB);
	
	if (GetLocalInt(oToB, "ChargeStatus") == 1)
	{
		SetLocalLocation(oPC, "bot9s_pc_pos_charge", lPC);
		DelayCommand(0.3f, RunPCChargePosition(oPC));
	}
	else DeleteLocalLocation(oPC, "bot9s_pc_pos_charge");
}

void main(int nTarget, float fPosX, float fPosY, float fPosZ)
{
	object oOrigin = OBJECT_SELF;
	object oPC = GetControlledCharacter(oOrigin);
	string sToB = GetFirstName(oPC) + "tob";
	object oToB = GetObjectByTag(sToB);
	string sData = GetLocalString(oToB, "BlackBox");
	string sClass = GetStringRight(sData, 3);
	string sNumber;

	if ((GetCurrentHitPoints(oPC) < 1) || (GetLocalInt(oToB, "RedCrusader") == 1))
	{
		return;
	}

	if (GetSubString(sData, 1, 1) == "_") // Number of Digits
	{
		sNumber = GetStringLeft(sData, 1);
	}
	else sNumber = GetStringLeft(sData, 2);
	
	int nRow = GetLocalInt(oToB, "BlueBoxSTR" + sNumber + sClass);

	if (nRow == GetLocalInt(oToB, "Strike1") || nRow == GetLocalInt(oToB, "Strike2") ||
	nRow == GetLocalInt(oToB, "Strike3") || nRow == GetLocalInt(oToB, "Strike4") ||
	nRow == GetLocalInt(oToB, "Strike5") || nRow == GetLocalInt(oToB, "Strike6") ||
	nRow == GetLocalInt(oToB, "Strike7") || nRow == GetLocalInt(oToB, "Strike8") ||
	nRow == GetLocalInt(oToB, "Strike9") || nRow == GetLocalInt(oToB, "Strike10") ||
	nRow == GetLocalInt(oToB, "Strike11") || nRow == GetLocalInt(oToB, "Strike12") ||
	nRow == GetLocalInt(oToB, "Strike13") || nRow == GetLocalInt(oToB, "Strike14"))
	{
		SendMessageToPC(oPC, "<color=red>This strike is currently enqueued.  Please select another.</color>");
		return;
	}

	string sManeuver = GetFirstName(oPC) + GetLocalString(oToB, "maneuvers_Script" + IntToString(nRow));
	object oManeuver = GetObjectByTag(sManeuver); //Object and script names are intended to be identical.
	int nMovement = GetLocalInt(oManeuver, "Movement");
	int nLocation = GetLocalInt(oManeuver, "Location");

	if (nMovement == 0) // Does the maneuver require us to move?
	{
		if (nLocation == 1) // Object or Location as the target?
		{
			IndexManeuverPosition(nRow, fPosX, fPosY, fPosZ);
		}
		else if (IntToObject(nTarget) == OBJECT_INVALID)
		{
			return;
		}
		else IndexStrikeTarget(nRow, nTarget);

		AssignCommand(oPC, SetStrike(nRow));
		ActionUseFeat(FEAT_STUDENT_OF_THE_SUBLIME_WAY, oPC);
	}
	else if (nMovement == 2) // Is this a charge attack?
	{
		object oTarget = IntToObject(nTarget);
		object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
		float fRange = GetWeaponRange(oPC) + StringToFloat(Get2DAString("appearance", "HITDIST", GetAppearanceType(oTarget)));

		if ((GetDistanceBetween(oPC, oTarget) >= FeetToMeters(10.0f)) && (!GetWeaponRanged(oWeapon)))
		{
			if (LineOfSightObject(oPC, oTarget) == TRUE)
			{	
				vector vStart = GetPosition(oPC);
				float fStart = GetZ(vStart);
				int nSupressAoO = GetLocalInt(oManeuver, "SupressAoO");

				if (nSupressAoO == 1)
				{
					if ((!IsInConversation(oPC)) || (GetNumCutsceneActionsPending() == 0))
					{
						SetCombatOverrides(oPC, OBJECT_INVALID, -1, -1, OVERRIDE_ATTACK_RESULT_DEFAULT, -1, -1, TRUE, FALSE, FALSE, FALSE);
					}
				}

				// Special Cases

				if (nRow == STRIKE_DOOM_CHARGE)
				{
					effect eDoom = EffectVisualEffect(VFX_TOB_DOOMCHARGE);
					ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDoom, oPC, 6.0f);
				}
				else if (nRow == STRIKE_LAW_BEARER)
				{
					effect eBearer = EffectVisualEffect(VFX_TOB_LAWBEARER);
					ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBearer, oPC, 6.0f);
				}
				else if (nRow == STRIKE_RADIANT_CHARGE)
				{
					effect eRadiant = EffectVisualEffect(VFX_TOB_RADIANT_CHARGE);
					ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRadiant, oPC, 6.0f);
				}
				else if (nRow == STRIKE_TIDE_OF_CHAOS)
				{
					effect eTide = EffectVisualEffect(VFX_TOB_TIDEOFCHAOS);
					ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eTide, oPC, 6.0f);
				}

				ClearAllActions();
				AssignCommand(oPC, ClearStrikes()); // Just in case.  Loops never seem to agree with me.
				SetLocalInt(oToB, "ChargeStatus", 1);
				DelayCommand(6.0f, SetLocalInt(oToB, "ChargeStatus", 0));
				DelayCommand(0.1f, RunPCChargePosition(oPC));
				DelayCommand(0.5f, ChargeRules(oPC, oTarget, fStart, fRange, nTarget, nRow, nLocation, fPosX, fPosY, fPosZ));
				ActionMoveToObject(oTarget, TRUE, fRange);
			}
			else SendMessageToPC(oPC, "<color=red>You do not have line of sight to the target.</color>");
		}
		else SendMessageToPC(oPC, "<color=red>You must be at least ten feet away from the target and equipped with a melee weapon to make a charge.</color>");
	}
	else //Normal Movement.
	{
		float fRange;
		float fDefaultRange = FeetToMeters(GetLocalFloat(oManeuver, "Range"));
		object oTarget = IntToObject(nTarget);
		object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
		
		if (fDefaultRange > 0.0f) // Is there a preferred attack range?
		{
			fRange = FeetToMeters(fDefaultRange);
		}
		else fRange = GetWeaponRange(oPC) + StringToFloat(Get2DAString("appearance", "HITDIST", GetAppearanceType(oTarget)));

		// Special Cases

		if (nRow == STRIKE_BOUNDING_ASSAULT)
		{
			effect eSpeed = EffectMovementSpeedIncrease(99);
			eSpeed = ExtraordinaryEffect(eSpeed);

			ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSpeed, oPC, 6.0f);
		}
		else if (nRow == STRIKE_DEVASTATING_THROW)
		{
			float fCheck = GetDistanceBetween(oPC, oTarget);
	
			if (fCheck < FeetToMeters(15.0f))
			{
				SendMessageToPC(oPC, "<color=red>You must be at least 15 feet away from your target to initiate a Devastating Throw.</color>");
				return;
			}
		}
		else if (nRow == STRIKE_DSRTTEMP)
		{
			float fDsrtTemp = GetMeleeRange(oPC);

			SetLocalInt(oPC, "DesertTempestActive", 1);
			SetLocalInt(oToB, "DesertWindStrike", 1);
			DelayCommand(6.0f, SetLocalInt(oToB, "DesertWindStrike", 0));
			SetLocalLocation(oPC, "DesertTempestLoc", GetLocation(oPC));
			DelayCommand(0.1f, DoDesertTempestLoc());
			DoDesertTempest(fDsrtTemp);
			ExpendManeuver(5, "STR");// Too powerful if you can cancel the maneuver before it starts.
		}
		else if (nRow == STRIKE_SLMDRCHRG)
		{
			if ((GetDistanceBetween(oPC, oTarget) <= FeetToMeters(10.0f)) || (GetWeaponRanged(oWeapon)))
			{
				SendMessageToPC(oPC, "<color=red>You must be at least ten feet away from the target and equipped with a melee weapon to make a charge.</color>");
				return;
			}

			int nNumber = GetLocalInt(oPC, "SalamanderTopNumber");
			effect eSpeed = EffectMovementSpeedIncrease(99);
			effect eAC = EffectACDecrease(2);
			effect eCharge = EffectLinkEffects(eSpeed, eAC);
			eCharge = ExtraordinaryEffect(eCharge);

			if (nNumber > 0) // Reinitiating this maneuver ends previous effects.
			{
				int s;

				s = 1;

				while (s <= nNumber)
				{
					DeleteLocalLocation(oPC, "SalamanderLoc" + IntToString(s));
					s++;
				}

				effect eTest;

				eTest = GetFirstEffect(oPC);

				while (GetIsEffectValid(eTest))
				{
					if (GetEffectSpellId(eTest) == 6554)
					{
						RemoveEffect(oPC, eTest);
						break;
					}
					eTest = GetNextEffect(oPC);
				}
			}

			ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCharge, oPC, 6.0f);
			SetLocalLocation(oPC, "SalamanderLoc", GetLocation(oPC));
			DeleteLocalInt(oPC, "SalamanderTimer"); //Reset the timer that tracks the duration of the effect.
			SetLocalInt(oToB, "DesertWindStrike", 1);
			DelayCommand(6.0f, SetLocalInt(oToB, "DesertWindStrike", 0));
			DelayCommand(0.1f, ExecuteScript("salamander_charge", oPC));
			ExpendManeuver(22, "STR");// Too powerful if you can cancel the maneuver before it starts.
		}

		if (GetDistanceBetween(oPC, oTarget) <= fRange)
		{
			if (nLocation == 1) // Object or Location as the target?
			{
				IndexManeuverPosition(nRow, fPosX, fPosY, fPosZ);
			}
			else if (IntToObject(nTarget) == OBJECT_INVALID)
			{
				return;
			}
			else IndexStrikeTarget(nRow, nTarget);

			AssignCommand(oPC, SetStrike(nRow));
			ActionUseFeat(FEAT_STUDENT_OF_THE_SUBLIME_WAY, oPC);
		}
		else
		{
			SetLocalInt(oToB, "StrikeMoveStatus", 1);
			DelayCommand(0.1f, RunPCStrikePosition(oPC));
			DelayCommand(0.5f, StrikeInRange(oPC, oTarget, fRange, nTarget, nRow, nLocation, fPosX, fPosY, fPosZ));
			ActionMoveToObject(oTarget, TRUE, fRange);
		}
	}
}