//============================================================================
//----------------------------------------------------------------------------
//									Room.c
//----------------------------------------------------------------------------
//============================================================================

#include "PLKeyEncoding.h"
#include "PLResources.h"
#include "PLToolUtils.h"
#include "PLPasStr.h"
#include "PLStandardColors.h"
#include "BitmapImage.h"
#include "DialogManager.h"
#include "Externs.h"
#include "FontFamily.h"
#include "House.h"
#include "InputManager.h"
#include "MainWindow.h"
#include "MemoryManager.h"
#include "RectUtils.h"
#include "ResolveCachingColor.h"


#define kDeleteRoomAlert		1005
#define kYesDoDeleteRoom		1


Boolean QueryDeleteRoom (void);
void SetToNearestNeighborRoom (short, short);


roomPtr		thisRoom;
Rect		backSrcRect;
DrawSurface	*backSrcMap;
short		numberRooms, thisRoomNumber, previousRoom;
short		leftThresh, rightThresh, lastBackground;
Boolean		autoRoomEdit, newRoomNow, noRoomAtAll;
Boolean		leftOpen, rightOpen, topOpen, bottomOpen;
Boolean		doBitchDialogs;

extern	short		tempTiles[];


//==============================================================  Functions
//--------------------------------------------------------------  SetInitialTiles

#ifndef COMPILEDEMO
void SetInitialTiles (short background, Boolean doRoom)
{
	short		i;
	
	if (background >= kUserBackground)
	{
		for (i = 0; i < kNumTiles; i++)
		{
			if (doRoom)
				thisRoom->tiles[i] = i;
			else
				tempTiles[i] = i;
		}
	}
	else
	{
		switch (background)
		{
			case kSimpleRoom:
			case kPaneledRoom:
			case kBasement:
			case kChildsRoom:
			case kAsianRoom:
			case kUnfinishedRoom:
			case kSwingersRoom:
			case kBathroom:
			case kLibrary:
			for (i = 0; i < kNumTiles; i++)
			{
				if (doRoom)
					thisRoom->tiles[i] = 1;
				else
					tempTiles[i] = 1;
			}
			if (doRoom)
			{
				thisRoom->tiles[0] = 0;
				thisRoom->tiles[kNumTiles - 1] = kNumTiles - 1;
			}
			else
			{
				tempTiles[0] = 0;
				tempTiles[kNumTiles - 1] = kNumTiles - 1;
			}
			break;
			
			case kSkywalk:
			for (i = 0; i < kNumTiles; i++)
			{
				if (doRoom)
					thisRoom->tiles[i] = i;
				else
					tempTiles[i] = i;
			}
			break;
			
			case kField:
			case kGarden:
			case kDirt:
			for (i = 0; i < kNumTiles; i++)
			{
				if (doRoom)
					thisRoom->tiles[i] = 0;
				else
					tempTiles[i] = 0;
			}
			break;
			
			case kMeadow:
			for (i = 0; i < kNumTiles; i++)
			{
				if (doRoom)
					thisRoom->tiles[i] = 1;
				else
					tempTiles[i] = 1;
			}
			break;
			
			case kRoof:
			for (i = 0; i < kNumTiles; i++)
			{
				if (doRoom)
					thisRoom->tiles[i] = 3;
				else
					tempTiles[i] = 3;
			}
			break;
			
			case kSky:
			for (i = 0; i < kNumTiles; i++)
			{
				if (doRoom)
					thisRoom->tiles[i] = 2;
				else
					tempTiles[i] = 2;
			}
			break;
			
			case kStratosphere:
			case kStars:
			for (i = 0; i < kNumTiles; i++)
			{
				if (doRoom)
					thisRoom->tiles[i] = i;
				else
					tempTiles[i] = i;
			}
			break;
			
			default:
			break;
		}
	}
}
#endif

//--------------------------------------------------------------  CreateNewRoom

