
//============================================================================
//----------------------------------------------------------------------------
//								   HouseLegal.c
//----------------------------------------------------------------------------
//============================================================================


#include "PLNumberFormatting.h"
#include "PLStringCompare.h"
#include "Externs.h"
#include "ObjectEdit.h"
#include "RectUtils.h"


void WrapBannerAndTrailer (void);
void ValidateNumberOfRooms (void);
void CheckDuplicateFloorSuite (void);
void CompressHouse (void);
void LopOffExtraRooms (void);
void ValidateRoomNumbers (void);
void CountUntitledRooms (void);
void CheckRoomNameLength (void);
void MakeSureNumObjectsJives (void);
void KeepAllObjectsLegal (void);
void CheckForStaircasePairs (void);


short		houseErrors, wasRoom;
Boolean		isHouseChecks;

extern	short		numberRooms;


//==============================================================  Functions
//--------------------------------------------------------------  KeepObjectLegal

// Does a test of the current object active for any illegal boundsÉ
// or values.  It corrects the erros and returns true if any changesÉ
// were made.

Boolean KeepObjectLegal (void)
{
	objectType	*theObject;
	Rect		bounds, roomRect;
	short		direction, dist;
	char		wasState;
	Boolean		unchanged;
	
	unchanged = true;
#ifndef COMPILEDEMO
	
	theObject = &thisRoom->objects[objActive];
	
	if (objActive == kInitialGliderSelected)
	{
		if ((*thisHouse)->initial.h < 0)
			(*thisHouse)->initial.h = 0;
		if ((*thisHouse)->initial.v < 0)
			(*thisHouse)->initial.v = 0;
		if ((*thisHouse)->initial.h > (kRoomWide - kGliderWide))
			(*thisHouse)->initial.h = kRoomWide - kGliderWide;
		if ((*thisHouse)->initial.v > (kTileHigh - kGliderHigh))
			(*thisHouse)->initial.v = kTileHigh - kGliderHigh;
		return (true);
	}
	
	QSetRect(&roomRect, 0, 0, kRoomWide, kTileHigh);
	
	switch (theObject->what)
	{
		case kFloorVent:
		case kCeilingVent:
		case kFloorBlower:
		case kCeilingBlower:
		case kSewerGrate:
		case kLeftFan:
		case kRightFan:
		case kTaper:
		case kCandle:
		case kStubby:
		case kTiki:
		case kBBQ:
		case kInvisBlower:
		case kGrecoVent:
		case kSewerBlower:
		case kLiftArea:
		GetObjectRect(&thisRoom->objects[objActive], &bounds);
		if (ForceRectInRect(&bounds, &roomRect))
		{
			theObject->data.a.topLeft.h = bounds.left;
			theObject->data.a.topLeft.v = bounds.top;
			unchanged = false;
			if (theObject->what == kLiftArea)
			{
				theObject->data.a.distance = RectWide(&bounds);
				theObject->data.a.tall = RectTall(&bounds) / 2;
			}
		}
		if ((theObject->what == kStubby) && (theObject->data.a.topLeft.h % 2 == 0))
		{
			theObject->data.a.topLeft.h--;
			unchanged = false;
		}
		if (((theObject->what == kTaper) || (theObject->what == kCandle) || 
				(theObject->what == kTiki) || (theObject->what == kBBQ)) && 
				(theObject->data.a.topLeft.h % 2 != 0))
		{
			theObject->data.a.topLeft.h--;
			unchanged = false;
		}
		if ((theObject->what == kFloorVent) && (theObject->data.a.topLeft.v != kFloorVentTop))
		{
			theObject->data.a.topLeft.v = kFloorVentTop;
			theObject->data.a.distance += 2;
		}
		if ((theObject->what == kFloorBlower) && 
				(theObject->data.a.topLeft.v != kFloorBlowerTop))
		{
			theObject->data.a.topLeft.v = kFloorBlowerTop;
			theObject->data.a.distance += 2;
		}
		if ((theObject->what == kSewerGrate) && 
				(theObject->data.a.topLeft.v != kSewerGrateTop))
		{
			theObject->data.a.topLeft.v = kSewerGrateTop;
			theObject->data.a.distance += 2;
		}
		if ((theObject->what == kFloorTrans) && 
				(theObject->data.a.topLeft.v != kFloorTransTop))
		{
			theObject->data.a.topLeft.v = kFloorTransTop;
			theObject->data.a.distance += 2;
		}
		if (ObjectHasHandle(&direction, &dist))
		{
			switch (direction)
			{
				case kAbove:
				dist = bounds.top - dist;
				if ((theObject->what == kFloorVent) || 
						(theObject->what == kFloorBlower) ||
						(theObject->what == kTaper) ||
						(theObject->what == kCandle) ||
						(theObject->what == kStubby))
				{
					if (dist < 36)
					{
						theObject->data.a.distance += dist - 36;
						unchanged = false;
					}
				}
				else
				{
					if (dist < 0)
					{
						theObject->data.a.distance += dist;
						unchanged = false;
					}
				}
				break;
				
				case kToRight:
				dist = bounds.right + dist;
				if (dist > kRoomWide)
				{
					theObject->data.a.distance += (kRoomWide - dist);
					unchanged = false;
				}
				break;
				
				case kBelow:
				dist = bounds.bottom + dist;
				if (dist > kTileHigh)
				{
					theObject->data.a.distance += (kTileHigh - dist);
					unchanged = false;
				}
				break;
				
				case kToLeft:
				dist = bounds.left - dist;
				if (dist < 0)
				{
					theObject->data.a.distance += dist;
					unchanged = false;
				}
				break;
			}
		}
		break;
		
		case kTable:
		case kShelf:
		case kCabinet:
		case kFilingCabinet:
		case kWasteBasket:
		case kMilkCrate:
		case kCounter:
		case kDresser:
		case kDeckTable:
		case kStool:
		case kTrunk:
		case kInvisObstacle:
		case kManhole:
		case kBooks:
		case kInvisBounce:
		GetObjectRect(&thisRoom->objects[objActive], &bounds);
		if (ForceRectInRect(&bounds, &roomRect))
		{
			theObject->data.b.bounds = bounds;
			unchanged = false;
		}
		if ((theObject->what == kManhole) && 
				(((bounds.left - 3) % 64) != 0))
		{
			theObject->data.b.bounds.left = 
					(((bounds.left + 29) / 64) * 64) + 3;
			theObject->data.b.bounds.right = 
					theObject->data.b.bounds.left + 
					RectWide(&srcRects[kManhole]);
			unchanged = false;
		}
		break;
		
		case kRedClock:
		case kBlueClock:
		case kYellowClock:
		case kCuckoo:
		case kPaper:
		case kBattery:
		case kBands:
		case kGreaseRt:
		case kGreaseLf:
		case kFoil:
		case kInvisBonus:
		case kStar:
		case kSparkle:
		case kHelium:
		case kSlider:
		GetObjectRect(&thisRoom->objects[objActive], &bounds);
		if (ForceRectInRect(&bounds, &roomRect))
		{
			theObject->data.c.topLeft.h = bounds.left;
			theObject->data.c.topLeft.v = bounds.top;
			unchanged = false;
		}
		if ((theObject->what == kGreaseRt) && 
				(bounds.right + theObject->data.c.length > kRoomWide))
		{
			theObject->data.c.length = kRoomWide - bounds.right;
			unchanged = false;
		}
		else if ((theObject->what == kGreaseLf) && 
				(bounds.left - theObject->data.c.length < 0))
		{
			theObject->data.c.length = bounds.left;
			unchanged = false;
		}
		else if ((theObject->what == kSlider) && 
				(bounds.left + theObject->data.c.length > kRoomWide))
		{
			theObject->data.c.length = kRoomWide - bounds.left;
			unchanged = false;
		}
		if (theObject->data.c.topLeft.h % 2 != 0)
		{
			theObject->data.c.topLeft.h--;
			unchanged = false;
		}
		if ((theObject->what != kStar) && 
				(theObject->data.c.length % 2 != 0))
		{
			theObject->data.c.length--;
			unchanged = false;
		}
		break;
		
		case kUpStairs:
		case kDownStairs:
		case kMailboxLf:
		case kMailboxRt:
		case kFloorTrans:
		case kCeilingTrans:
		case kDoorInLf:
		case kDoorInRt:
		case kDoorExRt:
		case kDoorExLf:
		case kWindowInLf:
		case kWindowInRt:
		case kWindowExRt:
		case kWindowExLf:
		case kInvisTrans:
		case kDeluxeTrans:
		GetObjectRect(&thisRoom->objects[objActive], &bounds);
		if (ForceRectInRect(&bounds, &roomRect))
		{
			theObject->data.d.topLeft.h = bounds.left;
			theObject->data.d.topLeft.v = bounds.top;
			unchanged = false;
			if (theObject->what == kDeluxeTrans)
			{
				theObject->data.d.tall = ((RectWide(&bounds) / 4) << 8) + 
						(RectTall(&bounds) / 4);
			}
		}
		if ((theObject->what == kDoorInLf) || 
				(theObject->what == kDoorInRt))
		{
			if (theObject->data.d.topLeft.h + 
					HalfRectWide(&srcRects[kDoorInLf]) > (kRoomWide / 2))
			{
				theObject->data.d.topLeft.h = kDoorInRtLeft;
				theObject->what = kDoorInRt;
			}
			else
			{
				theObject->data.d.topLeft.h = kDoorInLfLeft;
				theObject->what = kDoorInLf;
			}
		}
		if ((theObject->what == kDoorExRt) || 
				(theObject->what == kDoorExLf))
		{
			if (theObject->data.d.topLeft.h + 
					HalfRectWide(&srcRects[kDoorExRt]) > (kRoomWide / 2))
			{
				theObject->data.d.topLeft.h = kDoorExRtLeft;
				theObject->what = kDoorExRt;
			}
			else
			{
				theObject->data.d.topLeft.h = kDoorExLfLeft;
				theObject->what = kDoorExLf;
			}
		}
		if ((theObject->what == kWindowInLf) || 
				(theObject->what == kWindowInRt))
		{
			if (theObject->data.d.topLeft.h + 
					HalfRectWide(&srcRects[kWindowInLf]) > (kRoomWide / 2))
			{
				theObject->data.d.topLeft.h = kWindowInRtLeft;
				theObject->what = kWindowInRt;
			}
			else
			{
				theObject->data.d.topLeft.h = kWindowInLfLeft;
				theObject->what = kWindowInLf;
			}
		}
		if ((theObject->what == kWindowExRt) || 
				(theObject->what == kWindowExLf))
		{
			if (theObject->data.d.topLeft.h + 
					HalfRectWide(&srcRects[kWindowExRt]) > (kRoomWide / 2))
			{
				theObject->data.d.topLeft.h = kWindowExRtLeft;
				theObject->what = kWindowExRt;
			}
			else
			{
				theObject->data.d.topLeft.h = kWindowExLfLeft;
				theObject->what = kWindowExLf;
			}
		}
		
		if ((theObject->what == kInvisTrans) && 
				((theObject->data.d.topLeft.v + 
				theObject->data.d.tall) > kTileHigh))
		{
			theObject->data.d.tall = kTileHigh - 
				theObject->data.d.topLeft.v;
			unchanged = false;
		}
		if ((theObject->what == kInvisTrans) && 
				(theObject->data.d.wide < 0))
		{
			theObject->data.d.wide = 0;
			unchanged = false;
		}
		break;
		
		case kLightSwitch:
		case kMachineSwitch:
		case kThermostat:
		case kPowerSwitch:
		case kKnifeSwitch:
		case kInvisSwitch:
		case kTrigger:
		case kLgTrigger:
		case kSoundTrigger:
		GetObjectRect(&thisRoom->objects[objActive], &bounds);
		if (ForceRectInRect(&bounds, &roomRect))
		{
			theObject->data.e.topLeft.h = bounds.left;
			theObject->data.e.topLeft.v = bounds.top;
			unchanged = false;
		}
		if (theObject->data.e.topLeft.h % 2 != 0)
		{
			theObject->data.e.topLeft.h--;
			unchanged = false;
		}
		break;
		
		case kCeilingLight:
		case kLightBulb:
		case kTableLamp:
		case kHipLamp:
		case kDecoLamp:
		case kFlourescent:
		case kTrackLight:
		case kInvisLight:
		GetObjectRect(&thisRoom->objects[objActive], &bounds);
		if (ForceRectInRect(&bounds, &roomRect))
		{
			if ((theObject->what == kFlourescent) || (theObject->what == kTrackLight))
			{
				if (theObject->data.f.topLeft.h < bounds.left)
					theObject->data.f.topLeft.h = bounds.left;
				
				if (theObject->data.f.topLeft.v < bounds.top)
					theObject->data.f.topLeft.v = bounds.top;
				
				if ((theObject->data.f.topLeft.h + theObject->data.f.length) > bounds.right)
					theObject->data.f.length = bounds.right - theObject->data.f.topLeft.h;
			}
			else
			{
				theObject->data.f.topLeft.h = bounds.left;
				theObject->data.f.topLeft.v = bounds.top;
			}
			unchanged = false;
		}
		if (((theObject->what == kFlourescent) || 
				(theObject->what == kTrackLight)) && 
				((bounds.right > kRoomWide) || (bounds.left < 0)))
		{
			if (theObject->data.f.topLeft.h < 0)
			{
				theObject->data.f.topLeft.h = 0;
				unchanged = false;
			}
			if (bounds.left < 0)
			{
				bounds.left = 0;
				unchanged = false;
			}
			if (theObject->data.f.topLeft.h > kRoomWide)
			{
				theObject->data.f.topLeft.h = kRoomWide;
				unchanged = false;
			}
			if (bounds.right > kRoomWide)
			{
				bounds.right = kRoomWide;
				unchanged = false;
			}
			theObject->data.f.length = kRoomWide - bounds.left;
		}
		break;
		
		case kShredder:
		case kToaster:
		case kMacPlus:
		case kGuitar:
		case kTV:
		case kCoffee:
		case kOutlet:
		case kVCR:
		case kStereo:
		case kMicrowave:
		case kCinderBlock:
		case kFlowerBox:
		case kCDs:
		case kCustomPict:
		GetObjectRect(&thisRoom->objects[objActive], &bounds);
		if (ForceRectInRect(&bounds, &roomRect))
		{
			theObject->data.g.topLeft.h = bounds.left;
			theObject->data.g.topLeft.v = bounds.top;
			unchanged = false;
		}
		if ((theObject->what == kToaster) && 
				(bounds.top - theObject->data.g.height < 0))
		{
			theObject->data.g.height = bounds.top;
			unchanged = false;
		}
		if ((theObject->what == kTV) && 
				(theObject->data.g.topLeft.h % 2 == 0))
		{
			theObject->data.g.topLeft.h--;
			unchanged = false;
		}
		if (((theObject->what == kToaster) || 
				(theObject->what == kMacPlus) || 
				(theObject->what == kCoffee) || 
				(theObject->what == kOutlet) || 
				(theObject->what == kVCR) || 
				(theObject->what == kStereo) || 
				(theObject->what == kMicrowave)) && 
				(theObject->data.g.topLeft.h % 2 != 0))
		{
			theObject->data.g.topLeft.h--;
			unchanged = false;
		}
		break;
		
		case kBalloon:
		case kCopterLf:
		case kCopterRt:
		case kDartLf:
		case kDartRt:
		case kBall:
		case kDrip:
		case kFish:
		case kCobweb:
		GetObjectRect(&thisRoom->objects[objActive], &bounds);
		if (ForceRectInRect(&bounds, &roomRect))
		{
			theObject->data.h.topLeft.h = bounds.left;
			theObject->data.h.topLeft.v = bounds.top;
			unchanged = false;
		}
		if (((theObject->what == kBall) || 
				(theObject->what == kFish)) &&
				(bounds.top - theObject->data.h.length < 0))
		{
			theObject->data.h.length = bounds.top;
			unchanged = false;
		}
		if ((theObject->what == kDrip) && 
				(bounds.bottom + theObject->data.h.length > kTileHigh))
		{
			theObject->data.h.length = kTileHigh - bounds.bottom;
			unchanged = false;
		}
		if (((theObject->what == kBalloon) || 
				(theObject->what == kCopterLf) || 
				(theObject->what == kCopterRt) || 
				(theObject->what == kBall) || 
				(theObject->what == kDrip) || 
				(theObject->what == kFish)) && 
				(theObject->data.h.topLeft.h % 2 != 0))
		{
			theObject->data.h.topLeft.h--;
			unchanged = false;
		}
		break;
		
		case kOzma:
		case kMirror:
		case kMousehole:
		case kFireplace:
		case kFlower:
		case kWallWindow:
		case kBear:
		case kCalendar:
		case kVase1:
		case kVase2:
		case kBulletin:
		case kCloud:
		case kFaucet:
		case kRug:
		case kChimes:
		GetObjectRect(&thisRoom->objects[objActive], &bounds);
		if (ForceRectInRect(&bounds, &roomRect))
		{
			theObject->data.i.bounds = bounds;
			unchanged = false;
		}
		if (theObject->what == kMirror)
		{
			if (theObject->data.i.bounds.left % 2 != 0)
			{
				theObject->data.i.bounds.left--;
				unchanged = false;
			}
			if (theObject->data.i.bounds.right % 2 != 0)
			{
				theObject->data.i.bounds.right--;
				unchanged = false;
			}
		}
		break;
		
	}
	
#endif
	
	return (unchanged);
}

