//===========================================================================//
// File:	btl4gau2.cpp                                                        //
// Project: BattleTech          Brick: Gauge Renderer Manager                 //
// Contents: Cockpit instrument library, part 2 -- composite panel gauges      //
//           (see btl4gau2.hpp).                                               //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 02/22/96  CPB  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1996, Virtual World Entertainment, Inc. All rights reserved //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//
//
// RECONSTRUCTED from the shipped binary (BTL4OPT.EXE).  Behaviour follows the
// Ghidra pseudo-C in recovered/all/part_014.c (@004c6798..@004c9b50).  Class /
// member names taken from the CODE name-string pool; per-method @ADDR evidence
// is cited inline.  This TU links between btl4gaug.obj and btl4gau3.obj.
//
// Engine-internal helper map (consistent with btl4gaug.cpp / btl4rdr.cpp):
//      FUN_00444818 GraphicGauge ctor    FUN_00444870 GraphicGauge dtor
//      FUN_004448ac GraphicGauge::TestInstance
//      FUN_004440d4 Gauge-group ctor     FUN_00443f7c Gauge-group dtor
//      FUN_0044ae0c ChainOf<Gauge*> dtor (PrepEngrScreen child list)
//      FUN_004442b8 default GaugeRate    FUN_004442dc default ModeMask
//      FUN_00444290 alt default rate/mask
//      FUN_004700ac GaugeRenderer::InternName       FUN_004022e8 FreeName
//      FUN_00442aec/00442c12 BitMapCache  AddRef/Release (renderer+0x4C, +4)
//      FUN_00442d2b/00442e51 PixMapCache  AddRef/Release (renderer+0x4C, +0x20)
//      FUN_0041bfc0 Entity::FindAttributeIndex(name)
//      FUN_0041f98c Entity::FindSubObject(name)
//      FUN_00447f1c GaugeRenderer::InstallPort / FUN_00447f84 GetGraphicsPort
//      FUN_00417ab4 SharedData::Resolve / operator Entity*
//      FUN_0041a1a4 IsDerivedFrom(classDerivations)  (0x50f4bc = Generator)
//      FUN_0042076c Subsystem::FindDamageZone(record) -> index
//      FUN_004dcd94 Round(Scalar) -> int
//      FUN_004700bc NumericDisplay ctor   FUN_0047018c ::dtor
//      FUN_004703f4 NumericDisplay::Reset FUN_00470430 ::DrawAt FUN_00470758 ::Erase
//      FUN_00470ec8 NumericDisplay::SetColors  FUN_00470cfc NumericDisplayInteger ctor
//      FUN_00470888 NumericDisplayScalar ctor   FUN_00473c94 NumericDisplayScalarTwoState
//      FUN_004739d8 TwoState ctor        FUN_00471d00 BackgroundBitmap ctor
//      FUN_00472ef0 BarGraph ctor        FUN_00472fb4 BarGraph dtor
//      FUN_00474855 GaugeConnectionDirectOf<Scalar>::ctor  FUN_004749de <int>
//      FUN_004c2ec4 DrawClippedBitmap (file-private, btl4gaug)  FUN_004c2f88 -> 7
//      FUN_004c3134/004c31ec/004c3288  shared GaugeConnection ctors (btl4gaug TU)
//      FUN_004c4170 HorizTwoPartBar  FUN_004c4724 VertTwoPartBar
//      FUN_004c4d88 OneOfSeveral     FUN_004c5148 OneOfSeveralInt
//      FUN_004c5470 OneOfSeveralStates  FUN_004c5b7c LeakGauge(BitMapInverseWipe)
//      FUN_004c61c8 BitMapInverseWipeScalar  FUN_004c6244 SegmentArc270
//      FUN_004c3b98 ColorMapperArmor ctor (btl4gaug)
//      FUN_0040385c Verify   FUN_004dbb24 DebugStream<<char*  FUN_004db78c <<int
//      DAT_00524e20 DebugStream (warning channel)   DAT_004efc94 the Application
//
// Recovered constant-pool values:
//      0x43660000=230.0f / 0x433b0000=187.0f  SeekVoltageGraph x/y scale
//      0x461c3c00=9999.0f  BecameActive "force redraw" sentinel
//      0x463b8000=12000.0f generator max voltage
//      0x42c80000=100.0f   HeatSinkCluster numeric scale base
//      _DAT_004c8df0 heat numeric scale     _DAT_004c92e0 warning threshold
//      _DAT_004c6bdc/_DAT_004c6be0 seek-curve plot step/limit
//      DAT_0051936c PrepEngr engineer-screen number (1..12)
//