#ifndef COMPILEDEMO
Boolean CreateNewRoom (short h, short v)
{
	long		howMuch;
	PLError_t		theErr;
	short		i, availableRoom;
	char		wasState;
	
	CopyThisRoomToRoom();					// save off current room
	
	PasStringCopy(PSTR("Untitled Room"), thisRoom->name);
	thisRoom->leftStart = 32;				// fill out fields of new room
	thisRoom->rightStart = 32;
	thisRoom->bounds = 0;
	thisRoom->unusedByte = 0;
	thisRoom->visited = false;
	thisRoom->background = lastBackground;
	SetInitialTiles(thisRoom->background, true);
	thisRoom->floor = v;
	thisRoom->suite = h;
	thisRoom->openings = 0;
	thisRoom->numObjects = 0;
	for (i = 0; i < kMaxRoomObs; i++)		// zero out all objects
		thisRoom->objects[i].what = kObjectIsEmpty;
	
	availableRoom = -1;						// assume no available rooms
	if ((*thisHouse)->nRooms > 0)			// look for an empty room
		for (i = 0; i < (*thisHouse)->nRooms; i++)
			if ((*thisHouse)->rooms[i].suite == kRoomIsEmpty)
			{
				availableRoom = i;
				break;
			}
	
	if (availableRoom == -1)				// found no available rooms
	{
		// add new room to end of house
		if (!PortabilityLayer::MemoryManager::GetInstance()->ResizeHandle(thisHouse.MMBlock(), thisHouse.MMBlock()->m_size + sizeof(roomType)))
		{
			YellowAlert(kYellowUnaccounted, PLErrors::kOutOfMemory);
			return (false);
		}
		(*thisHouse)->rooms[(*thisHouse)->nRooms] = *thisRoom;
		(*thisHouse)->nRooms++;				// increment nRooms
		numberRooms = (*thisHouse)->nRooms;
		previousRoom = thisRoomNumber;
		thisRoomNumber = numberRooms - 1;
	}
	else
	{
		previousRoom = thisRoomNumber;
		thisRoomNumber = availableRoom;
	}
	
	if (noRoomAtAll)
		(*thisHouse)->firstRoom = thisRoomNumber;
	
	CopyThisRoomToRoom();
	UpdateEditWindowTitle();
	noRoomAtAll = false;
	fileDirty = true;
	UpdateMenus(false);

	const KeyDownStates *theKeys = PortabilityLayer::InputManager::GetInstance()->GetKeys();

	if (theKeys->IsSet(PL_KEY_EITHER_SPECIAL(kShift)))
		newRoomNow = false;
	else
		newRoomNow = autoRoomEdit;			// Flag to bring up RoomInfo
	
	return (true);
}
#endif

//--------------------------------------------------------------  ReadyBackground

