//===========================================================================//
// File:	mechsub.hpp                                                         //
// Project: BattleTech           Brick: Entity Manager                        //
// Contents: MechSubsystem -- BT damage-coupled base for all mech subsystems  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
//  --/--/95  ??   Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All Rights reserved //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//
//
// RECONSTRUCTED from the shipped binary.  No mechsub.hpp survived, but the
// surviving MECHTECH.HPP `#include <mechsub.hpp>` and references
// `MechSubsystem::TechStatusTypeCount`, `MechSubsystem *monitoredSubsystem`,
// confirming a distinct BT class named MechSubsystem.
//
// RECONCILIATION VERDICT:  MechSubsystem IS a distinct base class -- it is NOT
// an alias for the MUNGA `Subsystem` (RP/MUNGA/SUBSYSTM.HPP, which has no
// "Tech" status and no DamageZone coupling).  It sits between MUNGA Subsystem
// and HeatableSubsystem:
//
//      Simulation (MUNGA)
//        Subsystem (MUNGA, SUBSYSTM.HPP -- we have it)
//          MechSubsystem            <-- THIS FILE (classID 0xBBB, vtable 0x50e210)
//            HeatableSubsystem      (heat.cpp -- string @0x50e700, classID 0xBBC?)
//              HeatSink ...         (heat.cpp / heatfamily_reslice.cpp)
//            MechTech               (mechtech.cpp -- : MechSubsystem? see note)
//            <non-heatable mech subsystems>
//
// *** CLASSMAP CORRECTION (for the next reconciler) ***
// The heat.cpp / heat.hpp reconstruction attributed the cluster
// @0x4ac07c..@0x4ac9ec (vtable 0x50e210, dtor 0x4ac868) to its
// "Subsystem/HeatableSubsystem base".  The string and behavioural evidence say
// that cluster is actually MechSubsystem:
//   * CreateStreamedSubsystem @0x4ac9ec stamps classID 0xBBB and model size
//     0xE4, and parses ONLY damage/critical fields (PrintSimulationState,
//     CollisionCriticalHitWeight, VideoObjectName, VitalSubsystem) -- NO
//     thermal fields.  (Thermal init is HeatSink's @0x4ae150.)
//   * The ClassDerivations name string is "MechSubsystem" (@0x50def5,
//     @0x50e2fd), distinct from "HeatableSubsystem" (@0x50e700).
//   * The class couples the subsystem to a DamageZone (this+0xE0) and exposes
//     the subsystem status/alarm with state names @0x50df17:
//       Destroyed / Damaged / CoolantLeaking / Overheating / AmmoBurning /
//       Jammed / BadPower   (TechStatusTypeCount of these), plus the
//       PrintSimulationState names DefaultState / Destroyed / Exploding.
// heat.cpp's `HeatableSubsystem(currentTemperature@0x114)` ctor @0x4ac644 does
// NOT write 0x114 -- it is in fact a MechSubsystem ctor.  HeatableSubsystem is
// a (near-empty) layer above MechSubsystem; the temperature/heat fields belong
// to HeatSink (@0x4adda0).
//
// This reconstruction is BEST-EFFORT and overlaps heat.cpp; names of the
// MechSubsystem data members are inferred from usage.  See mechsub.cpp for the
// per-method @ADDR evidence.
//

#if !defined(MECHSUB_HPP)
#	define MECHSUB_HPP

#if !defined(SUBSYSTM_HPP)
#	include <subsystm.hpp>
#endif
#if !defined(DAMAGE_HPP)
#	include <damage.hpp>
#endif
#include <affnmtrx.hpp>			// AffineMatrix
#include <average.hpp>			// AverageOf<T>
#include <scalar.hpp>			// Scalar
#include <alarm.hpp>			// GaugeAlarm

#include "mechrecon.hpp"		// reconstruction shim (proxies, artifact globals, type aliases)