// See btl4gaug.cpp: suppress heat.hpp's optional DebugStream so the shared
// mechrecon ReconStream definition is the only one active in this TU.
#define BT_DEBUGSTREAM_DEFINED

#include <bt.hpp>
#pragma hdrstop

#if !defined(BTL4GAU2_HPP)
#	include <btl4gau2.hpp>
#endif
#if !defined(APP_HPP)
#	include <app.hpp>
#endif

static const Scalar SeekVoltageXScale   = 230.0f;	// 0x43660000
static const Scalar SeekVoltageYScale   = 187.0f;	// 0x433b0000
static const Scalar RedrawSentinel      = 9999.0f;	// 0x461c3c00
static const Scalar GeneratorMaxVoltage = 12000.0f;	// 0x463b8000
static const Scalar HeatNumericBase     = 100.0f;	// 0x42c80000

// (DebugStream warning channel, DAT_00524e20, is provided by the shared
//  reconstruction headers -- heat.hpp / mechrecon.hpp.)

//
// Unrecovered .data resource pool used by GeneratorCluster::Make.  Concrete
// bytes were not recovered from the optimised image; typed placeholders so the
// resolve-and-construct path compiles.  (BEST-EFFORT.)
//
static char DAT_00518f24[] = "GeneratorCluster";	// subsystem name to resolve
static int  DAT_00518ee0 = 0;						// GaugeRate
static char DAT_00518f68[] = "";					// background image name

//
// Original FUN_0041bfc0 = Entity::FindAttributeIndex(name) -> ordinal.  The
// WinTesla engine exposes attribute lookup via Simulation::AttributeIndexSet
// (Find/FindEntry by name) rather than a name->ordinal call, so this best-effort
// shim stands in for it; the stored indices are consumed by the (summarised)
// SeekVoltageGraph::Execute plot.
//
static int FindAttributeIndex(Entity *, const char *) { return -1; }


//###########################################################################
//###########################################################################
//   SeekVoltageGraph                @004c6798
//###########################################################################
//###########################################################################

//
// @004c6798 -- ctor (vtable PTR_FUN_0051a1fc).  GraphicGauge base, interns and
// ref-counts the "destroyed" bitmap, resolves the four SeekVoltage attribute
// indices off the weapon subsystem, sets the port extent (0x97,0x80,0x17d,0x13b)
// and stashes the 230x187 plot scale.
//
SeekVoltageGraph::SeekVoltageGraph(
	GaugeRate			rate,
	ModeMask			mode_mask,
	L4GaugeRenderer		*renderer,
	int					graphics_port_number,
	Entity				*subsystem,
	AttributeAccessor	*seek_voltage_pointer,
	const char			*destroyed_image,
	Logical				draw_cursor,
	const char			*identification_string
):
	GraphicGauge(rate, mode_mask, renderer, /*owner*/0xFFFF,
		graphics_port_number, identification_string)	// FUN_00444818
{
	// Original interned a copy of the name (FUN_004700ac) + AddRef'd it in the
	// bitmap cache; retain the persistent resource string and AddRef the bitmap.
	destroyedImage   = (char *)destroyed_image;
	renderer->warehousePointer->bitMapBin.Get(destroyedImage);		// FUN_00442aec (AddRef)

	currentSeekIndex = FindAttributeIndex(subsystem, "CurrentSeekVoltageIndex");	// FUN_0041bfc0
	minSeekIndex     = FindAttributeIndex(subsystem, "MinSeekVoltageIndex");
	maxSeekIndex     = FindAttributeIndex(subsystem, "MaxSeekVoltageIndex");
	seekVoltageTable = FindAttributeIndex(subsystem, "SeekVoltage");

	voltageSubsystem = (Entity *)seek_voltage_pointer;	// this[0x29]
	this->subsystem  = (Subsystem *)subsystem;			// this[0x2A]

	// graphicsView -> GraphicGauge::localView.  SetExtent == SetPositionWithinPort;
	// the original SetClip() (vtbl+0x0C) constrained drawing to that extent.
	localView.SetPositionWithinPort(0x97, 0x80, 0x17d, 0x13b);	// vtbl+0x08

	xScale          = SeekVoltageXScale;	// this[0x2C]
	yScale          = SeekVoltageYScale;	// this[0x2D]
	drawCursor      = draw_cursor;			// this[0x2F]
	destroyedShown  = 0;					// this[0x2E]
}