void ReadyBackground (short theID, short *theTiles)
{
	Rect					src, dest;
	THandle<BitmapImage>	thePicture;
	short					i;
	
	if ((noRoomAtAll) || (!houseUnlocked))
	{
		PortabilityLayer::ResolveCachingColor ltGrayColor = LtGrayForeColor();
		PortabilityLayer::ResolveCachingColor blackColor = StdColors::Black();

		workSrcMap->FillRect(workSrcRect, ltGrayColor);

		PortabilityLayer::RenderedFont *appFont = GetApplicationFont(9, PortabilityLayer::FontFamilyFlag_None, true);

		const Point textPoint = Point::Create(10, 20);
		if (houseUnlocked)
			workSrcMap->DrawString(textPoint, PSTR("No rooms"), blackColor, appFont);
		else
			workSrcMap->DrawString(textPoint, PSTR("Nothing to show"), blackColor, appFont);
		
		CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap), 
				(BitMap *)*GetGWorldPixMap(backSrcMap), 
				&workSrcRect, &workSrcRect, srcCopy);
		return;
	}
	
	thePicture = LoadHouseResource('PICT', theID).StaticCast<BitmapImage>();
	if (thePicture == nil)
	{
		thePicture = LoadHouseResource('Date', theID).StaticCast<BitmapImage>();
		if (thePicture == nil)
		{
			YellowAlert(kYellowNoBackground, 0);
			return;
		}
	}
	
	dest = (*thePicture)->GetRect();
	QOffsetRect(&dest, -dest.left, -dest.top);
	workSrcMap->DrawPicture(thePicture, dest);
	thePicture.Dispose();
	
	QSetRect(&src, 0, 0, kTileWide, kTileHigh);
	QSetRect(&dest, 0, 0, kTileWide, kTileHigh);
	for (i = 0; i < kNumTiles; i++)
	{
		src.left = theTiles[i] * kTileWide;
		src.right = src.left + kTileWide;
		CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap), 
				(BitMap *)*GetGWorldPixMap(backSrcMap), 
				&src, &dest, srcCopy);
		QOffsetRect(&dest, kTileWide, 0);
	}
	
	QSetRect(&src, 0, 0, kRoomWide, kTileHigh);
	QSetRect(&dest, 0, 0, kRoomWide, kTileHigh);
	CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap), 
			(BitMap *)*GetGWorldPixMap(workSrcMap), 
			&src, &dest, srcCopy);
}

//--------------------------------------------------------------  ReflectCurrentRoom

void ReflectCurrentRoom (Boolean forceMapRedraw)
{
#ifndef COMPILEDEMO
	if (theMode != kEditMode)
		return;
	
	if ((noRoomAtAll) || (!houseUnlocked))
	{
		CenterMapOnRoom(64, 1);
		UpdateMapWindow();
	}
	else
	{
		if ((!ThisRoomVisibleOnMap()) || (forceMapRedraw))
		{
			CenterMapOnRoom(thisRoom->suite, thisRoom->floor);
			UpdateMapWindow();			// whole map window redrawm
		}
		else
		{
			FindNewActiveRoomRect();	// find newly selected room rect
			FlagMapRoomsForUpdate();	// redraw only the portions required
		}
	}
	GenerateRetroLinks();
	UpdateEditWindowTitle();
	ReadyBackground(thisRoom->background, thisRoom->tiles);
	GetThisRoomsObjRects();
	DrawThisRoomsObjects();

	UpdateMainWindow();
#endif
}

//--------------------------------------------------------------  CopyRoomToThisRoom

void CopyRoomToThisRoom (short roomNumber)
{
	if (roomNumber == -1)
		return;
	
	CopyThisRoomToRoom();			// copy back to house
	ForceThisRoom(roomNumber);		// load new room from house
}

//--------------------------------------------------------------  CopyThisRoomToRoom

void CopyThisRoomToRoom (void)
{
	char		tagByte;
	
	if ((noRoomAtAll) || (thisRoomNumber == -1))
		return;
	
	(*thisHouse)->rooms[thisRoomNumber] = *thisRoom;	// copy back to house
}

//--------------------------------------------------------------  ForceThisRoom

void ForceThisRoom (short roomNumber)
{
	char		tagByte;
	
	if (roomNumber == -1)
		return;
	
	if (roomNumber < (*thisHouse)->nRooms)
		*thisRoom = (*thisHouse)->rooms[roomNumber];
	else
		YellowAlert(kYellowIllegalRoomNum, 0);
	
	previousRoom = thisRoomNumber;
	thisRoomNumber = roomNumber;
}

//--------------------------------------------------------------  RoomExists

Boolean RoomExists (short suite, short floor, short *roomNum)
{
	// pass in a suite and floor; returns true is it is a legitimate room
	houseType	*thisHousePtr;
	short		i;
	char		wasState;
	Boolean		foundIt;
	
	foundIt = false;
	
	if (suite < 0)
		return (foundIt);
	
	thisHousePtr = *thisHouse;
	
	for (i = 0; i < numberRooms; i++)
	{
		if ((thisHousePtr->rooms[i].floor == floor) && 
				(thisHousePtr->rooms[i].suite == suite))
		{
			foundIt = true;
			*roomNum = i;
			break;
		}
	}
	
	return (foundIt);
}

