namespace BP
{
	namespace Weapon
	{
		const float RIDING_GUN_MIN_SPEED                        = 0.5f;
		const float RIDING_GUN_TIME_TO_REFIRE                   = 0.7f;
		const float RIDING_GUN_STOMP_TIME                       = 100.0f;
		const int   RIDING_GUN_MACHINE_GUN_REFIRE_ITERATION     = 15;
		const kVec3 RIDING_GUN_POSITION                         = kVec3(40.0f, -80.0f, -150.0f);
		
		class RidingGun : ScriptWeapon
		{   
			int m_nWeaponSide;
			float m_fStompTime;
			//------------------------------------------------------------------------------------------------------------------------
			RidingGun(kWeapon @actor)
			{
				id = kWpn_RidingGun;
				super(actor);
				m_nWeaponSide = 1;
				m_fStompTime = 0;
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnBeginFire(void) override
			{
				ScriptWeapon::OnBeginFire();
				
				if (m_nWeaponSide > 0)
				{
					self.AnimTrackComponent().Blend(ANIM_WPN_FIRE_ARTILLERY_LEFT, 0, 8, 0);
				}
				else
				{
					self.AnimTrackComponent().Blend(ANIM_WPN_FIRE_ARTILLERY_RIGHT, 0, 8, 0);
				}
				
				m_nWeaponSide = -m_nWeaponSide;
			}
			//------------------------------------------------------------------------------------------------------------------------
			void ShakeScreen(void)
			{
				kVec3 vVel = self.Owner().Actor().MovementComponent().Velocity();
				float vx = Math::Fabs(vVel.x);
				float vy = Math::Fabs(vVel.y);
				float fSpeed = Math::Sqrt(vx*vx+vy*vy);
				
				m_fStompTime += fSpeed;
				
				if(m_fStompTime > RIDING_GUN_STOMP_TIME)
				{
					m_fStompTime -= RIDING_GUN_STOMP_TIME;
					
					// shake the screen
					float fShake = fSpeed * 50.0f;
					if(fShake > 50.0f)
					{
						fShake = 50.0f;
					}
					
					SpawnShake(kVec3(0, 0, fShake), self.Owner().Actor().Origin(), 10000, true);
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			bool CheckChargeForward(kActor@ pActor)
			{
				if (pActor.AnimTrackComponent().PlayingID() == ANIM_GROUND_ATTACK_COMBAT1 &&
					!pActor.AnimTrackComponent().CycleCompleted())
				{
					float sy = Math::Sin(self.Owner().Actor().Yaw());
					float cy = Math::Cos(self.Owner().Actor().Yaw());
					
					kVec3 vForward(sy, cy, 0.0f);
					vForward.Normalize();
					
					float fScale = 1.0f - pActor.AnimTrackComponent().TrackTime();
					
					ShakeScreen();
					
					self.Owner().Actor().MovementComponent().Velocity().x = vForward.x * (GAME_SCALE*fScale);
					self.Owner().Actor().MovementComponent().Velocity().y = vForward.y * (GAME_SCALE*fScale);
					return true;
				}
				
				return false;
			}
			//------------------------------------------------------------------------------------------------------------------------
			void DoMovementAnimations(kActor@ pActor)
			{
				kVec3 vVel = self.Owner().Actor().MovementComponent().Velocity();
				float vx = Math::Fabs(vVel.x);
				float vy = Math::Fabs(vVel.y);
				
				if (vx >= RIDING_GUN_MIN_SPEED || vy >= RIDING_GUN_MIN_SPEED)
				{
					if(pActor.AnimTrackComponent().PlayingID() != ANIM_GROUND_MOVE1)
					{
						pActor.AnimTrackComponent().Blend(ANIM_GROUND_MOVE1, 0, 32, ANF_LOOP);
					}
					else
					{
						ShakeScreen();
					}
				}
				else if (pActor.AnimTrackComponent().PlayingID() != ANIM_GROUND_IDLE1)
				{
					pActor.AnimTrackComponent().Blend(ANIM_GROUND_IDLE1, 0, 32, ANF_LOOP);
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			bool CheckChargeAttack(kActor@ pActor)
			{
				if ((self.Owner().Buttons() & BC_ALTFIRE) != 0)
				{
					pActor.AnimTrackComponent().Blend(ANIM_GROUND_ATTACK_COMBAT1, 2, 8, 0);
					return true;
				}
				
				return false;
			}
			//------------------------------------------------------------------------------------------------------------------------
			void UpdateArtilleryAnimations(void)
			{
				int animID = self.AnimTrackComponent().PlayingID();
				
				if (animID == ANIM_WPN_FIRE_ARTILLERY_LEFT || animID == ANIM_WPN_FIRE_ARTILLERY_RIGHT)
				{
					if(self.AnimTrackComponent().TrackTime() >= RIDING_GUN_TIME_TO_REFIRE)
					{
						self.AnimTrackComponent().Flags() |= ANF_CYCLECOMPLETED;
					}
				}
				
				if ((self.Owner().Buttons() & BC_JUMP) != 0)
				{
					if ((self.GameTicks() & RIDING_GUN_MACHINE_GUN_REFIRE_ITERATION) == 0)
					{
						self.AnimTrackComponent().Blend(ANIM_WPN_FIRE_MACHINE_GUN, 0, 8, 0);
					}
				}
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnTick(void) override
			{
				ScriptWeapon::OnTick();
				
				kActor@ pActor = self.GetTarget();
				if (!(pActor is null))
				{
					float zoffset = Math::Sin(Math::Min(self.Owner().Actor().Pitch(), 0.0f)) * (GAME_SCALE*7.5f);
					
					pActor.Yaw() = self.Yaw();
					pActor.Origin().z = RIDING_GUN_POSITION.z + zoffset;
					
					if (CheckChargeForward(pActor))
					{
						return;
					}
					
					if (CheckChargeAttack(pActor))
					{
						return;
					}
					
					DoMovementAnimations(pActor);
				}
				
				UpdateArtilleryAnimations();
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnRaise(void) override
			{
				ScriptWeapon::OnRaise();
				
				kActor@ pTriceratop = ActorFactory.Spawn(kActor_Monster_Triceratop_Head, RIDING_GUN_POSITION, 0.0f, 0.0f, 0.0f);
				self.SetTarget(pTriceratop);
			}
			//------------------------------------------------------------------------------------------------------------------------
			void OnLower(void) override
			{
				ScriptWeapon::OnLower();
				
				kActor@ pActor = self.GetTarget();
				if(pActor is null)
				{
					return;
				}
				
				pActor.Remove();
				
				@pActor = null;
				self.SetTarget(pActor);
			}
			//------------------------------------------------------------------------------------------------------------------------
		};
	}
}