//--------------------------------------------------------------  WrapBannerAndTrailer

// Tries to wrap around the text of the banner and trailer messages.

#ifndef COMPILEDEMO
void WrapBannerAndTrailer (void)
{
	char		wasState;
	
	WrapText((*thisHouse)->banner, 40);
	WrapText((*thisHouse)->trailer, 64);
}

//--------------------------------------------------------------  ValidateNumberOfRooms

// Makes sure the number of room count and actual number of rooms match.

void ValidateNumberOfRooms (void)
{
	long		countedRooms, reportsRooms;
	char		wasState;
	
	reportsRooms = (long)(*thisHouse)->nRooms;
	countedRooms = (GetHandleSize(thisHouse.StaticCast<void>()) - 
			sizeof(houseType)) / sizeof(roomType);
	if (reportsRooms != countedRooms)
	{
		(*thisHouse)->nRooms = (short)countedRooms;
		numberRooms = (*thisHouse)->nRooms;
		houseErrors++;
	}
}

//--------------------------------------------------------------  CheckDuplicateFloorSuite

// Error check, looks for rooms with the same floor suite (stacked).

void CheckDuplicateFloorSuite (void)
{
	#define		kRoomsTimesSuites	8192
	short		i, numRooms, bitPlace;
	char		*pidgeonHoles;
	char		wasState;
	
	pidgeonHoles = (char *)NewPtrClear(sizeof(char) * kRoomsTimesSuites);
	if (pidgeonHoles == nil)
		return;
	
	numRooms = (*thisHouse)->nRooms;
	for (i = 0; i < numRooms; i++)
	{
		if ((*thisHouse)->rooms[i].suite != kRoomIsEmpty)
		{
			bitPlace = (((*thisHouse)->rooms[i].floor + 7) * 128) + 
					(*thisHouse)->rooms[i].suite;
			//if ((bitPlace < 0) || (bitPlace >= 8192))
			//	DebugStr(PSTR("Blew array"));
			if (pidgeonHoles[bitPlace] != 0)
			{
				houseErrors++;
				(*thisHouse)->rooms[i].suite = kRoomIsEmpty;
			}
			else
				pidgeonHoles[bitPlace]++;
		}
	}
	
	DisposePtr((Ptr)pidgeonHoles);
}

