//===========================================================================//
// File:	dmgtable.hpp                                                        //
// Project: BattleTech           Brick: Entity Manager                        //
// Contents: Damage lookup table -- layered / pie-slice hit-location selector //
//---------------------------------------------------------------------------//
//   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 header survived for this module
// (dmgtable.hpp/.cpp).  The class cluster lives at @0x49de14..@0x49f5fb, was
// found ADJACENT to (but separate from) the DamageZone code in mechdmg.cpp,
// and is streamed from the ".tbl" notation file by the mech's
// CreateDamageZoneStream (@0x4a474c, mech.cpp) -- caller sites @0x49ed28 is
// invoked from the per-zone parser @line~11580 and the streamed form @0x49ea48
// from the object-stream reader @line~10423.
//
// Identifying strings (data @0x50bc00..0x50bd00):
//   "DamageZone" "video" "skeleton" "%s %f" "RotateWithTorso" "PieSlice"
//   "Layer" "TableEntryOf" "DamageZone Table Format!" "Not Found!"
//   "percentages do not sum to 100%(i.e., 1.0)!" "missing RotateWithTorso!"
//   "error in damage table format" " has bad format!"
// vtables: 0x50bd84 (DamageLookupTable), 0x50bd90 (PieSlice),
//          0x50bd9c (DamageZonePercentTable / leaf).
//
// The table is a three-level hit-location resolver:
//
//   DamageLookupTable  -- stack of armour LAYERS (penetration depth)
//     -> PieSlice      -- an angular sector wheel (optionally torso-relative)
//        -> DamageZonePercentTable
//                       -- a weighted list of {zone segment index, percentage}
//                          whose percentages must sum to 1.0; a uniform random
//                          roll then selects the final damage-zone index.
//
// Class names are reconstructed from the .tbl section keywords; member names
// are inferred from usage and flagged best-effort.  See dmgtable.cpp for the
// per-method @ADDR evidence.
//

#if !defined(DMGTABLE_HPP)
#	define DMGTABLE_HPP

#if !defined(PLUG_HPP)
#	include <plug.hpp>
#endif
#if !defined(TABLE_HPP)
#	include <table.hpp>
#endif

#include "mechrecon.hpp"		// reconstruction shim

//#####################    Forward Class Declarations  #######################
class Mech;
class NotationFile;
class GenericObjectStream;
class Point3D;

//###########################################################################
//#####################   DamageZonePercentTable   ##########################
//###########################################################################
//
//	Leaf node.  Holds a sorted, cumulative-weighted list of damage-zone
//	segment indices and the uniform random "roll" that turns a [0,1) draw into
//	one of those zones.  Built from a ".tbl" "DamageZone" page whose lines are
//	"<zoneName> <percentage>" ("%s %f") and whose percentages must total 1.0.
//	(vtable @0x50bd9c, ctor @0x49deb0, dtor @0x49df80, object size 0x2c.)
//
	class DamageZonePercentTable:
		public Plug
	{
	public:
		//
		// Stream constructor -- rebuilds the entry list from an object stream.
		// @0x49deb0  (FUN_004178cc base Plug ctor, then ReadEntries @0x49e5e4)
		//
		DamageZonePercentTable() {}						// reconstruction: stack-temp default ctor
		DamageZonePercentTable(
			Mech					*owner,
			GenericObjectStream		*stream
		);
		~DamageZonePercentTable();						// @0x49df80

		Logical
			TestInstance() const;						// @0x49e000 (returns True)

		//
		// @0x49de14 -- uniform random weighted roll.  Walks the entries in
		// ascending cumulative-percentage order, draws a [0,1) sample
		// (FUN_00408050) and returns the segment index (entry+0xc) of the first
		// entry whose cumulative threshold (entry+0x14) exceeds the draw.
		// Returns -1 if the list is empty.
		//
		int
			SelectZone() const;

		//
		// @0x49e00c -- parse a "DamageZone" page from the model .tbl: read the
		// "video"/"skeleton" model, then each "<zone> <pct>" line; resolve the
		// zone name to a skeleton segment index (Get_Segment_Index @0x4274f8),
		// accumulate the percentages and verify the total == 1.0.
		// Returns False (and logs) on a bad line, an unknown zone, or a total
		// that does not sum to 1.0.
		//
		static int
			BuildFromNotation(
				NotationFile			*model_file,
				const char				*model_name,
				const char				*page_name,
				NotationFile			*table_file,
				Mech					*owner,
				GenericObjectStream		*stream
			);

		//
		// @0x49e524 WriteEntries (serialise count + {threshold,zone} pairs),
		// @0x49e5e4 ReadEntries (deserialise into the entry table).
		//
		void	WriteEntries(GenericObjectStream *stream) const;	// @0x49e524
		void	ReadEntries (GenericObjectStream *stream);			// @0x49e5e4

	protected:
		Mech			*owner;			// @0x0c  param_1[3]
		void			*refCount;		// @0x10  param_1[4]  (MemoryBlock/RefCount)
		ReconTable<int>	entries;		// @0x14  param_1+5  sorted by cumulative %
										//   each entry: zoneIndex@+0xc, cumulativePercent@+0x14
	};

