//===========================================================================//
// File:	emitter.hpp                                                         //
// Project: BattleTech           Brick: Entity Manager                        //
// Contents: Emitter -- energy/beam weapon base (PPC, GaussRifle derive)      //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
//  --/--/95  JM   Initial coding.                                           //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//
//
// RECONSTRUCTED from the shipped binary (Ghidra pseudo-C, module cluster
// @004ba478-@004bb478, file=bt/emitter.cpp; the abstract-stub @004ba45c is
// emitted at the head of this translation unit but belongs to mechweap.hpp).
// Cross-referenced HEAVILY against:
//   * the SURVIVING derived sources PPC.HPP/PPC.CPP and GAUSS.HPP/GAUSS.CPP
//     (both `: public Emitter`; both chain ctor + FireWeapon to Emitter), and
//   * the SURVIVING EMITTER.TCP test (names: dischargeVoltage, outputVoltage,
//     currentLevel, EmitterSimulation, ResetToInitialState), and
//   * the reconstructed base mechweap.hpp/mechweap.cpp (MechWeapon layout).
// See emitter.cpp for per-method @ADDR evidence and the resolved constants.
//
// Inheritance chain (from CLASSMAP.md + the ctor chain @004bb120 -> @004b99a8):
//      ... -> PoweredSubsystem -> MechWeapon (vtable @00511d2c, ctor @004b99a8)
//                              -> Emitter    (vtable @00512078, ctor @004bb120)
//                                 ├─ PPC        (vtable @0051214c, ctor @004bb888)
//                                 └─ GaussRifle (vtable @00512934)
//
// The Emitter ctor @004bb120 installs PTR_FUN_00512078 and chains to the
// MechWeapon ctor @004b99a8.  PPC::FireWeapon (@004bb878) is a one-liner that
// tail-calls Emitter::FireWeapon (@004bace8) -- exactly as PPC.CPP shows.
// GaussRifle::FireWeapon overrides instead (sets outputVoltage = 0).
//
// Field offsets in comments are byte offsets into the shipped object.  Member
// names come from EMITTER.TCP / GAUSS.HPP where available, otherwise inferred
// from usage and flagged best-effort.  PoweredSubsystem occupies everything
// below +0x31c; MechWeapon occupies +0x31c..+0x3ef; Emitter starts at +0x3f0.
//

#if !defined(EMITTER_HPP)
#	define EMITTER_HPP

#if !defined(MECHWEAP_HPP)
#	include <mechweap.hpp>
#endif

//#####################    Forward Class Declarations  #######################
class Mech;
class ResourceFile;
class NotationFile;

//###########################################################################
//####################     Emitter Model Resource     #######################
//###########################################################################
//
// Extends the MechWeapon resource record.  The Emitter-specific fields begin
// at +0x1BC in the parsed record (see CreateStreamedSubsystem @004bb478).
// The parser stamps subsystemModelSize = 0x1DC and classID = EmitterClassID
// (0xBC8).
//
	struct Emitter__SubsystemResource:
		public MechWeapon::SubsystemResource
	{
		Scalar	graphicLength;				// +0x1BC  "GraphicLength" (beam visual length)
		Scalar	dischargeTime;				// +0x1C0  "DischargeTime" (beam-on duration)
		Scalar	seekVoltage[5];				// +0x1C4  "SeekVoltage"  (per-index charge curve)
		int		seekVoltageRecommendedIndex;// +0x1D8  "SeekVoltageRecommendedIndex"
	};										// sizeof == 0x1DC