//--------------------------------------------------------------  CompressHouse

// Removes place-holder (deleted) rooms from the middle of the file.

void CompressHouse (void)
{
	short		wasFirstRoom, roomNumber, probe;
	char		wasState;
	Boolean		compressing, probing;
	
	wasFirstRoom = (*thisHouse)->firstRoom;
	compressing = true;
	roomNumber = (*thisHouse)->nRooms - 1;	// start with last room
	do
	{
		if ((*thisHouse)->rooms[roomNumber].suite != kRoomIsEmpty)
		{									// if not an empty roomÉ
			probe = 0;						// start looking for empty slot
			probing = true;
			do
			{								// test room at probe to see if empty
				if ((*thisHouse)->rooms[probe].suite == kRoomIsEmpty)
				{							// if it is, copy room there
					(*thisHouse)->rooms[probe] = (*thisHouse)->rooms[roomNumber];
					(*thisHouse)->rooms[roomNumber].suite = kRoomIsEmpty;
					if (roomNumber == wasFirstRoom)
						(*thisHouse)->firstRoom = probe;
					if (roomNumber == wasRoom)
						wasRoom = probe;
					probing = false;
				}
				probe++;					// bump probe up to next room
				if ((probing) && (probe >= roomNumber))
				{							// we reached the current room
					probing = false;		// we can look no further
					compressing = false;	// so we can compress no more
				}
			}
			while (probing);
		}
		roomNumber--;						// go on to room preceding
		if (roomNumber <= 0)				// stop if we reach the first room
			compressing = false;
	}
	while (compressing);
}

