/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Combat																		  *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/Combat/mapmgr.h           $*
 *                                                                                             *
 *                       Author:: Patrick Smith                                                *
 *                                                                                             *
 *                     $Modtime:: 1/10/02 10:31a                                              $*
 *                                                                                             *
 *                    $Revision:: 8                                                           $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#if defined(_MSC_VER)
#pragma once
#endif

#ifndef __MAP_MGR_H
#define __MAP_MGR_H

#include "vector2.h"
#include "vector3.h"
#include "wwstring.h"
#include "bittype.h"
#include "saveloadsubsystem.h"
#include "combatchunkid.h"


///////////////////////////////////////////////////////////////////////
// Global singleton instance
///////////////////////////////////////////////////////////////////////
extern class MapMgrClass _TheMapMgrSaveLoadSubsystem;


////////////////////////////////////////////////////////////////
//
//	MapMgrClass
//
////////////////////////////////////////////////////////////////
class MapMgrClass : public SaveLoadSubSystemClass
{
public:

	////////////////////////////////////////////////////////////////
	//	Public constants
	////////////////////////////////////////////////////////////////
	enum
	{
		CLOUD_WIDTH			= 20,
		CLOUD_HEIGHT		= 20,
		CLOUD_VECTOR_SIZE	= ((CLOUD_WIDTH * CLOUD_HEIGHT) / 32) + 1,
	};

	////////////////////////////////////////////////////////////////
	//	Public methods
	////////////////////////////////////////////////////////////////

	//
	//	This is the texture that will be used to display the map
	//
	static void					Set_Map_Texture (const char *filename);
	static void					Get_Map_Texture_Filename (StringClass &filename);
	static const char *		Get_Map_Texture_Pathname (void)			{ return MapTextureName; }
	
	//
	//	Map centering and scale.
	//
	//		Note:	The scale means "how many pixels (of map) per meter (of world space)".
	//				This value can differ in the X and Y axes.
	//
	//				The map center is the pixel position (x,y) where world space (0, 0, 0) is.
	//

	static const Vector2 &	Get_Map_Scale (void)							{ return MapScale; }
	static void					Set_Map_Scale (const Vector2 &scale)	{ MapScale = scale; }

	static const Vector2 &	Get_Map_Center (void)						{ return MapCenterPoint; }
	static void					Set_Map_Center (const Vector2 &pos)		{ MapCenterPoint = pos; }

	//
	//	Cloud support
	//
	static void					Clear_Cloud_Cell (const Vector3 &pos);
	static void					Clear_Cloud_Cells (const Vector3 &pos, int pixel_radius);
	static void					Clear_Cloud_Cell (int x_pos, int y_pos);
	static void					Clear_Cloud_Cell_By_Pixel (int x_pos, int y_pos);
	static void					Clear_All_Cloud_Cells (void)				{ ::memset (CloudVector, 0, sizeof (CloudVector)); }
	static void					Cloud_All_Cells (void)						{ ::memset (CloudVector, 0xFF, sizeof (CloudVector)); }
	static bool					Is_Cell_Visible (int x_pos, int y_pos);

	//
	// VTOL Support.  Some maps do not support VTOL aircraft.
	//
	static void					Enable_VTOL_Vehicles(bool onoff)			{ EnableVTOL = onoff; }		
	static bool					Are_VTOL_Vehicles_Enabled(void)			{ return EnableVTOL; }

	//
	//	From SaveLoadSubSystemClass
	//
	uint32						Chunk_ID (void) const			{ return CHUNKID_MAPMGR; }

	//
	//	Title support
	//
	static void					Set_Map_Title (int string_id)	{ MapTitleID = string_id; }
	static int					Get_Map_Title (void)				{ return MapTitleID; }

	//
	//	Player marker control
	//
	static bool					Is_Player_Marker_Visible (void)	{ return IsPlayerMarkerVisible; }
	static void					Show_Player_Marker (bool onoff)	{ IsPlayerMarkerVisible = onoff; }

protected:

	//
	//	From SaveLoadSubSystemClass
	//
	bool							Save (ChunkSaveClass &csave);
	bool							Load (ChunkLoadClass &cload);
	void							On_Post_Load (void);
	const char *				Name (void) const					{ return "MapMgrClass"; }	

	//
	//	Save load support
	//
	void							Load_Variables (ChunkLoadClass &cload);
	
private:

