#define MW4PRINT

#define Check_Pointer(x)
#define Check_Object(x)
#define Verify(x)
#define gosASSERT(x)

#define MString CString
#define GetLengthSafe GetLength

#define Scalar float

#define Max_Clamp(v,c) if (v>c) v=c; else (void)0

class ReplicatorID;
class MemoryStream;
class DynamicMemoryStream;

namespace Adept
{
	enum
	{
		BeamDamageType = 0,
		MissileDamageType,
		ProjectileDamageType,
		SplashDamageType,
		HeatDamageType,
		RammingDamageFromAboveType,
		RammingDamageFromBelowType,
		RammingDamageFromLeftType,
		RammingDamageFromRightType,
		RammingDamageFromAheadType,
		RammingDamageFromBehindType,
		HighExplosiveDamageType,
		LavaDamageType,
		AmmoFireDamageType

	};
    namespace DamageObject
    {
		enum {
			NullZone=-1,
			LeftLegZone = 0,	//Mech pieces must follow default zone
			RightLegZone,
			LeftArmZone,
			RightArmZone,
			RightTorsoZone,
			LeftTorsoZone,
			CenterTorsoZone,
			HeadZone,
			SpecialZone1,
			SpecialZone2,
			VehicleHullZone, //All Vehicle and non-mech zones must be after the specials
			VehicleWeaponZone,
			VehicleSpecialZone,
			DefaultZone,
			NextDamageZone
		};
		enum {
			NullArmorZone=-1,
			LeftLegArmorZone = 0,
			RightLegArmorZone,
			LeftArmArmorZone,
			RightArmArmorZone,
			RightTorsoArmorZone,
			LeftTorsoArmorZone,
			CenterTorsoArmorZone,
			CenterRearTorsoArmorZone,
			HeadArmorZone,
			SpecialArmorZone1,
			SpecialArmorZone2,
			DefaultArmorZone
		};
    }

	class AdeptNetMissionParameters
	{
	public:
		int m_runDedicated;
		int m_closedGame;
		int m_playerLimit;
		

		int m_visibility;

		
		AdeptNetMissionParameters();

		virtual void ResetParameters(void);
		virtual void SaveParameters(DynamicMemoryStream *stream);
		virtual void LoadParameters(MemoryStream *stream);
	};
}
using namespace Adept;

namespace NetMissionParameters
{
	class TeamParameters
	{
	public:
		int m_maxPlayersOnTeam;
		int m_minimumTonnage;
		int m_maximumTonnage;
		int m_maximumTotalTonnage;
		Scalar m_currentTotalTonnage;
		int m_skin;
		int m_alignment;

		DWORD m_allowedMech[2];
		DWORD m_allowedBeam[2];
		DWORD m_allowedMissile[2];
		DWORD m_allowedProjectile[2];
		DWORD m_allowedSubsystem[2];

		TeamParameters();
		void ResetParameters(int index);
		void SaveParameters(DynamicMemoryStream *stream);
		void LoadParameters(MemoryStream *stream);

	};

	class MWNetMissionParameters : public AdeptNetMissionParameters
	{
	public:

		int m_joinInProgress;
		int m_joinInProgressCutOff;
		int m_joinInProgressCutOffTime;

		int m_heatOn;
		int m_killLimit;
		int m_killLimitNumber;
		int m_respawnLimit;
		int m_respawnLimitNumber;
		int m_forceRespawn;
		int m_splashOn;
		int m_weaponjamOn;
		int m_ammobayfireOn;
// MSL 5.05 Advance Mode
		int m_advancemodeOn;
// MSL 5.06 Armor Mode
		int m_armormodeOn;
		int m_splashPercentage;
		int m_unlimitedAmmo;
		int m_friendlyFirePercentage;
		int m_allowZoom;
		int m_allow3rdPerson;
		int m_allowAutoAim;
		int m_allowDeadToChat;
		int m_invulnerableDrop;
		int m_isNight;

		
		int m_weather;
		int m_reportStats;
		int m_serverConnection;
		int m_serverBandwidth;

		int m_radarMode;

		int m_onlyStockMech;
		int m_minimumTonnage;
		int m_maximumTonnage;

		int m_gameLength;
		int m_serverRecycle;
		int m_recycleDelay;
		int m_playMissionReview;

		int m_ruleType;
		int m_deadMechCantSee;
		int m_deadMechCantSeeOtherTeam;

		int m_allowdecaltransfer;
		int m_useMapCycle;
		int m_pureMapCycle;

		


		DWORD m_allowedMech[2];
		DWORD m_allowedBeam[2];
		DWORD m_allowedMissile[2];
		DWORD m_allowedProjectile[2];
		DWORD m_allowedSubsystem[2];

		// there are always 8 teams,
		// but sometimes a team won't allow players
		int m_teamAllowed;
		int m_teamCount;
		TeamParameters m_teamParams[8];

