//===========================================================================//
// File:	ProjectileWeapon.hpp													
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 05/18/99	 DPB  Created File
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#pragma once

#include "MW4.hpp"
#include "Weapon.hpp"

namespace MechWarrior4
{
	class Vehicle;
	class ProjectileWeapon;
	class AmmoBay;

	//##########################################################################
	//###############    Projectile::ExecutionStateEngine    ###################
	//##########################################################################

	class ProjectileWeapon__ExecutionStateEngine:
		public Weapon__ExecutionStateEngine
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef Weapon__ExecutionStateEngine BaseClass;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		typedef ProjectileWeapon__ExecutionStateEngine*
			(*Factory)(
				ProjectileWeapon *weapon,
				FactoryRequest *request
			);

		static ProjectileWeapon__ExecutionStateEngine*
			Make(
				ProjectileWeapon *weapon,
				FactoryRequest *request
			);

	protected:
		ProjectileWeapon__ExecutionStateEngine(
			ClassData *class_data,
			ProjectileWeapon *weapon,
			FactoryRequest *request
		);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// State stuff
	//
	public:
		enum {
			FiringState = Weapon__ExecutionStateEngine::StateCount,
			ReloadingState,
			JammedState,
			HeatJammedState,
			AmmoFireState,
			RechargingState,
			StateCount
		};

	int
		RequestState(
			int new_state,
			void* data = NULL
		);

	protected:
		static const StateEntry
			StateEntries[];

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
      	TestInstance() const;
	};
		
	//##########################################################################
	//#####################   ProjectileWeapon::GameModel    ###################
	//##########################################################################

	class ProjectileWeapon__GameModel;

	typedef Weapon__ClassData						ProjectileWeapon__ClassData;
	typedef Weapon__Message							ProjectileWeapon__Message;
	typedef Weapon__CreateMessage					ProjectileWeapon__CreateMessage;

	class ProjectileWeapon__GameModel:
		public Weapon__GameModel
	{
	public:
		typedef Weapon__GameModel BaseClass;
		
		Stuff::Scalar
			fireRate;

		Stuff::Vector3D
			initialLinearVelocity;

		Stuff::Vector3D
			initialLinearAcceleration;

		Adept::ResourceID
			projectileModelResource;

		Stuff::Scalar
			targetLockTime;

		Stuff::Scalar
			m_timeToPotentialJam;

		Stuff::Scalar
			m_timeToJam;
		
		Stuff::Scalar
			m_heatToJam;

		Stuff::Scalar
			m_heatToUnjam;

		// Time for which RTX will be unavailable after jamming
		Stuff::Scalar
			m_timeToUnjam;

// MSL 5.03 Ammo Bay Fire
		Stuff::Scalar
			m_timeToAmmoBay;

		enum {
			FireRateAttributeID = Weapon__GameModel::NextAttributeID,
			InitialLinearVelocityAttributeID,
			InitialLinearAccelerationAttributeID,
			ProjectileModelResourceAttributeID,
			TargetLockTimeAttributeID,
			TimeToPotentialJamAttributeID,
			TimeToJamAttributeID,
			TimeToUnjamAttributeID,
			HeatToJamAttributeID,
			HeatToUnjamAttributeID,
			TimeToAmmoBayAttributeID,
			NextAttributeID
		};

		static bool
			ReadAndVerify(
				ProjectileWeapon__GameModel *model,
				ModelAttributeEntry *attribute_entry,
				const char *data,
				char **error,
				int error_buffer = 128
			);

		static void
			ConstructGameModel(Script *script);
	};
	
	//##########################################################################
	//###########################   ProjectileWeapon    ########################
	//##########################################################################

	class ProjectileWeapon:
		public Weapon
	{
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

		typedef Weapon BaseClass;

	//##########################################################################
	// Inheritance support
	//
	public:
		typedef ProjectileWeapon__ClassData							ClassData;
		typedef ProjectileWeapon__GameModel							GameModel;
		typedef ProjectileWeapon__Message							Message;
		typedef ProjectileWeapon__ExecutionStateEngine				ExecutionStateEngine;
		typedef ProjectileWeapon__CreateMessage						CreateMessage;


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Run-time Construction and Destruction Support
	//
	public:
		static ProjectileWeapon*
			Make(
				CreateMessage *message,
				ReplicatorID *base_id
			);
		void
			Respawn(Adept::Entity::CreateMessage *message);
		void
			CommonCreation(CreateMessage *message);

	protected:
		ProjectileWeapon(
			ClassData *class_data,
			CreateMessage *message,
			ReplicatorID *base_id,
			ElementRenderer::Element *element
		);

		~ProjectileWeapon();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Class Data & Game Model Support
	//
	public:
		
		const GameModel*
			GetGameModel()
				{return Cast_Pointer(const GameModel*, gameModelResource.GetPointer());}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Shared Data support
	//
	public:
		static ClassData
			*DefaultData;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Attribute Support
	//
	public:
		enum {
			ProjectileStartSFXAttributeID = Weapon::NextAttributeID,
			NextAttributeID
		};

	public:
		//
		// Attributes
		//
		int
			projectileStartSFX;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Simulation Support
	//
	public:
		void
			PreCollisionExecute(Stuff::Time till);

		void
			PostCollisionExecute(Stuff::Time till);

		virtual void
			CreateProjectile(Stuff::Time till);

		void
			CleanUpProjectiles();
		void
			DestroySubsystem();

		bool
			ReadyToFire(void);
		void 
			StartJamState();

		Origin3D *initialPositions;

// MSL 5.03 Weapon Jammed
		void 
			StartHeatJamState();

// MSL 5.03 Ammo Bay Fire
		void 
			StartFireState();

		Stuff::Time
			m_jamStartTime;

		// Last time that the player started firing the RTX 
		Stuff::Time
			m_fireStartTime;

		// Time at which the RTX stopped firing
		Stuff::Time
			m_fireEndTime;

// MSL 5.03 Ammo Bay Fire
		Stuff::Time
			m_ammofireStartTime;

		// Time we first entered recharge. Used to help minimize difference between server and client on what the
		// cumulative fire time is. Server enters recharge more often when packets aren't arriving faster than .25 seconds.
		Stuff::Time
			m_enterRecharge;

		bool 
			m_jamThisFrame;

		bool 
			m_heatJamThisFrame;

		bool
			fireRequest;

		int
			projectilesFired;

// MSL 5.06 Armor Mode
		int
			m_ArmorMode;

		Adept::Entity::CollisionQuery
			targetQuery;

		Stuff::Line3D collisionLine;
		Stuff::Normal3D collisionNormal;

		Stuff::SlotOf<Adept::Entity *>
			targetQueryEntity;
		AmmoBay
			*ammoBay;

	protected:
		void
			Fire(Adept::Entity::CollisionQuery *query,
				Stuff::Time time_locked,
				const Stuff::Point3D& lockedTargetEntityPartOffset);

		void QuickFire (Adept::Entity *target);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Support
	//
	public:
		void
      		TestInstance() const;
	};

	inline
		ProjectileWeapon__ExecutionStateEngine::ProjectileWeapon__ExecutionStateEngine(
			ClassData *class_data,
			ProjectileWeapon *mover,
			FactoryRequest *request
		):
			Weapon__ExecutionStateEngine(class_data, mover, request)
	{
	}

}