//--------------------------------------------------------------  LopOffExtraRooms

// Deletes all empty rooms hanging off the end of the house file.

void LopOffExtraRooms (void)
{
	long		newSize;
	short		r, count;
	char		wasState;
	Str255		message;
	
	count = 0;
	r = (*thisHouse)->nRooms;		// begin at last room
	do
	{
		r--;						// look for trailing empties
		if ((*thisHouse)->rooms[r].suite == kRoomIsEmpty)
			count++;
		else
			r = 0;
	}
	while (r > 0);
	
	if (count > 0)					// if there were trailing emptiesÉ
	{
		r = (*thisHouse)->nRooms - count;
		newSize = sizeof(houseType) + (sizeof(roomType) * (long)r);
		if (SetHandleSize(thisHouse.StaticCast<void>(), newSize) != PLErrors::kNone)	// resize house handle (shrink)
		{
			ForeColor(redColor);
			GetLocalizedString(16, message);
			SetMessageWindowMessage(message);
		}
		(*thisHouse)->nRooms -= count;
		numberRooms = (*thisHouse)->nRooms;
	}
}

//--------------------------------------------------------------  ValidateRoomNumbers

// Error check - ensures that the floor and suite numbers are within legal ranges.

void ValidateRoomNumbers (void)
{
	short		i, numRooms;
	char		wasState;
	Str255		message;
	
	numRooms = (*thisHouse)->nRooms;
	if (numRooms < 0)
	{
		(*thisHouse)->nRooms = 0;
		numRooms = 0;
	}
	for (i = 0; i < numRooms; i++)
	{
		if ((*thisHouse)->rooms[i].suite != kRoomIsEmpty)
		{
			if (((*thisHouse)->rooms[i].floor > 56) || 
					((*thisHouse)->rooms[i].floor < -7))
			{
				(*thisHouse)->rooms[i].suite = kRoomIsEmpty;
				ForeColor(redColor);
				GetLocalizedString(17, message);
				SetMessageWindowMessage(message);
				houseErrors++;
				ForeColor(blackColor);
			}
			if (((*thisHouse)->rooms[i].suite >= 128) || 
					((*thisHouse)->rooms[i].suite < 0))
			{
				(*thisHouse)->rooms[i].suite = kRoomIsEmpty;
				ForeColor(redColor);
				GetLocalizedString(18, message);
				SetMessageWindowMessage(message);
				houseErrors++;
				ForeColor(blackColor);
			}
		}
	}
}