		int m_maxPlayers;
		int m_maxBots;
		int m_mapID;
		char m_mapName[128];
		char m_scenarioName[128];
		char m_scenarioPath[128];
		char m_serverName[256];
		char m_serverIP[256];
		char m_serverCPU[256];
		char m_scriptName[256];
		char m_scenarioText[1024];

		__int64 m_mapClientCRC;

		MWNetMissionParameters();

		void ResetParameters(void);
		void SaveParameters(DynamicMemoryStream *stream);
		void LoadParameters(MemoryStream *stream);

	};
};
using namespace NetMissionParameters;

namespace CBucketManager
{
	enum Bucket_Type {
		KILL_LINK		= 0,				// linked to mission scoring system
		DEATH_LINK		= 1,       // linked to mission scoring system
												// mods
		KILLS					= 2,
		FRIENDLY_KILLS			= 3,
		ENEMY_KILLS				= 4,
		KILLS_BY_TONNAGE		= 5,
		FRIENDLY_KILLS_BY_TONNAGE = 6,
		ENEMY_KILLS_BY_TONNAGE	= 7,
		DEATHS					= 8,
		SUICIDES				= 9,
		DAMAGE_INFLICT			= 10,
		FRIENDLY_DAMAGE_INFLICT	= 11,
		ENEMY_DAMAGE_INFLICT	= 12,
		DAMAGE_RECEIVE			= 13,
		FRIENDLY_DAMAGE_RECEIVE	= 14,
		ENEMY_DAMAGE_RECEIVE	= 15,
		COMPONENT_KILLS			= 16,
		COMPONENT_DEATHS		= 17,
		FRIENDLY_COMPONENT_KILLS = 18,
		FRIENDLY_COMPONENT_DEATHS = 19,
		ENEMY_COMPONENT_KILLS	= 20,
		ENEMY_COMPONENT_DEATHS	= 21,
		DFA						= 22,
		SHOTS_HIT				= 23,
		SHOTS_FIRED				= 24,
		HEAD_SHOTS				= 25,
		ARM_SHOTS				= 26,
		LEG_SHOTS				= 27,
		TORSO_SHOTS				= 28,
		KILLS_PC				= 29,
		KILLS_AI				= 30,
		BLANK					= 31,		// used just to hold values
// these are automatically checked
		SHUTDOWN_TIMER			= 32,
		OBJECTIVE				= 33,	  // mod2 is distance
		OBJECTIVE_CONTESTED		= 34,
		OBJECTIVE_UNCONTESTED	= 35,
		FLAGS_TAKEN				= 36,
		FLAGS_DROPPED			= 37,
		FLAGS_CAPTURED			= 38,
		FLAG_HOLD_TIME			= 39,
		TIME					= 40,
		ALIVE_PLAYERS			= 41,
		DEAD_PLAYERS			= 42,
		CUSTOM					= 43,
// MSL 5.04 bucket
//			MAX_TYPES				= 44
		ENEMY_TURRET_KILLS		= 44,	
		FRIENDLY_TURRET_KILLS	= 45,
		ENEMY_BUILDING_KILLS	= 46,
		FRIENDLY_BUILDING_KILLS	= 47,
		MAX_TYPES				= 48
	};
}

using namespace CBucketManager;

namespace MWApplication
{
	enum Bandwidth_Type{
		c_14_4kbps = 0,
		c_28_8kbps,
		c_56_6kbps,
		c_64_kbps,
		c_128_kbps,
		c_384_kbps,
		c_768_kbps,
		c_1500_kbps,
		c_10_Mbps,
		c_100_Mbps
	};

	enum Connection_Type{
		Modem = 0,
		ISDN,
		xDSL,
		Cable,
		LAN
	};
}
using namespace MWApplication;

class ReplicatorID
{
public:
	ReplicatorID() : connectionID(0), localID(0)
    {Check_Pointer(this);}

	ReplicatorID(const ReplicatorID& id) : connectionID(id.connectionID), localID(id.localID)
    {Check_Pointer(this); Check_Object(&id);}

	explicit ReplicatorID(BYTE connection_id) : connectionID(connection_id), localID(0)
	{Check_Pointer(this);}

	ReplicatorID(BYTE connection_id, WORD local_id) : connectionID(connection_id), localID(local_id)
	{Check_Pointer(this);}

public:
	static ReplicatorID Null;

    bool operator!() const { Check_Object(this); return operator==(Null); }

	ReplicatorID& operator=(const ReplicatorID& id)
	{
		Check_Pointer(this); Check_Object(&id);
		connectionID = id.connectionID; localID = id.localID;
		return *this;
	}