//--------------------------------------------------------------  RoomNumExists

Boolean RoomNumExists (short roomNum)
{
	short		floor, suite, whoCares;
	Boolean		exists;
	
	exists = false;
	if (GetRoomFloorSuite(roomNum, &floor, &suite))
		exists = RoomExists(suite, floor, &whoCares);
	
	return (exists);
}

//--------------------------------------------------------------  DeleteRoom

void DeleteRoom (Boolean doWarn)
{
#ifndef COMPILEDEMO
	short		wasFloor, wasSuite;
	char		wasState;
	Boolean		firstDeleted;
	
	if ((theMode != kEditMode) || (noRoomAtAll))
		return;
	
	if (doWarn)
	{
		if (!QueryDeleteRoom())
			return;
	}
	
	DeselectObject();
	
	wasFloor = (*thisHouse)->rooms[thisRoomNumber].floor;
	wasSuite = (*thisHouse)->rooms[thisRoomNumber].suite;
	firstDeleted = ((*thisHouse)->firstRoom == thisRoomNumber);	// is room "first"
	thisRoom->suite = kRoomIsEmpty;
	(*thisHouse)->rooms[thisRoomNumber].suite = kRoomIsEmpty;
	
	noRoomAtAll = (RealRoomNumberCount() == 0);					// see if now no rooms
	if (noRoomAtAll)
		thisRoomNumber = kRoomIsEmpty;
	else
		SetToNearestNeighborRoom(wasFloor, wasSuite);
	
	if (firstDeleted)
	{
		(*thisHouse)->firstRoom = thisRoomNumber;
	}
	
	newRoomNow = false;
	fileDirty = true;
	UpdateMenus(false);
	ReflectCurrentRoom(false);
#endif
}

//--------------------------------------------------------------  QueryDeleteRoom

#ifndef COMPILEDEMO
Boolean QueryDeleteRoom (void)
{
	short		hitWhat;
	
//	CenterAlert(kDeleteRoomAlert);
	hitWhat = PortabilityLayer::DialogManager::GetInstance()->DisplayAlert(kDeleteRoomAlert, nullptr);
	if (hitWhat == kYesDoDeleteRoom)
		return (true);
	else
		return (false);
}
#endif

//--------------------------------------------------------------  DoesNeighborRoomExist

short DoesNeighborRoomExist (short whichNeighbor)
{
#ifndef COMPILEDEMO
	short		newH, newV, newRoomNumber;
	
	if (theMode != kEditMode)
		return(-1);
	
	newH = thisRoom->suite;
	newV = thisRoom->floor;
	
	switch (whichNeighbor)
	{
		case kRoomAbove:
		newV++;
		break;
		
		case kRoomBelow:
		newV--;
		break;
		
		case kRoomToRight:
		newH++;
		break;
		
		case kRoomToLeft:
		newH--;
		break;
	}
	
	if (RoomExists(newH, newV, &newRoomNumber))
		return (newRoomNumber);
	else
		return (-1);
#endif
}

//--------------------------------------------------------------  SelectNeighborRoom

void SelectNeighborRoom (short whichNeighbor)
{
#ifndef COMPILEDEMO
	short		newRoomNumber;
	
	newRoomNumber = DoesNeighborRoomExist(whichNeighbor);
	
	if (newRoomNumber != -1)
	{
		DeselectObject();
		CopyRoomToThisRoom(newRoomNumber);
		ReflectCurrentRoom(false);
	}
#endif
}

//--------------------------------------------------------------  GetNeighborRoomNumber

