//============================================================================//
// File:	seeker.hpp                                                          	//
// Project: BattleTech																			//
// Contents: A subsystem which guides, seeks out and finds a target           	//
//----------------------------------------------------------------------------//
//   Date    Who  Modification                                               	//
// --------  ---  ------------------------------------------------------------//
// 04/13/95  JM  Initial coding.                                              //
// 07/12/95  GDU  Complied with new libraries, added seeker logic             //
//----------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved  //
//                   	PROPRIETARY AND CONFIDENTIAL                          //
//============================================================================//
//
// RECONSTRUCTED from the shipped binary (Ghidra pseudo-C, module cluster
// @004bec34-@004bee70 in part_013.c) cross-referenced HEAVILY against the
// SURVIVING SEEKER.HPP and the MUNGA SUBSYSTM.HPP base interface.  The class
// declaration below is the surviving header; the only additions are the byte
// offsets observed in the decompiled object (see seeker.cpp for per-method
// @ADDR evidence).
//
// Inheritance chain established from the decomp:
//      Simulation -> Subsystem (FUN_0041c52c base ctor) -> Seeker
// The Seeker ctor (@004bec34) installs vtable PTR_LAB_00512ce8 and chains to
// the Subsystem base ctor @0041c52c with the shared resource &DAT_00512bec.
// Every vtable slot other than the destructor inherits the Subsystem base
// (vtable @00512ce8 holds only 0x41xxxx engine slots), so the Seeker's real
// behaviour lives in the non-virtual Performance method LeadTarget().
//
// Field offsets in comments are byte offsets into the shipped object; the
// Subsystem base occupies everything below +0xE4.  Member names are taken
// verbatim from the surviving SEEKER.HPP.
//

#if !defined (SEEKER_HPP)
#define	SEEKER_HPP

#if !defined(SUBSYSTM_HPP)
	#include <subsystm.hpp>
#endif

#if !defined(POINT3D_HPP)
	#include <point3d.hpp>
#endif



//######################### Forward Class Declarations ########################
	class Missile;
	class Entity;

//######################### Seeker Subsystem Resource ##########################
//
// The Seeker carries no resource fields of its own -- the shared default
// record &DAT_00512bec (resolved at @004bec34) is the bare Subsystem record.
//
	struct Seeker__SubsystemResource:
		public Subsystem::SubsystemResource
		{
		};

//###########################################################################
//#########################     CLASS -- Seeker    ##########################
//###########################################################################
//
//	(vtable @00512ce8, ctor @004bec34, dtor @004bee44.)
//
	class Seeker : public Subsystem
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Messaging Support
	//
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Shared Data Support
	//
	public:
		static Derivation ClassDerivations;
		static Receiver::MessageHandlerSet MessageHandlers;
		static SharedData DefaultData;


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Attribute Support
	//
	//	Attribute IDs verified against the IndexEntry table @00512d50:
	//		TargetPositionAttributeID    == 0x341  (string @0051012e "...")
	//		RangeToTargetAttributeID     == 0x345
	//		RangeFromCreationAttributeID == 0x34d
	//
	public:
		enum {
			TargetPositionAttributeID = Subsystem::NextAttributeID,
			RangeToTargetAttributeID,
			RangeFromCreationAttributeID,
			NextAttributeID
		};

	private:
		static const IndexEntry AttributePointers[];

	protected:
		static AttributeIndexSet	AttributeIndex;

	//
	// public attribute declarations go here
	//
	public:
		Point3D			targetPosition;          // @0xE4  for thruster (lead/aim point)
		Point3D			creationPoint;			 // @0xF0  where the missile was fired from
		Entity	      *targetEntity;             // @0xFC  homing target (0 == dumb-fire)
		Point3D			targetOffset;             // @0x100 aim offset within the target
		Scalar			 rangeToTarget,           // @0x10C distance to targetPosition
						 rangeFromCreation,       // @0x110 distance travelled from creationPoint
						 startingRangeToTarget;   // @0x114 rangeToTarget sampled at spawn

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Model Support
	//
	public:
		enum {
			Empty = Subsystem::StateCount,
			StateCount};

		typedef void
			(Seeker::*Performance)(Scalar time_slice);


		// @004beae4 -- recompute targetPosition by leading the moving
		// targetEntity along its velocity (clamped lead window 200..300 m).
		void
			LeadTarget();

		// FindTarget(time_slice) is the per-frame Performance entry point.  In
		// the shipped binary its body is folded into the Missile guidance pass
		// (Missile::MoveAndCollide @004bef78, which samples this->targetPosition
		// at +0x1c4); the standalone update is LeadTarget().  Declared to match
		// the surviving header and MISSILE.TCP's seeker->FindTarget(time_slice).
		void
			FindTarget(Scalar time_slice);

		void
			SetPerformance(Performance performance)
			{
				Check(this);
				activePerformance = (Simulation::Performance)performance;
			}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// 	TestClass Support
	//
	public:

		static Logical
			TestClass(Missile &);
		void
			ResetToInitialState();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Construction and Destruction
	//
	public:
		typedef Seeker__SubsystemResource SubsystemResource;

		Seeker  (											// @004bec34
			Missile			*owner,
			int				subsystem_ID,
			SubsystemResource	*subsystem_resource,
			Entity *target,
			const Point3D offset
		);
		~Seeker();											// @004bee44

		Logical
      	TestInstance() const;
	};
#endif