//--------------------------------------------------------------  CountUntitledRooms

// Returns the number of rooms left "Untitled".

void CountUntitledRooms (void)
{
	short		i, numRooms;
	char		wasState;
	
	numRooms = (*thisHouse)->nRooms;
	for (i = 0; i < numRooms; i++)
	{
		if (((*thisHouse)->rooms[i].suite != kRoomIsEmpty) && 
				(StrCmp::EqualCaseInsensitive((*thisHouse)->rooms[i].name, PSTR("Untitled Room"))))
			houseErrors++;
	}
}

//--------------------------------------------------------------  CheckRoomNameLength

// Error check - ensures the length of the room name is legal.

void CheckRoomNameLength (void)
{
	short		i, numRooms;
	char		wasState;
	
	numRooms = (*thisHouse)->nRooms;
	for (i = 0; i < numRooms; i++)
	{
		(*thisHouse)->rooms[i].unusedByte = 0;
		
		if (((*thisHouse)->rooms[i].suite != kRoomIsEmpty) && 
				((*thisHouse)->rooms[i].name[0] > 27))
		{
			(*thisHouse)->rooms[i].name[0] = 27;
			houseErrors++;
		}
	}
}

//--------------------------------------------------------------  MakeSureNumObjectsJives

// Error check - ensures the actual count of objects equals number of objects.