short GetNeighborRoomNumber (short which)
{
	short		hDelta, vDelta, i;
	short		roomH, roomV;
	short		roomNum;
	char		wasState;
	
	switch (which)
	{
		case kCentralRoom:
		hDelta = 0;
		vDelta = 0;
		break;
		
		case kNorthRoom:
		hDelta = 0;
		vDelta = 1;
		break;
		
		case kNorthEastRoom:
		hDelta = 1;
		vDelta = 1;
		break;
		
		case kEastRoom:
		hDelta = 1;
		vDelta = 0;
		break;
		
		case kSouthEastRoom:
		hDelta = 1;
		vDelta = -1;
		break;
		
		case kSouthRoom:
		hDelta = 0;
		vDelta = -1;
		break;
		
		case kSouthWestRoom:
		hDelta = -1;
		vDelta = -1;
		break;
		
		case kWestRoom:
		hDelta = -1;
		vDelta = 0;
		break;
		
		case kNorthWestRoom:
		hDelta = -1;
		vDelta = 1;
		break;
	}
	
	roomNum = kRoomIsEmpty;
	roomH = (*thisHouse)->rooms[thisRoomNumber].suite + hDelta;
	roomV = (*thisHouse)->rooms[thisRoomNumber].floor + vDelta;
	
	for (i = 0; i < numberRooms; i++)
	{
		if (((*thisHouse)->rooms[i].suite == roomH) && 
				((*thisHouse)->rooms[i].floor == roomV))
		{
			roomNum = i;
			break;
		}
	}
	
	return (roomNum);
}

//--------------------------------------------------------------  SetToNearestNeighborRoom

void SetToNearestNeighborRoom (short wasFloor, short wasSuite)
{
	// searches in a clockwise spiral pattern (from thisRoom) for aÉ
	// legitimate neighboring room - then sets thisRoom to it
	short		distance, h, v;
	short		hStep, vStep;
	short		testRoomNum, testH, testV;
	char		wasState;
	Boolean		finished;
	
	finished = false;
	distance = 1;	// we begin our walk a distance of one from source room
	h = -1;			// we begin with the neighbor to the leftÉ
	v = 0;			// and on the same floor
	hStep = 0;		// we don't 'walk' left or rightÉ
	vStep = -1;		// instead, we 'walk' up
	
	do
	{
		testH = wasSuite + h;
		testV = wasFloor + v;
		
		if (RoomExists(testH, testV, &testRoomNum))		// if a legitimate room
		{
			CopyRoomToThisRoom(testRoomNum);
			finished = true;
		}
		else
		{
			h += hStep;
			v += vStep;
			if ((h > distance) || (h < -distance) || (v > distance) || (v < -distance))
			{			// we have walked beyond the bounds of our spiral
				if ((hStep == -1) && (vStep == 0))	// we expand our spiral out
				{
					distance++;
					hStep = 0;						// begin travelling up again
					vStep = -1;
				}
				else
				{
					h -= hStep;						// first, back up a step
					v -= vStep;
					
					if (hStep == 0)					// we were travelling up or down
					{
						if (vStep == -1)			// we were travelling upÉ
							hStep = 1;				// so begin travelling right
						else						// we were travelling downÉ
							hStep = -1;				// so begin travelling left
						vStep = 0;
					}
					else
					{
						hStep = 0;					// begin travelling down
						vStep = 1;
					}
					h += hStep;						// proceed a step now
					v += vStep;
				}
			}
		}
	} while (!finished);
}

//--------------------------------------------------------------  GetRoomFloorSuite

Boolean GetRoomFloorSuite (short room, short *floor, short *suite)
{
	char		wasState;
	Boolean		isRoom;
	
	if ((*thisHouse)->rooms[room].suite == kRoomIsEmpty)
	{
		*floor = 0;
		*suite = kRoomIsEmpty;
		isRoom = false;
	}
	else
	{
		*suite = (*thisHouse)->rooms[room].suite;
		*floor = (*thisHouse)->rooms[room].floor;
		isRoom = true;
	}
	
	return (isRoom);
}

//--------------------------------------------------------------  GetRoomNumber