//
// @004c68ac -- dtor.  Release the destroyed bitmap, GraphicGauge::~GraphicGauge.
//
// @004c6920 -- BecameActive: previousVoltage = 9999.0f (force first redraw).
//
// @004c6934 -- Execute.  If the subsystem is destroyed (subsys+0x40 == 1) draw
// the centred "destroyed" bitmap once.  Otherwise, when the live seek voltage
// (subsys vtbl+0x3c sampler) changes: clear (SetupClip @004c6be4), re-plot the
// 0..1 voltage curve as a polyline (step _DAT_004c6bdc up to _DAT_004c6be0,
// Round each point), then draw the min/max tick marks (DrawTicks @004c6c6c)
// and, if drawCursor, the live cursor at the current seek index
// (DrawCursor @004c6c30).
//


//###########################################################################
//   ConfigMapGauge                  @004c6d80
//###########################################################################
//
// @004c6d80 -- ctor (vtable PTR_FUN_0051a1b8).  GraphicGauge base; interns the
// joystick base bitmap "btjoy.pcc" (BitMapCache) and the four config-state
// pixmaps cm_off/cm_other/cm_only/cm_both.pcc (PixMapCache); sets the port
// origin (x,y); subsystem = param_9.
// @004c6e54 -- dtor: release btjoy bitmap + 4 pixmaps, GraphicGauge::~GraphicGauge.
// @004c6ee0 -- SetColor: this[0x25] = color.
// @004c6ef4 -- BecameActive: dirty=1; previousState[0..3] = -1.
// @004c6f1c -- Execute.  When dirty, blit the base joystick bitmap.  Then for
// each of the 4 config slots, read the control-mapper state via the table
// DAT_00518eb8 (renderer+0x3c port + 0x1c0 + slot*0x20, sampler vtbl+0x24) and,
// if it changed, MoveTo + stretch-blit the matching cm_* pixmap.
//


//###########################################################################
//   OneOfSeveral data-driven lamps  @004c70a4 / @004c7160
//###########################################################################
//
// @004c70a4 -- AnimatedSubsystemLamp ctor (vtable PTR_FUN_0051a174): chains
// OneOfSeveral::OneOfSeveral (@004c4d88, fromImageStrip=1), selected=0, then
// AddConnection(new <conn @004c3134>(&selected, source)).  dtor @004c7134.
//
// @004c7160 -- AnimatedSourceLamp ctor (vtable PTR_FUN_0051a130): identical but
// the connection ctor is @004c31ec.  dtor @004c71f0.
//
// Both add the connection via (*this+0x34) AddConnection and otherwise inherit
// OneOfSeveral::Execute @004c4f28 (frame select + blit).
//


//###########################################################################
//   ScalarBarGauge                  @004c721c / @004c72ac
//###########################################################################
//
// @004c721c -- ctor (vtable PTR_FUN_0051a0e4): chains the MUNGA L4 bar primitive
// (@00472ef0) then AddConnection(new <conn @004c3288>(&value, source)).
// @004c72ac -- same vtable, but AddConnection(new GaugeConnectionDirectOf<Scalar>
// (@00474855)(&value, scalar)).  Both share dtor @004c733c (chains @00472fb4).
// Used as the generator-voltage bar with range 0..12000.0f.
//


//###########################################################################
//###########################################################################
//   GeneratorCluster                @004c7368 Make / @004c746c ctor
//###########################################################################
//###########################################################################

//
// @004c7368 -- Make.  Resolve the named subsystem ("GeneratorCluster") via
// Entity::FindSubObject (DAT_00518f24); on failure warn "Subsystem <name> not
// found" and return 0.  Else allocate (0xb4) and construct, passing the four
// resource strings / colours from DAT_00518e..00519298.
//
Logical
	GeneratorCluster::Make(
		int				/*display_port_index*/,
		Vector2DOf<int>	/*position*/,
		Entity			*entity,
		GaugeRenderer	*gauge_renderer
	)
{
	Subsystem *subsystem = entity->FindSubsystem((char *)&DAT_00518f24);	// FUN_0041f98c
	if (subsystem == NULL)
	{
		DebugStream << "Subsystem " << (char *)&DAT_00518f24
					<< " not found\n";			// FUN_004dbb24 x3
		return False;
	}

	GeneratorCluster *gauge = (GeneratorCluster *)operator new(0xb4);
	if (gauge != NULL)
	{
		//
		// Construct with the recovered subsystem + name; the geometry / colour /
		// image-name resource arguments (DAT_00518f68..00519298) were not
		// recovered from the optimised image, so are passed as typed placeholders.
		//
		new (gauge) GeneratorCluster(
			(GaugeRate)DAT_00518ee0,			// rate
			(ModeMask)0,						// mode mask
			(L4GaugeRenderer *)gauge_renderer,
			0,									// graphics port number
			0, 0,								// x, y
			(char *)&DAT_00518f68,				// background image
			0,									// color
			(char *)0,							// temperature tile
			(Scalar *)0, (Scalar *)0,			// temp low / high
			(char *)0,							// voltage tile
			(Scalar *)0,						// voltage low
			(char *)0,							// leak image
			(char *)0, (char *)0,				// lampA / lampB images
			0, 0,								// on / off colours
			subsystem,
			"GeneratorCluster");
	}
	return True;
}

