#include "scripts/common.txt"
#include "scripts/BP_common.txt"
#include "scripts/BP_MapCommon.txt"

//Tag IDs
//1000: Start Warp / Player Reset Point
//1001: Player Hummer
//1002: Tank
//1003: Death Hummer Pos
//1004: Death Tank Pos
//1005: Death Cam Pos
//1006: PreChase Hummer Start Point
//1007: PreChase Tank Start Point
//1008: Chase Hummer Start Point
//1009: Chase Tank Start Point
//1010: Is Pre Chase Complete?
//1011: Is Chase Complete?
//1012: 


kActor@ playerHummer;
kActor@ tank;
kActor@ playerResetPoint;
kActor@ camLook;
kActor@ deathHummerPos;
kActor@ deathTankPos;
kActor@ deathCamPos;
kActor@ hummerStartPreChasePos;
kActor@ tankStartPreChasePos;
kActor@ hummerStartChasePos;
kActor@ tankStartChasePos;
kActor@ preChaseComplete;
kActor@ chaseComplete;

const int CINEMATIC_NONE = 0;
const int CINEMATIC_PRECHASE = 1;
const int CINEMATIC_CHASE = 2;
const int CINEMATIC_DEATH = 3;
const int CINEMATIC_WIN = 4;

const float MAX_JUMP_HEIGHT = 300.0f;
const float MAX_TANK_JUMP_HEIGHT = 160.0f;
const float JUMP_UP_TIME = 1.0f;
const float JUMP_DOWN_TIME = 0.75f;

uint16 mapInputButtons = 0;
float targetYaw = 0.0f;
float turnYaw = Math::Deg2Rad(15.0f);
float wheelTurnSpeed = Math::Deg2Rad(30.0f);
float wheelAngle = 0.0f;
float maxForwardSpeed = 11.0f;
float forwardSpeedRate = 0.0f;
float strafeSpeed = 8.0f;
float camyOffset = 0.0f;
float camyTargetOffset = 0.0f;
bool hummerLightsOn;
kVec3 forwardDir(0.0f, 1.0f, 0.0f);
kVec3 rightDir(1.0f, 0.0f, 0.0f);
int camFollowType;
int cinematicActive;
float lastHummerHP;
int hummerJump;
float hummerJumpTime;
int tankJump;
float tankJumpTime;
const float hpTextX = 0.015625f;
const float hpTextY = 0.913888f;