void MakeSureNumObjectsJives (void)
{
	short		i, h, numRooms, count;
	char		wasState;
	
	numRooms = (*thisHouse)->nRooms;
	for (i = 0; i < numRooms; i++)
	{
		if ((*thisHouse)->rooms[i].suite != kRoomIsEmpty)
		{
			count = 0;
			for (h = 0; h < kMaxRoomObs; h++)
			{
				if ((*thisHouse)->rooms[i].objects[h].what != kObjectIsEmpty)
					count++;
			}
			if (count != (*thisHouse)->rooms[i].numObjects)
			{
				houseErrors++;
				(*thisHouse)->rooms[i].numObjects = count;
			}
		}
	}
}

//--------------------------------------------------------------  KeepAllObjectsLegal

// Repeatedly calls KeepObjectLegal() on ALL objects in a house.  Wow!

void KeepAllObjectsLegal (void)
{
	short		i, h, numRooms;
	char		wasState;
	Str255		message;
	
	numRooms = (*thisHouse)->nRooms;
	for (i = 0; i < numRooms; i++)
	{
		if ((*thisHouse)->rooms[i].suite != kRoomIsEmpty)
		{
			ForceThisRoom(i);
			for (h = 0; h < kMaxRoomObs; h++)
			{
				objActive = h;
				if (thisRoom->objects[objActive].what != kObjectIsEmpty)
				{
					if (!KeepObjectLegal())
					{
						ForeColor(redColor);
						GetLocalizedString(19, message);
						SetMessageWindowMessage(message);
						houseErrors++;
						ForeColor(blackColor);
						DelayTicks(60);
					}
				}
			}
			CopyThisRoomToRoom();
		}
	}
}