//###########################################################################
//#########################        Emitter        ##########################
//###########################################################################
//
//	Base class for charge-and-discharge beam weapons.  It accumulates charge
//	(currentLevel) toward a per-index target (seekVoltage), exposing a
//	normalised outputVoltage; when fully charged and triggered it discharges,
//	converting the stored energy into damage + self-heat and projecting a beam
//	at the owning Mech's current target.  (vtable @00512078, ctor @004bb120,
//	dtor @004bb3c8.)
//
	class Emitter:
		public MechWeapon
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Shared Data Support
	//
	public:
		static Derivation ClassDerivations;
		static Receiver::MessageHandlerSet MessageHandlers;
		static AttributeIndexSet AttributeIndex;
		static SharedData DefaultData;

		// Update record (replication) -- extends the MechWeapon record with the
		// Emitter beam-replication fields appended by WriteUpdateRecord (@004ba65c).
		struct Emitter__UpdateRecord:
			public MechWeapon::UpdateRecord
		{
			int			firingActive;		// message[6]
			int			targetLocalFlag;	// message[10]
			Point3D		beamEndpoint;		// message[7]
			int			beamFlag;			// message[11]
			RGBColor	color;
			int			payloadCount;		// message+0xc (AdvanceSeekVoltage)
		};
		typedef Emitter__UpdateRecord UpdateRecord;

		// Proxy for the linked voltage source (Generator segment) the decomp reads
		// through the SharedData connection (voltage/state/ratedVoltage/heatLoad).
		struct VoltageSource {
			Scalar	voltage;
			int		state;
			Scalar	ratedVoltage;
			Scalar	heatLoad;
		};

	protected:
		// State / flag accessors the recovered bodies read (mapped onto the
		// MechWeapon weaponAlarm + Simulation flags).
		int		GetWeaponState();
		int		GetVoltageState();
		LWord	GetFlags();
		int		GetFaultState();
		void	SetDirty();
		void	ClearDirty();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Simulation Support
	//
	//	The per-frame step runs through the Simulation "activePerformance"
	//	member-function pointer (see GAUSS.HPP SetPerformance).  EmitterSimulation
	//	is the installed performance for this class.
	//
	public:
		typedef void (Emitter::*Performance)(Scalar time_slice);

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

		// @004baa88 -- the installed per-frame performance: drive the
		// Loading->Loaded->Firing state machine, recharge, and fire on edge.
		void
			EmitterSimulation(Scalar time_slice);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Firing
	//
	//	The real discharge implementation.  PPC::FireWeapon chains straight here
	//	(@004bb878); GaussRifle::FireWeapon overrides it.
	//
	protected:
		virtual void
			FireWeapon();								// vtable slot 18, @004bace8

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Subsystem / Simulation virtual overrides (vtable @00512078)
	//
	//	Slot indices verified against the MechWeapon vtable @00511d2c:
	//		slot  6  TakeDamage           (MechWeapon base @004b964c)
	//		slot  7  WriteUpdateRecord    (MechWeapon base @004b9690)
	//		slot 10  ResetToInitialState  (MechWeapon base @004b96ec)
	//		slot 13  PrintState           (MechWeapon base @004b9d00)
	//		slot 16  ReadyToDischarge     (Simulation interface)
	//		slot 17  ComputeOutputVoltage (Simulation interface)
	//		slot 18  FireWeapon
	//
	public:
		void
			TakeDamage(Damage &damage);					// slot  6, @004ba568
		void
			ResetToInitialState();						// slot 10, @004ba4d0
		void
			PrintState();								// slot 13, @004bb014

	protected:
		void
			WriteUpdateRecord(							// slot  7, @004ba65c
				UpdateRecord	*message,
				int				update_model
			);

		// @004ba6e0 -- True when the supplied (or linked) voltage source can
		// satisfy the current seekVoltage index and is in the "ready" state (2).
		Logical
			ReadyToDischarge(VoltageSource *source);	// slot 16

		// @004ba738 -- recompute outputVoltage = currentLevel / seekVoltage[idx],
		// snapped to 1.0 near full and clamped to [0,1].
		void
			ComputeOutputVoltage();						// slot 17

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Internal charge / discharge helpers (non-virtual; called by the sim)
	//
	protected:
		// @004ba838 -- track the linked voltage source: derive a seek rate and
		// integrate currentLevel; dump the I^2R heat back into the source.
		void
			TrackSeekVoltage(Scalar time_slice);

		// @004ba8d0 -- count the beam-on dischargeTimer down; when it expires
		// (or the firing message is refused) drop back to the Loaded state.
		void
			ServiceDischarge(Scalar time_slice);

		// @004ba9a8 -- reset the transient firing/beam fields and re-arm to the
		// Loading state (alarm level 3).
		void
			ResetFiringState();

		// @004baa20 -- keep an active beam alive for another frame (re-send the
		// beam message, or tear it down if the target subsystem is gone).
		void
			ContinueDischarge();

		// @004ba478 -- advance the seekVoltage index, wrapping modulo the count;
		// re-arm if it wrapped.  (best-effort name)
		int
			AdvanceSeekVoltage(UpdateRecord *message);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Test Class Support  (EMITTER.TCP)
	//
	public:
		static Logical
			TestClass(Mech&);
		Logical
			TestInstance() const;

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

		Emitter(
			Mech				*owner,
			int					subsystem_ID,
			SubsystemResource	*subsystem_resource,
			SharedData			&shared_data = DefaultData
		);
		~Emitter();

		static int
			CreateStreamedSubsystem(					// @004bb478
				ResourceFile				*resource_file,
				NotationFile				*model_file,
				const char					*model_name,
				const char					*subsystem_name,
				SubsystemResource			*subsystem_resource,
				NotationFile				*subsystem_file,
				const ResourceDirectories	*directories,
				int							passes = 1
			);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Local data for the energy-weapon base class.
	// Byte offsets into the shipped object; MechWeapon ends at +0x3EF.
	//
	protected:
		// --- charge curve (seek voltage) ---
		int		seekVoltageIndex;			// @0x3F0  current charge-curve index
		int		seekVoltageRecommendedIndex;// @0x3F4  resource recommended index (reset target)
		int		seekStepCounter;			// @0x3F8  reset 0   (best-effort)
		int		seekVoltageCount;			// @0x3FC  index modulus / count-1 (best-effort)
		Scalar	seekVoltage[5];				// @0x400  per-index target voltages (heat-scaled)
		Scalar	currentLevel;				// @0x414  accumulated charge   (EMITTER.TCP: currentLevel)
		Scalar	outputVoltage;				// normalised discharge readiness (EMITTER.TCP: outputVoltage)

		// --- additional firing/beam scratch referenced by the recovered bodies ---
		Point3D		beamHitPoint;			// last hit point
		Vector3D	beamImpact;				// impact delta
		Scalar		beamImpactScalar;		// per-shot damage energy at impact
		RGBColor	beamColor;				// beam/team colour
		LinearMatrix	beamHitData;		// pip transform for DrawWeaponPip
		int			firingArmed;			// trigger-armed flag
		Scalar		energyRampTime;			// seek-curve ramp time working value
		// heatAccumulator removed -- it SHADOWED the inherited HeatSink::pendingHeat
		// (@0x1c8, the heat sim's per-frame input); FireWeapon now writes pendingHeat (E5).

		// NOTE: outputVoltage is MechWeapon's recharge-level slot @0x320, reused
		//       by Emitter as the normalised discharge readiness (EMITTER.TCP:
		//       outputVoltage; == 1.0 means "fully charged -> Loaded").

		// --- beam / firing transient state (network-replicated) ---
		int			firingActive;			// @0x418  reset 0; FireWeapon sets 1   (best-effort)
		EulerAngles	beamOrientation;		// @0x41C  aim orientation (3 floats), zeroed at reset
		Vector3D	beamScale;				// @0x42C  reset (1,1,1)                (best-effort)
		Scalar		beamLengthRatio;		// @0x434  range / graphicLength        (best-effort)
		Scalar		graphicLength;			// @0x438  resource GraphicLength
		Scalar		dischargeTime;			// @0x43C  resource DischargeTime
		Scalar		dischargeTimer;			// @0x440  beam-on countdown (reset = dischargeTime)
		Scalar		damageFraction;			// @0x444  damageAmount / (damageAmount + heatCostToFire)
		Scalar		energyTotal;			// @0x448  (damageAmount + heatCostToFire) * 1.0e7  (best-effort)
		Scalar		damagePortion;			// @0x44C  per-shot damage energy           (best-effort)
		Scalar		heatPortion;			// @0x450  per-shot self-heat energy        (best-effort)
		Scalar		energyCoefficient;		// @0x454  energyTotal / (seekVoltage^2 * k) (best-effort)
		Scalar		seekReserved;			// @0x458  reset 0                          (best-effort)
		Scalar		seekRate;				// @0x45C  d(level)/dt working value         (best-effort)
		Point3D		beamEndpoint;			// @0x460  last hit / beam-end point (replicated)
		int			beamFlag;				// @0x46C  beam-active flag        (replicated)
		int			targetLocalFlag;		// @0x470  target-relative vs world (replicated)
		Entity		*targetEntity;			// @0x474  current beam target    (replicated)
	};											// sizeof ~= 0x478

#endif