//
// @004c746c -- ctor (vtable PTR_FUN_0051a0a0).  GraphicGauge base; resolves
// CurrentTemperature/DegradationTemperature/FailureTemperature/
// CoolantMassLeakRate/OutputVoltage attribute indices; interns the background
// image; then builds the five child gauges (each parented at this graphics
// port, offset from x,y):
//      this[0x26] = new VertTwoPartBar(...,CurrentTemp,Degrade,Fail)   @004c4724
//      this[0x27] = new ScalarBarGauge(0..12000, OutputVoltage)        @004c72ac
//      this[0x28] = new LeakGauge(CoolantMassLeakRate)                 @004c5b7c
//      this[0x29] = new TwoState(lampA, subsys+0x1d4)                  @004739d8
//      this[0x2A] = new TwoState(lampB, subsys+0x1d4)                  @004739d8
//      this[0x2B] = subsystem
// @004c7778 -- dtor: release the background, delete the five children, base dtor.
//


//###########################################################################
//###########################################################################
//   PrepEngrScreen                  @004c7b30 Make / @004c7bf0 ctor
//###########################################################################
//###########################################################################

//
// @004c7b30 -- Make.  DAT_0051936c is the engineer-screen number; must be 1..12
// or "PrepEngr: screen number out of range <n>" is warned.  Allocates (0x90)
// and constructs with seven status-image names (DAT_005193b0..00519548).
//
// @004c7bf0 -- ctor (vtable PTR_FUN_0051a06c).  Derives from the non-graphic
// Gauge group (FUN_004440d4) -- it owns no GraphicsView, only a child-gauge
// chain at +0x24.  Interns and BitMapCache-AddRefs the seven status pixmaps
// (this[0x1D..0x23]); stores mech (this[0x1B]) and screen number (this[0x1C]).
//
// @004c7d14 -- dtor: release + free the seven images, tear down the child chain
// (FUN_0044ae0c), Gauge-group dtor (FUN_00443f7c).
//
// @004c7e48 -- Execute.  Walk the mech's critical-subsystem roster
// (mech+0x124 count, mech+0x128 array).  For each subsystem that (a) is a
// Generator-derived weapon (IsDerivedFrom 0x50f4bc) and (b) belongs to the
// selected screen (subsys+0x1dc == screenNumber), draw its label and -- via
// NumericDisplay (FUN_004700bc/0047043 0) -- its temperature and a HeatSink
// read-out, then dispatch on ClassID to lay out the weapon's status bitmaps
// (FUN_004c79c8 = draw three labelled status cells):
//      0xBC3 Sensor           -> one cell + ammo bitmap (this[0x23])
//      0xBC6                  -> two cells (this[0x22],this[0x20])
//      0xBC8/0xBD4 Emitter/PPC -> three cells (this[0x1E..0x20])
//      0xBCD/0xBD0 Proj/Missile -> one cell (this[0x21])
//      0xBCE GaussRifle       -> warn "Gauss rifle not yet supported", one cell
//


//###########################################################################
//###########################################################################
//   SubsystemCluster family         @004c8140 base
//###########################################################################
//###########################################################################