//--------------------------------------------------------------  CheckForStaircasePairs

// Ensures that for every up-stair there is a down-stair.

void CheckForStaircasePairs (void)
{
	short		i, h, g, numRooms, neighbor;
	char		wasState;
	Boolean		hasStairs;
	Str255		message;
	
	numRooms = (*thisHouse)->nRooms;
	for (i = 0; i < numRooms; i++)
	{
		if ((*thisHouse)->rooms[i].suite != kRoomIsEmpty)
		{
			for (h = 0; h < kMaxRoomObs; h++)
			{
				if ((*thisHouse)->rooms[i].objects[h].what == kUpStairs)
				{
					thisRoomNumber = i;
					neighbor = GetNeighborRoomNumber(kNorthRoom);
					if (neighbor == kRoomIsEmpty)
					{
						ForeColor(redColor);
						GetLocalizedString(20, message);
						SetMessageWindowMessage(message);
						ForeColor(blackColor);
						DelayTicks(60);
					}
					else
					{
						hasStairs = false;
						for (g = 0; g < kMaxRoomObs; g++)
						{
							if ((*thisHouse)->rooms[neighbor].objects[g].what == 
									kDownStairs)
								hasStairs = true;
						}
						if (!hasStairs)
						{
							ForeColor(redColor);
							GetLocalizedString(21, message);
							SetMessageWindowMessage(message);
							ForeColor(blackColor);
							DelayTicks(60);
						}
					}
				}
				else if ((*thisHouse)->rooms[i].objects[h].what == kDownStairs)
				{
					thisRoomNumber = i;
					neighbor = GetNeighborRoomNumber(kSouthRoom);
					if (neighbor == kRoomIsEmpty)
					{
						ForeColor(redColor);
						GetLocalizedString(22, message);
						SetMessageWindowMessage(message);
						ForeColor(blackColor);
						DelayTicks(60);
					}
					else
					{
						hasStairs = false;
						for (g = 0; g < kMaxRoomObs; g++)
						{
							if ((*thisHouse)->rooms[neighbor].objects[g].what == 
									kUpStairs)
								hasStairs = true;
						}
						if (!hasStairs)
						{
							ForeColor(redColor);
							GetLocalizedString(23, message);
							SetMessageWindowMessage(message);
							ForeColor(blackColor);
							DelayTicks(60);
						}
					}
				}
			}
		}
	}
}
#endif

//--------------------------------------------------------------  CheckHouseForProblems

// Calls all the above functions and reports (and corrects) errors.