//#####################    Reconstruction type aliases   #####################
#if !defined(BT_RECON_TYPE_ALIASES)
#	define BT_RECON_TYPE_ALIASES
	typedef AffineMatrix		Matrix34;		// 3x4 affine (AFFNMTRX.h)
	typedef GaugeAlarm			AlarmIndicator;	// GAUGALRM.h
	typedef AverageOf<Scalar>	FilteredScalar;	// 15-sample running average (AVERAGE.h)
#endif

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

//###########################################################################
//#####################   MechSubsystem Model Resource   ####################
//###########################################################################
//
// Extends the base Subsystem resource.  The mech-specific fields begin at +0x30
// in the parsed resource record (see MechSubsystem::CreateStreamedSubsystem
// @0x4ac9ec).  Resource record size = 0xE4.
//
	struct MechSubsystem__SubsystemResource:
		public Subsystem::SubsystemResource
	{
		Scalar	armorByFacing[5];			// +0x30  per-facing armour (default -1.0f)
		Scalar	structureReference;			// +0x44  health/structure divisor (default -1.0f)
		int		vitalSubsystemIndex;		// +0x48  "VitalSubsystem" segment (default -1)
		char	videoObjectName[128];		// +0x4C  "VideoObjectName" (default "None")
		ResourceDescription::ResourceID
				alarmModel;					// +0xCC  (resolved id; the RECORD reserves a
											//         12-byte field here -- @004ac9ec parses
											//         it via FUN_00408944 as 3 floats.  The
											//         reconstruction only consumes the leading
											//         id, but the 12-byte footprint MUST be
											//         preserved or every field below slides
											//         8 bytes low and the heat resource --
											//         which begins at +0xE4 -- misaligns.)
		int		_alarmModelReserved[2];		// +0xD0  remainder of the 12-byte 0xCC field
		int		printSimulationState;		// +0xD8  "PrintSimulationState"
		Scalar	collisionCriticalHitWeight;	// +0xDC  "CollisionCriticalHitWeight"
		Scalar	criticalReference;			// +0xE0  (default -1.0f)
	};

