using System;
using System.Drawing;
using System.Collections;

using DarkStrideToolbox;


namespace MetalMarines
{
	public class Island
	{
		#region Properties
		private double m_nElapsedTimeSinceBarSwitch = 0;
		private bool m_bBarInDefaultPos = true;

		//0=UpperRight, 1=UpperLeft, 2=LowerLeft, 3=LowerRight
		private int m_nDirection = 0;

		private int m_nWidth = 50;
		private int m_nHeight = 50;

		private Square[,] m_oTerrain = null;
		private bool m_bBasesPlaced = false;

		private long m_nOwnerSocketID = -1;
		private string m_sGlobalID = "";
		private string m_sAIOwnerGlobalID = "";
		private string m_sOwnerName = "";
		private double m_nCredits = 100;
		private double m_nFuel = 100;
		//Notice that these aren't transmitted over the wire.  We will always have our own build info so it
		//will be populated and we don't care about our opponents.
		private double m_nCreditIncomePerSecond = 1;
		private double m_nFuelIncomePerSecond = 1;
		private double m_nBuildPerSecond = 1;
		private long m_nMaxBasesToPlace = 3;
		private int m_nColor = System.Drawing.Color.Red.ToArgb();

		private static string m_cSQUARE_SEP = "[ISS]";
		private static string m_cISLAND_SEP = "[IS]";

		private DSSortedList m_oIslandsPeopleHaveSeen = new DSSortedList();
		//private Square[,] m_oWhatIveSeen = null;
		//private bool m_bHaveInitialized = false;
		private Game m_oGame = null;

		//These paramaters are used for team setup
		private TeamSetup m_oTeamSetup = null;
		private string m_sGlobalIDOfPlayerWhoseTeamImOn = "";
		private bool m_bTeamJoinApproved = false;
		private bool m_bTeamQuitPending = false;

		private bool m_bImDead = false;
		private long m_nBasesLeft = 0;

		//This is how we know to flash the team button
		private long m_nNumberOfTeamMembers = -1;
		private bool m_bTeamChanged = false;

		private double m_nFuelSharedPerMinute = 0;
		private double m_nCreditsSharedPerMinute = 0;
		private double m_nFuelSharedUsed = 0;
		private double m_nCreditsSharedUsed = 0;

		private bool m_bNeedToSendWholeIsland = false;
		#endregion


		public Island( Game oGame )
		{
			m_sGlobalID = DSMisc.GetGUID();
			m_oGame = oGame;
			m_oTerrain = new Square[ m_nWidth,m_nHeight ];
			//m_oWhatIveSeen = new Square[ m_nWidth,m_nHeight ];

			for( int x=0 ; x<m_nWidth; x++ )
			{
				for( int y=0 ; y<m_nHeight ; y++ )
				{
					m_oTerrain[ x,y ] = new Square( m_oGame );
					m_oTerrain[ x,y ].X = x;
					m_oTerrain[ x,y ].Y = y;

					/*m_oWhatIveSeen[ x,y ] = new Square( m_oGame );
					m_oWhatIveSeen[ x,y ].DeSerialize( m_oTerrain[ x,y ].Serialize() );*/
				}
			}
		}
		public void GenerateNewGUID()
		{
			m_sGlobalID = DSMisc.GetGUID();
		}


		public void Advance( double nElapsedTime )
		{
			Square[,] oWhatIveSeen = null;
			DSSortedList oList = null;
			Square oSquare = null;
			MMAttack oMMAttack = null;
			long nTempX = 0, nTempY = 0;
			long nTempDir = 0;
			long nTargetX = 0, nTargetY = 0;
			long nCommandsLeft = 0;
			long nNewTeamCount = 0;
			double nTargetOffsetX = 0, nTargetOffsetY = 0;
			double nTempOffsetX = 0, nTempOffsetY = 0;
			double nCreditIncomePerSecond = 1;
			double nFuelIncomePerSecond = 1;
			double nBuildPerSecond = 1;
			bool bMove = false;
			bool bFound = false;


			//07/02/2006 Chris Hill  Was / 2 but I think it was to wealthy.
			//Increase our wealth!
			if( m_oGame.App.GameState != enumStates.MapEditor )
			{
				m_nCredits += m_nCreditIncomePerSecond * ( nElapsedTime / 2.5 );
				m_nFuel += m_nFuelIncomePerSecond * ( nElapsedTime / 2.5 );
			}


			//Check our blinky bar
			m_nElapsedTimeSinceBarSwitch += nElapsedTime;
			bFound = false;
			//Any MM launching?  If not ignore the flashy
			for( int i=0 ; i<m_oGame.MetalMarineAttacks.Count ; i++ )
			{
				oMMAttack = (MMAttack)m_oGame.MetalMarineAttacks.GetByIndex( i );
				if( oMMAttack.SourceIslandGlobalID == m_sGlobalID &&
					oMMAttack.Launched == false && oMMAttack.PercentAlongPath < 90 )
				{
					bFound = true;
				}
			}
			if( m_nElapsedTimeSinceBarSwitch > .9 && 
				( 
					m_bBarInDefaultPos == false ||
					bFound == true
				)
			  )
			{
				m_nElapsedTimeSinceBarSwitch = 0;
				m_bBarInDefaultPos = ( !m_bBarInDefaultPos );
			}


			//Decrease our shared stuff
			m_nCreditsSharedUsed -= m_nCreditsSharedPerMinute * nElapsedTime;
			if( m_nCreditsSharedUsed < 0 ){ m_nCreditsSharedUsed = 0; }
			m_nFuelSharedUsed -= m_nFuelSharedPerMinute * nElapsedTime;
			if( m_nFuelSharedUsed < 0 ){ m_nFuelSharedUsed = 0; }

			//Advance our squares
			for( int nX=0 ; nX<m_nWidth ; nX++ )
			{
				for( int nY=0 ; nY<m_nHeight ; nY++ )
				{
					for( int nVisIndex=0 ; nVisIndex<m_oIslandsPeopleHaveSeen.Count ; nVisIndex++ )
					{
						//In case this isn't our island, advance the animations that we can see
						oWhatIveSeen = (Square[,])m_oIslandsPeopleHaveSeen.GetByIndex( nVisIndex );
						oSquare = oWhatIveSeen[ nX,nY ];
						oSquare.Advance( nElapsedTime,m_nBuildPerSecond,this,false );
					}

					//Then if this is our island advance it for real.
					oSquare = GetSquare( nX,nY );
					oSquare.Advance( nElapsedTime,m_nBuildPerSecond,this,true );

					//Add up our command centers
					if( 
						(
							oSquare.GobBuildingKey == Game.m_cGOB_BASE_KEY ||
							oSquare.UnderCamoBuildingKey == Game.m_cGOB_BASE_KEY 
						)
						&&
						(
							oSquare.SquareStatus == enumSquareStatus.Built || 
							oSquare.SquareStatus == enumSquareStatus.Building 
						)
					  )
					{
						nCommandsLeft++;
					}

					if( oSquare.SquareStatus == enumSquareStatus.Built )
					{
						nCreditIncomePerSecond	+= (double)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_MONEYINCOME_CLMN );
						nBuildPerSecond			+= (double)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_BLDINCOME_CLMN );
						nFuelIncomePerSecond	+= (double)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_FUELINCOM_CLMN );
					}

