void AddTextToBlankSectorBox( void )
{
	UINT32 hStringHandle;
	UINT16 usSectorValue = 0;


	// get the sector value
	usSectorValue = SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY );

	switch( usSectorValue )
	{
		case SEC_D2: //Chitzena SAM
			if( !fSamSiteFound[ SAM_SITE_ONE ] )
				AddMonoString( &hStringHandle, pLandTypeStrings[ TROPICS ] );
			else
				AddMonoString( &hStringHandle, pLandTypeStrings[ TROPICS_SAM_SITE ] );
			break;
		case SEC_D15: //Drassen SAM
			if( !fSamSiteFound[ SAM_SITE_TWO ] )
				AddMonoString( &hStringHandle, pLandTypeStrings[ SPARSE ] );
			else
				AddMonoString( &hStringHandle, pLandTypeStrings[ SPARSE_SAM_SITE ] );
			break;
		case SEC_I8: //Cambria SAM
			if( !fSamSiteFound[ SAM_SITE_THREE ] )
				AddMonoString( &hStringHandle, pLandTypeStrings[ SAND ] );
			else
				AddMonoString( &hStringHandle, pLandTypeStrings[ SAND_SAM_SITE ] );
			break;
		// SAM Site 4 in Meduna is within town limits, so it's handled in AddTextToTownBox()

		default:
			AddMonoString( &hStringHandle, pLandTypeStrings[ ( SectorInfo[ usSectorValue ].ubTraversability[ 4 ] ) ] );
			break;
	}

	// blank line
	AddMonoString( &hStringHandle, L"" );

	// sector
	AddSectorToBox();
}
void AddTextToBlankSectorBox( void )
{
	UINT32 hStringHandle;
	UINT16 usSectorValue = 0;


	// get the sector value
	usSectorValue = SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY );

	AssertGE(usSectorValue, 0);
	AssertLT(usSectorValue,256);

	////////////////////////////////////
	// HEADROCK HAM 5:
	// Read and verify XML sector names
	BOOLEAN fSectorHasXMLNames = TRUE;
	CHAR16 zUnexplored[MAX_SECTOR_NAME_LENGTH];
	CHAR16 zExplored[MAX_SECTOR_NAME_LENGTH];
	
	wcscpy( zUnexplored, gzSectorNames[ usSectorValue ][0] );
	wcscpy( zExplored, gzSectorNames[ usSectorValue ][2] );

	if (zUnexplored[0] == 0 || zExplored[0] == 0)
	{
		fSectorHasXMLNames = FALSE;
	}

	if (fSectorHasXMLNames) // ABOVE GROUND XML
	{
		// HEADROCK HAM 3.6: The program can now read custom names from XML for all above-ground sectors.
		// In the event that a specific name or set of names is missing, the program generates a default
		// name as it always has.
		// I've also updated the SAM Site sectors to rely on SamSite.XML data.
		
		BOOLEAN fVisited = (SectorInfo[ usSectorValue ].uiFlags & SF_ALREADY_VISITED);
		BOOLEAN fSAMSiteKnown = FALSE;

		// Test for known SAM Site at this location
		for (UINT16 x=0; x < MAX_NUMBER_OF_SAMS; x++)
		{
			if ( pSamList[x] == usSectorValue )
			{
				if ( fSamSiteFound[ x ] )
				{
					fSAMSiteKnown = TRUE;
				}
			}
		}

		if (fVisited || fSAMSiteKnown)
		{
			AddMonoString( &hStringHandle, zExplored );
		}
		else
		{
			AddMonoString( &hStringHandle, zUnexplored );
		}
	}
	else // ABOVE GROUND HARDCODED
	{
		switch( usSectorValue )
		{
			case SEC_D2: //Chitzena SAM
				if( !fSamSiteFound[ SAM_SITE_ONE ] )
					AddMonoString( &hStringHandle, pLandTypeStrings[ TROPICS ] );
				else
					AddMonoString( &hStringHandle, pLandTypeStrings[ TROPICS_SAM_SITE ] );
				break;
			case SEC_D15: //Drassen SAM
				if( !fSamSiteFound[ SAM_SITE_TWO ] )
					AddMonoString( &hStringHandle, pLandTypeStrings[ SPARSE ] );
				else
					AddMonoString( &hStringHandle, pLandTypeStrings[ SPARSE_SAM_SITE ] );
				break;
			case SEC_I8: //Cambria SAM
				if( !fSamSiteFound[ SAM_SITE_THREE ] )
					AddMonoString( &hStringHandle, pLandTypeStrings[ SAND ] );
				else
					AddMonoString( &hStringHandle, pLandTypeStrings[ SAND_SAM_SITE ] );
				break;
			// SAM Site 4 in Meduna is within town limits, so it's handled in AddTextToTownBox()

			default:
				AddMonoString( &hStringHandle, pLandTypeStrings[ ( SectorInfo[ usSectorValue ].ubTraversability[ 4 ] ) ] );
				break;
		}
	}

	// blank line
	AddMonoString( &hStringHandle, L"" );

	// sector
	AddSectorToBox();

	// HEADROCK HAM 3.6: Facilities
	AddFacilitiesToBox( bCurrentTownMineSectorX, bCurrentTownMineSectorY, &hStringHandle, FALSE );
}
// adds text to mine info box
void AddTextToMineBox( void )
{
	UINT8 ubMineIndex;
	UINT8 ubTown;
	UINT32 hStringHandle;
	CHAR16 wString[ 64 ];


	ubMineIndex = GetMineIndexForSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY );

	// name of town followed by "mine"
	//swprintf( wString, L"%s %s", pTownNames[ GetTownAssociatedWithMine( ubMineIndex ) ], pwMineStrings[ 0 ] );
	swprintf( wString, L"%s %s", pTownNames[ GetTownAssociatedWithMine( ubMineIndex ) ], MineralsName[gMineStatus[ubMineIndex].ubMineType].sType );
	AddMonoString( &hStringHandle, wString );

	// blank line
	AddMonoString( &hStringHandle, L"" );


	// sector
	AddSectorToBox();

	// mine status
	swprintf( wString, L"%s:", pwMineStrings[ 9 ]);
	AddMonoString( &hStringHandle, wString );

	// check if mine is empty (abandoned) or running out
	if (gMineStatus[ ubMineIndex ].fEmpty)
	{
		// abandonded
		wcscpy( wString, pwMineStrings[ 5 ] );
	}
	else
	if (gMineStatus[ ubMineIndex ].fShutDown)
	{
		// shut down
		wcscpy( wString, pwMineStrings[ 6 ] );
	}
	else
	if (gMineStatus[ ubMineIndex ].fRunningOut)
	{
		// running out
		wcscpy( wString, pwMineStrings[ 7 ] );
	}
	else
	{
		// producing
		wcscpy( wString, pwMineStrings[ 8 ] );
	}
	AddSecondColumnMonoString( &hStringHandle, wString );


	// if still producing
	if (!gMineStatus[ ubMineIndex ].fEmpty)
	{
		// current production
		swprintf( wString, L"%s:", pwMineStrings[ 3 ]);
		AddMonoString( &hStringHandle, wString );

		swprintf( wString, L"%d", PredictDailyIncomeFromAMine( ubMineIndex, TRUE ) );
		InsertCommasForDollarFigure( wString );
		InsertDollarSignInToString( wString );
		AddSecondColumnMonoString( &hStringHandle, wString );


		// potential production
		swprintf( wString, L"%s:", pwMineStrings[ 4 ]);
		AddMonoString( &hStringHandle, wString );

		swprintf( wString, L"%d", GetMaxDailyRemovalFromMine( ubMineIndex ) );
		InsertCommasForDollarFigure( wString );
		InsertDollarSignInToString( wString );
		AddSecondColumnMonoString( &hStringHandle, wString );


		// if potential is not nil
		if (GetMaxPeriodicRemovalFromMine(ubMineIndex) > 0)
		{
			// production rate (current production as a percentage of potential production)
			swprintf( wString, L"%s:", pwMineStrings[ 10 ]);
			AddMonoString( &hStringHandle, wString );
			swprintf( wString, L"%d%%%%", (PredictDailyIncomeFromAMine(ubMineIndex, TRUE) * 100 ) / GetMaxDailyRemovalFromMine(ubMineIndex) );
			AddSecondColumnMonoString( &hStringHandle, wString );
		}


		// town control percentage
		swprintf( wString, L"%s:", pwMineStrings[ 12 ]);
		AddMonoString( &hStringHandle, wString );
		//swprintf( wString, L"%d%%%%", (GetTownSectorsUnderControl( gMineLocation[ ubMineIndex ].bAssociatedTown ) *	100) / GetTownSectorSize( gMineLocation[ ubMineIndex ].bAssociatedTown ));
		swprintf( wString, L"%d%%%%", (GetTownSectorsUnderControl( gMineStatus[ ubMineIndex ].bAssociatedTown ) *	100) / GetTownSectorSize( gMineStatus[ ubMineIndex ].bAssociatedTown ));
		AddSecondColumnMonoString( &hStringHandle, wString );

		//ubTown = gMineLocation[ ubMineIndex ].bAssociatedTown;
		ubTown = gMineStatus[ ubMineIndex ].bAssociatedTown;
		if( gTownLoyalty[ ubTown ].fStarted && gfTownUsesLoyalty[ ubTown ])
		{
			// town loyalty percentage
			swprintf( wString, L"%s:", pwMineStrings[ 13 ]);
			AddMonoString( &hStringHandle, wString );
			//swprintf( wString, L"%d%%%%", gTownLoyalty[ gMineLocation[ ubMineIndex ].bAssociatedTown ].ubRating);
			swprintf( wString, L"%d%%%%", gTownLoyalty[ gMineStatus[ ubMineIndex ].bAssociatedTown ].ubRating);
			AddSecondColumnMonoString( &hStringHandle, wString );
		}

/* gradual monster infestation concept was ditched, now simply IN PRODUCTION or SHUT DOWN
		// percentage of miners working
		swprintf( wString, L"%s:", pwMineStrings[ 14 ]);
		AddMonoString( &hStringHandle, wString );
		swprintf( wString, L"%d%%%%", gubMonsterMineInfestation[ gMineStatus[ ubMineIndex ].bMonsters ]);
		AddSecondColumnMonoString( &hStringHandle, wString );
*/

		// ore type (silver/gold
		swprintf( wString, L"%s:", pwMineStrings[ 11 ]);
		AddMonoString( &hStringHandle, wString );
		AddSecondColumnMonoString( &hStringHandle, MineralsName[gMineStatus[ubMineIndex].ubMineType].sMinerals );
		//AddSecondColumnMonoString( &hStringHandle, (gMineStatus[ubMineIndex].ubMineType == SILVER_MINE) ? pwMineStrings[ 1 ] : pwMineStrings[ 2 ] );
	}