	ReplicatorID& operator+=(const ReplicatorID& id)
	{
		Check_Object(this); Check_Object(&id);
		connectionID = static_cast<BYTE>(connectionID + id.connectionID);
		localID = static_cast<WORD>(localID + id.localID);
		return *this;
	}

	ReplicatorID& operator+=(WORD span)
    {
        Check_Object(this); localID = static_cast<WORD>(localID + span); return *this;
    }

	ReplicatorID& operator++()
	{Check_Pointer(this); ++localID; return *this;}

	bool operator<(const ReplicatorID& id) const
	{
		Check_Object(this); Check_Object(&id);
		return
			(connectionID == id.connectionID) ?
				(localID < id.localID) :
				(connectionID < id.connectionID);
	}

	bool operator<=(const ReplicatorID& id) const
	{
		Check_Object(this); Check_Object(&id);
		return
			(connectionID == id.connectionID) ?
				(localID <= id.localID) :
				(connectionID < id.connectionID);
	}

	bool operator>(const ReplicatorID& id) const
	{
		Check_Object(this); Check_Object(&id);
		return
			(connectionID == id.connectionID) ?
				(localID > id.localID) :
				(connectionID > id.connectionID);
	}

	bool operator>=(const ReplicatorID& id) const
	{
		Check_Object(this); Check_Object(&id);
		return
			(connectionID == id.connectionID) ?
				(localID >= id.localID) :
				(connectionID > id.connectionID);
	}

	bool operator==(const ReplicatorID& id) const
	{
		Check_Object(this); Check_Object(&id);
		return (connectionID == id.connectionID && localID == id.localID);
	}

	bool operator!=(const ReplicatorID& id) const
	{
		Check_Object(this); Check_Object(&id);
		return
			(connectionID != id.connectionID || localID != id.localID);
	}

	BYTE connectionID;
	WORD localID;
};


const int End_Of_Stream=-1;

const int Empty_Bit_Buffer=-20;


class MemoryStream
{
public:
	MemoryStream(void *stream_start, DWORD stream_size, DWORD initial_offset=0);
	virtual ~MemoryStream();

public:
	virtual void* GetPointer() const
		{Check_Object(this); return currentPosition;}
    BYTE* GetStreamStart() const
        {Check_Object(this); return streamStart; }
	DWORD GetIndex() const
		{Check_Object(this); return currentPosition - streamStart;}
	DWORD GetSize() const
		{Check_Object(this); return streamSize;}

	DWORD GetBufferBytesUsed()
		{Check_Object(this); return highWaterByte - streamStart;}


	DWORD GetBytesUsed() const
		{Check_Object(this); return currentPosition - streamStart;}
	virtual DWORD GetBytesRemaining() const
		{Check_Object(this); return streamSize - GetBytesUsed();}


	void AdvanceToDwordBoundary()
		{
			Check_Pointer(this);

			if((int)currentPosition & 0x3)
			{
				AdvancePointer(4-(int)currentPosition & 0x3);
			}

			Check_Object(this);
		}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Assignment methods
//
public:
	virtual void SetPointer(void *new_pointer)
		{
			Check_Pointer(this);
			currentPosition = (BYTE*)new_pointer;

			if (currentPosition > highWaterByte)
				highWaterByte = currentPosition;

			Check_Object(this);
		}
	void operator=(void *new_pointer)
		{SetPointer(new_pointer);}

	virtual void SetPointer(DWORD index)
		{
			Check_Pointer(this);
			currentPosition = streamStart + index;
			
			if (currentPosition > highWaterByte)
				highWaterByte = currentPosition;

			Check_Object(this);
		}
	void operator=(DWORD index)
		{SetPointer(index);}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Stream methods
//
public:
	void Rewind()
		{SetPointer((DWORD) 0U);currentBit = Empty_Bit_Buffer;}

	virtual bool AllocateBytes(DWORD count)
		{return GetBytesRemaining() <= count;}
	virtual MemoryStream& AdvancePointer(DWORD count)
		{
			Check_Object(this);
			currentPosition += count;

			if (currentPosition > highWaterByte)
				highWaterByte = currentPosition;

			Verify(currentPosition >= streamStart);
			Verify(currentPosition <= streamStart + streamSize);

			Check_Object(this);
			return *this;
		}
	MemoryStream& operator+=(DWORD count)
		{return AdvancePointer(count);}

	virtual MemoryStream& RewindPointer(DWORD count)
		{
			Check_Object(this);
			currentPosition -= count;

			if (currentPosition > highWaterByte)
				highWaterByte = currentPosition;

			Verify(currentPosition >= streamStart);
			Verify(currentPosition <= streamStart + streamSize);

			Check_Object(this);
			return *this;
		}
	MemoryStream& operator-=(DWORD count)
		{return RewindPointer(count);}