short GetRoomNumber (short floor, short suite)
{
	// pass in a floor and suite; returns the room index into the house file
	short		roomNum, i;
	char		wasState;
	
	roomNum = kRoomIsEmpty;
	
	for (i = 0; i < numberRooms; i++)
	{
		if (((*thisHouse)->rooms[i].suite == suite) && 
				((*thisHouse)->rooms[i].floor == floor))
		{
			roomNum = i;
			break;
		}
	}
	
	return (roomNum);
}

//--------------------------------------------------------------  IsRoomAStructure

Boolean	IsRoomAStructure (short roomNum)
{
	char		wasState;
	Boolean		isStructure;
	
	if (roomNum == kRoomIsEmpty)
		return (false);
	
	if ((*thisHouse)->rooms[roomNum].background >= kUserBackground)
	{
		if ((*thisHouse)->rooms[roomNum].bounds != 0)
		{
			isStructure = (((*thisHouse)->rooms[roomNum].bounds & 32) == 32);
		}
		else
		{
			if ((*thisHouse)->rooms[roomNum].background < kUserStructureRange)
				isStructure = true;
			else
				isStructure = false;
		}
	}
	else
	{
		switch ((*thisHouse)->rooms[roomNum].background)
		{
			case kPaneledRoom:
			case kSimpleRoom:
			case kChildsRoom:
			case kAsianRoom:
			case kUnfinishedRoom:
			case kSwingersRoom:
			case kBathroom:
			case kLibrary:
			case kSkywalk:
			case kRoof:
			isStructure = true;
			break;
			
			default:
			isStructure = false;
			break;
		}
	}
	
	return (isStructure);
}

//--------------------------------------------------------------  DetermineRoomOpenings

void DetermineRoomOpenings (void)
{
	short		whichBack, leftTile, rightTile;
	short		boundsCode;
	
	whichBack = thisRoom->background;
	leftTile = thisRoom->tiles[0];
	rightTile = thisRoom->tiles[kNumTiles - 1];
	
	if (whichBack >= kUserBackground)
	{
		if (thisRoom->bounds != 0)
			boundsCode = thisRoom->bounds >> 1;
		else
			boundsCode = GetOriginalBounding(whichBack);
		leftOpen = ((boundsCode & 0x0001) == 0x0001);
		rightOpen = ((boundsCode & 0x0004) == 0x0004);
		
		if (leftOpen)
			leftThresh = kNoLeftWallLimit;
		else
			leftThresh = kLeftWallLimit;
		
		if (rightOpen)
			rightThresh = kNoRightWallLimit;
		else
			rightThresh = kRightWallLimit;
	}
	else
	{
		switch (whichBack)
		{
			case kSimpleRoom:
			case kPaneledRoom:
			case kBasement:
			case kChildsRoom:
			case kAsianRoom:
			case kUnfinishedRoom:
			case kSwingersRoom:
			case kBathroom:
			case kLibrary:
			case kSky:
			if (leftTile == 0)
				leftThresh = kLeftWallLimit;
			else
				leftThresh = kNoLeftWallLimit;
			if (rightTile == (kNumTiles - 1))
				rightThresh = kRightWallLimit;
			else
				rightThresh = kNoRightWallLimit;
			leftOpen = (leftTile != 0);
			rightOpen = (rightTile != (kNumTiles - 1));
			break;
			
			case kDirt:
			if (leftTile == 1)
				leftThresh = kLeftWallLimit;
			else
				leftThresh = kNoLeftWallLimit;
			if (rightTile == (kNumTiles - 1))
				rightThresh = kRightWallLimit;
			else
				rightThresh = kNoRightWallLimit;
			leftOpen = (leftTile != 0);
			rightOpen = (rightTile != (kNumTiles - 1));
			break;
			
			case kMeadow:
			if (leftTile == 6)
				leftThresh = kLeftWallLimit;
			else
				leftThresh = kNoLeftWallLimit;
			if (rightTile == 7)
				rightThresh = kRightWallLimit;
			else
				rightThresh = kNoRightWallLimit;
			leftOpen = (leftTile != 6);
			rightOpen = (rightTile != 7);
			break;
			
			case kGarden:
			case kSkywalk:
			case kField:
			case kStratosphere:
			case kStars:
			leftThresh = kNoLeftWallLimit;
			rightThresh = kNoRightWallLimit;
			leftOpen = true;
			rightOpen = true;
			break;
			
			default:
			if (leftTile == 0)
				leftThresh = kLeftWallLimit;
			else
				leftThresh = kNoLeftWallLimit;
			
			if (rightTile == (kNumTiles - 1))
				rightThresh = kRightWallLimit;
			else
				rightThresh = kNoRightWallLimit;
			
			leftOpen = (leftTile != 0);
			rightOpen = (rightTile != (kNumTiles - 1));
			break;
		}
	}
	
	if (DoesRoomHaveFloor())
		bottomOpen = false;
	else
		bottomOpen = true;
	
	if (DoesRoomHaveCeiling())
		topOpen = false;
	else
		topOpen = true;
}