//###########################################################################
//##########################   MechSubsystem   #############################
//###########################################################################
//
//	Abstract BT base for every subsystem mounted in a mech.  Owns a DamageZone
//	(this+0xE0) representing its armour facings and structural integrity, a
//	3+-level status alarm (this+0x2C) reported by the cockpit MechTech, and the
//	critical-hit / damage-distribution machinery.
//	(vtable @0x50e210, ctors @0x4ac530 / @0x4ac644, dtor @0x4ac868,
//	classID 0xBBB, resource model size 0xE4.)
//
	class MechSubsystem:
		public Subsystem
	{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Shared Data Support
	//
	public:
		static Derivation ClassDerivations;		// name string "MechSubsystem"
		static SharedData DefaultData;
		static Recon	MessageHandlers;		// SharedData ctor operand
		enum { StateCount = 7 };				// TechStatusTypeCount

		// alarm-changed callback (vtable slot +0x34) + host back-pointer
		void			OnAlarmChanged();
		Mech			*owner;					// owning mech (== hostEntity)

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Status model
	//
	public:
		// Damage/condition status states (alarm @this+0x2C).  Parsed from the
		// state-name table @0x50df17 by ConfigureActivePress (@0x4ac194).
		enum TechStatusType {
			Destroyed		= 0,
			Damaged			= 1,
			CoolantLeaking	= 2,
			Overheating		= 3,
			AmmoBurning		= 4,
			Jammed			= 5,
			BadPower		= 6,
			TechStatusTypeCount		// = 7  (referenced by MECHTECH.HPP)
		};

		// Simulation-state values stored at this+0x40 (printed by PrintState).
		enum SimulationState {
			DefaultState	= 0,
			DestroyedState	= 1,
			ExplodingState	= 2
		};

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

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

		// @0x4ac530 -- light ctor (name + classID); DamageZone named "None".
		MechSubsystem(
			Mech						*owner,
			int							subsystem_ID,
			const char					*subsystem_name,
			RegisteredClass::ClassID	class_id,
			SharedData					&shared_data = DefaultData
		);

		// @0x4ac644 -- resource ctor; copies armorByFacing[5] -> DamageZone+0x144,
		// structureReference -> DamageZone+0x140, and pre-inverts the armour
		// scalars (1.0 / (armour * reference)) where above epsilon.
		// (heat.cpp mislabels this as "HeatableSubsystem".)
		MechSubsystem(
			Mech						*owner,
			int							subsystem_ID,
			SubsystemResource			*subsystem_resource,
			SharedData					&shared_data = DefaultData
		);

		~MechSubsystem();				// @0x4ac868

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

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Subsystem virtual overrides (slots on vtable @0x50e210)
	//
	public:
		LWord
			GetStatusFlags();						// slot 12, @0x4ac144
		void
			ResetToInitialState(Logical powered);	// slot  8, @0x4ac1d4
		void
			PrintState();							// slot 13, @0x4ac8c0
		Logical
			HandleMessage(int message);				// @0x4ac0bc
		virtual void
			TakeDamage(Damage &damage);				// slot via this+0x24 (see DamageDelta)
		Logical
			IsDamaged();							// @0x4ac9c8 (bus-state query)

		// Critical-state readouts for ColorMapperCritical (CriticalConnection):
		// the raw simulation state (DefaultState=0 / Destroyed=1 / Exploding=2) and
		// the subsystem's own damage zone (a real DamageZone behind the proxy type;
		// set in the ctor via `new DamageZone(...)`, mechsub.cpp).
		int
			GetSimulationState() const	{ return simulationState; }
		ReconDamageZone *
			GetDamageZoneProxy() const	{ return damageZone; }

		// gauge-complete wave: this subsystem's OWN structural damage [0,1] (0=intact,
		// 1=destroyed) -- the engine DamageZone::damageLevel of the zone the ctor built
		// (new DamageZone(this,0) @0xE0).  Read via the ENGINE type's NAMED member (not
		// the ReconDamageZone proxy, whose offset-0 structureLevel aliases the vtable
		// ptr as a float = garbage).  The binary reads *(this[0x38]+0x158) here (== the
		// same anchor UpdateCoolant/SensorSimulation use).  Defined in mechsub.cpp.
		Scalar	GetSubsystemDamageLevel() const;
		void	SetSubsystemDamageLevel(Scalar level);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Internal helpers
	//
	protected:
		// @0x4ac07c -- run TakeDamage and return the resulting drop in
		// structureLevel (DamageZone+0x158).
		Scalar	ApplyDamageAndMeasure(Damage &damage);

		// @0x4ac22c -- clear structure & both alarms to the inactive level.
		void	ClearStatus();

		// @0x4ac274 -- distribute a critical hit across the contained critical
		// subsystems, scaling damage by 1/criticalCount and logging
		// "ammo explosion damaging ".
		void	DistributeCriticalHit(Damage &damage);

		// @0x4ac194 -- map a status-state name string -> TechStatusType value
		// using the name table @0x50de74 (ConfigureActivePress support).
		static Logical
			LookupStatusType(const char *name, int *out_value);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Local data (byte offsets into the shipped object)
	//
	protected:
		AlarmIndicator	statusAlarm;		// @0x2C  this+0xb (condition/status alarm)
		int				simulationState;	// @0x40  DefaultState/Destroyed/Exploding
		ReconDamageZone	*damageZone;		// @0xE0  this[0x38] (0x160-byte zone)
		int				videoObjectFlag;	// @0xE4  this[0x39]
		Mech			*hostEntity;		// @0xE8  this[0x3a]
		int				subsystemId2;		// @0xEC  this[0x3b]
		SubsystemResource *resource;		// @0xF0  this[0x3c]
		void			*refCount;			// @0xF4  this[0x3d]
		ResourceDescription::ResourceID
						alarmModel;			// @0xF8  this[0x3e]
		int				printSimulationState;	// @0x104 this[0x41]
		Scalar			criticalReference;	// @0x108 this[0x42]
		Scalar			collisionCriticalHitWeight;	// @0x10C this[0x43]
		int				vitalSubsystemIndex;	// @0x110 this[0x44] (default -1)
	};

#endif
