//===========================================================================//
// File:	NetDamage.cpp				
// Contents : All movement messages and rewind capabilites				
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 01/06/1999  JSE  Inital coding
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Microsoft Corp.										 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//





#include "MW4Headers.hpp"
#include "NetDamage.hpp"
#include "MWEntityManager.hpp"
#include "MWDamageObject.hpp"
#include "Mech.hpp"
#include "MWApplication.hpp"

#include <Adept\CollisionGrid.hpp>
#include <Adept\Tile.hpp>
#include "Adept\NetStatCollector.hpp"

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void MechExternalDamageUpdate::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth, Scalar rate)
{
	Check_Object(entity);
	Check_Object(memory_stream);

	Mech *mech = Cast_Object(Mech*, entity);

	int current_bit = memory_stream->GetCurrentBitCount();

	DamageObject *damage_object;
	SortedChainIteratorOf<DamageObject *, int> damage_iterator(&mech->damageObjects);
	
	int current_life = 0; // jcem: critical error - should clear before ReadBits(...)...
	memory_stream->ReadBits(&current_life,2);


	bool destroyed;

	memory_stream->ReadBit(destroyed);
    if (destroyed) {
        memory_stream->ReadBytes(&mech->m_whoShotMeLast.connectionID, sizeof(mech->m_whoShotMeLast.connectionID));
        memory_stream->ReadBytes(&mech->m_whoShotMeLast.localID, sizeof(mech->m_whoShotMeLast.localID));
    }
	



	// if the lives match...
	if (current_life == (mech->respawnCount % 4))
	{
	
		if (destroyed && !entity->IsDestroyed())
		{
			entity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		}


		while((damage_object = damage_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(damage_object);
			int damage_level = 0;
			memory_stream->ReadBits(&damage_level,2);
			damage_object->SetCurrentDamageLevel(damage_level);
		}

		MWInternalDamageObject *internal_damage_object;
		SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&mech->internalDamageObjects);
		while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(internal_damage_object);
			int damage_level = 0;
			memory_stream->ReadBits(&damage_level,2);
			internal_damage_object->SetCurrentDamageLevel(damage_level);
		}
	}
	else
	{
		//if (destroyed)
		//	SPEW(("jerryeds","SKIP DESTROY"));
		//else
		//	SPEW(("jerryeds", "SKIP DAMAGE"));

		while((damage_object = damage_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(damage_object);
			int damage_level = 0;
			memory_stream->ReadBits(&damage_level,2);
		}

		MWInternalDamageObject *internal_damage_object;
		SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&mech->internalDamageObjects);
		while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(internal_damage_object);
			int damage_level = 0;
			memory_stream->ReadBits(&damage_level,2);
		}
	}


	Network::GetInstance()->netStatCollector[Network::MechInternalBitSizeStat].AddToStatistic(connection, memory_stream->GetCurrentBitCount() - current_bit);
	
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//