//--------------------------------------------------------------  GetOriginalBounding

short GetOriginalBounding (short theID)
{
	boundsHand	boundsRes;
	short		boundCode;
	
	boundsRes = LoadHouseResource('bnds', theID).StaticCast<boundsType>();
	if (boundsRes == nil)
	{
		if (PictIDExists(theID))
			YellowAlert(kYellowNoBoundsRes, 0);
		boundCode = 0;
	}
	else
	{
		if (boundsRes.MMBlock()->m_size != sizeof(boundsType))
			return 0;	// Corrupted resource

		boundCode = 0;
		if ((*boundsRes)->left)
			boundCode += 1;
		if ((*boundsRes)->top)
			boundCode += 2;
		if ((*boundsRes)->right)
			boundCode += 4;
		if ((*boundsRes)->bottom)
			boundCode += 8;
		boundsRes.Dispose();
	}
	
	return (boundCode);
}

//--------------------------------------------------------------  GetNumberOfLights

short GetNumberOfLights (short where)
{
	houseType	*thisHousePtr;
	short		i, count;
	char		wasState;
	
	if (theMode == kEditMode)
	{
		switch (thisRoom->background)
		{
			case kGarden:
			case kSkywalk:
			case kMeadow:
			case kField:
			case kRoof:
			case kSky:
			case kStratosphere:
			case kStars:
			count = 1;
			break;
			
			case kDirt:
			count = 0;
			if ((thisRoom->tiles[0] == 0) && (thisRoom->tiles[1] == 0) && 
					(thisRoom->tiles[2] == 0) && (thisRoom->tiles[3] == 0) && 
					(thisRoom->tiles[4] == 0) && (thisRoom->tiles[5] == 0) &&
					(thisRoom->tiles[6] == 0) && (thisRoom->tiles[7] == 0))
				count = 1;
			break;
			
			default:
			count = 0;
			break;
		}
		if (count == 0)
		{
			for (i = 0; i < kMaxRoomObs; i++)
			{
				switch (thisRoom->objects[i].what)
				{
					case kDoorInLf:
					case kDoorInRt:
					case kWindowInLf:
					case kWindowInRt:
					case kWallWindow:
					count++;
					break;
					
					case kCeilingLight:
					case kLightBulb:
					case kTableLamp:
					case kHipLamp:
					case kDecoLamp:
					case kFlourescent:
					case kTrackLight:
					case kInvisLight:
					if (thisRoom->objects[i].data.f.initial)
						count++;
					break;
				}
			}
		}
	}
	else
	{
		thisHousePtr = *thisHouse;
		switch (thisHousePtr->rooms[where].background)
		{
			case kGarden:
			case kSkywalk:
			case kMeadow:
			case kField:
			case kRoof:
			case kSky:
			case kStratosphere:
			case kStars:
			count = 1;
			break;
			
			case kDirt:
			count = 0;
			if ((thisHousePtr->rooms[where].tiles[0] == 0) && 
					(thisHousePtr->rooms[where].tiles[1] == 0) && 
					(thisHousePtr->rooms[where].tiles[2] == 0) && 
					(thisHousePtr->rooms[where].tiles[3] == 0) && 
					(thisHousePtr->rooms[where].tiles[4] == 0) && 
					(thisHousePtr->rooms[where].tiles[5] == 0) &&
					(thisHousePtr->rooms[where].tiles[6] == 0) && 
					(thisHousePtr->rooms[where].tiles[7] == 0))
				count = 1;
			break;
			
			default:
			count = 0;
			break;
		}
		if (count == 0)
		{
			for (i = 0; i < kMaxRoomObs; i++)
			{
				switch (thisHousePtr->rooms[where].objects[i].what)
				{
					case kDoorInLf:
					case kDoorInRt:
					case kWindowInLf:
					case kWindowInRt:
					case kWallWindow:
					count++;
					break;
					
					case kCeilingLight:
					case kLightBulb:
					case kTableLamp:
					case kHipLamp:
					case kDecoLamp:
					case kFlourescent:
					case kTrackLight:
					case kInvisLight:
					if (thisHousePtr->rooms[where].objects[i].data.f.state)
						count++;
					break;
				}
			}
		}
	}
	return (count);
}