					//If this is a MM square then see if it needs to defend us in any way
					if( oSquare.SquareStatus == enumSquareStatus.Built && 
						(bool)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_FIRESMM_CLMN ) == true &&
						oSquare.Armed == true  )
					{
						//This means this square is a MM that can defend... find the closest MMattack
						oMMAttack = m_oGame.FindClosestMMAttack( m_sGlobalID,oSquare.MMX,oSquare.MMY,oSquare.MMPosOffsetX,oSquare.MMPosOffsetY );
						//Check if this is within range
						if( oMMAttack != null )
						{
							oList = Game.GetSquaresInRadiusSortedList( Game.m_nLANDCOMBAT_MAXRANGE,oSquare.X,oSquare.Y );
							if( oList.ContainsKey( oMMAttack.TargetX.ToString() + "," + oMMAttack.TargetY.ToString() ) == false )
							{
								oMMAttack = null;
							}
						}

						//If we don't find one then head home
						bMove = false;
						if( oMMAttack == null && 
							( oSquare.MMX != oSquare.X || oSquare.MMY != oSquare.Y ||
							  oSquare.MMPosOffsetX != 0 || oSquare.MMPosOffsetY != 0 ) )
						{
							//Walk home
							nTargetX = oSquare.X;
							nTargetY = oSquare.Y;
							nTargetOffsetX = 0;
							nTargetOffsetY = 0;
							bMove = true;
							oSquare.MMFiring = false;
						}
						else if( oMMAttack != null )
						{
							//Walk twords the invader
							nTargetX = oMMAttack.TargetX;
							nTargetY = oMMAttack.TargetY;
							nTargetOffsetX = oMMAttack.LandedPosOffsetX;
							nTargetOffsetY = oMMAttack.LandedPosOffsetY;
							bMove = true;

							//Are we currently close enough to fire?
							oSquare.MMFiring = ( DSMath.Distance( oSquare.MMX,oSquare.MMY,nTargetX,nTargetY ) <= Game.m_nLANDCOMBAT_MAXRANGE );
						}

						//If we are firing do damage
						if( oSquare.MMFiring == true && oMMAttack != null )
						{
							oMMAttack.MMStrength -= ( (double)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_MMOFFENSE_CLMN ) / Game.m_nMMDAMAGEMODIFIER ) * nElapsedTime; 
							if( oMMAttack.MMStrength <= 0 )
							{
								m_oGame.AddMMExplosion( oMMAttack.TargetX,oMMAttack.TargetY,m_sGlobalID );
							}
						}
						else
						{
							oSquare.MMFiring = false;
						}