void CheckHouseForProblems (void)
{
#ifndef COMPILEDEMO
	Str255		message, message2;
	short		wasActive;
	
	houseErrors = 0;
	CopyThisRoomToRoom();
	wasRoom = thisRoomNumber;
	wasActive = objActive;
	GetLocalizedString(24, message);
	OpenMessageWindow(message);
	
	SpinCursor(3);
	GetLocalizedString(25, message);
	SetMessageWindowMessage(message);
	WrapBannerAndTrailer();
	
	if (isHouseChecks)
	{
		SpinCursor(3);
		GetLocalizedString(26, message);
		SetMessageWindowMessage(message);
		ValidateNumberOfRooms();
		if (houseErrors != 0)
		{
			GetLocalizedString(27, message);
			SetMessageWindowMessage(message);
			DelayTicks(60);
			houseErrors = 0;
		}
	}
	
	if (isHouseChecks)
	{
		SpinCursor(3);
		houseErrors = 0;
		CheckDuplicateFloorSuite();
		if (houseErrors != 0)
		{
			NumToString((long)houseErrors, message);
			GetLocalizedString(28, message2);
			PasStringConcat(message, message2);
			ForeColor(redColor);
			SetMessageWindowMessage(message);
			ForeColor(blackColor);
			DelayTicks(45);
		}
	}
	
	SpinCursor(3);
	CompressHouse();
	SpinCursor(3);
	LopOffExtraRooms();
	
	if (isHouseChecks)
	{
		SpinCursor(3);
		ValidateRoomNumbers();
		if (houseErrors != 0)
		{
			NumToString((long)houseErrors, message);
			GetLocalizedString(29, message2);
			PasStringConcat(message, message2);
			ForeColor(redColor);
			SetMessageWindowMessage(message);
			ForeColor(blackColor);
			DelayTicks(60);
		}
	}
	
	if (isHouseChecks)
	{
		SpinCursor(3);
		houseErrors = 0;
		CountUntitledRooms();
		if (houseErrors != 0)
		{
			NumToString((long)houseErrors, message);
			GetLocalizedString(30, message2);
			PasStringConcat(message, message2);
			ForeColor(blueColor);
			SetMessageWindowMessage(message);
			ForeColor(blackColor);
			DelayTicks(45);
		}
	}
	
	if (isHouseChecks)
	{
		SpinCursor(3);
		houseErrors = 0;
		CheckRoomNameLength();
		if (houseErrors != 0)
		{
			NumToString((long)houseErrors, message);
			GetLocalizedString(31, message2);
			PasStringConcat(message, message2);
			ForeColor(blueColor);
			SetMessageWindowMessage(message);
			ForeColor(blackColor);
			DelayTicks(45);
		}
	}
	
	if (isHouseChecks)
	{
		SpinCursor(3);
		houseErrors = 0;
		MakeSureNumObjectsJives();
		if (houseErrors != 0)
		{
			NumToString((long)houseErrors, message);
			GetLocalizedString(32, message2);
			PasStringConcat(message, message2);
			ForeColor(redColor);
			SetMessageWindowMessage(message);
			ForeColor(blackColor);
			DelayTicks(60);
		}
	}
	
	if (isHouseChecks)
	{
		SpinCursor(3);
		houseErrors = 0;
		GetLocalizedString(33, message);
		SetMessageWindowMessage(message);
		KeepAllObjectsLegal();
		if (houseErrors != 0)
		{
			NumToString((long)houseErrors, message);
			GetLocalizedString(34, message2);
			PasStringConcat(message, message2);
			ForeColor(redColor);
			SetMessageWindowMessage(message);
			ForeColor(blackColor);
			DelayTicks(60);
		}
	}
	
	if (isHouseChecks)
	{
		SpinCursor(3);
		houseErrors = 0;
		CheckForStaircasePairs();
	}
	
	if (isHouseChecks)
	{
		SpinCursor(3);
		if (CountStarsInHouse() < 1)
		{
			ForeColor(redColor);
			GetLocalizedString(35, message);
			SetMessageWindowMessage(message);
			ForeColor(blackColor);
			DelayTicks(60);
		}
	}
	
	InitCursor();
	CloseMessageWindow();
	ForceThisRoom(wasRoom);
	objActive = wasActive;
#endif
}