//--------------------------------------------------------------  IsShadowVisible

Boolean IsShadowVisible (void)
{
	short		boundsCode;
	Boolean		hasFloor;
	
	if (thisRoom->background >= kUserBackground)
	{
		if (thisRoom->bounds != 0)			// is this a version 2.0 house?
			boundsCode = (thisRoom->bounds >> 1);
		else
			boundsCode = GetOriginalBounding(thisRoom->background);
		hasFloor = ((boundsCode & 0x0008) != 0x0008);
	}
	else
	{
		switch (thisRoom->background)
		{
			case kRoof:
			case kSky:
			case kStratosphere:
			case kStars:
			hasFloor = false;
			break;
			
			default:
			hasFloor = true;
			break;
		}
	}
	
	return (hasFloor);
}

//--------------------------------------------------------------  DoesRoomHaveFloor

Boolean DoesRoomHaveFloor (void)
{
	short		boundsCode;
	Boolean		hasFloor;
	
	if (thisRoom->background >= kUserBackground)
	{
		if (thisRoom->bounds != 0)			// is this a version 2.0 house?
			boundsCode = (thisRoom->bounds >> 1);
		else
			boundsCode = GetOriginalBounding(thisRoom->background);
		hasFloor = ((boundsCode & 0x0008) != 0x0008);
	}
	else
	{
		switch (thisRoom->background)
		{
			case kSky:
			case kStratosphere:
			case kStars:
			hasFloor = false;
			break;
			
			default:
			hasFloor = true;
			break;
		}
	}
	
	return (hasFloor);
}

//--------------------------------------------------------------  DoesRoomHaveCeiling

Boolean DoesRoomHaveCeiling (void)
{
	short		boundsCode;
	Boolean		hasCeiling;
	
	if (thisRoom->background >= kUserBackground)
	{
		if (thisRoom->bounds != 0)			// is this a version 2.0 house?
			boundsCode = (thisRoom->bounds >> 1);
		else
			boundsCode = GetOriginalBounding(thisRoom->background);
		hasCeiling = ((boundsCode & 0x0002) != 0x0002);
	}
	else
	{
		switch (thisRoom->background)
		{
			case kGarden:
			case kMeadow:
			case kField:
			case kRoof:
			case kSky:
			case kStratosphere:
			case kStars:
			hasCeiling = false;
			break;
			
			default:
			hasCeiling = true;
			break;
		}
	}
	return (hasCeiling);
}