	////////////////////////////////////////////////////////////////
	//	Private member data
	////////////////////////////////////////////////////////////////
	static bool				IsPlayerMarkerVisible;
	static int				MapTitleID;
	static StringClass	MapTextureName;
	static Vector2			MapCenterPoint;
	static Vector2			MapScale;
	static Vector2			MapSize;
	static uint32			CloudVector[CLOUD_VECTOR_SIZE];
	static bool				EnableVTOL;
};


////////////////////////////////////////////////////////////////
//	Clear_Cloud_Cell
////////////////////////////////////////////////////////////////
inline void
MapMgrClass::Clear_Cloud_Cell (const Vector3 &pos)
{
	if (MapSize.X <= 0 || MapSize.Y <= 0) {
		return ;
	}

	//
	//	Calculate where (in map pixels) this position lies
	//
	float map_x_pos	= MapCenterPoint.X + (pos.X * MapScale.X);
	float map_y_pos	= MapCenterPoint.Y - (pos.Y * MapScale.Y);

	//
	//	Convert this map coordinate into a cell coordinate
	//
	int cell_x	= int((map_x_pos / MapSize.X) * CLOUD_WIDTH);
	int cell_y	= int((map_y_pos / MapSize.Y) * CLOUD_HEIGHT);

	//
	//	Clamp the cells
	//
	cell_x = max (cell_x, 0);
	cell_y = max (cell_y, 0);
	cell_x = min (cell_x, CLOUD_WIDTH - 1);
	cell_y = min (cell_y, CLOUD_HEIGHT - 1);

	//
	//	Determine which bit we need to clear
	//
	int bit_offset	= (cell_y * CLOUD_WIDTH) + cell_x;
	int index		= bit_offset / 32;
	int bit			= (bit_offset - (index * 32)) + 1;

	//
	//	Clear the bit
	//
	CloudVector[index] &= ~(1 << bit);
	return ;
}


////////////////////////////////////////////////////////////////
//	Clear_Cloud_Cell
////////////////////////////////////////////////////////////////
inline void
MapMgrClass::Clear_Cloud_Cell (int x_pos, int y_pos)
{
	if (MapSize.X <= 0 || MapSize.Y <= 0) {
		return ;
	}

	//
	//	Clamp the cells
	//
	int cell_x	= max (x_pos, 0);
	int cell_y	= max (y_pos, 0);
	cell_x		= min (x_pos, CLOUD_WIDTH - 1);
	cell_y		= min (y_pos, CLOUD_HEIGHT - 1);

	//
	//	Determine which bit we need to clear
	//
	int bit_offset	= (cell_y * CLOUD_WIDTH) + cell_x;
	int index		= bit_offset / 32;
	int bit			= (bit_offset - (index * 32)) + 1;

	//
	//	Clear the bit
	//
	CloudVector[index] &= ~(1 << bit);
	return ;
}


////////////////////////////////////////////////////////////////
//	Clear_Cloud_Cell_By_Pixel
////////////////////////////////////////////////////////////////
inline void
MapMgrClass::Clear_Cloud_Cell_By_Pixel (int x_pos, int y_pos)
{
	if (MapSize.X <= 0 || MapSize.Y <= 0) {
		return ;
	}

	//
	//	Convert this map coordinate into a cell coordinate
	//
	int cell_x	= int((x_pos / MapSize.X) * CLOUD_WIDTH);
	int cell_y	= int((y_pos / MapSize.Y) * CLOUD_HEIGHT);

	//
	//	Clamp the cells
	//
	cell_x = max (cell_x, 0);
	cell_y = max (cell_y, 0);
	cell_x = min (cell_x, CLOUD_WIDTH - 1);
	cell_y = min (cell_y, CLOUD_HEIGHT - 1);

	//
	//	Determine which bit we need to clear
	//
	int bit_offset	= (cell_y * CLOUD_WIDTH) + cell_x;
	int index		= bit_offset / 32;
	int bit			= (bit_offset - (index * 32)) + 1;

	//
	//	Clear the bit
	//
	CloudVector[index] &= ~(1 << bit);
	return ;
}


////////////////////////////////////////////////////////////////
//	Is_Cell_Visible
////////////////////////////////////////////////////////////////
inline bool
MapMgrClass::Is_Cell_Visible (int x_pos, int y_pos)
{
	int bit_offset	= (y_pos * CLOUD_WIDTH) + x_pos;
	int index		= bit_offset / 32;
	int bit			= (bit_offset - (index * 32)) + 1;
	
	//
	//	Index into the vector to see if this cell is clouded or not
	//
	return ((CloudVector[index] & (1 << bit)) == 0);
}

#endif //__MAP_MGR_H