//
// @004c8140 -- SubsystemCluster ctor (vtable PTR_FUN_0051a020).  GraphicGauge
// base.  Resolves InputVoltage/HeatSink/CurrentTemperature/Degradation/Failure
// attribute indices, then builds the panel's child gauges into its port:
//      this[0x26] HorizTwoPartBar (temperature)            @004c4170
//      this[0x27] AnimatedSubsystemLamp ("CoolingLoop",btploop) @004c70a4
//      this[0x29] AnimatedSourceLamp   ("PowerSource",btpbus)  @004c7160 (if InputVoltage)
//      this[0x24] BackgroundBitmap (if background present)  @00471d00
//      this[0x28] AnimatedSubsystemLamp (bteloop)           @004c70a4
//      this[0x2D] OneOfSeveralInt (btecmode, subsys+0x134)  @004c5148
//      this[0x2A] AnimatedSourceLamp (btebus)               @004c7160 (if InputVoltage)
//      this[0x25] ScalarBarGauge (evolt, GeneratorVoltage)  @004c721c (if InputVoltage)
//      this[0x2E] OneOfSeveralStates (btemode, subsys+0x2b8) @004c5470
//                 (only when subsystem IsDerivedFrom Generator 0x50f4bc)
//      this[0x2C] VertTwoPartBar x2 (temperatures)          @004c4724
//      this[0x2F] LeakGauge (eleak, CoolantMassLeakRate)    @004c5b7c
//      this[0x30] subsystem ; this[0x31] operating
// @004c87dc -- dtor: GraphicGauge::~GraphicGauge (children freed by subclasses).
// @004c88e4 -- Execute: operating = (subsys+0x40==1); when it changes, repaint
// the panel frame (operational => coloured rectangle; offline => background
// bitmap blit) and forward enable to the temperature/loop children
// (SetEnable @004c8a28 / FUN_00444650).
//
// @004c8a6c -- HeatSinkCluster ctor (vtable PTR_FUN_00519fd4): chains
// SubsystemCluster, this[0x36]=100.0f, then builds four failure TwoStates
// (this[0x37] heat, this[0x38] btehfail, this[0x39] btepfail subsys+0x324,
// this[0x3A] btesfail subsys+0x320) and a NumericDisplayScalar (this[0x3B],
// helv18, this[0x36]) plus a Scalar connection (&this[0x35], subsys+0x31c).
// Execute @004c8db0: failFlag = (failSubsystem+0x40==1); heatLoadScaled =
// heatLoad * _DAT_004c8df0; chain SubsystemCluster::Execute.
//
// @004c8fc4 -- WeaponCluster ctor (vtable PTR_FUN_00519f38): chains
// SubsystemCluster; resolves "PercentDone"; interns the cluster image
// (this[0x33]); warns "WeaponCluster missing <name>" if absent; centres a
// SegmentArc270 recharge dial (this[0x34], 0..360, @004c6244) and a
// ConfigMapGauge (this[0x35], "ConfigMap", @004c6d80); adds a Scalar connection
// (&percentDone, PercentDone).  Execute @004c9290: chain base Execute; when
// percentDone > _DAT_004c92e0 toggle the warning lamp (DrawWarningLamp @004c932c).
//
// @004c93b0 -- EnergyWeaponCluster ctor (vtable PTR_FUN_00519ee8): chains
// WeaponCluster; adds a SeekVoltageGraph (this[0x3A], "EngrGraph", edestryd.pcc,
// @004c6798) reading OutputVoltage, and a seek-step OneOfSeveralInt (this[0x3B],
// bteseek.pcc, subsys+0x3f0, @004c5148).  dtor @004c94dc.
//
// @004c9558 -- BallisticWeaponCluster ctor (vtable PTR_FUN_00519e98): chains
// WeaponCluster; resolves the ammo bin (Resolve subsys+0x43c) and builds:
//      this[0x45]/[0x46] NumericDisplayInteger (ammo counts)     @00470cfc
//      this[0x42] TwoState (btejam)  this[0x43] TwoState (btefire) @004739d8
//      this[0x3F] GraphicsViewRecord erase tracker               @0044ad78
//      this[0x40] NumericDisplayScalarTwoState (helv42)          @00473c94
//      this[0x41] TwoState (edestryd)                            @004739d8
//      this[0x44] BitMapInverseWipeScalar (bteejtm, subsys+0x3f8) @004c61c8
// Execute @004c9a38: jammed = (subsys+0x364==5 weaponAlarm Jammed); read the
// ammo-bin reload state (bin+0x18c) and, while reloading, compute elapsed
// seconds (frame clock @00414b60 / DAT_0052140c); chain WeaponCluster::Execute.
// TestInstance @004c9adc: True unless the ammo bin is present and the eject
// wipe is mid-cycle.  dtor @004c9940 frees the GraphicsViewRecord + numeric.
//

// === btl4gau3.cpp begins at @004c9bd0 (PlayerStatusMappingGroup) -- not this TU.