#ifdef _DEBUG
	// dollar amount remaining in mine
	wcscpy( wString, L"Remaining (DEBUG):");
	AddMonoString( &hStringHandle, wString );

	swprintf( wString, L"%d", GetTotalLeftInMine( ubMineIndex ) );
	InsertCommasForDollarFigure( wString );
	InsertDollarSignInToString( wString );
	AddSecondColumnMonoString( &hStringHandle, wString );
#endif

}
// adds text to town info box
void AddTextToTownBox( void )
{
	UINT32 hStringHandle = 0;
	CHAR16 wString[ 64 ];
	UINT8 ubTownId = 0;
	UINT16 usTownSectorIndex;
	INT16 sMineSector = 0;


	// remember town id
	ubTownId = GetTownIdForSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY );
	Assert((ubTownId >= FIRST_TOWN) && (ubTownId < NUM_TOWNS));

	usTownSectorIndex = SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY );

	AssertGE(usTownSectorIndex, 0);
	AssertLT(usTownSectorIndex,256);

	////////////////////////////////////
	// HEADROCK HAM 5:
	// Read and verify XML sector names
	BOOLEAN fSectorHasXMLNames = TRUE;
	CHAR16 zUnexplored[MAX_SECTOR_NAME_LENGTH];
	CHAR16 zExplored[MAX_SECTOR_NAME_LENGTH];
	
	wcscpy( zUnexplored, gzSectorNames[ usTownSectorIndex ][0] );
	wcscpy( zExplored, gzSectorNames[ usTownSectorIndex ][2] );

	if (zUnexplored[0] == 0 || zExplored[0] == 0)
	{
		fSectorHasXMLNames = FALSE;
	}

	if (fSectorHasXMLNames) // ABOVE GROUND XML
	{
		// HEADROCK HAM 3.6: The program can now read custom names from XML for all above-ground sectors.
		// In the event that a specific name or set of names is missing, the program generates a default
		// name as it always has.
		// I've also updated the SAM Site sectors to rely on SamSite.XML data.
		
		BOOLEAN fVisited = (SectorInfo[ usTownSectorIndex ].uiFlags & SF_ALREADY_VISITED);
		BOOLEAN fSAMSiteKnown = FALSE;

		// Test for known SAM Site at this location
		for (UINT16 x=0; x < MAX_NUMBER_OF_SAMS; x++)
		{
			if ( pSamList[x] == usTownSectorIndex )
			{
				if ( fSamSiteFound[ x ] )
				{
					fSAMSiteKnown = TRUE;
				}
			}
		}

		if (fVisited || fSAMSiteKnown)
		{
			AddMonoString( &hStringHandle, zExplored );
		}
		else
		{
			AddMonoString( &hStringHandle, zUnexplored );
		}
	}
	else // ABOVE GROUND HARDCODED
	{
		switch( usTownSectorIndex )
		{
			case SEC_B13:
				AddMonoString( &hStringHandle, pLandTypeStrings[ DRASSEN_AIRPORT_SITE ] );
				break;
			case SEC_F8:
				AddMonoString( &hStringHandle, pLandTypeStrings[ CAMBRIA_HOSPITAL_SITE ] );
				break;
			case SEC_J9: //Tixa
				//if( !fFoundTixa )
				if( gfHiddenTown[ TIXA ] == FALSE )
					AddMonoString( &hStringHandle, pLandTypeStrings[ SAND ] );
				else
					AddMonoString( &hStringHandle, pTownNames[ TIXA ] );
				break;
			case SEC_K4: //Orta
				//if( !fFoundOrta )
				if( gfHiddenTown[ ORTA ] == FALSE )
					AddMonoString( &hStringHandle, pLandTypeStrings[ SWAMP ] );
				else
					AddMonoString( &hStringHandle, pTownNames[ ORTA ] );
				break;
			case SEC_N3:
				AddMonoString( &hStringHandle, pLandTypeStrings[ MEDUNA_AIRPORT_SITE ] );
				break;
			default:
				if( usTownSectorIndex == SEC_N4 && fSamSiteFound[ SAM_SITE_FOUR ] )
				{	//Meduna's SAM site
					AddMonoString( &hStringHandle, pLandTypeStrings[ MEDUNA_SAM_SITE ] );
				}
				else
				{ // town name
					swprintf( wString, L"%s", pTownNames[ ubTownId ] );
					AddMonoString( &hStringHandle, wString );
				}
				break;
		}
	}

	// blank line
	AddMonoString( &hStringHandle, L"" );

	// sector
	AddSectorToBox();

	// town size
	if( gfHiddenTown[ GetTownIdForSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) ] )
	{
	swprintf( wString, L"%s:", pwTownInfoStrings[ 0 ] );
	AddMonoString( &hStringHandle, wString );
	swprintf( wString, L"%d",	GetTownSectorSize( ubTownId ) );
	AddSecondColumnMonoString( &hStringHandle, wString );
	}

	// main facilities
	// HEADROCK HAM 3.6: This function now does all the work of assembling a facility entry.
	AddFacilitiesToBox( bCurrentTownMineSectorX, bCurrentTownMineSectorY, &hStringHandle, TRUE );

	// the concept of control is only meaningful in sectors where militia can be trained
	if ( MilitiaTrainingAllowedInSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY, 0 ) &&
		gfHiddenTown[ GetTownIdForSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) ] )
	{
		// town control
		swprintf( wString, L"%s:", pwTownInfoStrings[ 2 ] );
		AddMonoString( &hStringHandle, wString );
		swprintf( wString, L"%d%%%%",	(GetTownSectorsUnderControl( ubTownId ) * 100) / GetTownSectorSize( ubTownId ));
		AddSecondColumnMonoString( &hStringHandle, wString );
	}

	// the concept of town loyalty is only meaningful in towns where loyalty is tracked
	if( gTownLoyalty[ ubTownId ].fStarted && gfTownUsesLoyalty[ ubTownId ] &&
		gfHiddenTown[ GetTownIdForSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) ] )
	{
		// town loyalty
		swprintf( wString, L"%s:", pwTownInfoStrings[ 5 ] );
		AddMonoString( &hStringHandle, wString );
		swprintf( wString, L"%d%%%%", gTownLoyalty[ ubTownId ].ubRating );
		AddSecondColumnMonoString( &hStringHandle, wString );
	}

	// if the town has a mine
	sMineSector = GetMineSectorForTown( ubTownId );
	if( sMineSector != -1 && gfHiddenTown[ GetTownIdForSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) ] )
	{
		// Associated Mine: Sector
	swprintf( wString, L"%s:",	pwTownInfoStrings[ 4 ] );
		AddMonoString( &hStringHandle, wString );
	GetShortSectorString( ( INT16 )( sMineSector % MAP_WORLD_X ), ( INT16 )( sMineSector / MAP_WORLD_X ), wString );
		AddSecondColumnMonoString( &hStringHandle, wString );
	}
}
void CreateDestroyTownInfoBox( void )
{
	// create destroy pop up box for town/mine info
	static BOOLEAN fCreated = FALSE;
	SGPRect pDimensions;
	SGPPoint pPosition;
	INT8 bTownId = 0;

	if( ( fCreated == FALSE ) && ( fShowTownInfo == TRUE ) )
	{
		// create pop up box
		CreateTownInfoBox( );

		// decide what kind of text to add to display

		if ( bCurrentTownMineSectorZ == 0 )
		{
			// only show the mine info when mines button is selected, otherwise we need to see the sector's regular town info
			if ( ( IsThereAMineInThisSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) == TRUE) && fShowMineFlag )
			{
				AddTextToMineBox( );
			}
			else
			{
				bTownId = GetTownIdForSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY );

				// do we add text for the town box?
				if( bTownId != BLANK_SECTOR )
				{
					// add text for town box
					AddTextToTownBox( );
				}
				else
				{
					// just a blank sector (handles SAM sites if visible)
					AddTextToBlankSectorBox( );
				}
			}

			// add "militia", "militia training", "control" "enemy forces", etc. lines text to any popup box
			AddCommonInfoToBox();
		}
		else	// underground
		{
			// sector
			AddSectorToBox();
		}

		AddItemsInSectorToBox();


		// set font type
	SetBoxFont(ghTownMineBox, BLOCKFONT2);

		// set highlight color
		SetBoxHighLight(ghTownMineBox, FONT_WHITE);

		SetBoxSecondColumnForeground( ghTownMineBox, FONT_WHITE );
		SetBoxSecondColumnBackground( ghTownMineBox, FONT_BLACK );
		SetBoxSecondColumnHighLight( ghTownMineBox, FONT_WHITE );
		SetBoxSecondColumnShade( ghTownMineBox, FONT_BLACK );
		SetBoxSecondColumnFont( ghTownMineBox, BLOCKFONT2 );
		SetBoxSecondColumnMinimumOffset( ghTownMineBox, 20 );

		// unhighlighted color
		SetBoxForeground(ghTownMineBox, FONT_YELLOW);

		// background color
		SetBoxBackground(ghTownMineBox, FONT_BLACK);

		// shaded color..for darkened text
		SetBoxShade( ghTownMineBox, FONT_BLACK );

		// give title line (0) different color from the rest
		SetBoxLineForeground( ghTownMineBox, 0, FONT_LTGREEN );

		// ressize box to text
		ResizeBoxToText( ghTownMineBox );

		// make box bigger to this size
		GetBoxSize( ghTownMineBox , &pDimensions );

		if( pDimensions.iRight < BOX_BUTTON_WIDTH )
		{
			// resize box to fit button
			pDimensions.iRight += BOX_BUTTON_WIDTH;
		}

		pDimensions.iBottom += BOX_BUTTON_HEIGHT;

		SetBoxSize( ghTownMineBox, pDimensions );

		ShowBox( ghTownMineBox );

		// now position box
		MinWidthOfTownMineInfoBox( );
		PositionTownMineInfoBox( );

		// now add the button
		AddInventoryButtonForMapPopUpBox( );

		// now position box
		PositionTownMineInfoBox( );

		fCreated = TRUE;
	}
	else if( ( fCreated == TRUE ) && ( fShowTownInfo == FALSE ) )
	{

		// get box size
		GetBoxSize( ghTownMineBox, &pDimensions );

		// get position
		GetBoxPosition( ghTownMineBox, &pPosition);

		// destroy pop up box
		RemoveBox( ghTownMineBox );
		ghTownMineBox = -1;

		// remove inventory button
		RemoveInventoryButtonForMapPopUpBox( );

		// restore background
		RestoreExternBackgroundRect( ( INT16 )pPosition.iX, ( INT16 )pPosition.iY, ( INT16 ) ( pDimensions.iRight - pDimensions.iLeft ), ( INT16 ) ( pDimensions.iBottom - pDimensions.iTop + 3 ) );

		fCreated = FALSE;
	}


	return;
}
// adds text to town info box
void AddTextToTownBox( void )
{
	UINT32 hStringHandle = 0;
	CHAR16 wString[ 64 ];
	UINT8 ubTownId = 0;
	UINT16 usTownSectorIndex;
	INT16 sMineSector = 0;


	// remember town id
	ubTownId = GetTownIdForSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY );
	Assert((ubTownId >= FIRST_TOWN) && (ubTownId < NUM_TOWNS));

	usTownSectorIndex = SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY );

	switch( usTownSectorIndex )
	{
		case SEC_B13:
			AddMonoString( &hStringHandle, pLandTypeStrings[ DRASSEN_AIRPORT_SITE ] );
			break;
		case SEC_F8:
			AddMonoString( &hStringHandle, pLandTypeStrings[ CAMBRIA_HOSPITAL_SITE ] );
			break;
		case SEC_J9: //Tixa
			if( !fFoundTixa )
				AddMonoString( &hStringHandle, pLandTypeStrings[ SAND ] );
			else
				AddMonoString( &hStringHandle, pTownNames[ TIXA ] );
			break;
		case SEC_K4: //Orta
			if( !fFoundOrta )
				AddMonoString( &hStringHandle, pLandTypeStrings[ SWAMP ] );
			else
				AddMonoString( &hStringHandle, pTownNames[ ORTA ] );
			break;
		case SEC_N3:
			AddMonoString( &hStringHandle, pLandTypeStrings[ MEDUNA_AIRPORT_SITE ] );
			break;
		default:
			if( usTownSectorIndex == SEC_N4 && fSamSiteFound[ SAM_SITE_FOUR ] )
			{	//Meduna's SAM site
				AddMonoString( &hStringHandle, pLandTypeStrings[ MEDUNA_SAM_SITE ] );
			}
			else
			{ // town name
				swprintf( wString, L"%s", pTownNames[ ubTownId ] );
				AddMonoString( &hStringHandle, wString );
			}
			break;
	}
	// blank line
	AddMonoString( &hStringHandle, L"" );

	// sector
	AddSectorToBox();

	// town size
	swprintf( wString, L"%s:", pwTownInfoStrings[ 0 ] );
	AddMonoString( &hStringHandle, wString );
	swprintf( wString, L"%d",  GetTownSectorSize( ubTownId ) );
	AddSecondColumnMonoString( &hStringHandle, wString );

	// main facilities
	swprintf( wString, L"%s:", pwTownInfoStrings[ 8 ] );
	AddMonoString( &hStringHandle, wString );
	wcscpy(wString, L"");
	GetSectorFacilitiesFlags( bCurrentTownMineSectorX, bCurrentTownMineSectorY, wString );
	AddSecondColumnMonoString( &hStringHandle, wString );

	// the concept of control is only meaningful in sectors where militia can be trained
	if ( MilitiaTrainingAllowedInSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY, 0 ) )
	{
		// town control
		swprintf( wString, L"%s:", pwTownInfoStrings[ 2 ] );
		AddMonoString( &hStringHandle, wString );
		swprintf( wString, L"%d%%%%",  (GetTownSectorsUnderControl( ubTownId ) * 100) / GetTownSectorSize( ubTownId ));
		AddSecondColumnMonoString( &hStringHandle, wString );
	}

	// the concept of town loyalty is only meaningful in towns where loyalty is tracked
	if( gTownLoyalty[ ubTownId ].fStarted && gfTownUsesLoyalty[ ubTownId ])
	{
		// town loyalty
		swprintf( wString, L"%s:", pwTownInfoStrings[ 5 ] );
		AddMonoString( &hStringHandle, wString );
		swprintf( wString, L"%d%%%%", gTownLoyalty[ ubTownId ].ubRating );
		AddSecondColumnMonoString( &hStringHandle, wString );
	}

	// if the town has a mine
	sMineSector = GetMineSectorForTown( ubTownId );
	if( sMineSector != -1 )
	{
		// Associated Mine: Sector
	  swprintf( wString, L"%s:",  pwTownInfoStrings[ 4 ] );
		AddMonoString( &hStringHandle, wString );
	  GetShortSectorString( ( INT16 )( sMineSector % MAP_WORLD_X ), ( INT16 )( sMineSector / MAP_WORLD_X ), wString );
		AddSecondColumnMonoString( &hStringHandle, wString );
	}
}