						//Actually move
						if( bMove == true )
						{
							Game.MoveMMTowordsGoal( this,nElapsedTime,
													oSquare.MMX,oSquare.MMY,oSquare.MMPosOffsetX,oSquare.MMPosOffsetY,
													nTargetX,nTargetY,nTargetOffsetX,nTargetOffsetY,
													ref nTempX,ref nTempY,ref nTempOffsetX,ref nTempOffsetY,
													ref nTempDir );

							oSquare.MMX = nTempX;
							oSquare.MMY = nTempY;
							oSquare.MMPosOffsetX = nTempOffsetX;
							oSquare.MMPosOffsetY = nTempOffsetY;
							oSquare.MMDirection = nTempDir;

							//Advance animations
							if( oSquare.MMTimeSinceAnimationChange > .7 )
							{
								oSquare.MMTimeSinceAnimationChange = 0;
								oSquare.MMAnimationCell++;
								if( oSquare.MMAnimationCell > 3 && oSquare.MMFiring == false )
								{
									oSquare.MMAnimationCell = 0;
								}
								else if( oSquare.MMAnimationCell > 4 )
								{
									oSquare.MMAnimationCell = 0;
								}
							}
							else
							{
								oSquare.MMTimeSinceAnimationChange += nElapsedTime;
							}
						}
					}
				}
			}

			//Are we dead now?
			m_nBasesLeft = nCommandsLeft;
			if( nCommandsLeft == 0 && m_bBasesPlaced == true )
			{
				m_bImDead = true;
			}

			//Save our results
			m_nCreditIncomePerSecond	= nCreditIncomePerSecond;
			m_nBuildPerSecond			= nBuildPerSecond;
			m_nFuelIncomePerSecond		= nFuelIncomePerSecond;


			//Check for any team changes
			nNewTeamCount = m_oGame.GetTeamCount( this );
			if( nNewTeamCount != m_nNumberOfTeamMembers && m_nNumberOfTeamMembers != -1 && IsMyIsland() == true )
			{
				m_bTeamChanged = true;
			}
			m_nNumberOfTeamMembers = nNewTeamCount;
		}


		public Square GetSquare( long nX, long nY )
		{
			Square oSquare = null;

            if( nX >= 0 && nX < m_oTerrain.GetLength( 0 ) &&
				nY >= 0 && nY < m_oTerrain.GetLength( 1 ) )
			{
				oSquare = m_oTerrain[ nX,nY ];
			}

			return( oSquare );
		}
		//If this is my island then I can see everything, otherwise show me only what I can see.
		public Square GetSquareICanSee( long nX,long nY,Island oIslandOfPersonAsking )
		{
			Square[,] oWhatIveSeen = null;
			Square oSquare = null;
			
			
			if( nX >= 0 && nX < m_oTerrain.GetLength( 0 ) &&
				nY >= 0 && nY < m_oTerrain.GetLength( 1 ) )
			{
				if( 
					(
						(
							oIslandOfPersonAsking == null &&
							this.IsMyIsland() == true
						)
						||	
						(
							oIslandOfPersonAsking != null &&
							this.GlobalID == oIslandOfPersonAsking.GlobalID
						)
					)
					||
					(
						m_oTerrain[ nX,nY ] != null &&
						m_oTerrain[ nX,nY ].SquareStatus == enumSquareStatus.Built &&
						(bool)Game.GetBldStat( m_oTerrain[ nX,nY ].GobBuildingKey,Game.m_cGOB_BLDSTATS_VISIBLEINFOW_CLMN ) == true
					) ||
					m_oGame.Debug_FullVision == true
				  )
				{
					oSquare = m_oTerrain[ nX,nY ];
				}
				else
				{
					oWhatIveSeen = (Square[,])m_oIslandsPeopleHaveSeen.GetByKey( oIslandOfPersonAsking.GlobalID );
					if( oWhatIveSeen == null )
					{
						oWhatIveSeen = CloneTerrain( false,false );

//Check for problems
Square oS = null;
for( int x=0 ; x<m_nWidth; x++ )
{
	for( int y=0 ; y<m_nHeight ; y++ )
	{
		oS = (Square)oWhatIveSeen[ x,y ];
		if( oS.X != x || oS.Y != y )
		{
			oS = null;
		}
	}
}

						m_oIslandsPeopleHaveSeen.Add( oIslandOfPersonAsking.GlobalID,oWhatIveSeen );
					}
					oSquare = oWhatIveSeen[ nX,nY ];
				}
			}
			return( oSquare );
		}
		private Square[,] CloneTerrain( bool bRevealBuildings,bool bRevealTerrain )
		{
			Square oSquareICanSee = null;
			Square[,] oWhatIveSeen = null;

			
			oWhatIveSeen = new Square[ m_nWidth,m_nHeight ];

			for( int x=0 ; x<m_nWidth; x++ )
			{
				for( int y=0 ; y<m_nHeight ; y++ )
				{
					oSquareICanSee = GetSquare( x,y );
					oWhatIveSeen[ x,y ] = new Square( m_oGame );

					if( bRevealBuildings == true ||
						bRevealTerrain == true ||
						(
							oSquareICanSee.SquareStatus == enumSquareStatus.Built &&
							(bool)Game.GetBldStat( oSquareICanSee.GobBuildingKey,Game.m_cGOB_BLDSTATS_ISARROW_CLMN ) == true 
						)
					  )
					{
						oWhatIveSeen[ x,y ].DeSerialize( oSquareICanSee.Serialize() );

						if( bRevealTerrain == false )
						{
							oWhatIveSeen[ x,y ].SquareType = Game.m_cDEFAULTTERRAINKEY;
						}
						if( bRevealBuildings == false )
						{
							oWhatIveSeen[ x,y ].SquareStatus = enumSquareStatus.Empty;
						}
					}
					else
					{
						oWhatIveSeen[ x,y ].X = x;
						oWhatIveSeen[ x,y ].Y = y;
					}
				}
			}


			return( oWhatIveSeen );
		}


		public double CalculateChanceToHit( long nAAFiringSquareX,long nAAFiringSquareY,long nMisTargetX,long nMisTargetY )
		{
			long nDistance = 0;
			double nChanceToHit = 0;
			Square oSquare = null;
			DSSortedList oRetVal = new DSSortedList();


			//Go through and total up our chance to hit
			for( int nX=0 ; nX<m_nWidth ; nX++ )
			{
				for( int nY=0 ; nY<m_nHeight ; nY++ )
				{
					oSquare = GetSquare( nX,nY );
					nDistance = (long)Game.GetDistance( oSquare.X,oSquare.Y,nAAFiringSquareX,nAAFiringSquareY );

					//Does this square affect this shot?
					if( oSquare.SquareStatus == enumSquareStatus.Built &&
						(
							(
								(bool)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_FIRESAA_CLMN ) == true &&
								oSquare.X == nAAFiringSquareX && oSquare.Y == nAAFiringSquareY
							)
							||
							(
								(bool)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_RADAREFFECT_CLMN ) == true &&
								nDistance <= (int)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_AARANGE_CLMN ) == true
							)
						)
					  )
					{
						nChanceToHit += (double)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_AABASEBOOST_CLMN ) -
										(double)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_AALOSSPERSQUARE_CLMN ) * nDistance;
					}
				}
			}

			nChanceToHit = DSMisc.Min( nChanceToHit,.90 );


			return( nChanceToHit );
		}
		public DSSortedList GetAAShots()
		{
			Square oSquare = null;
			DSSortedList oRetVal = new DSSortedList();


			for( int nX=0 ; nX<m_nWidth ; nX++ )
			{
				for( int nY=0 ; nY<m_nHeight ; nY++ )
				{
					oSquare = GetSquare( nX,nY );

					if( (bool)Game.GetTrnStat( oSquare.SquareType,Game.m_cGOB_TRNSTATS_CANBEBUILTON_CLMN ) == true &&
						oSquare.SquareStatus == enumSquareStatus.Built &&
						(bool)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_FIRESAA_CLMN ) == true )
					{
						oRetVal.Add( nX.ToString() + "," + nY.ToString(),oSquare ); 
					}
				}
			}


			return( oRetVal );
		}

		public bool CanBuildOnSquare( long nGobBuildingKeyBeingPlaced,long nX,long nY )
		{
			Point oEndPoint;
			object oValue = null;
			long nParentKey = 0;
			long nDeltaX = 0;
			long nDeltaY = 0;
			DSGobTable oTable = null;
			Square oSquare = null;
			bool bSquareCanBeBuiltOn = false;
			bool bFound = false;


			//Go through looking for the actual building if their is one
			bSquareCanBeBuiltOn = true;
			oTable = Game.GobFile.GetTable( Game.m_cGOB_BLDSTATS_TABLE );
			for( int nRow=0 ; nRow<oTable.RowCount ; nRow++ )
			{
				oValue = oTable.GetData( Game.m_cGOB_BLDSTATS_GT1SQAR_PRNTBLDKEY_TABLE,nRow );
				if( oValue != null && oValue.GetType().ToString() != "System.DBNull" )
				{
					nParentKey = (long)oValue;
					if( nParentKey == nGobBuildingKeyBeingPlaced )
					{
						bFound = true;

						//Get this changed key
						nDeltaX = (long)oTable.GetData( Game.m_cGOB_BLDSTATS_GT1SQR_PRNTDELTAX_TABLE,nRow );
						nDeltaY = (long)oTable.GetData( Game.m_cGOB_BLDSTATS_GT1SQR_PRNTDELTAY_TABLE,nRow );
						oEndPoint = Game.MoveUpRight( nDeltaX,nX,nY );
						oEndPoint = Game.MoveUpLeft( nDeltaY*-1,oEndPoint.X,oEndPoint.Y );
						oSquare = GetSquare( oEndPoint.X,oEndPoint.Y );

						//Can we build here?
						if( oSquare != null && 
							(bool)Game.GetTrnStat( oSquare.SquareType,Game.m_cGOB_TRNSTATS_CANBEBUILTON_CLMN ) == true && 
							oSquare.SquareStatus != enumSquareStatus.Destroyed &&
							(
								oSquare.SquareStatus == enumSquareStatus.Empty ||	
								(
									(
										(bool)oTable.GetData( Game.m_cGOB_BLDSTATS_CANCAMO_CLMN,nRow ) == true &&
										oSquare.UnderCamoBuildingKey == Game.m_cCAMO_NOCAMOBUILT
									) 
									&&
									(bool)oTable.GetData( Game.m_cGOB_BLDSTATS_CANBECAMOD_CLMN,nRow ) == true 
								)
							)
						  )
						{
							//We can build this peice here
						}
						else
						{
							//We can't build this peice here
							bSquareCanBeBuiltOn = false;
						}
					}
				}
			}

			//If we didn't find any parent keys then use the old detection system
			if( bFound == false )
			{
				bSquareCanBeBuiltOn = false;

				oSquare = GetSquare( nX,nY );
				if( oSquare != null && 
					(bool)Game.GetTrnStat( oSquare.SquareType,Game.m_cGOB_TRNSTATS_CANBEBUILTON_CLMN ) == true && 
					oSquare.SquareStatus != enumSquareStatus.Destroyed &&
					(
						oSquare.SquareStatus == enumSquareStatus.Empty ||	
						(
							(
								(bool)Game.GetBldStat( nGobBuildingKeyBeingPlaced,Game.m_cGOB_BLDSTATS_CANCAMO_CLMN ) == true &&
								oSquare.UnderCamoBuildingKey == Game.m_cCAMO_NOCAMOBUILT
							) 
							&&
							(bool)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_CANBECAMOD_CLMN ) == true 
						)
					)
				)
				{
				
					bSquareCanBeBuiltOn = true;
				}
			}


			return( bSquareCanBeBuiltOn );
		}


		public void SetSquare( long nGobBuildingKeyBeingPlaced,long nScreenX,long nScreenY )
		{
			SetSquare( nGobBuildingKeyBeingPlaced,nScreenX,nScreenY,false );
		}
		public void SetSquare( long nGobBuildingKeyBeingPlaced,long nScreenX,long nScreenY,bool bInstantBuild )
		{
			Point oEndPoint;
			object oValue = null;
			long nDeltaX = 0;
			long nDeltaY = 0;
			long nParentKey = 0;
			long nBuildingKey = 0;
			bool bFound = false;
			DSGobTable oTable = null;
			Square oSquare = null;


			//Go through looking for the actual building if their is one
			oTable = Game.GobFile.GetTable( Game.m_cGOB_BLDSTATS_TABLE );
			for( int nRow=0 ; nRow<oTable.RowCount ; nRow++ )
			{
				oValue = oTable.GetData( Game.m_cGOB_BLDSTATS_GT1SQAR_PRNTBLDKEY_TABLE,nRow );
				if( oValue != null && oValue.GetType().ToString() != "System.DBNull" )
				{
					nParentKey = (long)oValue;
					if( nParentKey == nGobBuildingKeyBeingPlaced )
					{
						bFound = true;
try
{
						//Get this changed key
						nDeltaX = (long)oTable.GetData( Game.m_cGOB_BLDSTATS_GT1SQR_PRNTDELTAX_TABLE,nRow );
						nDeltaY = (long)oTable.GetData( Game.m_cGOB_BLDSTATS_GT1SQR_PRNTDELTAY_TABLE,nRow );
						oEndPoint = Game.MoveUpRight( nDeltaX,nScreenX,nScreenY );
						oEndPoint = Game.MoveUpLeft( nDeltaY*-1,(long)oEndPoint.X,(long)oEndPoint.Y );

						nBuildingKey = (long)oTable.GetData( Game.m_cGOB_BLDSTATS_BLDKEY_CLMN,nRow );

						oSquare = GetSquare( (long)oEndPoint.X,(long)oEndPoint.Y );
						oSquare.SetSquare( nBuildingKey,bInstantBuild );
}
catch( System.Exception oEx )
{
	DSMisc.ShowErrors( oEx );
}
					}
				}
			}

			if( bFound == false )
			{
				oSquare = GetSquare( nScreenX,nScreenY );
				oSquare.SetSquare( nGobBuildingKeyBeingPlaced,bInstantBuild );
			}
		}

		public void Resize( int nNewWidth,int nNewHeight )
		{
			DSSortedList oIslands = new DSSortedList();
			Square[,] oWhatIveSeen = null;


			//Is this a new map?
			if( nNewHeight != m_nHeight || nNewWidth != m_nWidth )
			{
				m_nHeight = nNewHeight;
				m_nWidth = nNewWidth;

				m_oTerrain = ResizeArray( m_oTerrain,nNewWidth,nNewHeight );

				//Resize all the knwon terrains
				for( int i=0 ; i<m_oIslandsPeopleHaveSeen.Count ; i++ )
				{
					oWhatIveSeen = (Square[,])m_oIslandsPeopleHaveSeen.GetByIndex( i );
					oWhatIveSeen = ResizeArray( oWhatIveSeen,nNewWidth,nNewHeight );
					oIslands.Add( m_oIslandsPeopleHaveSeen.GetKey( i ),oWhatIveSeen );
				}
				m_oIslandsPeopleHaveSeen = oIslands;
			}
		}
		private Square[,] ResizeArray( Square[,] oaSourceArray,int nNewWidth,int nNewHeight )
		{
			Square[,] oaNewArray = null;


			oaNewArray = new Square[ nNewWidth,nNewHeight ];

			for( int x=0 ; x<nNewWidth; x++ )
			{
				for( int y=0 ; y<nNewHeight ; y++ )
				{
					if( x >= oaSourceArray.GetLength( 0 ) ||
						y >= oaSourceArray.GetLength( 1 ) ||
						oaSourceArray[ x,y ] == null )
					{
						oaNewArray[ x,y ] = new Square( m_oGame );
						oaNewArray[ x,y ].X = x;
						oaNewArray[ x,y ].Y = y;
					}
					else
					{
						oaNewArray[ x,y ] = oaSourceArray[ x,y ];
					}
				}
			}

			return( oaNewArray );
		}
		//0=Left, 1=Up, 2=Right, 3=Down
		public void ShiftTerrain( int nDirectionToShift )
		{
			Square[,] oaNewArray = null;
int x1 = 0;
int y1 = 0;
			try
			{
				oaNewArray = new Square[ m_nWidth,m_nHeight ];

				for( int x=0 ; x<m_nWidth; x++ )
				{
					for( int y=0 ; y<m_nHeight ; y++ )
					{
x1 = x;
y1 = y;
						//0=Left
						if( nDirectionToShift == 0 && x-1 >= 0 )
						{
							oaNewArray[ x-1,y ] = m_oTerrain[ x,y ];
						}
						//1=Up
						else if( nDirectionToShift == 1 && y-1 >= 0 )
						{
							oaNewArray[ x,y-1 ] = m_oTerrain[ x,y ];
						}
						//2=Right
						else if( nDirectionToShift == 2 && x+1 < m_oTerrain.GetLength( 0 ) )
						{
							oaNewArray[ x+1,y ] = m_oTerrain[ x,y ];
						}
						//3=Down
						else if( nDirectionToShift == 3 && y+1 < m_oTerrain.GetLength( 1 ) )
						{
							oaNewArray[ x,y+1 ] = m_oTerrain[ x,y ];
						}

						//Cover the borders from the shift
						if( 
							( nDirectionToShift == 0 && x == m_oTerrain.GetLength( 0 ) - 1 ) ||
							( nDirectionToShift == 1 && y == m_oTerrain.GetLength( 1 ) - 1 ) ||
							( nDirectionToShift == 2 && x == 0 ) ||
							( nDirectionToShift == 3 && y == 0 ) 
						  )
						{
							oaNewArray[ x,y ] = new Square( m_oGame );
							oaNewArray[ x,y ].X = x;
							oaNewArray[ x,y ].Y = y;
						}

						if( oaNewArray[ x,y ] != null )
						{
							oaNewArray[ x,y ].MMX = x;
							oaNewArray[ x,y ].MMY = y;
						}
					}
				}

				m_oTerrain = oaNewArray;
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}
		}

		public void ResetMMPositions()
		{
			Square oSquare = null;


			for( int nX=0 ; nX<m_nWidth ; nX++ )
			{
				for( int nY=0 ; nY<m_nHeight ; nY++ )
				{
					oSquare = GetSquare( nX,nY );
					oSquare.MMPosOffsetX = 0;
					oSquare.MMPosOffsetY = 0;
					oSquare.MMX = nX;
					oSquare.MMY = nY;
				}
			}
		}


		public void RotateIsland( int nDirection )
		{
			ArrayList oCompositeBuildingLocations = null;
			ArrayList oCompositeBuildingKeys = null;
			DSSortedList oIslands = new DSSortedList();
			Square[,] oWhatIveSeen = null;


			//Find the buildings that are composites
			GetCompositeBuildingLocations( out oCompositeBuildingLocations,out oCompositeBuildingKeys );
			m_oTerrain = RotateOneIsland( m_oTerrain,nDirection );

			//Resize all the knwon terrains
			for( int i=0 ; i<m_oIslandsPeopleHaveSeen.Count ; i++ )
			{
				oWhatIveSeen = (Square[,])m_oIslandsPeopleHaveSeen.GetByIndex( i );
				oWhatIveSeen = RotateOneIsland( oWhatIveSeen,nDirection );
				oIslands.Add( m_oIslandsPeopleHaveSeen.GetKey( i ),oWhatIveSeen );
			}
			m_oIslandsPeopleHaveSeen = oIslands;

			//Now reapply them
			ApplyCompositeBuildings( nDirection,oCompositeBuildingLocations,oCompositeBuildingKeys );
		}
		private void ApplyCompositeBuildings( long nNewDirection,ArrayList oCompositeBuildingLocations,ArrayList oCompositeBuildingKeys )
		{
			long nEndX = 0, nEndY = 0;
			long nOriginalGOBKey = 0;
			Point oEndPoint = Point.Empty;


			for( int i=0 ; i<oCompositeBuildingLocations.Count ; i++ )
			{
				oEndPoint = (Point)oCompositeBuildingLocations[ i ];
				nOriginalGOBKey = (long)oCompositeBuildingKeys[ i ];

				//Rotate all the composite building locations
				//Ok heres the deal, we find the composite building pre-rotate so our placement
				//coordinates aren't valid after the rotation.  So translate them.
				RotateCoordinates( oEndPoint.X,oEndPoint.Y,nNewDirection,out nEndX,out nEndY );

				SetSquare( nOriginalGOBKey,nEndX,nEndY,true );
			}
		}
		private void GetCompositeBuildingLocations( out ArrayList oCompositeBuildingLocations,
													out ArrayList oCompositeBuildingKeys )
		{
			DSSortedList oBuildingsFound = new DSSortedList();
			long nOriginalGOBKey = 0;
			long nDeltaX = 0, nDeltaY = 0;
			long nCenterX = 0, nCenterY = 0;
			string sKey = "";
			object oValue = null;
			Point oEndPoint = Point.Empty;
			Square oSquare = null;


			oCompositeBuildingLocations = new ArrayList();
			oCompositeBuildingKeys = new ArrayList();

			//Now handle composite buildings.  When you rotate, they get all screwed up.  We fix it by 
			//Finding there center, then reapplying the source building.
			//ToDo: This will rebuild this composite building many times over, once for each composite 
			//peice.  Enhance it to only do it once per building.
			for( int nX=0 ; nX<m_nWidth; nX++ )
			{
				for( int nY=0 ; nY<m_nHeight ; nY++ )
				{
					oSquare = GetSquare( nX,nY );

					//Is this square part of a composite building?
					if( oSquare.SquareStatus == enumSquareStatus.Built )
					{
						//Get our parent.  If we have one it means we are a composite building.
						oValue = Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_GT1SQAR_PRNTBLDKEY_TABLE );
						if( oValue != null && oValue.GetType().ToString() != "System.DBNull" )
						{
							//Find out what the starting building was
							//nOriginalGOBKey = (long)Game.GetBldStat( (long)oValue,Game.m_cGOB_BLDSTATS_GT1SQAR_PRNTBLDKEY_TABLE );
							nOriginalGOBKey = (long)oValue;

							//It doesn't appear to be finding the parent properly
							//You get a streak of new buildings when you rotate.

							//Ok we know its a composite, find the center
							nDeltaX = (long)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_GT1SQR_PRNTDELTAX_TABLE );
							nDeltaY = (long)Game.GetBldStat( oSquare.GobBuildingKey,Game.m_cGOB_BLDSTATS_GT1SQR_PRNTDELTAY_TABLE );
							oEndPoint = Game.MoveDownRight( nDeltaY*-1,nX,nY );
							oEndPoint = Game.MoveUpRight( nDeltaX*-1,oEndPoint.X,oEndPoint.Y );
							nCenterX = oEndPoint.X;
							nCenterY = oEndPoint.Y;
try
{
							//Now rebuild at that center square
							sKey = nCenterX.ToString() + "," + nCenterY.ToString();
							if( oBuildingsFound.Contains( sKey ) == false )
							{
try
{
								//Now save the location we are going to rebuild at
								oBuildingsFound.Add( sKey );
								oCompositeBuildingLocations.Add( oEndPoint );
								oCompositeBuildingKeys.Add( nOriginalGOBKey );
}
catch( System.Exception oEx )
{
	DSMisc.ShowErrors( oEx );
}
							}
}
catch( System.Exception oEx )
{
	DSMisc.ShowErrors( oEx );
}
						}
					}
				}
			}
		}
		private Square[,] RotateOneIsland( Square[,] oaIsland,int nDirection )
		{
			long nOldType = 0;
			long nEndX = 0, nEndY = 0;
			Point oEndPoint = Point.Empty;
			Square[,] oaNewTerrainArray = oaIsland;


			if( nDirection != 0 )
			{
				oaNewTerrainArray = new Square[ m_nWidth,m_nHeight ];

				for( int x=0 ; x<m_nWidth; x++ )
				{
					for( int y=0 ; y<m_nHeight ; y++ )
					{
						//Get new location
						RotateCoordinates( x,y,nDirection,out nEndX,out nEndY );

						//Copy over the square
						if( nEndX < 0 || nEndX > m_nWidth ||
							nEndY < 0 || nEndY > m_nHeight )
						{
							oaNewTerrainArray[ x,y ] = new Square( m_oGame );
						}
						else
						{
							oaNewTerrainArray[ x,y ] = oaIsland[ nEndX,nEndY ];
						}

						oaNewTerrainArray[ x,y ].X = x;
						oaNewTerrainArray[ x,y ].Y = y;
						oaNewTerrainArray[ x,y ].MMX = x;
						oaNewTerrainArray[ x,y ].MMY = y;

						nOldType = oaNewTerrainArray[ x,y ].SquareType;
						if( nDirection == 0 )
						{
							oaNewTerrainArray[ x,y ].SquareType = (int)Game.GetTrnStat( nOldType,Game.m_cGOB_TRNSTATS_GRAPHICINDEX_DIR0_CLMN );
						}
						else if( nDirection == 1 )
						{
							oaNewTerrainArray[ x,y ].SquareType = (int)Game.GetTrnStat( nOldType,Game.m_cGOB_TRNSTATS_GRAPHICINDEX_DIR1_CLMN );
						}
						else if( nDirection == 2 )
						{
							oaNewTerrainArray[ x,y ].SquareType = (int)Game.GetTrnStat( nOldType,Game.m_cGOB_TRNSTATS_GRAPHICINDEX_DIR2_CLMN );
						}
						else if( nDirection == 3 )
						{
							oaNewTerrainArray[ x,y ].SquareType = (int)Game.GetTrnStat( nOldType,Game.m_cGOB_TRNSTATS_GRAPHICINDEX_DIR3_CLMN );
						}
					}
				}
			}

			m_nDirection = nDirection;


			return( oaNewTerrainArray );
		}
		private void RotateCoordinates( long nStartX,long nStartY,long nDirection,out long nEndX,out long nEndY )
		{
			nEndX = -1;
			nEndY = -1;

			//0=UpperRight, 1=UpperLeft, 2=LowerLeft, 3=LowerRight
			if( nDirection == 0 )
			{
				nEndX = nStartX;
				nEndY = nStartY;
			}
			else if( nDirection == 1 )
			{
				if( ( m_nWidth-nStartX-1 ) % 2 == 0 )
				{
					nEndX = m_nWidth-nStartX-1;
					nEndY = nStartY;
				}
				else
				{
					if( m_nWidth % 2 == 0 )
					{
						if( nStartY-1 >= 0 )
						{
							nEndX = m_nWidth-nStartX-1;
							nEndY = nStartY-1;
						}
						else
						{
							nEndX = nStartX;
							nEndY = nStartY;
						}
					}
					else
					{
						nEndX = m_nWidth-nStartX-1;
						nEndY = nStartY;
					}
				}
			}
			else if( nDirection == 2 )
			{
				if( ( m_nWidth-nStartX-1 ) % 2 != 0 )
				{
					nEndX = m_nWidth-nStartX-1;
					nEndY = m_nHeight-nStartY-1;
				}
				else
				{
					if( m_nWidth % 2 == 0 )
					{
						nEndX = m_nWidth-nStartX-1;
						nEndY = m_nHeight-nStartY-1;
					}
					else
					{
						if( m_nHeight-nStartY < m_nHeight )
						{
							nEndX = m_nWidth-nStartX-1;
							nEndY = m_nHeight-nStartY;
						}
						else
						{
							nEndX = nStartX;
							nEndY = nStartY;
						}	
					}
				}
			}
			else if( nDirection == 3 )
			{
				if( nStartX % 2 == 0 )
				{
					if( m_nHeight-nStartY < m_nHeight )
					{
						nEndX = nStartX;
						nEndY = m_nHeight-nStartY;
					}
					else
					{
						nEndX = nStartX;
						nEndY = nStartY;
					}
				}
				else
				{
					nEndX = nStartX;
					nEndY = m_nHeight-nStartY-1;
				}
			}
		}

		public Point GetArrowCorner()
		{
			int nX = 0, nY = 0;
			Point oArrow = new Point( 0,0 );

			//0=UpperRight, 1=UpperLeft, 2=LowerLeft, 3=LowerRight
			if( m_nDirection == 0 )
			{
				nX = m_nWidth;
				nY = 0;
			}
			else if( m_nDirection == 1 )
			{
				nX = 0;
				nY = 0;
			}
			else if( m_nDirection == 2 )
			{
				nX = 0;
				nY = m_nHeight;
			}
			else if( m_nDirection == 3 )
			{
				nX = m_nWidth;
				nY = m_nHeight;
			}

			oArrow = new Point( nX,nY );


			return( oArrow );
		}


		public string Serialize( bool bChangesOnly )
		{
			string sRetVal = "";
			string sSquares = "";
			Square oSquare = null;


			//Now write all the square information
			for( int nX=0 ; nX<m_nWidth ; nX++ )
			{
				for( int nY=0 ; nY<m_nHeight ; nY++ )
				{
					oSquare = GetSquare( nX,nY );

					if( 
						(
							bChangesOnly == false &&
							(
								oSquare.SquareType != Game.m_cDEFAULTTERRAINKEY  ||
								oSquare.SquareStatus != enumSquareStatus.Empty 
							)
						)
						||
						(
							bChangesOnly == true &&
							(
								oSquare.NeedToBeSent == true ||
								m_bNeedToSendWholeIsland == true 
							)
						)
					  )
					{
						sSquares += nX.ToString() + m_cSQUARE_SEP + 
									nY.ToString() + m_cSQUARE_SEP + 
									oSquare.Serialize() + m_cSQUARE_SEP;
						oSquare.NeedToBeSent = false;
					}
				}
			}

			sRetVal = sSquares + m_cISLAND_SEP +
					  m_nWidth.ToString() + m_cISLAND_SEP +
					  m_nHeight.ToString() + m_cISLAND_SEP +
					  m_bBasesPlaced.ToString() + m_cISLAND_SEP +
					  m_nOwnerSocketID.ToString() + m_cISLAND_SEP +
					  m_nCredits.ToString() + m_cISLAND_SEP +
					  m_nFuel.ToString() + m_cISLAND_SEP + 
					  m_sGlobalIDOfPlayerWhoseTeamImOn + m_cISLAND_SEP + 
					  m_bTeamJoinApproved.ToString() + m_cISLAND_SEP + 
					  m_bImDead.ToString() + m_cISLAND_SEP + 
					  m_nFuelSharedPerMinute.ToString() + m_cISLAND_SEP + 
					  m_nCreditsSharedPerMinute.ToString() + m_cISLAND_SEP +
					  m_bTeamQuitPending.ToString() + m_cISLAND_SEP +
					  m_nFuelSharedUsed.ToString() + m_cISLAND_SEP +
					  m_nCreditsSharedUsed.ToString() + m_cISLAND_SEP + 
					  m_nMaxBasesToPlace.ToString() + m_cISLAND_SEP + 
						//Not true!  The direction is used to decide which way is front.
					  //Always store a 0.  Direction is only used for in game rotations so
				      //that we know which direction the attacks can come from safetly.
					  //"0" + m_cISLAND_SEP + 
					  m_nDirection.ToString() + m_cISLAND_SEP + 
					  m_sGlobalID + m_cISLAND_SEP + 
					  m_sOwnerName + m_cISLAND_SEP + 
					  m_nColor.ToString() + m_cISLAND_SEP + 
					  m_sAIOwnerGlobalID + m_cISLAND_SEP;

			if( m_oTeamSetup != null )
			{
				sRetVal += m_oTeamSetup.Serialize();
			}
			sRetVal += m_cISLAND_SEP;

			m_bNeedToSendWholeIsland = false;


			return( sRetVal );
		}
		public void DeSerialize( string sRecord )
		{
			string[] saIslandParamaters = null;
			string[] saAllSquares = null;
			int nX = 0;
			int nY = 0;
			int nNext = 0;
			int nTempH = 0;
			int nTempW = 0;
			Square oSquare = null;


			saIslandParamaters = DSMisc.Split( sRecord,m_cISLAND_SEP );
			saAllSquares = DSMisc.Split( saIslandParamaters[ 0 ],m_cSQUARE_SEP );

			//Update this island
			nTempW					= Convert.ToInt16( saIslandParamaters[ 1 ] );
			nTempH					= Convert.ToInt16( saIslandParamaters[ 2 ] );
			m_bBasesPlaced			= Convert.ToBoolean( saIslandParamaters[ 3 ] );
			m_nOwnerSocketID		= Convert.ToInt64( saIslandParamaters[ 4 ] );
			m_nCredits				= Convert.ToDouble( saIslandParamaters[ 5 ] );
			m_nFuel					= Convert.ToDouble( saIslandParamaters[ 6 ] );
			m_sGlobalIDOfPlayerWhoseTeamImOn	= saIslandParamaters[ 7 ];
			if( m_sGlobalIDOfPlayerWhoseTeamImOn == "-1" )
			{
				m_sGlobalIDOfPlayerWhoseTeamImOn = "";
			}
			m_bTeamJoinApproved		= Convert.ToBoolean( saIslandParamaters[ 8 ] );
			m_bImDead				= Convert.ToBoolean( saIslandParamaters[ 9 ] );
			m_nFuelSharedPerMinute	= Convert.ToInt64( saIslandParamaters[ 10 ] );
			m_nCreditsSharedPerMinute = Convert.ToInt64( saIslandParamaters[ 11 ] );
			m_bTeamQuitPending		= Convert.ToBoolean( saIslandParamaters[ 12 ] );
			m_nFuelSharedUsed		= Convert.ToDouble( saIslandParamaters[ 13 ] );
			m_nCreditsSharedUsed	= Convert.ToDouble( saIslandParamaters[ 14 ] );
			m_nMaxBasesToPlace		= Convert.ToInt64( saIslandParamaters[ 15 ] );

			if( saIslandParamaters.Length == 23 )
			{
				m_nDirection = Convert.ToInt32( saIslandParamaters[ 16 ] );
				//m_nDirection = 0;

				m_sGlobalID			= saIslandParamaters[ 17 ] ;
				m_sOwnerName		= saIslandParamaters[ 18 ] ;
				m_nColor			= Convert.ToInt32( saIslandParamaters[ 19 ] );
				m_sAIOwnerGlobalID	= saIslandParamaters[ 20 ] ;
				nNext = 21;
			}
			else if( saIslandParamaters.Length == 22 )
			{
				m_nDirection = Convert.ToInt32( saIslandParamaters[ 16 ] );
				//m_nDirection = 0;

				m_sGlobalID		= saIslandParamaters[ 17 ] ;
				m_sOwnerName	= saIslandParamaters[ 18 ] ;
				m_nColor		= Convert.ToInt32( saIslandParamaters[ 19 ] );
				nNext = 20;
			}
			else if( saIslandParamaters.Length == 21 )
			{
				m_nDirection = Convert.ToInt32( saIslandParamaters[ 16 ] );
				//m_nDirection = 0;

				m_sGlobalID = saIslandParamaters[ 17 ] ;
				m_sOwnerName = saIslandParamaters[ 18 ] ;
				nNext = 19;
			}
			else if( saIslandParamaters.Length == 19 )
			{
				m_nDirection = Convert.ToInt32( saIslandParamaters[ 16 ] );
				//m_nDirection = 0;

				nNext = 17;
			}
			else
			{
				nNext = 16;
			}

			if( saIslandParamaters.Length >= 18 && saIslandParamaters[ nNext ].Length > 0 )
			{
				m_oTeamSetup = new TeamSetup();
				m_oTeamSetup.DeSerialize( saIslandParamaters[ nNext ] );
			}
			else
			{
				m_oTeamSetup = null;				
			}


			//Is this a new map?
			Resize( nTempW,nTempH );


//Check for problems
Square oS = null;
for( int x=0 ; x<this.Width; x++ )
{
	for( int y=0 ; y<this.Height ; y++ )
	{
		oS = (Square)this.GetSquare( x,y );
		if( oS.X != x || oS.Y != y )
		{
			oS = null;
		}
	}
}

			//Deserialize the squares they sent us
			for( int i=0 ; i<saAllSquares.Length-2 ; i+=3 )
			{
				//Update the square
				nX = Convert.ToInt16( saAllSquares[ i ] );
				nY = Convert.ToInt16( saAllSquares[ i+1 ] );
				oSquare = m_oTerrain[ nX,nY ];
				oSquare.DeSerialize( saAllSquares[ i+2 ] );
				m_oTerrain[ nX,nY ] = oSquare;
				oSquare.X = nX;
				oSquare.Y = nY;


//Check for problems
//Square oS = null;
for( int x=0 ; x<this.Width; x++ )
{
	for( int y=0 ; y<this.Height ; y++ )
	{
		oS = (Square)this.GetSquare( x,y );
		if( oS.X != x || oS.Y != y )
		{
			oS = null;
		}
	}
}

				/*//If this is the first time we get the island from our opponents set it as what 
				//we can see.  This is neccessary so we can find out where they placed their bases.
				if( m_bHaveInitialized == false )
				{
					oSquare = new Square( m_oGame );
					oSquare.DeSerialize( saAllSquares[ i+2 ] );
					oSquare.SquareStatus = enumSquareStatus.Empty;
					m_oWhatIveSeen[ Convert.ToInt16( saAllSquares[ i ] ),
									Convert.ToInt16( saAllSquares[ i+1 ] ) ] = oSquare;
				}*/
			}
		}

        
		public DSSortedList GetCompositeBuilding( long nX,long nY )
		{
			DSSortedList oList = new DSSortedList();
			Point oEndPoint;
			DSGobTable oTable = null;
			object oValue = null;
			long nGTParent = 0;
			long nBuilding = 0;
			long nDeltaX = 0,nDeltaY = 0;
			long nCenterX = 0,nCenterY = 0;
			long nKey = 0;


			//First of all find out what the type of building is at this point
			nBuilding = m_oTerrain[ nX,nY ].GobBuildingKey;
			
			if( nBuilding >= 0 && 
				(
					m_oTerrain[ nX,nY ].SquareStatus == enumSquareStatus.Built ||
					m_oTerrain[ nX,nY ].SquareStatus == enumSquareStatus.Building  
				)
			  )
			{
				//Now our building parent
				oValue = Game.GetBldStat( nBuilding,Game.m_cGOB_BLDSTATS_GT1SQAR_PRNTBLDKEY_TABLE );
				if( oValue != null && oValue.GetType().ToString() != "System.DBNull" )
				{
					//Identify our parent
					nGTParent = (long)oValue;

					//Find the center of our building
					nDeltaX = (long)Game.GetBldStat( nBuilding,Game.m_cGOB_BLDSTATS_GT1SQR_PRNTDELTAX_TABLE );
					nDeltaY = (long)Game.GetBldStat( nBuilding,Game.m_cGOB_BLDSTATS_GT1SQR_PRNTDELTAY_TABLE );
					oEndPoint = Game.MoveDownRight( nDeltaY*-1,nX,nY );
					oEndPoint = Game.MoveUpRight( nDeltaX*-1,oEndPoint.X,oEndPoint.Y );
					nCenterX = oEndPoint.X;
					nCenterY = oEndPoint.Y;

					//Now walk and find any other peices of this building to destroy
					oTable = Game.GobFile.GetTable( Game.m_cGOB_BLDSTATS_TABLE );
					for( int nRow=0 ; nRow<oTable.RowCount ; nRow++ )
					{
						oValue = oTable.GetData( Game.m_cGOB_BLDSTATS_GT1SQAR_PRNTBLDKEY_TABLE,nRow );
						if( oValue != null && oValue.GetType().ToString() != "System.DBNull" )
						{
							if( (long)oValue == nGTParent )
							{
								//Get this changed key
								nDeltaX = (long)oTable.GetData( Game.m_cGOB_BLDSTATS_GT1SQR_PRNTDELTAX_TABLE,nRow );
								nDeltaY = (long)oTable.GetData( Game.m_cGOB_BLDSTATS_GT1SQR_PRNTDELTAY_TABLE,nRow );
								oEndPoint = Game.MoveUpRight( nDeltaX,nCenterX,nCenterY );
								oEndPoint = Game.MoveDownRight( nDeltaY,oEndPoint.X,oEndPoint.Y );

								oList.Add( nKey.ToString(),oEndPoint );
								nKey++;
							}
						}
					}
				}
			}


			return( oList );
		}



		public void UpdateSquaresICanSeeFromRefresh( MissleAttack oAttack,Island oIslandOwnerWhoCanNowSee )
		{
			UpdateSquaresICanSeeFromRefresh( oAttack.TargetX,oAttack.TargetY,4,oIslandOwnerWhoCanNowSee );
		}
		public void UpdateSquaresICanSeeFromRefresh( MMAttack oAttack,Island oIslandOwnerWhoCanNowSee )
		{
			UpdateSquaresICanSeeFromRefresh( oAttack.TargetX,oAttack.TargetY,4,oIslandOwnerWhoCanNowSee );
		}
		public void UpdateSquaresICanSeeFromRefresh( long nX,long nY,long nRadius,Island oIslandOwnerWhoCanNowSee )
		{
			Square[,] oWhatICanSee = null;
			Square oSquare = null;
			Square oSquareICanSee = null;
			System.Drawing.Point[] oaRadius = null;


			if( this.GlobalID != oIslandOwnerWhoCanNowSee.GlobalID )
			{
				oaRadius = Game.GetSquaresInRadius( nRadius,nX,nY );

				//Get the square to update
				oWhatICanSee = (Square[,])m_oIslandsPeopleHaveSeen.GetByKey( oIslandOwnerWhoCanNowSee.GlobalID );

				//Now update the squares
				for( long nSqrNdx=0 ; nSqrNdx<oaRadius.Length ; nSqrNdx++ )
				{
					oSquare = GetSquare( oaRadius[ nSqrNdx ].X,oaRadius[ nSqrNdx ].Y );
					if( oSquare != null )
					{
						oSquareICanSee = oWhatICanSee[ oaRadius[ nSqrNdx ].X,oaRadius[ nSqrNdx ].Y ];
						oSquareICanSee.DeSerialize( oSquare.Serialize() );
					}
				}
			}
		}

		public void RevealAllTerrainTo( Island oIslandOwnerWhoCanNowSee )
		{
			Square[,] oWhatTheyCanSee = null;


			try
			{
				if( this.GlobalID != oIslandOwnerWhoCanNowSee.GlobalID &&
					 m_oIslandsPeopleHaveSeen.ContainsKey( oIslandOwnerWhoCanNowSee.GlobalID ) == false )
				{
					//Get the square to update
					oWhatTheyCanSee = (Square[,])m_oIslandsPeopleHaveSeen.GetByKey( oIslandOwnerWhoCanNowSee.GlobalID );
					oWhatTheyCanSee = CloneTerrain( false,true );

					m_oIslandsPeopleHaveSeen.Add( oIslandOwnerWhoCanNowSee.GlobalID,oWhatTheyCanSee );
				}
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}
		}


		public bool IsMyIsland()
		{			
			bool bRetVal = false;

			try
			{
				bRetVal = 
					( 
						m_oGame.App.SinglePlayerMode == true &&
						m_nOwnerSocketID == 0
					)
					||
					m_oGame.App.GameState == enumStates.MapEditor 
					||
					(
						m_oGame.App.SinglePlayerMode == false &&
						m_oGame.GameEngine.DirectPlay.Me.SocketID == m_nOwnerSocketID
					);
			}
			catch( System.Exception oEx )
			{
				DSMisc.ShowErrors( oEx );
			}

			return( bRetVal );
		}


		public long GetNumberOfBasesOnIsland()
		{
			Square oSquare = null;
			long nNumBases = 0;


			for( int nX=0 ; nX<m_nWidth ; nX++ )
			{
				for( int nY=0 ; nY<m_nHeight ; nY++ )
				{
					oSquare = GetSquare( nX,nY );

					if( oSquare.SquareStatus == enumSquareStatus.Built && oSquare.GobBuildingKey == Game.m_cGOB_BASE_KEY )
					{
						nNumBases++;						
					}
				}
			}


			return( nNumBases );
		}



		#region Properties
		public int Width
		{
			get
			{
				return( m_nWidth );
			}
		}
		public int Height
		{
			get
			{
				return( m_nHeight );
			}
		}
		public bool BasesPlaced
		{
			get
			{
				return( m_bBasesPlaced );
			}
			set
			{
				m_bBasesPlaced = value;
			}
		}
		public long OwnerSocketID
		{
			get
			{
				return( m_nOwnerSocketID );
			}
			set
			{
				m_nOwnerSocketID = value;
			}
		}
		public string OwnerName
		{
			get
			{
				return( m_sOwnerName );
			}
			set
			{
				m_sOwnerName = value;
			}
		}
		public string GlobalID
		{
			get
			{
				return( m_sGlobalID );
			}
			set
			{
				m_sGlobalID = value;
			}
		}
		public double Fuel
		{
			get
			{
				return( m_nFuel );
			}
			set
			{
				m_nFuel = value;
			}
		}
		public double Credits
		{
			get
			{
				return( m_nCredits );
			}
			set
			{
				m_nCredits = value;
			}
		}
		public double CreditIncomePerSecond
		{
			get
			{
				return( m_nCreditIncomePerSecond );
			}
			set
			{
				m_nCreditIncomePerSecond = value;
			}
		}
		public double BuildPerSecond
		{
			get
			{
				return( m_nBuildPerSecond );
			}
			set
			{
				m_nBuildPerSecond = value;
			}
		}
		public double FuelIncomePerSecond
		{
			get
			{
				return( m_nFuelIncomePerSecond );
			}
			set
			{
				m_nFuelIncomePerSecond = value;
			}
		}
		public string GlobalIDOfPlayerWhoseTeamImOn
		{
			get
			{
				return( m_sGlobalIDOfPlayerWhoseTeamImOn );
			}
			set
			{
				m_sGlobalIDOfPlayerWhoseTeamImOn = value;
			}
		}
		public TeamSetup TeamSetup
		{
			get
			{
				return( m_oTeamSetup );
			}
			set
			{
				m_oTeamSetup = value;
			}
		}
		public bool TeamJoinApproved
		{
			get
			{
				return( m_bTeamJoinApproved );
			}
			set
			{
				m_bTeamJoinApproved = value;
			}
		}
		public bool TeamQuitPending
		{
			get
			{
				return( m_bTeamQuitPending);
			}
			set
			{
				m_bTeamQuitPending = value;
			}
		}
		public bool ImDead
		{
			get
			{
				return( m_bImDead );
			}
			set
			{
				m_bImDead = value;
			}
		}
		public long BasesLeft
		{
			get
			{
				return( m_nBasesLeft );
			}
			set
			{
				m_nBasesLeft = value;
			}
		}
		public long NumberOfTeamMembers
		{
			get
			{
				return( m_nNumberOfTeamMembers );
			}
			set
			{
				m_nNumberOfTeamMembers = value;
			}
		}
		public bool TeamChanged
		{
			get
			{
				return( m_bTeamChanged );
			}
			set
			{
				m_bTeamChanged = value;
			}
		}
		public double FuelSharedPerMinute
		{
			get
			{
				return( m_nFuelSharedPerMinute );
			}
			set
			{
				m_nFuelSharedPerMinute = value;
			}
		}
		public double CreditsSharedPerMinute
		{
			get
			{
				return( m_nCreditsSharedPerMinute );
			}
			set
			{
				m_nCreditsSharedPerMinute = value;
			}
		}
		public double FuelSharedUsed
		{
			get
			{
				return( m_nFuelSharedUsed );
			}
			set
			{
				m_nFuelSharedUsed = value;
			}
		}
		public double CreditsSharedUsed
		{
			get
			{
				return( m_nCreditsSharedUsed );
			}
			set
			{
				m_nCreditsSharedUsed = value;
			}
		}
		public long MaxBasesToPlace
		{
			get
			{
				return( m_nMaxBasesToPlace );
			}
			set
			{
				m_nMaxBasesToPlace = value;
			}
		}
		public int Direction
		{
			get
			{
				return( m_nDirection );
			}
			set
			{
				m_nDirection = value;
			}
		}
		public bool NeedToSendWholeIsland
		{
			get
			{
				return( m_bNeedToSendWholeIsland );
			}
			set
			{
				m_bNeedToSendWholeIsland = value;
			}
		}
		public string AIOwnerGlobalID
		{
			get
			{
				return( m_sAIOwnerGlobalID );
			}
			set
			{
				m_sAIOwnerGlobalID = value;
			}
		}
		public double ElapsedTimeSinceBarSwitch
		{
			get
			{
				return( m_nElapsedTimeSinceBarSwitch );
			}
			set
			{
				m_nElapsedTimeSinceBarSwitch = value;
			}
		}
		public bool BarInDefaultPos
		{
			get
			{
				return( m_bBarInDefaultPos );
			}
			set
			{
				m_bBarInDefaultPos = value;
			}
		}
		public int Color
		{
			get
			{
				return( m_nColor );
			}
			set
			{
				m_nColor = value;
			}
		}			
		#endregion
	}
}