//###########################################################################
//#############################   PieSlice   ################################
//###########################################################################
//
//	An angular sector "wheel".  N equal-angle slices (each 2*PI/N radians) wrap
//	a circle; the slice that contains the incoming hit direction is chosen and
//	its leaf DamageZonePercentTable is rolled.  When "RotateWithTorso" is set
//	the incoming angle is measured relative to the live torso orientation
//	(orientationSource+0x1d8), so the slice layout turns with the mech's torso.
//	(vtable @0x50bd90, ctor @0x49e740, object size 0x30.)
//
	class PieSlice:
		public Plug
	{
	public:
		//
		// @0x49e740 -- stream constructor.  Reads owner@+0xc and sliceCount@+0x2c,
		// builds 'sliceCount' DamageZonePercentTable children (@0x49deb0) each
		// keyed to a cumulative angle i*(2*PI/sliceCount), and caches the torso
		// orientation source = owner+0x438.
		//
		PieSlice(
			Mech					*owner,
			GenericObjectStream		*stream
		);
		~PieSlice();

		//
		// @0x49e678 -- pick a slice for incoming angle 'theta' (radians).  When
		// rotateWithTorso is set, theta is shifted by the torso orientation
		// (orientationSource+0x1d8) and wrapped into [0, 2*PI).  The slice index
		// = floor(theta * sliceCount / (2*PI)) feeds the child table lookup.
		//
		DamageZonePercentTable *
			SelectSlice(Scalar theta) const;

		//
		// @0x49e88c -- parse a "PieSlice" page: read the mandatory bool
		// "RotateWithTorso" (logged "missing RotateWithTorso!" if absent), then
		// each named sub-page as a DamageZonePercentTable (@0x49e00c).
		// Logs "error in damage table format" on a malformed entry.
		//
		static int
			BuildFromNotation(
				NotationFile			*model_file,
				const char				*model_name,
				const char				*page_name,
				NotationFile			*table_file,
				Mech					*owner,
				GenericObjectStream		*stream
			);

	protected:
		Mech			*owner;					// @0x0c  param_1[3]
		void			*orientationSource;		// @0x10  param_1[4] = owner+0x438 (torso)
		ReconTable<DamageZonePercentTable*>
						slices;					// @0x14  param_1+5
		int				rotateWithTorso;		// @0x28  (read first in BuildFromNotation)
		int				sliceCount;				// @0x2c  param_1[0xb]
	};

//###########################################################################
//#########################   DamageLookupTable   ###########################
//###########################################################################
//
//	Top-level table streamed from the ".tbl" key for a mech.  A stack of armour
//	LAYERS: the deeper a shot penetrates, the higher the layer index selected.
//	Each layer is a PieSlice wheel.  (vtable @0x50bd84, ctor @0x49ea48,
//	dtor @0x49eadc, object size 0x30.)
//
	class DamageLookupTable:
		public Plug
	{
	public:
		//
		// @0x49ea48 -- stream constructor.  Reads layerCount@+0x28 and builds
		// that many PieSlice layers (@0x49e740).
		//
		DamageLookupTable(
			Mech					*owner,
			GenericObjectStream		*stream
		);
		~DamageLookupTable();					// @0x49eadc

		Logical
			TestInstance() const;				// @0x49eb48 / @0x49e880 (returns True)

		//
		// @0x49eb54 -- resolve a hit to a damage zone.  Transforms the impact
		// point into the mech frame (owner+0xd0), derives a penetration-depth
		// fraction (clamped against the armour reference at owner+0x2ec[+0xc]),
		// maps it to a layer index, fetches that layer's PieSlice and forwards
		// an incident angle (computed from the hit direction, or a random draw
		// when the direction is degenerate) to PieSlice::SelectSlice (@0x49e678).
		//
		void
			ResolveHit(const Point3D &impact) const;

		//
		// @0x49ed28 -- parse the layered table.  Reads consecutive "Layer1",
		// "Layer2", ... pages (number suffix via FUN_004dd3ec), parsing each as
		// a PieSlice page (@0x49e88c).  Logs "<name> has bad format!" when no
		// layers are found.
		//
		static int
			BuildFromNotation(
				NotationFile			*model_file,
				const char				*model_name,
				NotationFile			*table_file,
				Mech					*owner,
				GenericObjectStream		*stream
			);

	protected:
		Mech			*owner;					// @0x0c  param_1[3]
		ReconTable<PieSlice*>
						layers;					// @0x10  param_1+4
		int				layerCount;				// @0x28  param_1[10]
	};

//###########################################################################
// Tool support -- entry comparator
//
//	@0x49f301 -- orders table entries by their cumulative threshold (+0x14)
//	within an epsilon (_DAT_0049f369 ~= 1.0e-4).  Used to keep the entry tables
//	sorted so the SelectZone / SelectSlice scans are monotone.
//
	int
		CompareTableEntryThreshold(const void *a, const void *b);

#endif