int MechExternalDamageUpdate::SizeFunction(Entity *entity)
{
	Check_Object(entity);

	Mech *mech = Cast_Object(Mech*, entity);

	int size = 0;

	DamageObject *damage_object;
	SortedChainIteratorOf<DamageObject *, int> damage_iterator(&mech->damageObjects);
	while((damage_object = damage_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
		
		++size;
	}

	MWInternalDamageObject *internal_damage_object;
	SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&mech->internalDamageObjects);
	while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(internal_damage_object);
		++size;
	}

	return size;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechExternalDamageUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
{
	
	Mech *mech = Cast_Object(Mech*, entity);

	int size = 0;

	DamageObject *damage_object;
	SortedChainIteratorOf<DamageObject *, int> damage_iterator(&mech->damageObjects);
	while((damage_object = damage_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
		
		++size;
	}

	MWInternalDamageObject *internal_damage_object;
	SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&mech->internalDamageObjects);
	while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(internal_damage_object);
		++size;
	}

	return (size * 2)+3;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool MechExternalDamageUpdate::MaintainActiveFlagFunction(Entity *entity,Point3D cull_location)
{
	Point3D entity_location;
	entity_location = entity->GetLocalToWorld();

	Point3D distance;
	distance.Subtract(cull_location, entity_location);

	// if the mech is within 1200 meters and is on than it is active
	if (distance.GetLengthSquared() < 1440000.0f)
	{

		Mech *mech = Cast_Object(Mech*, entity);

		if (mech->takenDamageThisFrame)
		{
			return true;
		}
	}


	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void MechExternalDamageUpdate::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
{
	Check_Object(memory_stream);
	
	int current_bit = memory_stream->GetCurrentBitCount();

	int throw_away;
// MSL 5.03 Merc Fix
	memory_stream->ReadBits(&throw_away,3);
//	memory_stream->ReadBits(&throw_away,2);
//
//    int destroyed = 0;
//    memory_stream->ReadBits(&destroyed,1);
//    if (destroyed) {
//        memory_stream->ReadBytes(&throw_away, sizeof(BYTE/*connectionID*/));
//        memory_stream->ReadBytes(&throw_away, sizeof(WORD/*localID*/));
//    }

	for (int i = 0; i < size; ++i)
	{
		memory_stream->ReadBits(&throw_away,2);
	}

	Network::GetInstance()->netStatCollector[Network::MechInternalBitSizeStat].AddToStatistic(connection,memory_stream->GetCurrentBitCount() - current_bit);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void MechExternalDamageUpdate::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
{
	Check_Object(entity);
	Check_Object(memory_stream);

	Mech *mech = Cast_Object(Mech*, entity);


	int current_bit = memory_stream->GetCurrentBitCount();

	int current_life = (mech->respawnCount % 4);
	memory_stream->WriteBits(&current_life,2);

	if (entity->IsDestroyed())
	{
		memory_stream->WriteBit(true);
// MSL 5.03 Merc Fix
//        memory_stream->WriteBytes(&mech->m_whoShotMeLast.connectionID, sizeof(mech->m_whoShotMeLast.connectionID));
//        memory_stream->WriteBytes(&mech->m_whoShotMeLast.localID, sizeof(mech->m_whoShotMeLast.localID));
	}
	else
	{
		memory_stream->WriteBit(false);
	}



	DamageObject *damage_object;
	SortedChainIteratorOf<DamageObject *, int> damage_iterator(&mech->damageObjects);
	while((damage_object = damage_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
		int damage_level = damage_object->GetCurrentDamageLevel();
		memory_stream->WriteBits(&damage_level,2);
		
	}

	MWInternalDamageObject *internal_damage_object;
	SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&mech->internalDamageObjects);
	while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(internal_damage_object);
		int damage_level = internal_damage_object->GetCurrentDamageLevel();
		memory_stream->WriteBits(&damage_level,2);
	
	}

	Network::GetInstance()->netStatCollector[Network::MechInternalBitSizeStat].AddToStatistic(connection,memory_stream->GetCurrentBitCount() - current_bit);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//




void MechInternalDamageUpdate::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth, Scalar rate)
{
	Check_Object(entity);
	Check_Object(memory_stream);

	Mech *mech = Cast_Object(Mech*, entity);

	int current_bit = memory_stream->GetCurrentBitCount();

	int current_life = 0; // jcem: critical error - should clear before ReadBits(...)...
	memory_stream->ReadBits(&current_life,2);


	// if the lives match...
	if (current_life == mech->respawnCount % 4)
	{

		DamageObject *damage_object;
		SortedChainIteratorOf<DamageObject *, int> damage_iterator(&mech->damageObjects);
		while((damage_object = damage_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(damage_object);
			Scalar damage_level = 0.0f;
			memory_stream->ReadBitsToScaledFloat(damage_level,0.0f, 1.0f,BitDepthManager::BitDepth(UpdateType,InternalDamageEntryID));
			damage_object->SetHighResDamageLevel(damage_level);
			//SPEW(("jerryeds", "DECODE - EXT : %f", damage_level));
		}

		MWInternalDamageObject *internal_damage_object;
		SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&mech->internalDamageObjects);
		while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(internal_damage_object);
			Scalar damage_level = 0.0f;
			memory_stream->ReadBitsToScaledFloat(damage_level,0.0f, 1.0f,BitDepthManager::BitDepth(UpdateType,InternalDamageEntryID));
			internal_damage_object->SetHighResDamageLevel(damage_level);
			//SPEW(("jerryeds", "DECODE - INT : %f", damage_level));
		}
	}
	else
	{
		DamageObject *damage_object;
		SortedChainIteratorOf<DamageObject *, int> damage_iterator(&mech->damageObjects);
		while((damage_object = damage_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(damage_object);
			Scalar damage_level = 0.0f;
			memory_stream->ReadBitsToScaledFloat(damage_level,0.0f, 1.0f,BitDepthManager::BitDepth(UpdateType,InternalDamageEntryID));
		}

		MWInternalDamageObject *internal_damage_object;
		SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&mech->internalDamageObjects);
		while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
		{
			Check_Object(internal_damage_object);
			Scalar damage_level = 0.0f;
			memory_stream->ReadBitsToScaledFloat(damage_level,0.0f, 1.0f,BitDepthManager::BitDepth(UpdateType,InternalDamageEntryID));
		}
	}

	Network::GetInstance()->netStatCollector[Network::MechInternalBitSizeStat].AddToStatistic(connection, memory_stream->GetCurrentBitCount() - current_bit);

	//SPEW(("jerryeds",""));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//


int MechInternalDamageUpdate::SizeFunction(Entity *entity)
{
	Check_Object(entity);

	Mech *mech = Cast_Object(Mech*, entity);

	int size = 0;

	DamageObject *damage_object;
	SortedChainIteratorOf<DamageObject *, int> damage_iterator(&mech->damageObjects);
	while((damage_object = damage_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
		
		++size;
	}

	MWInternalDamageObject *internal_damage_object;
	SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&mech->internalDamageObjects);
	while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(internal_damage_object);
		++size;
	}

	return size;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int MechInternalDamageUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
{
	

	Mech *mech = Cast_Object(Mech*, entity);

	int size = 0;

	DamageObject *damage_object;
	SortedChainIteratorOf<DamageObject *, int> damage_iterator(&mech->damageObjects);
	while((damage_object = damage_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(damage_object);
		
		++size;
	}

	MWInternalDamageObject *internal_damage_object;
	SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&mech->internalDamageObjects);
	while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(internal_damage_object);
		++size;
	}

	return (size * BitDepthManager::BitDepth(UpdateType,InternalDamageEntryID)) + 2;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

bool MechInternalDamageUpdate::MaintainActiveFlagFunction(Entity *entity,Point3D cull_location)
{

	Mech *mech = Cast_Object(Mech*, entity);

// MSL 5.03 Merc Fix
	Point3D entity_location;
	entity_location = entity->GetLocalToWorld();

	Point3D distance;
	distance.Subtract(cull_location, entity_location);

	if (distance.GetLengthSquared() < 1440000.0f)
	{
		if (mech->takenDamageThisFrame)
		{
			return true;
		}
	}

	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MechInternalDamageUpdate::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
{
	
	Check_Object(memory_stream);
	
	int current_bit = memory_stream->GetCurrentBitCount();

	int throw_away;

	memory_stream->ReadBits(&throw_away,2);

	for (int i = 0; i < size; ++i)
	{
	
		memory_stream->ReadBits(&throw_away,BitDepthManager::BitDepth(UpdateType,InternalDamageEntryID));
	}

	Network::GetInstance()->netStatCollector[Network::MechInternalBitSizeStat].AddToStatistic(connection, memory_stream->GetCurrentBitCount() - current_bit);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void MechInternalDamageUpdate::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
{
	Check_Object(entity);
	Check_Object(memory_stream);

	Mech *mech = Cast_Object(Mech*, entity);

	int current_bit = memory_stream->GetCurrentBitCount();

	int current_life = mech->respawnCount % 4;
	memory_stream->WriteBits(&current_life,2);


	DamageObject *damage_object;
	SortedChainIteratorOf<DamageObject *, int> damage_iterator(&mech->damageObjects);
	while((damage_object = damage_iterator.ReadAndNext()) != NULL)
	{
		
		Check_Object(damage_object);
		Scalar damage_level = damage_object->GetHighResDamageLevel();
		//SPEW(("jerryeds", "ENCODE - EXT : %f", damage_level));
		DWORD scaled_damage = Scaled_Float_To_Bits(damage_level,0.0f,1.0f,BitDepthManager::BitDepth(UpdateType,InternalDamageEntryID));

		if (scaled_damage == 0)
		{
			if (damage_level > 0.0f)
				scaled_damage+=1;
		}

		memory_stream->WriteBits(&scaled_damage,BitDepthManager::BitDepth(UpdateType,InternalDamageEntryID));
	}

	MWInternalDamageObject *internal_damage_object;
	SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&mech->internalDamageObjects);
	while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
	{
		Check_Object(internal_damage_object);
		Scalar damage_level = internal_damage_object->GetHighResDamageLevel();
		//SPEW(("jerryeds", "ENCODE - INT : %f", damage_level));

		DWORD scaled_damage = Scaled_Float_To_Bits(damage_level,0.0f,1.0f,BitDepthManager::BitDepth(UpdateType,InternalDamageEntryID));

		if (scaled_damage == 0)
		{
			if (damage_level > 0.0f)
				scaled_damage+=1;
		}

		memory_stream->WriteBits(&scaled_damage,BitDepthManager::BitDepth(UpdateType,InternalDamageEntryID));
	}

	Network::GetInstance()->netStatCollector[Network::MechInternalBitSizeStat].AddToStatistic(connection, memory_stream->GetCurrentBitCount() - current_bit);


	//SPEW(("jerryeds",""));
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//


void VehicleDamageUpdate::Decode(Entity *, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth, Scalar rate)
{
	Check_Object(memory_stream);



	int current_bit = memory_stream->GetCurrentBitCount();

	MWEntityManager *manager = Cast_Object(MWEntityManager*, MWEntityManager::GetInstance());

	Stuff::ChainIteratorOf<Airplane*> iterator1(&manager->servedAirplanes);
	Entity *entity;
	while ((entity = iterator1.ReadAndNext()) != NULL)
	{
		bool destroyed;

		memory_stream->ReadBit(destroyed);

		if (destroyed && !entity->IsDestroyed())
		{
			entity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		}
		
	}

	Stuff::ChainIteratorOf<Boat*> iterator2(&manager->servedBoats);
	while ((entity = iterator2.ReadAndNext()) != NULL)
	{
		bool destroyed;

		memory_stream->ReadBit(destroyed);

		if (destroyed && !entity->IsDestroyed())
		{
			entity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		}
	}

	Stuff::ChainIteratorOf<Dropship*> iterator3(&manager->servedDropships);
	while ((entity = iterator3.ReadAndNext()) != NULL)
	{
		bool destroyed;

		memory_stream->ReadBit(destroyed);

		if (destroyed && !entity->IsDestroyed())
		{
			entity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		}
	}

	Stuff::ChainIteratorOf<Helicopter*> iterator4(&manager->servedHelicopters);
	while ((entity = iterator4.ReadAndNext()) != NULL)
	{
		bool destroyed;

		memory_stream->ReadBit(destroyed);

		if (destroyed && !entity->IsDestroyed())
		{
			entity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		}
	}

	Stuff::ChainIteratorOf<Hovercraft*> iterator5(&manager->servedHovercraft);
	while ((entity = iterator5.ReadAndNext()) != NULL)
	{
		bool destroyed;

		memory_stream->ReadBit(destroyed);

		if (destroyed && !entity->IsDestroyed())
		{
			entity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		}
	}

	Stuff::ChainIteratorOf<Tank*> iterator7(&manager->servedTanks);
	while ((entity = iterator7.ReadAndNext()) != NULL)
	{
		bool destroyed;

		memory_stream->ReadBit(destroyed);

		if (destroyed && !entity->IsDestroyed())
		{
			entity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		}
	}

	Stuff::ChainIteratorOf<Truck*> iterator8(&manager->servedTrucks);
	while ((entity = iterator8.ReadAndNext()) != NULL)
	{
		bool destroyed;

		memory_stream->ReadBit(destroyed);

		if (destroyed && !entity->IsDestroyed())
		{
			entity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		}
	}

	Stuff::ChainIteratorOf<Turret*> iterator9(&manager->servedTurrets);
	while ((entity = iterator9.ReadAndNext()) != NULL)
	{
		bool destroyed;

		memory_stream->ReadBit(destroyed);

		if (destroyed && !entity->IsDestroyed())
		{
			entity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
		}
	}




	Network::GetInstance()->netStatCollector[Network::VehicleBitSizeStat].AddToStatistic(connection, memory_stream->GetCurrentBitCount() - current_bit);

	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//


int VehicleDamageUpdate::SizeFunction(Entity *)
{
	

	int size = 0;

	MWEntityManager *manager = Cast_Object(MWEntityManager*, MWEntityManager::GetInstance());


	Stuff::ChainIteratorOf<Airplane*> iterator1(&manager->servedAirplanes);
	Entity *entity;
	while ((entity = iterator1.ReadAndNext()) != NULL)
	{
		++size;
	}

	Stuff::ChainIteratorOf<Boat*> iterator2(&manager->servedBoats);
	while ((entity = iterator2.ReadAndNext()) != NULL)
	{
		++size;
	}

	Stuff::ChainIteratorOf<Dropship*> iterator3(&manager->servedDropships);
	while ((entity = iterator3.ReadAndNext()) != NULL)
	{
		++size;
	}

	Stuff::ChainIteratorOf<Helicopter*> iterator4(&manager->servedHelicopters);
	while ((entity = iterator4.ReadAndNext()) != NULL)
	{
		++size;
	}

	Stuff::ChainIteratorOf<Hovercraft*> iterator5(&manager->servedHovercraft);
	while ((entity = iterator5.ReadAndNext()) != NULL)
	{
		++size;
	}

	Stuff::ChainIteratorOf<Tank*> iterator7(&manager->servedTanks);
	while ((entity = iterator7.ReadAndNext()) != NULL)
	{
		++size;
	}

	Stuff::ChainIteratorOf<Truck*> iterator8(&manager->servedTrucks);
	while ((entity = iterator8.ReadAndNext()) != NULL)
	{
		++size;
	}

	Stuff::ChainIteratorOf<Turret*> iterator9(&manager->servedTurrets);
	while ((entity = iterator9.ReadAndNext()) != NULL)
	{
		++size;
	}


	return size;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int VehicleDamageUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
{
	
	
	return SizeFunction(entity);
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void VehicleDamageUpdate::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
{
	
	Check_Object(memory_stream);
	
	int current_bit = memory_stream->GetCurrentBitCount();

	for (int i = 0; i < size; ++i)
	{
		int throw_away;
		memory_stream->ReadBits(&throw_away,1);
	}

	Network::GetInstance()->netStatCollector[Network::VehicleBitSizeStat].AddToStatistic(connection, memory_stream->GetCurrentBitCount() - current_bit);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void VehicleDamageUpdate::Encode(Entity *, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
{
	Check_Object(memory_stream);


	int current_bit = memory_stream->GetCurrentBitCount();

	MWEntityManager *manager = Cast_Object(MWEntityManager*, MWEntityManager::GetInstance());


	Stuff::ChainIteratorOf<Airplane*> iterator1(&manager->servedAirplanes);
	Entity *entity;
	while ((entity = iterator1.ReadAndNext()) != NULL)
	{
		if (entity->IsDestroyed())
		{
			memory_stream->WriteBit(true);
		}
		else
		{
			memory_stream->WriteBit(false);
		}
	}

	Stuff::ChainIteratorOf<Boat*> iterator2(&manager->servedBoats);
	while ((entity = iterator2.ReadAndNext()) != NULL)
	{
		if (entity->IsDestroyed())
		{
			memory_stream->WriteBit(true);
		}
		else
		{
			memory_stream->WriteBit(false);
		}
	}

	Stuff::ChainIteratorOf<Dropship*> iterator3(&manager->servedDropships);
	while ((entity = iterator3.ReadAndNext()) != NULL)
	{
		if (entity->IsDestroyed())
		{
			memory_stream->WriteBit(true);
		}
		else
		{
			memory_stream->WriteBit(false);
		}
	}

	Stuff::ChainIteratorOf<Helicopter*> iterator4(&manager->servedHelicopters);
	while ((entity = iterator4.ReadAndNext()) != NULL)
	{
		if (entity->IsDestroyed())
		{
			memory_stream->WriteBit(true);
		}
		else
		{
			memory_stream->WriteBit(false);
		}
	}

	Stuff::ChainIteratorOf<Hovercraft*> iterator5(&manager->servedHovercraft);
	while ((entity = iterator5.ReadAndNext()) != NULL)
	{
		if (entity->IsDestroyed())
		{
			memory_stream->WriteBit(true);
		}
		else
		{
			memory_stream->WriteBit(false);
		}
	}

	Stuff::ChainIteratorOf<Tank*> iterator7(&manager->servedTanks);
	while ((entity = iterator7.ReadAndNext()) != NULL)
	{
		if (entity->IsDestroyed())
		{
			memory_stream->WriteBit(true);
		}
		else
		{
			memory_stream->WriteBit(false);
		}
	}

	Stuff::ChainIteratorOf<Truck*> iterator8(&manager->servedTrucks);
	while ((entity = iterator8.ReadAndNext()) != NULL)
	{
		if (entity->IsDestroyed())
		{
			memory_stream->WriteBit(true);
		}
		else
		{
			memory_stream->WriteBit(false);
		}
	}

	Stuff::ChainIteratorOf<Turret*> iterator9(&manager->servedTurrets);
	while ((entity = iterator9.ReadAndNext()) != NULL)
	{
		if (entity->IsDestroyed())
		{
			memory_stream->WriteBit(true);
		}
		else
		{
			memory_stream->WriteBit(false);
		}
	}


	Network::GetInstance()->netStatCollector[Network::VehicleBitSizeStat].AddToStatistic(connection, memory_stream->GetCurrentBitCount() - current_bit);

}



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

//Some helpfull stuff for finding tiles in the far clip

//row column
int TileBlockOffsets[16][2] = {
	{ 6,-6},
	{ 6,-3},
	{ 6, 0},
	{ 6, 3},
	{ 6, 6},
	{ 3, 6},
	{ 0, 6},
	{-3, 6},
	{-6, 6},
	{-6, 3},
	{-6, 0},
	{-6,-3},
	{-6,-6},
	{-3,-6},
	{ 0,-6},
	{ 3,-6}
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

//this is how damage updates work...

// you get a 3x3 block of tiles that is centered on you at a high frequency.  This is the ImidiateAreaUpdate



/*


  ImidiateAreaUpdate.  Each box is a tile.  Each group of 3x3's is a block
  The center X represents where you are standing in the world.
  Every tile is updated

			 - - - 
			| | | |
			 - - -
			| |X| |
			 - - -
			| | | |
			 _ _ _



*/



// you get 8 3x3 blocks of tiles that immidiatly surrund your imidiatearea block. 
// This is lower frequency and is the SecondaryAreaUpdate

/*


  SecondaryAreaUpdate.  Each box is a block of tiles (3x3).
  The center X represents where you are standing in the world. ( in the center square of that 3x3 of tiles )
  Only the boxes with *'s in them are updated.  The 3x3 block you are in is not updated.

			 -- -- -- 
			|* |* |* |
			 -- -- --
			|* |X |* |
			 -- -- --
			|* |* |* |
			 -- -- --


*/

/*


  FarAreaUpdate.  Each box is a block of tiles (3x3).
  The center X represents where you are standing in the world ( in the center square of that 3x3 of tiles )
  
  These are infrequent.  You only receive updates for 9 boxes.  The start box is 4 counter clockwise of the direction
  you are facing


		 -- -- -- -- --
		| 4| 3| 2| 1| 0|
		 -- -- -- -- --
		| 5|  |  |  |15|
		 -- -- -- -- --
		| 6|  |X |  |14|
		 -- -- -- -- --
		| 7|  |  |  |13|
		 -- -- -- -- -- 
		| 8| 9|10|11|12|
		 -- -- -- -- -- 
*/

/*

// if the degree is between the minimum for that tile and the minum for the next tile
// use that index number
Scalar TileBlockRanges[16]
{
	 -56.25,  -33.75  //1
	 -33.75,  -11.25  //2
	 -11.25,   11.25  //3
	  11.25,   33.75  //4
	  33.75,   56.25  //5
	  56.25,   78.75  //6
	  78.75,  101.25  //7
	 101.25,  123.75  //8
	 123.75,  146.25  //9
	 146.25,  168.75  //10
	 168.75, -168.75  //11 -- special...
	-146.25, -168.75, //12
	-123.75, -146.25, //13
	-101.25, -123.75, //14
	 -78.75, -101.25, //15
	 -56.25,  -78.75, //16
}

*/


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

int CalculateStartTile(Scalar degrees)
{

	// just a balance to make less if checks...
	if (degrees < -11.25)
	{

		if (degrees < -101.25)
		{
			if (degrees < -168.75)		//10 -- special...this is on the radian border
			{
				return 6;
			}
			else if (degrees < -146.25) //11
			{
				return 7;
			}
			else if (degrees < -123.75) //12
			{
				return 8;
			}
			else						//13
			{
				Verify(degrees < -101.25);
				return 9;
			}
		}
		else
		{
			if (degrees <  -78.75)		//14
			{
				return 10;
			}
			else if (degrees <  -56.25) //15
			{
				return 11;
			}
			else if (degrees <  -33.75) //0
			{
				return 12;
			}
			else						//1
			{
				Verify (degrees <  -11.25);
				Verify (degrees >=  -33.75);
				return 13;
			}
		}
	}
	else
	{
		if (degrees < 101.25)
		{

			if (degrees <  13.25)		 //2
			{
				return 14;
			}
			else if (degrees <  33.75)   //3
			{
				return 15;
			}
			else if (degrees <   56.25)  //4
			{
				return 0;
			}
			else if (degrees <   78.75)  //5
			{
				return 1;
			}
			else						 //6
			{
				Verify (degrees <   101.25);
				return 2;
			}
		}
		else
		{

			if (degrees <  123.75)  //7
			{
				return 3;
			}
			else if (degrees <  146.25)  //8
			{
				return 4;
			}
			else if (degrees <  168.75)  //9
			{
				return 5;
			}
			else //if (degrees > 168.75 || degrees < -168.75)  //10 -- special...this is on the radian border
			{
				Verify (degrees > 168.75);
				return 6;
			}
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	FindRowAndColumn(WORD tile, int *row, int *column)
{

	BYTE l_row, l_column;
	CollisionGrid::Instance->FindRowAndColumn(tile, &l_row, &l_column);
	*row = (int)l_row;
	*column = (int)l_column;

}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GetSize(int *max_row, int *max_column)
{

	BYTE l_max_row, l_max_column;
	CollisionGrid::Instance->GetSize(&l_max_row, &l_max_column);

	*max_row = l_max_row;
	*max_column = l_max_column;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void NearBuildingExternalDamageUpdate::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth, Scalar rate)
{
	Check_Object(entity);
	Check_Object(memory_stream);


	Check_Object(CollisionGrid::Instance);
	int row, column;
	WORD tile = 0; // jcem: critical error - should clear before ReadBits(...)...
	memory_stream->ReadBits(&tile, 11);//1024
	FindRowAndColumn(tile, &row, &column);
	
	ReadTileBlock(row,column,memory_stream, connection);
	
	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,11);


}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void NearBuildingExternalDamageUpdate::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
{
	Check_Object(memory_stream);
	

	Check_Object(CollisionGrid::Instance);
	int row, column;
	WORD tile = 0; // jcem: critical error - should clear before ReadBits(...)...

	memory_stream->ReadBits(&tile, 11);//1024
	FindRowAndColumn(tile, &row, &column);
	
	ReadTileBlock(row,column,memory_stream, connection, true);
	
	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,11);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int NearBuildingExternalDamageUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
{
	
	MWEntityManager *manager = Cast_Object(MWEntityManager*, MWEntityManager::GetInstance());

	int current_bit = 0;
	current_bit += 11;
	current_bit += manager->maximumNearBuildings;

	
	return current_bit;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void NearBuildingExternalDamageUpdate::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
{
	Check_Object(entity);
	Check_Object(memory_stream);


	// figure out our tile and send all the appropriate tiles...




	Point3D position = MWApplication::GetInstance()->servedConnectionData[entity->GetReplicatorID().connectionID].vehiclePosition;
	

	Check_Object(CollisionGrid::Instance);
	
	int row, column;
	WORD tile;

	tile = CollisionGrid::Instance->FindElementIndex(position.z, position.x);
	FindRowAndColumn(tile, &row, &column);

	Verify(tile < 2048);
	memory_stream->WriteBits(&tile, 11);//1024

	WriteTileBlock(row,column,memory_stream, connection);

	
	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,11);

	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//



void NearBuildingExternalDamageUpdate::WriteTileBlock(int row, int column, DynamicMemoryStream *memory_stream, int connection)
{
	Check_Object(memory_stream);


	int min_row = 0;
	int max_row = 0;
	int min_column = 0;
	int max_column = 0;


	GetSize(&max_row, &max_column);
	

	//SPEW(("jerryeds", "CENTER - ROW:%d COL:%d - MaxRow:%d -- MaxCol:%d", row, column, max_row, max_column));



	for (int row_counter=(row-1); row_counter<=row+1; ++row_counter)
	{

		if (row_counter < min_row || row_counter >= max_row)
		{
			//SPEW(("jerryeds","SKIP ROW:%d", row_counter));
			continue;
		}

		for (int column_counter=(column-1); column_counter<=column+1; ++column_counter)
		{

			if (column_counter < min_column || column_counter >= max_column)
			{
				//SPEW(("jerryeds","SKIP COL:%d", column_counter));
				continue;
			}


			WORD index = (WORD)((row_counter*max_column)+column_counter);


			//SPEW(("jerryeds","WRITING %d:<%d:%d>", index, row_counter, column_counter));

			WriteTileDamageStream(index, memory_stream, connection);
		

		}

	}


	//SPEW(("jerryeds",""));

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//


void NearBuildingExternalDamageUpdate::ReadTileBlock(int row, int column, MemoryStream *memory_stream, int connection, bool skip)
{
	Check_Object(memory_stream);



	int min_row = 0;
	int max_row = 0;
	int min_column = 0;
	int max_column = 0;

	
	GetSize(&max_row, &max_column);


	//SPEW(("jerryeds", "CENTER - ROW:%d COL:%d - MaxRow:%d -- MaxCol:%d", row, column, max_row, max_column));


	for (int row_counter=(row-1); row_counter<=row+1; ++row_counter)
	{

		if (row_counter < min_row || row_counter >= max_row)
		{
			//SPEW(("jerryeds","SKIP ROW:%d", row_counter));
			continue;
		}

		for (int column_counter=(column-1); column_counter<=column+1; ++column_counter)
		{

			if (column_counter < min_column || column_counter >= max_column)
			{
				//SPEW(("jerryeds","SKIP COL:%d", column_counter));
				continue;
			}


			WORD index = (WORD)((row_counter*max_column)+column_counter);

			//SPEW(("jerryeds","READING %d:<%d:%d>", index, row_counter, column_counter));

			ReadTileDamageStream(index, memory_stream, connection, skip);
		

		}

	}


	//SPEW(("jerryeds",""));

}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void
	NearBuildingExternalDamageUpdate::WriteTileDamageStream(WORD index, DynamicMemoryStream *mem_stream, int connection)
{
	Tile *tile = CollisionGrid::Instance->GetTile(index);
	Check_Object(tile);

	// if we don't have anything don't write anything..
	if (!tile->GetDamagableEntityCount())
	{
		//SPEW(("jerryeds", "SKIP EMPTY TILE"));
		return;
	}

	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,tile->GetDamagableEntityCount());


	int bytes_left = tile->GetDamagableEntityCount() >> 3;
	BYTE bits_left = (BYTE)(tile->GetDamagableEntityCount() & 0x7);

	int current_index = tile->GetDamageBitStart() >> 3;


	Verify(current_index+bytes_left < EntityManager::GetInstance()->tileBoundDamage.GetSize());
	BYTE *memory = (BYTE*)EntityManager::GetInstance()->tileBoundDamage.GetPointer();


	while (bytes_left > 0)
	{
		
		//for (int i = 0; i < 8; ++i)
		//{
		//	int value = (memory[current_index]&(0x1 << i))?1:0;
		//	SPEW(("jerryeds", "%d +", value));
		//}

		mem_stream->WriteBits(&memory[current_index], 8);
		++current_index;
		--bytes_left;
	}

	if (bits_left > 0)
	{
		//for (int i = 0; i < bits_left; ++i)
		//{
		//	int value = (memory[current_index]&(0x1 << i))?1:0;
		//	SPEW(("jerryeds", "%d +", value));
		//}

		mem_stream->WriteBits(&memory[current_index], bits_left);
		++current_index;
		bits_left = 0;
	}

	//SPEW(("jerryeds",""));

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void
	NearBuildingExternalDamageUpdate::ReadTileDamageStream(WORD index, MemoryStream *mem_stream,  int connection, bool skip )
{
	

	Tile *tile = CollisionGrid::Instance->GetTile(index);
	Check_Object(tile);

	// if we don't have anything don't read anything..
	if (!tile->GetDamagableEntityCount())
	{
		return;
	}

	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,tile->GetDamagableEntityCount());

	// set up all the initilization variables...
	bool different = false;
	int start_bit = tile->GetDamageBitStart() >> 3;

	int bytes_left = tile->GetDamagableEntityCount() >> 3;
	BYTE bits_left = (BYTE)(tile->GetDamagableEntityCount() & 0x7);
	int current_index = 0;
	Verify(current_index+bytes_left < EntityManager::GetInstance()->tileBoundDamage.GetSize());
	BYTE *memory = (BYTE*)EntityManager::GetInstance()->tileBoundDamage.GetPointer();

	// read all the damage bytes...
	BYTE comp_memory[256];
	while (bytes_left)
	{
		mem_stream->ReadBits(&comp_memory[current_index], 8);

		// if we have different bits mark it down
		if (comp_memory[current_index] != memory[start_bit+current_index])
		{
			different = true;
		}

		

		++current_index;
		--bytes_left;
	}

	// read the remainder bits..
	if (bits_left)
	{
		comp_memory[current_index] = 0;
		mem_stream->ReadBits(&comp_memory[current_index], bits_left);
	
		if (comp_memory[current_index] != memory[start_bit+current_index])
		{
			different = true;
		}
		
		++current_index;
		bits_left = 0;
	}


	// if we are in skip mode don't apply this stuff.
	if (skip)
		return;

	// if the incomming data is different than our state...
	if (different)
	{
	
		bytes_left = tile->GetDamagableEntityCount() >> 3;
		bits_left = (BYTE)(tile->GetDamagableEntityCount() & 0x7);
		current_index = tile->GetDamageBitStart() >> 3;


	
	
		int current_bit = 0;




		#if defined (_ARMOR)
			int entity_count = 0;
		#endif


		Entity *entity;

		// step thru all the entities...
		for (int i = 0; i < tile->GetDamagableEntityCount(); ++i)
		{

			entity = tile->GetDamagableEntity(i);
			Check_Object(entity);

			//Verify (entity->damageObject != NULL);

											
			#if defined (_ARMOR)
				++entity_count;
			#endif


			int byte = current_bit >> 3;
			BYTE bit = (BYTE)(current_bit & 0x7);

			bool destroyed = (comp_memory[byte] & (0x1<<bit))?true:false;

			// if it needs to be destroyed than do it.
			if (destroyed && !entity->IsDestroyed())
			{
				entity->ReactToDestruction(InternalDamageObject::DestructionDamageMode, 0);
			}

			++current_bit;

		
		}
		
		#if defined (_ARMOR)
			if (entity_count != tile->GetDamagableEntityCount())
			STOP(("Damage is messed up"));
		#endif

	}




}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SecondaryBuildingExternalDamageUpdate::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth, Scalar rate)
{
	Check_Object(entity);
	Check_Object(memory_stream);


	// figure out our tile and send all the appropriate tiles...
	Check_Object(CollisionGrid::Instance);
			
	int row, column;

	WORD tile = 0; // jcem: critical error - should clear before ReadBits(...)...

	memory_stream->ReadBits(&tile, 11);//2048
	FindRowAndColumn(tile, &row, &column);


	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,11);

	NearBuildingExternalDamageUpdate::ReadTileBlock((row+3),(column+3),memory_stream, connection);
	NearBuildingExternalDamageUpdate::ReadTileBlock((row+3),column,memory_stream, connection);
	NearBuildingExternalDamageUpdate::ReadTileBlock((row+3),(column-3),memory_stream, connection);

	NearBuildingExternalDamageUpdate::ReadTileBlock(row,(column+3),memory_stream, connection);
	NearBuildingExternalDamageUpdate::ReadTileBlock(row,(column-3),memory_stream, connection);

	NearBuildingExternalDamageUpdate::ReadTileBlock((row-3),(column+3),memory_stream, connection);
	NearBuildingExternalDamageUpdate::ReadTileBlock((row-3),column,memory_stream, connection);
	NearBuildingExternalDamageUpdate::ReadTileBlock((row-3),(column-3),memory_stream, connection);


}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void SecondaryBuildingExternalDamageUpdate::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
{
	Check_Object(memory_stream);



	// figure out our tile and send all the appropriate tiles...
	Check_Object(CollisionGrid::Instance);
	int row, column;
	WORD tile = 0; // jcem: critical error - should clear before ReadBits(...)...

	memory_stream->ReadBits(&tile, 11);//2048
	FindRowAndColumn(tile, &row, &column);

	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,11);


	NearBuildingExternalDamageUpdate::ReadTileBlock((row+3),(column+3),memory_stream, connection, true);
	NearBuildingExternalDamageUpdate::ReadTileBlock((row+3),column,memory_stream, connection, true);
	NearBuildingExternalDamageUpdate::ReadTileBlock((row+3),(column-3),memory_stream, connection, true);

	NearBuildingExternalDamageUpdate::ReadTileBlock(row,(column+3),memory_stream, connection, true);
	NearBuildingExternalDamageUpdate::ReadTileBlock(row,(column-3),memory_stream, connection, true);

	NearBuildingExternalDamageUpdate::ReadTileBlock((row-3),(column+3),memory_stream, connection, true);
	NearBuildingExternalDamageUpdate::ReadTileBlock((row-3),column,memory_stream, connection, true);
	NearBuildingExternalDamageUpdate::ReadTileBlock((row-3),(column-3),memory_stream, connection, true);


}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int SecondaryBuildingExternalDamageUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
{
	
	MWEntityManager *manager = Cast_Object(MWEntityManager*, MWEntityManager::GetInstance());

	int current_bit = 0;
	current_bit += 11;
	current_bit += manager->maximumMidBuildings;

	
	return current_bit;
}

	


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void SecondaryBuildingExternalDamageUpdate::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
{
	Check_Object(entity);
	Check_Object(memory_stream);


	// figure out our tile and send all the appropriate tiles...
	Point3D position = MWApplication::GetInstance()->servedConnectionData[entity->GetReplicatorID().connectionID].vehiclePosition;
	


	Check_Object(CollisionGrid::Instance);
	
	int row, column;
	WORD tile;

	tile = CollisionGrid::Instance->FindElementIndex(position.z, position.x);
	FindRowAndColumn(tile, &row, &column);

	Verify(tile < 2048);
	memory_stream->WriteBits(&tile, 11);//2048

	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,11);

	
	NearBuildingExternalDamageUpdate::WriteTileBlock((row+3),(column+3),memory_stream, connection);
	NearBuildingExternalDamageUpdate::WriteTileBlock((row+3),column,memory_stream, connection);
	NearBuildingExternalDamageUpdate::WriteTileBlock((row+3),(column-3),memory_stream, connection);

	NearBuildingExternalDamageUpdate::WriteTileBlock(row,(column+3),memory_stream, connection);
	NearBuildingExternalDamageUpdate::WriteTileBlock(row,(column-3),memory_stream, connection);

	NearBuildingExternalDamageUpdate::WriteTileBlock((row-3),(column+3),memory_stream, connection);
	NearBuildingExternalDamageUpdate::WriteTileBlock((row-3),column,memory_stream, connection);
	NearBuildingExternalDamageUpdate::WriteTileBlock((row-3),(column-3),memory_stream, connection);



}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void FarBuildingExternalDamageUpdate::Decode(Entity *entity, MemoryStream *memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth, Scalar rate)
{
	Check_Object(entity);
	Check_Object(memory_stream);


	Check_Object(CollisionGrid::Instance);
	int row, column;
	WORD tile = 0; // jcem: critical error - should clear before ReadBits(...)...

	memory_stream->ReadBits(&tile, 11);//2048
	FindRowAndColumn(tile, &row, &column);

	
	int start_tile = 0; // jcem: critical error - should clear before ReadBits(...)...

	memory_stream->ReadBits(&start_tile, 4);//16
	
	//SPEW(("jerryeds", "READ FAR TILE : %d : %d ", tile, start_tile));

	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,14);


	int current_tile = start_tile;
	for (int i = 0; i < 9; ++i)
	{
		NearBuildingExternalDamageUpdate::ReadTileBlock(
			(row+TileBlockOffsets[current_tile][0]),
			(column+TileBlockOffsets[current_tile][1]),
			memory_stream,
			connection
		);

		//SPEW(("jerryeds", "READ_TILE : %d : %d", row+TileBlockOffsets[current_tile][0], column+TileBlockOffsets[current_tile][1]));


		current_tile++;
		if (current_tile > 15)
			current_tile = 0;
	}

	//SPEW(("jerryeds", ""));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void FarBuildingExternalDamageUpdate::Skip(MemoryStream *memory_stream, int size, Time till, int connection, int debug_level, int bandwidth)
{
	Check_Object(memory_stream);
	

	Check_Object(CollisionGrid::Instance);
	int row, column;

	WORD tile = 0; // jcem: critical error - should clear before ReadBits(...)...

	memory_stream->ReadBits(&tile, 11);//2048
	FindRowAndColumn(tile, &row, &column);
	


	int start_tile = 0; // jcem: critical error - should clear before ReadBits(...)...

	memory_stream->ReadBits(&start_tile, 4);//16
	
	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,14);


	int current_tile = start_tile;
	for (int i = 0; i < 9; ++i)
	{
		NearBuildingExternalDamageUpdate::ReadTileBlock(
			(row+TileBlockOffsets[current_tile][0]),
			(column+TileBlockOffsets[current_tile][1]),
			memory_stream,
			connection,
			true
		);

		current_tile++;
		if (current_tile > 15)
			current_tile = 0;
	}
		

}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int FarBuildingExternalDamageUpdate::MaxSize(Entity *entity, int debug_level, int bandwidth)
{
	
	MWEntityManager *manager = Cast_Object(MWEntityManager*, MWEntityManager::GetInstance());

	int current_bit = 0;
	current_bit += 15;
	current_bit += manager->maximumFarBuildings;

	
	return current_bit;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void FarBuildingExternalDamageUpdate::Encode(Entity *entity, DynamicMemoryStream *memory_stream, int connection, int debug_level, int bandwidth)
{
	Check_Object(entity);
	Check_Object(memory_stream);



	Point3D position = MWApplication::GetInstance()->servedConnectionData[entity->GetReplicatorID().connectionID].vehiclePosition;
	

	Check_Object(CollisionGrid::Instance);
	
	int row, column;
	WORD tile;

	tile = CollisionGrid::Instance->FindElementIndex(position.z, position.x);
	FindRowAndColumn(tile, &row, &column);



	//figure out which friggin square to start with...

	YawPitchRange angle = MWApplication::GetInstance()->servedConnectionData[entity->GetReplicatorID().connectionID].vehicleRotation;
	

	Scalar degrees = angle.yaw * Degrees_Per_Radian;


	// Actually what we want is the 4 squares less ( counter clockwise )
	// than the square we hit.  Then we update 9 tiles clockwise from that number...

	int start_tile = CalculateStartTile(degrees);

	Verify(tile < 2048);
	Verify(start_tile < 16);
	memory_stream->WriteBits(&tile, 11);//2048
	memory_stream->WriteBits(&start_tile, 4);//16
	
	//SPEW(("jerryeds", "WRITE FAR : %d :  %d ", tile, start_tile));

	Network::GetInstance()->netStatCollector[Network::BuildingDamageBitSizeStat].AddToStatistic(connection,14);


	int current_tile = start_tile;
	for (int i = 0; i < 9; ++i)
	{


		//int t_row = row+TileBlockOffsets[current_tile][0];
		//int t_col = column+TileBlockOffsets[current_tile][1];
		//SPEW(("jerryeds", "WriteBlock - %d - TILEBLOCK : %d : %d", current_tile, t_row, t_col));
		

		NearBuildingExternalDamageUpdate::WriteTileBlock(
			(row+TileBlockOffsets[current_tile][0]),
			(column+TileBlockOffsets[current_tile][1]),
			memory_stream,
			connection
		);

		//SPEW(("jerryeds", "WRITE_TILE : %d : %d", row+TileBlockOffsets[current_tile][0], column+TileBlockOffsets[current_tile][1]));


		current_tile++;
		if (current_tile > 15)
			current_tile = 0;
	}

	//SPEW(("jerryeds", ""));

}