	virtual MemoryStream& ReadBytes(
		void *ptr,
		DWORD number_of_bytes
	);
	virtual MemoryStream& WriteBytes(
		const void *ptr,
		DWORD number_of_bytes
	);

	MemoryStream& ReadSwappedBytes(
		void *ptr,
		DWORD number_of_bytes
	);
	MemoryStream& WriteSwappedBytes(
		const void *ptr,
		DWORD number_of_bytes
	);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Bit operators  
//
// WARNING - DO NOT MIX AND MATCH WITH BYTE METHODS!!!!!
//

private:
	int currentBit;

	BYTE workingBitBuffer;

	MemoryStream& ReadUnsafeBits(void *ptr, DWORD number_of_bits);

public:
	int GetCurrentBitCount()
	{
		Check_Object(this);
		int current_bit = GetBytesUsed() * 8;
		if (currentBit != Empty_Bit_Buffer)
		{
			current_bit -= (8-currentBit);
		}

		return current_bit;
	}

	MemoryStream& ReadBit(bool &bit_value);
	MemoryStream& WriteBit(const bool &bit_value);

	MemoryStream& ReadBits(__int64 *ptr, DWORD number_of_bits)
		{
			Verify(number_of_bits <= 64);
			Check_Object(this); Check_Pointer(ptr);
			*ptr = 0; return ReadUnsafeBits(ptr, number_of_bits);
		}
	
	MemoryStream& ReadBits(int *ptr, DWORD number_of_bits)
		{
			Verify(number_of_bits <= 32);
			Check_Object(this); Check_Pointer(ptr);
			*ptr = 0; return ReadUnsafeBits(ptr, number_of_bits);
		}

	MemoryStream& ReadBits(BYTE *ptr, DWORD number_of_bits)
		{
			Verify(number_of_bits <= 8);
			Check_Object(this); Check_Pointer(ptr);
			*ptr = 0; return ReadUnsafeBits(ptr, number_of_bits);
		}


	MemoryStream& ReadBits(WORD *ptr, DWORD number_of_bits)
		{
			Verify(number_of_bits <= 16);
			Check_Object(this); Check_Pointer(ptr);
			*ptr = 0; return ReadUnsafeBits(ptr, number_of_bits);
		}

	MemoryStream& ReadBits(DWORD *ptr, DWORD number_of_bits)
		{
			Verify(number_of_bits <= 32);
			Check_Object(this); Check_Pointer(ptr);
			*ptr = 0; return ReadUnsafeBits(ptr, number_of_bits);
		}

	MemoryStream& ReadBits(float *ptr, DWORD number_of_bits)
		{
			Verify(number_of_bits == 32);
			Check_Object(this); Check_Pointer(ptr);
			*ptr = 0.0; return ReadUnsafeBits(ptr, number_of_bits);
		}


	MemoryStream& ReadBits(double *ptr, DWORD number_of_bits)
		{
			Verify(number_of_bits == 64);
			Check_Object(this); Check_Pointer(ptr);
			*ptr = 0.0; return ReadUnsafeBits(ptr, number_of_bits);
		}

	MemoryStream& WriteBits(const void *ptr, DWORD number_of_bits);
	
	MemoryStream& ReadBitsToScaledInt(int &number, int min, int max,  DWORD number_of_bits);
	MemoryStream& WriteScaledIntToBits(const int &number, int min, int max,  DWORD number_of_bits);

	MemoryStream& ReadBitsToScaledFloat(float &number, float min, float max,  DWORD number_of_bits);
	MemoryStream& WriteScaledFloatToBits(const float &number, float min, float max,  DWORD number_of_bits);


	void WriteByteAlign();

	void ReadByteAlign();



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected data
//
protected:
	BYTE
		*streamStart,
		*currentPosition,
		*highWaterByte;
	DWORD streamSize;
};

class DynamicMemoryStream:
	public MemoryStream
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, destruction, and testing
//
public:
	DynamicMemoryStream(DWORD stream_size=0);
	DynamicMemoryStream(
		void *stream_start,
		DWORD stream_size,
		DWORD initial_offset=0
	);
	DynamicMemoryStream(const DynamicMemoryStream& otherStream);
	~DynamicMemoryStream();

	void TestInstance() const
		{
			Verify((DWORD)(currentPosition - streamStart) <= streamSize);
			Verify(streamSize <= bufferSize);
		}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Accessors
//
public:
	DWORD GetBufferSize()
		{
			Check_Object(this);
			return bufferSize;
		}

	void SetSize(DWORD stream_length)
		{
			Check_Object(this);
			Verify(stream_length <= bufferSize);
			streamSize = stream_length;
		}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Stream methods
//
public:
	MemoryStream& WriteBytes(
		const void *ptr,
		DWORD number_of_bytes
	);
	
	bool AllocateBytes(DWORD count);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
	DWORD bufferSize;
	bool ownsStream;
};