//------------------------------------------------------------------------------------------------------------------------
// Start Map
//------------------------------------------------------------------------------------------------------------------------
$script 0
{
	StartMap();
	
	cinematicActive = CINEMATIC_NONE;
	
	@hummerStartPreChasePos = World.GetActorByTID(1006);
	@tankStartPreChasePos = World.GetActorByTID(1007);
	@hummerStartChasePos = World.GetActorByTID(1008);
	@tankStartChasePos = World.GetActorByTID(1009);
	@preChaseComplete = World.GetActorByTID(1010);
	@chaseComplete = World.GetActorByTID(1011);

	@playerResetPoint = World.GetActorByTID(1000);
	@playerHummer = World.GetActorByTID(1001);
	hummerLightsOn = true;
	playerHummer.ClipFlags() |= CF_IGNOREBLOCKERS | CF_CLIPEDGES | CF_DROPOFF | CF_WALKWALLS | CF_COLLIDEFLOORS | CF_NOSLOPESTEP | CF_COLLIDEHEIGHT | CF_NOFLOORADJUST | CF_NOCEILINGADJUST | CF_COLLIDEWATER;
	//playerHummer.ClipFlags() |= CF_NOCLIPACTORS | CF_CLIPEDGES | CF_DROPOFF | CF_WALKWALLS | CF_COLLIDEFLOORS | CF_NOSLOPESTEP | CF_COLLIDEHEIGHT | CF_NOFLOORADJUST | CF_NOCEILINGADJUST | CF_COLLIDEWATER;

	playerHummer.Flags() |= AF_IGNORESOUNDEVENTS | AF_ALWAYSACTIVE | AF_CANBETOUCHED;
	playerHummer.Flags() &= ~AF_SOLID;
	playerHummer.Origin() = hummerStartPreChasePos.Origin();
	playerHummer.SetSector(hummerStartPreChasePos.SectorIndex());
	
	playerHummer.Health() = 100;
	lastHummerHP = playerHummer.Health();
	
	@tank = World.GetActorByTID(1002);
	tank.SetTarget(playerHummer);
	tank.Health() = 100;
	@camLook = ActorFactory.Spawn("DummyActor", 0.0f, 0.0f, 0.0f, 0.0f, 0);

	@deathHummerPos = World.GetActorByTID(1003);
	@deathTankPos = World.GetActorByTID(1004);
	@deathCamPos = World.GetActorByTID(1005);

	Game.CallDelayedMapScript(1, instigator, 0); //Update Map
	
	if (chaseComplete.IsPersistentMarked())
	{
		//warp to next level
	}
}
//------------------------------------------------------------------------------------------------------------------------
// Update Map
//------------------------------------------------------------------------------------------------------------------------
$script 1
{
	TickMap();
	
	//wait until not in cinematic (the regeneration cinematic) then start the chase cinematic
	if (cinematicActive == CINEMATIC_NONE && !Camera.Active())
	{
		if (preChaseComplete.IsPersistentMarked())
		{
			StartChase(instigator);
		}
		else
		{
			//start prechase
			cinematicActive = CINEMATIC_PRECHASE;
			Camera.StartCinematic(CMF_NO_LETTERBOX | CMF_NO_INITIAL_FADEOUT);
			Camera.SetLookAtActor(camLook);
			Camera.ClearFinalView();
			Camera.ClearViewTracks();
			Camera.fov = 90.0f;
			playerHummer.Origin() = hummerStartPreChasePos.Origin();
			playerHummer.SetSector(hummerStartPreChasePos.SectorIndex());

			DisableWeapon();
			
			Game.CallDelayedMapScript(10, instigator, 17.0f); //end pre chase
		}
	}
	
	mapInputButtons = InputUpdate(mapInputButtons);
	
	if (cinematicActive == CINEMATIC_CHASE || cinematicActive == CINEMATIC_PRECHASE)
		UpdateChase(instigator);

	$restart;
}
//------------------------------------------------------------------------------------------------------------------------
void UpdateChase(kActor@ instigator)
{
	if (lastHummerHP != playerHummer.Health())
	{
		lastHummerHP = playerHummer.Health();
		if (playerHummer.Health() == 1)
		{
			Game.HaltMapScript(5); //end chase
			playerHummer.AnimState().Set(anim_aiDeathStand, 3.0f, ANF_ROOTMOTION);
			playerHummer.Velocity() = Math::vecZero;
			Game.CallDelayedMapScript(6, instigator, 0.5f); //died
		}
	}
	
	if (playerHummer.Health() == 1)
	{
		return;
	}
	
	if (cinematicActive == CINEMATIC_CHASE)
	{
		//PlayWavCinematicMusic("music_chase.ksnd"); //music length = 57 seconds
	}

	//Reset Player Position - if I don't position close to camera then everything gets darker for some reason
	// Player.Actor().Origin() = playerResetPoint.Origin();
	kVec3 playerPos = Camera.origin;
	playerPos.z = Player.Actor().FloorHeight();
	Player.Actor().Origin() = playerPos;
	int playerSectorIndex = Player.Actor().GetSectorIndexAtLocation(playerPos);
	Player.Actor().SetSector(playerSectorIndex);
	Player.Actor().Flags() &= ~AF_SOLID;
	
	//SetCamera Position behind the player
	camLook.Origin() = playerHummer.Origin() + kVec3(0.0f, 600.0f, 0.0f); //camera looks ahead of the player
	
	Camera.origin = playerHummer.Origin() - (forwardDir * 700.0f);// + kVec3(0.0f, 0.0f, 350.0f);
	//Camera.origin.z = Math::Minf(Camera.origin.z, 350.0f);
	Camera.origin.z = 350.0f;
	//cam x postiion is the tank
	//Camera.origin.x = tank.Origin().x;// 153.5999905f;//Math::Clampf(camLook.Origin().x, -307.199982, 614.399963);
	if (cinematicActive == CINEMATIC_PRECHASE)
	{
		Camera.origin.x = Math::Clampf(playerHummer.Origin().x, 4277.0f, 5140.0f);
	}
	else
	{
		if (camFollowType == 0) //follow player
		{
			Camera.origin.x = Math::Clampf(playerHummer.Origin().x, -280.0f, 580.0f);
		}
		else if (camFollowType == 1) //follow tank
		{
			Camera.origin.x = Math::Clampf(tank.Origin().x, -280.0f, 580.0f);
		}
	}
	Camera.origin.y -= camyOffset;
	
	camyOffset = Math::SmoothStepBP(camyOffset, camyTargetOffset, 0.1f);	
	
	//Set Hummer Velocity
	playerHummer.Velocity() = forwardDir * (maxForwardSpeed * forwardSpeedRate);
	playerHummer.Velocity() += rightDir * ((playerHummer.Yaw() / turnYaw) * strafeSpeed);
	switch (hummerJump)
	{
		case 1: //going up to max height
		{
			hummerJumpTime = Math::Minf(hummerJumpTime + GAME_DELTA_TIME, JUMP_UP_TIME);
			playerHummer.Origin().z = Math::SmoothStepBP(0.0f, MAX_JUMP_HEIGHT, hummerJumpTime / JUMP_UP_TIME);
			playerHummer.Pitch() = Math::SmoothStepBP(0.0f, Math::Deg2Rad(-15.0f), hummerJumpTime / (JUMP_UP_TIME - 0.5f));
			if (hummerJumpTime >= JUMP_UP_TIME)
			{
				hummerJump = 2;
				hummerJumpTime = 0.0f;
			}
			break;
		}
		case 2: //going down to zero
		{
			hummerJumpTime = Math::Minf(hummerJumpTime + GAME_DELTA_TIME, JUMP_DOWN_TIME);
			playerHummer.Origin().z = Math::SmoothStepBP(MAX_JUMP_HEIGHT, 0.0f, hummerJumpTime / JUMP_DOWN_TIME);
			playerHummer.Pitch() = Math::SmoothStepBP(Math::Deg2Rad(-15.0f), 0.0f, hummerJumpTime / JUMP_DOWN_TIME);
			if (hummerJumpTime >= JUMP_DOWN_TIME)
			{
				playerHummer.Pitch() = 0.0f;
				hummerJump = 0;
				hummerJumpTime = 0.0f;
			}
			break;
		}
	}
	
	//Set Hummer Yaw
	playerHummer.Yaw() = playerHummer.Yaw().Interpolate(targetYaw, 0.05f);
	
	kQuat qTurnRotation = kQuat(-playerHummer.Yaw(), 0, 0, 1);
	playerHummer.RenderModel().SetRotationOffset(16, kQuat(wheelAngle, 0, 1, 0) * qTurnRotation); // 16 = left front
	playerHummer.RenderModel().SetRotationOffset(14, kQuat(wheelAngle, 0, 1, 0) * qTurnRotation); // 14 = right front
	playerHummer.RenderModel().SetRotationOffset(18, wheelAngle, 0, 1, 0); // 18 = left back
	playerHummer.RenderModel().SetRotationOffset(12, wheelAngle, 0, 1, 0); // 12 = right back
	
	wheelAngle -= (wheelTurnSpeed * forwardSpeedRate);

	tank.SetTarget(playerHummer);
	kActor@ target = tank.GetTarget();
	if (target !is null)
	{
		//tank.Origin() = target.Origin();
		//tank.Origin().y -= 200.0f;
		if (tank.Origin().y >= target.Origin().y - 800.0f)
		{
			tank.Origin().y = target.Origin().y - 650.0f;
		}
		else if (tank.Origin().y < target.Origin().y - 650.0f)
		{
			tank.Origin().y = target.Origin().y - 650.0f;
		}
		
		switch (tankJump)
		{
			case 1: //going up to max height
			{
				tankJumpTime = Math::Minf(tankJumpTime + GAME_DELTA_TIME, JUMP_UP_TIME);
				tank.Origin().z = Math::SmoothStepBP(0.0f, MAX_TANK_JUMP_HEIGHT, tankJumpTime / JUMP_UP_TIME);
				tank.Pitch() = Math::SmoothStepBP(0.0f, Math::Deg2Rad(-15.0f), tankJumpTime / (JUMP_UP_TIME - 0.5f));
				if (tankJumpTime >= JUMP_UP_TIME)
				{
					tankJump = 2;
					tankJumpTime = 0.0f;
				}
				break;
			}
			case 2: //going down to zero
			{
				tankJumpTime = Math::Minf(tankJumpTime + GAME_DELTA_TIME, JUMP_DOWN_TIME);
				tank.Origin().z = Math::SmoothStepBP(MAX_TANK_JUMP_HEIGHT, 0.0f, tankJumpTime / JUMP_DOWN_TIME);
				tank.Pitch() = Math::SmoothStepBP(Math::Deg2Rad(-15.0f), 0.0f, tankJumpTime / JUMP_DOWN_TIME);
				if (tankJumpTime >= JUMP_DOWN_TIME)
				{
					tank.Pitch() = 0.0f;
					tankJump = 0;
					tankJumpTime = 0.0f;
				}
				break;
			}
		}
	
	}

		
	//Input Update
	targetYaw = 0.0f;
	if (InputStrafeLeftPress())
	{
		if (playerHummer.CheckPosition(playerHummer.Origin() + kVec3(-1.0f, 0.0f, 0.0f)))
		{
			targetYaw = Math::Clampf(playerHummer.Yaw() - turnYaw, -turnYaw, turnYaw);
		}
		else
		{
			playerHummer.PlaySound("sounds/shaders/carscratch.ksnd");
			Game.SpawnFx("fx/carscratch.kfx", playerHummer.Origin(), playerHummer.SectorIndex());
		}
	}
	else if (InputStrafeRightPress())
	{
		if (playerHummer.CheckPosition(playerHummer.Origin() + kVec3(1.0f, 0.0f, 0.0f)))
		{
			targetYaw = Math::Clampf(playerHummer.Yaw() + turnYaw, -turnYaw, turnYaw);
		}
		else
		{
			playerHummer.PlaySound("sounds/shaders/carscratch.ksnd");
			Game.SpawnFx("fx/carscratch.kfx", playerHummer.Origin(), playerHummer.SectorIndex());
		}
	}
	
	if (playerHummer.GameTicks() % 6 == 0)
	{
		for (int i = 0; i < 2; i++)
		{
			kVec3 pos(-75.0f + (i * 100.0f), -50.0f, 0.0f);
			//dust trail
			if (Math::RandMax(2) == 0)
				playerHummer.SpawnFx("fx/generic_135.kfx", pos);
			else
				playerHummer.SpawnFx("fx/generic_136.kfx", pos);
		}
	}
	
	if (InputAttackDown())
	{
		hummerLightsOn = !hummerLightsOn;
		if (hummerLightsOn)
			playerHummer.RenderModel().HideSection(0, 18, false);
		else
			playerHummer.RenderModel().HideSection(0, 18, true);
	}
	
	if (InputJumpDown() && cinematicActive == CINEMATIC_CHASE)
	{
		camFollowType++;
		// if (camFollowType == 1) //follow tank and tank is active
		// {
			// camFollowType++
		// }
		
		switch (camFollowType)
		{
			case 1: //follow tank
				break;
			default: //0: //follow player
				camFollowType = 0;
				break;
		}
	}
	
	//test input remove later
	if (InputWeaponRightDown())
	{
		playerHummer.Health() = 1;
	}
	
	playerHummer.PlaySound("sounds/shaders/carloop.ksnd");
	tank.PlaySound("sounds/shaders/tankmove.ksnd");
	
	forwardSpeedRate = 1.0f;
	camyTargetOffset = 50.0f;
	// forwardSpeedRate = 0.8f;
	// camyTargetOffset = 50.0f;
	// if (InputForwardPress())
	// {
		// forwardSpeedRate = 1.0f;
		// camyTargetOffset = 100.0f;
	// }
	// else if (InputBackwardPress())
	// {
		// forwardSpeedRate = 0.6f;
		// camyTargetOffset = 0.0f;
	// }
}
//------------------------------------------------------------------------------------------------------------------------
// Tank Shot Hit Player
//------------------------------------------------------------------------------------------------------------------------
$script 2
{
	if (hummerJump == 0) //if not jumping off ramp
	{
		playerHummer.Health() = Math::Max(playerHummer.Health() - 20, 1);
		if (Math::RandMax(2) == 0)
			playerHummer.PlaySound("sounds/shaders/explosion_1.ksnd");
		else
			playerHummer.PlaySound("sounds/shaders/explosion_2.ksnd");
		playerHummer.SpawnFx("fx/explosion.kfx", Math::vecZero);
		playerHummer.RunFxEvent("HitFlash");
	}
}
//------------------------------------------------------------------------------------------------------------------------
// Hummer Hit Debris
//------------------------------------------------------------------------------------------------------------------------
$script 3
{
	playerHummer.Health() = Math::Max(playerHummer.Health() - 2, 1);
}
//------------------------------------------------------------------------------------------------------------------------
// Hummer Hit Enemy Debris
//------------------------------------------------------------------------------------------------------------------------
$script 4
{
	playerHummer.Health() = Math::Min(playerHummer.Health() + 1, 100);
}
//------------------------------------------------------------------------------------------------------------------------
// Finished Chase (Time up)
//------------------------------------------------------------------------------------------------------------------------
$script 5
{
	Game.PrintLine("Finished Chase", 0);
	chaseComplete.MarkPersistentBit(false);
}
//------------------------------------------------------------------------------------------------------------------------
// Died in chase
//------------------------------------------------------------------------------------------------------------------------
$script 6
{
	Game.HaltMapScript(5); //end chase
	Game.HaltMapScript(10); //end pre chase
	
	cinematicActive = CINEMATIC_DEATH;
	playerHummer.Origin() = deathHummerPos.Origin();
	playerHummer.SetSector(deathHummerPos.SectorIndex());
	playerHummer.Yaw() = deathHummerPos.Yaw();
	playerHummer.Pitch() = 0.0f;
	playerHummer.Roll() = 0.0f;
	playerHummer.Velocity() = Math::vecZero;
	playerHummer.AnimState().Set(0, 4.0f, ANF_LOOP|ANF_ROOTMOTION);
	
	tank.Health() = 1;
	tank.Origin() = deathTankPos.Origin();
	tank.SetSector(deathTankPos.SectorIndex());
	tank.Yaw() = deathTankPos.Yaw();
	tank.Pitch() = 0.0f;
	tank.Roll() = 0.0f;
	tank.Velocity() = Math::vecZero;
	tank.RunFxEvent("ClearFx");
	tank.RenderModel().SetRotationOffset(1, 0, 0, 0, 1);

	Camera.StartCinematic();
	Camera.SetLookAtActor(playerHummer);
	Camera.ClearFinalView();
	Camera.ClearViewTracks();
	Camera.fov = 74.0f;
	Camera.origin = deathCamPos.Origin();
	while (Camera.CinematicState() != 2) { delay(0.000001f); } //wait until cinema has started to fade in	
	Game.CallDelayedMapScript(7, instigator, 0.0f); //update died cinematic
	playerHummer.AnimState().Set(anim_aiDeathStand, 6.0f, ANF_ROOTMOTION);
	delay(2.0f);
	tank.AnimState().Blend(1, 4.0f, 8.0f, ANF_ROOTMOTION);
	playerHummer.SpawnFx("fx/explosion.kfx", Math::vecZero);
	Game.PlaySound("sounds/shaders/carsquish.ksnd");
	delay(1.0f);
	EndDeathCinematic(7);
}
//------------------------------------------------------------------------------------------------------------------------
// Update Died in chase cinematic
//------------------------------------------------------------------------------------------------------------------------
$script 7
{
	tank.Origin().y += 7.0f;
    if (Camera.UserInterrupted())
    {
		EndDeathCinematic(6);
        return;
    }
	$restart;
}
//------------------------------------------------------------------------------------------------------------------------
void EndDeathCinematic(const int haltScriptID)
{
	Game.HaltMapScript(haltScriptID);
	PlayLoop.HandlePlayerDeath();
}
//------------------------------------------------------------------------------------------------------------------------
// instigator hit a ramp
//------------------------------------------------------------------------------------------------------------------------
$script 8
{
	if (@instigator == @playerHummer)
	{
		if (hummerJump == 0)
		{
			hummerJump = 1;
			hummerJumpTime = 0.0f;
		}
	}
	else
	{
		if (tankJump == 0)
		{
			tankJump = 1;
			tankJumpTime = 0.0f;
		}
	}
}
//------------------------------------------------------------------------------------------------------------------------
// picked up health - instigator (hummer)
//------------------------------------------------------------------------------------------------------------------------
$script 9
{
	playerHummer.PlaySound("sounds/shaders/health_pickup_1.ksnd");
	Game.PrintLine("$str_135", 0); // 2 Health
	playerHummer.Health() = Math::Min(playerHummer.Health() + 2, 100);	
}
//------------------------------------------------------------------------------------------------------------------------
// Finished Pre Chase (Time up)
//------------------------------------------------------------------------------------------------------------------------
$script 10
{
	//show cinematic of tank coming through wall
	
	StartChase(instigator);
}
//------------------------------------------------------------------------------------------------------------------------
void StartChase(kActor@ instigator)
{
	preChaseComplete.MarkPersistentBit(false);
	cinematicActive = CINEMATIC_CHASE;
	Camera.StartCinematic(CMF_NO_LETTERBOX | CMF_NO_INITIAL_FADEOUT);
	Camera.SetLookAtActor(camLook);
	Camera.ClearFinalView();
	Camera.ClearViewTracks();
	Camera.fov = 90.0f;
	
	playerHummer.Origin() = hummerStartChasePos.Origin();
	playerHummer.SetSector(hummerStartChasePos.SectorIndex());
	tank.Origin() = tankStartChasePos.Origin();
	tank.SetSector(tankStartChasePos.SectorIndex());
	
	//Reset Player Position
	// Player.Actor().Origin() = playerResetPoint.Origin();
	// Player.Actor().SetSector(playerResetPoint.SectorIndex());
	DisableWeapon();
	
	Game.CallDelayedMapScript(5, instigator, 57.0f); //end chase
}
//------------------------------------------------------------------------------------------------------------------------
