diff --git a/ApplicationResourcePatches/STR/1006.txt b/ApplicationResourcePatches/STR/1006.txt new file mode 100644 index 0000000..413ecb7 --- /dev/null +++ b/ApplicationResourcePatches/STR/1006.txt @@ -0,0 +1,26 @@ +A never-before-seen error has arisen. Proceed with caution! (Save and Quit immediately.) +I failed to open the house's resource fork. Any unique room backgrounds are not accessible. +I failed to add a resource to the house's resource fork. See error number. +I failed to create a new resource fork for the house. See error number for problem. +There are no houses on this drive! About your only option is to create your own new house with the Editor. +This house is incompatible with us! You'll need to upgrade Glider PRO to use this house. Do not attempt to play/edit this house! +The background specified by this room was not found! Try re-selecting a new background (the Room Info menu). +The room number is out of bounds. I suspect the house file is corrupt. Try deleting this "illegal" room though. +The data is missing that specifies where the openings in this room are. The house may be damaged. Try selecting a new background though. +There was a problem with the clipboard (Cut, Copy and Paste commands). I couldn't guess why. +I think we just ran out of memory. Quit now and give Glider PROª more memory. +We failed to write the house to disk. (That shouldn't have happened.) +Well, the music didn't load. Glider PROª will still run, you'll just be musically challenged. +Wow, there was a problem bringing sounds up. You might try giving Glider PROª more memory - otherwise ... silence. +Some kind of strange Apple Event error. I think I would just ignore it. Or call Casady & Greene with the error number. +Did you save the house on the same volume Glider PRO is on? I saved the house but had to re-open the old house because I couldn't find the new one. +Wow, I couldn't find the old or new house. Go to the Select House menu item and see if it's there. If not, make sure they're on the same volume as Glider PRO. +Couldn't create a saved game structure. Memory is probably too low. +The saved game doesn't match the house. Either this game was saved for a different house or the house was modified recently. +This saved game is an old version. We cannot use this game with this house. +The number of rooms saved doesn't match the number of house rooms. We cannot use this game with this house. +The QuickTimeª movie that goes with this house will not be used. Glider PROª must have enough memory to easily load the entire movie into RAM. +This house has no rooms! Do not attempt to play this house! Select a new house to play. +There was an error generating or parsing a links list. Memory may be tight. +This house contains invalid data that couldn't be repaired. Select a new house to play. +This house contained invalid data, which was repaired. Some things may be missing or not work correctly. \ No newline at end of file diff --git a/ApplicationResourcePatches/manifest.json b/ApplicationResourcePatches/manifest.json index b403f5a..fb2e19e 100644 --- a/ApplicationResourcePatches/manifest.json +++ b/ApplicationResourcePatches/manifest.json @@ -37,7 +37,8 @@ "LICS/1003.txt" : "ApplicationResourcePatches/LICS/1003.txt", "LICS/1004.txt" : "ApplicationResourcePatches/LICS/1004.txt", "LICS/1005.txt" : "ApplicationResourcePatches/LICS/1005.txt", - "LICS/1006.txt" : "ApplicationResourcePatches/LICS/1006.txt" + "LICS/1006.txt" : "ApplicationResourcePatches/LICS/1006.txt", + "STR$23/1006.txt" : "ApplicationResourcePatches/STR/1006.txt" }, "delete" : [ diff --git a/GpApp/GliderDefines.h b/GpApp/GliderDefines.h index 6925196..5e167a0 100644 --- a/GpApp/GliderDefines.h +++ b/GpApp/GliderDefines.h @@ -39,6 +39,8 @@ #define kYellowQTMovieNotLoaded 22 #define kYellowNoRooms 23 #define kYellowCantOrderLinks 24 +#define kYellowHouseDamaged 25 +#define kYellowHouseRepaired 26 #define kSwitchIfNeeded 0 @@ -261,6 +263,8 @@ #define kMaxStars 4 #define kMaxShredded 4 #define kMaxDynamicObs 18 +#define kMaxSoundTriggers 1 +#define kMaxStairs 1 #define kMaxMasterObjects 216 // kMaxRoomObs * 9 #define kMaxViewWidth 1536 #define kMaxViewHeight (kTileHigh*3+20) @@ -626,3 +630,13 @@ static const Boolean kFaceLeft = FALSE; // Conflicts with GP input driver #define kBBQCoalsComponent 1 #define kPendulumComponent 1 #define kStarComponent 1 + + +#define kMapGroundValue 56 +#define kUpwardVentMinY 36 + +#define kMouseholeBottom 295 +#define kFireplaceBottom 297 +#define kManholeSits 322 +#define kGrecoVentTop 303 +#define kSewerBlowerTop 292 diff --git a/GpApp/GliderProtos.h b/GpApp/GliderProtos.h index b09caf5..a40734a 100644 --- a/GpApp/GliderProtos.h +++ b/GpApp/GliderProtos.h @@ -9,6 +9,7 @@ #include "GliderStructs.h" struct GpMouseInputEvent; +struct houseType; //-------------------------------------------------------------- Prototypes @@ -124,7 +125,7 @@ void DoHouseInfo (void); // --- HouseInfo.c Boolean OpenHouse (Boolean load); // --- HouseIO.c Boolean OpenSpecificHouse (const VFileSpec &); Boolean SaveHouseAs (void); -Boolean ReadHouse (GpIOStream *houseStream); +Boolean ReadHouse (GpIOStream *houseStream, bool untrusted); Boolean WriteHouse (Boolean); Boolean CloseHouse (void); void OpenHouseResFork (void); @@ -149,7 +150,7 @@ void GetDemoInput (gliderPtr); // --- Input.c void GetInput (gliderPtr); SInt16 MergeFloorSuite (SInt16, SInt16); // --- Link.c -void ExtractFloorSuite (SInt16, SInt16 *, SInt16 *); +void ExtractFloorSuite (const houseType *house, SInt16, SInt16 *, SInt16 *); void UpdateLinkControl (void); void UpdateLinkWindow (void); void OpenLinkWindow (void); @@ -321,6 +322,7 @@ void DuplicateObject (void); void MoveObject (SInt16, Boolean); void DeselectObject (void); Boolean ObjectHasHandle (SInt16 *, SInt16 *); +Boolean BlowerTypeHasUpperLimit (SInt16); void HandleBlowerGlider (void); void SelectNextObject (void); void SelectPrevObject (void); diff --git a/GpApp/GliderStructs.h b/GpApp/GliderStructs.h index 328c595..1323aa9 100644 --- a/GpApp/GliderStructs.h +++ b/GpApp/GliderStructs.h @@ -191,7 +191,7 @@ struct houseType Str255 banner; // 256 Str255 trailer; // 256 scoresType highScores; // 292 - gameType savedGame; // 40 + gameType savedGame_Unused; // 40 Boolean hasGame; // 1 Boolean unusedBoolean; // 1 int16_t firstRoom; // 2 diff --git a/GpApp/House.cpp b/GpApp/House.cpp index 78042ed..94da04a 100644 --- a/GpApp/House.cpp +++ b/GpApp/House.cpp @@ -385,7 +385,7 @@ void GenerateLinksList (void) thisObject = thisHousePtr->rooms[r].objects[i]; if (thisObject.data.e.where != -1) { - ExtractFloorSuite(thisObject.data.e.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisObject.data.e.where, &floor, &suite); roomLinked = GetRoomNumber(floor, suite); objectLinked = (short)thisObject.data.e.who; linksList[numLinks].srcRoom = r; @@ -405,7 +405,7 @@ void GenerateLinksList (void) thisObject = thisHousePtr->rooms[r].objects[i]; if (thisObject.data.d.where != -1) { - ExtractFloorSuite(thisObject.data.d.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisObject.data.d.where, &floor, &suite); roomLinked = GetRoomNumber(floor, suite); objectLinked = (short)thisObject.data.d.who; linksList[numLinks].srcRoom = r; @@ -597,7 +597,7 @@ void GenerateRetroLinks (void) thisObject = thisHousePtr->rooms[r].objects[i]; if (thisObject.data.e.where != -1) { - ExtractFloorSuite(thisObject.data.e.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisObject.data.e.where, &floor, &suite); roomLinked = GetRoomNumber(floor, suite); if (roomLinked == thisRoomNumber) { @@ -620,7 +620,7 @@ void GenerateRetroLinks (void) thisObject = thisHousePtr->rooms[r].objects[i]; if (thisObject.data.d.where != -1) { - ExtractFloorSuite(thisObject.data.d.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisObject.data.d.where, &floor, &suite); roomLinked = GetRoomNumber(floor, suite); if (roomLinked == thisRoomNumber) { @@ -794,7 +794,7 @@ void ConvertHouseVer1To2 (void) case kDeluxeTrans: if (thisRoom->objects[h].data.d.where != -1) { - ExtractFloorSuite(thisRoom->objects[h].data.d.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisRoom->objects[h].data.d.where, &floor, &suite); floor += kNumUndergroundFloors; thisRoom->objects[h].data.d.where = MergeFloorSuite(floor, suite); } @@ -810,7 +810,7 @@ void ConvertHouseVer1To2 (void) case kLgTrigger: if (thisRoom->objects[h].data.e.where != -1) { - ExtractFloorSuite(thisRoom->objects[h].data.e.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisRoom->objects[h].data.e.where, &floor, &suite); floor += kNumUndergroundFloors; thisRoom->objects[h].data.e.where = MergeFloorSuite(floor, suite); } diff --git a/GpApp/HouseIO.cpp b/GpApp/HouseIO.cpp index 9466ab3..e0cb0f7 100644 --- a/GpApp/HouseIO.cpp +++ b/GpApp/HouseIO.cpp @@ -15,6 +15,7 @@ #include "IGpLogDriver.h" #include "IGpSystemServices.h" #include "ObjectEdit.h" +#include "RectUtils.h" #include "ResourceManager.h" #include "PLDialogs.h" @@ -158,7 +159,7 @@ Boolean OpenHouse (Boolean read) if (read) { - Boolean readOK = ReadHouse(houseStream); + Boolean readOK = ReadHouse(houseStream, theHousesSpecs[thisHouseIndex].m_dir != PortabilityLayer::VirtualDirectories::kGameData); houseStream->Close(); return readOK; @@ -523,7 +524,7 @@ bool ByteSwapHouse(housePtr house, size_t sizeInBytes, bool isSwappedAfter) SanitizePascalStr(house->banner); SanitizePascalStr(house->trailer); ByteSwapScores(&house->highScores); - ByteSwapSavedGame(&house->savedGame); + ByteSwapSavedGame(&house->savedGame_Unused); PortabilityLayer::ByteSwap::BigInt16(house->firstRoom); PortabilityLayer::ByteSwap::BigInt16(house->nRooms); @@ -542,10 +543,1402 @@ bool ByteSwapHouse(housePtr house, size_t sizeInBytes, bool isSwappedAfter) return true; } -Boolean ReadHouse (GpIOStream *houseStream) +static bool FailCheck(bool value) +{ + return value; +} + +static bool SucceedCheck(bool value) +{ + return value; +} + +static bool LCheck(bool value) +{ + if (!value) + return FailCheck(value); + + return value; +} + +static bool RCheck(bool value) +{ + if (value) + return SucceedCheck(value); + + return value; +} + +template +bool LegalizePascalStr(uint8_t(&chars)[TSize], bool &anyRepairs) +{ + const size_t maxLength = TSize - 1; + if (chars[0] > maxLength) + { + chars[0] = static_cast(maxLength); + anyRepairs = RCheck(true); + return true; + } + + return true; +} + +static void LegalizeBoolean(Boolean &b) +{ + if (b < 0 || b > 1) + b = 1; +} + +static bool LegalizeScores(scoresType *scores, bool &anyRepairs) +{ + if (!LegalizePascalStr(scores->banner, anyRepairs)) + return LCheck(false); + + for (int i = 0; i < kMaxScores; i++) + if (!LegalizePascalStr(scores->names[i], anyRepairs)) + return LCheck(false); + + return true; +} + +static bool LegalizeRoomLayout(houseType *house, size_t roomNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + if (room->suite == kRoomIsEmpty) + return true; + + if (room->suite < 0 || room->suite >= kMaxNumRoomsH) + { + room->suite = kRoomIsEmpty; + anyRepairs = RCheck(true); + return true; + } + + if (room->floor > (kMaxNumRoomsV - kNumUndergroundFloors) || room->floor <= -kNumUndergroundFloors) + { + room->suite = kRoomIsEmpty; + anyRepairs = RCheck(true); + return true; + } + + for (size_t ori = 0; ori < roomNum; ori++) + { + const roomType *otherRoom = house->rooms + ori; + if (otherRoom->floor == room->floor && otherRoom->suite == room->suite) + { + room->suite = kRoomIsEmpty; + anyRepairs = RCheck(true); + return true; + } + } + + return true; +} + +static void LegalizeTopLeft(Point &topLeft, bool &anyRepairs) +{ + if (topLeft.h < 0) + { + anyRepairs = RCheck(true); + topLeft.h = 0; + } + else if (topLeft.h >= kRoomWide) + { + anyRepairs = RCheck(true); + topLeft.h = kRoomWide - 1; + } + + if (topLeft.v < 0) + { + anyRepairs = RCheck(true); + topLeft.v = 0; + } + else if (topLeft.v >= kTileHigh) + { + anyRepairs = RCheck(true); + topLeft.v = kTileHigh - 1; + } +} + +template +void LegalizeExpect(const TCondA &condA, const TCondB &condB, TSet &set, const TSetTo &setTo, bool &anyRepairs) +{ + if (condA == condB && set != setTo) + { + set = setTo; + anyRepairs = RCheck(true); + } +} + +static Boolean ForceRectInRoomRect(Rect &rect) +{ + Rect roomRect; + QSetRect(&roomRect, 0, 0, kRoomWide, kTileHigh); + + return ForceRectInRect(&rect, &roomRect); +} + + +static bool LegalizeBlower(houseType *house, size_t roomNum, size_t objectNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + objectType *obj = room->objects + objectNum; + blowerType *blower = &obj->data.a; + + LegalizeBoolean(blower->initial); + LegalizeBoolean(blower->state); + + int direction = -1; + for (int i = 0; i < 4; i++) + { + if (blower->vector & (1 << i)) + { + if (direction >= 0) + anyRepairs = RCheck(true); + else + direction = i; + } + } + + static const int kDirectionUp = 0; + static const int kDirectionRight = 1; + static const int kDirectionDown = 2; + static const int kDirectionLeft = 3; + + if (direction < 0 || direction > 3) + direction = kDirectionUp; + + LegalizeTopLeft(blower->topLeft, anyRepairs); + + switch (obj->what) + { + case kFloorVent: + case kFloorBlower: + case kSewerGrate: + case kTaper: + case kCandle: + case kStubby: + case kTiki: + case kBBQ: + case kGrecoVent: + case kSewerBlower: + if (direction != kDirectionUp) + direction = kDirectionUp; + break; + case kCeilingVent: + case kCeilingBlower: + if (direction != kDirectionDown) + direction = kDirectionDown; + break; + case kRightFan: + if (direction != kDirectionRight) + direction = kDirectionRight; + break; + case kLeftFan: + if (direction != kDirectionLeft) + direction = kDirectionLeft; + break; + case kInvisBlower: + case kLiftArea: + break; + default: + return LCheck(false); + } + + LegalizeExpect(obj->what, kFloorVent, blower->topLeft.v, kFloorVentTop, anyRepairs); + LegalizeExpect(obj->what, kFloorBlower, blower->topLeft.v, kFloorBlowerTop, anyRepairs); + LegalizeExpect(obj->what, kSewerGrate, blower->topLeft.v, kSewerGrateTop, anyRepairs); + LegalizeExpect(obj->what, kCeilingVent, blower->topLeft.v, kCeilingVentTop, anyRepairs); + LegalizeExpect(obj->what, kCeilingBlower, blower->topLeft.v, kCeilingBlowerTop, anyRepairs); + + if (blower->vector != (1 << direction)) + { + blower->vector = static_cast(1 << direction); + + // Unfortunately there's a lot of invalid directional data with fans, but because of how the code works, it has no effect + //anyRepairs = RCheck(true); + } + + if (blower->distance < 0) + { + blower->distance = 0; + anyRepairs = RCheck(true); + } + + if (obj->what == kLiftArea) + { + int maxWidth = kRoomWide - blower->topLeft.h; + int maxHeight = kTileHigh - blower->topLeft.v; + + if (blower->distance > maxWidth) + { + blower->distance = maxWidth; + anyRepairs = RCheck(true); + } + + if (blower->tall * 2 > maxHeight) + { + blower->tall = static_cast(maxHeight / 2); + anyRepairs = RCheck(true); + } + + return true; + } + + Rect positionedRect = srcRects[obj->what]; + ZeroRectCorner(&positionedRect); + OffsetRect(&positionedRect, blower->topLeft.h, blower->topLeft.v); + + const Rect basePositionedRect = positionedRect; + + if (ForceRectInRoomRect(positionedRect)) + { + anyRepairs = RCheck(true); + blower->topLeft.h = positionedRect.left; + blower->topLeft.v = positionedRect.top; + } + + int maxDistance = 0; + switch (direction) + { + case kDirectionUp: + { + int highestAllowed = BlowerTypeHasUpperLimit(obj->what) ? kUpwardVentMinY : 0; + maxDistance = blower->topLeft.v - highestAllowed; + } + break; + case kDirectionRight: + maxDistance = kRoomWide - positionedRect.right; + break; + case kDirectionDown: + maxDistance = kTileHigh - positionedRect.bottom; + break; + case kDirectionLeft: + maxDistance = positionedRect.left; + break; + default: + assert(false); + return LCheck(false); + } + + if (blower->distance > maxDistance) + { + blower->distance = maxDistance; + anyRepairs = RCheck(true); + } + + return true; +} + +static bool LegalizeFurniture(houseType *house, size_t roomNum, size_t objectNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + objectType *obj = room->objects + objectNum; + furnitureType *furniture = &obj->data.b; + + bool isVertConstrained = false; + bool isHorizConstrained = false; + bool isBottomConstrained = false; + + int bottomConstraint = 0; + + switch (obj->what) + { + default: + assert(false); + return LCheck(false); + + case kTable: + case kShelf: + case kDeckTable: + isVertConstrained = true; + break; + case kBooks: + case kFilingCabinet: + case kWasteBasket: + case kMilkCrate: + case kStool: + case kTrunk: + isVertConstrained = true; + isHorizConstrained = true; + break; + case kCabinet: + case kInvisObstacle: + case kInvisBounce: + // No constraints + break; + case kCounter: + isBottomConstrained = true; + bottomConstraint = kCounterBottom; + break; + case kDresser: + isBottomConstrained = true; + bottomConstraint = kDresserBottom; + break; + case kManhole: + isVertConstrained = true; + isHorizConstrained = true; + isBottomConstrained = true; + bottomConstraint = kManholeSits; + break; + }; + + const Rect baseRect = srcRects[obj->what]; + + if (NormalizeRect(&furniture->bounds)) + anyRepairs = RCheck(true); + + Point topLeft = Point::Create(furniture->bounds.left, furniture->bounds.top); + LegalizeTopLeft(topLeft, anyRepairs); + + if (obj->what == kManhole) + { + if (((topLeft.h - 3) % 64) != 0) + { + topLeft.h = (((topLeft.h + 29) / 64) * 64) + 3; + anyRepairs = RCheck(true); + } + } + + uint16_t width = furniture->bounds.Width(); + uint16_t height = furniture->bounds.Height(); + + if (width > kRoomWide) + { + width = kRoomWide; + anyRepairs = RCheck(true); + } + + if (height > kTileHigh) + { + height = kTileHigh; + anyRepairs = RCheck(true); + } + + LegalizeExpect(isVertConstrained, true, height, baseRect.Height(), anyRepairs); + LegalizeExpect(isHorizConstrained, true, width, baseRect.Width(), anyRepairs); + + furniture->bounds.left = topLeft.h; + furniture->bounds.top = topLeft.v; + furniture->bounds.bottom = topLeft.v + static_cast(height); + furniture->bounds.right = topLeft.h + static_cast(width); + + if (ForceRectInRoomRect(furniture->bounds)) + anyRepairs = RCheck(true); + + if (isBottomConstrained && furniture->bounds.bottom != bottomConstraint) + { + if (furniture->bounds.top > bottomConstraint) + furniture->bounds.top = bottomConstraint; + + furniture->bounds.bottom = bottomConstraint; + anyRepairs = RCheck(true); + } + + return true; +} + +static bool LegalizeBonus(houseType *house, size_t roomNum, size_t objectNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + objectType *obj = room->objects + objectNum; + bonusType *bonus = &obj->data.c; + + LegalizeBoolean(bonus->state); + LegalizeBoolean(bonus->initial); + + if (obj->what == kInvisBonus && bonus->points < 0) + { + anyRepairs = RCheck(true); + bonus->points = 0; + } + + LegalizeTopLeft(bonus->topLeft, anyRepairs); + + switch (obj->what) + { + default: + return LCheck(false); + + 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: + break; + }; + + Rect objRect = srcRects[obj->what]; + ZeroRectCorner(&objRect); + + if (obj->what == kSlider) + { + if (bonus->length < 0) + { + anyRepairs = RCheck(true); + bonus->length = 0; + } + else if (bonus->length > kRoomWide) + { + anyRepairs = RCheck(true); + bonus->length = kRoomWide; + } + + objRect.right = bonus->length; + } + + QOffsetRect(&objRect, bonus->topLeft.h, bonus->topLeft.v); + + if (ForceRectInRoomRect(objRect)) + { + anyRepairs = RCheck(true); + bonus->topLeft.h = objRect.left; + bonus->topLeft.v = objRect.top; + } + + int maxLength = -1; + if (obj->what == kGreaseRt) + maxLength = kRoomWide - objRect.right; + + if (obj->what == kGreaseLf) + maxLength = objRect.left; + + if (obj->what == kSlider) + maxLength = kRoomWide - bonus->topLeft.h; + + if (maxLength >= 0) + { + if (bonus->length < 0) + { + anyRepairs = RCheck(true); + bonus->length = 0; + } + else if (bonus->length > maxLength) + { + anyRepairs = RCheck(true); + bonus->length = maxLength; + } + } + + return true; +} + +static void LegalizeRoomLink(houseType *house, int16_t &where, bool &anyRepairs) +{ + // Leftover -1 from version conversion, these are generally valid + if (where == -100) + where = -1; + + if (where < -1) + { + anyRepairs = RCheck(true); + where = -1; + } + else if (where >= 0) + { + SInt16 floor, suite; + ExtractFloorSuite(house, where, &floor, &suite); + + if (suite < 0 || suite >= kMaxNumRoomsH) + { + anyRepairs = RCheck(true); + where = -1; + } + + if (floor > (kMaxNumRoomsV - kNumUndergroundFloors) || floor <= -kNumUndergroundFloors) + { + anyRepairs = RCheck(true); + where = -1; + } + } +} + +static bool LegalizeTransport(houseType *house, size_t roomNum, size_t objectNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + objectType *obj = room->objects + objectNum; + transportType *transport = &obj->data.d; + + LegalizeTopLeft(transport->topLeft, anyRepairs); + LegalizeRoomLink(house, transport->where, anyRepairs); + + Rect objRect = srcRects[obj->what]; + ZeroRectCorner(&objRect); + + if (obj->what == kInvisTrans) + { + if (transport->tall < 0) + { + anyRepairs = RCheck(true); + transport->tall = 0; + } + else if (transport->tall > kTileHigh) + { + anyRepairs = RCheck(true); + transport->tall = kTileHigh; + } + + objRect.right = transport->wide; + objRect.bottom = transport->tall; + } + + + if (obj->what == kDeluxeTrans) + { + uint8_t codedWidth = static_cast((transport->tall >> 8) & 0xff); + uint8_t codedHeight = static_cast((transport->tall) & 0xff); + + objRect.right = codedWidth * 4; + objRect.bottom = codedHeight * 4; + } + + QOffsetRect(&objRect, transport->topLeft.h, transport->topLeft.v); + + if (ForceRectInRoomRect(objRect)) + { + anyRepairs = RCheck(true); + transport->topLeft.h = objRect.left; + transport->topLeft.v = objRect.top; + + if (obj->what == kDeluxeTrans) + transport->tall = static_cast(((objRect.Width() / 4) << 8) + objRect.Height() / 4); + else if (obj->what == kInvisTrans) + { + transport->wide = objRect.Width(); + transport->tall = objRect.Height(); + } + } + + switch (obj->what) + { + default: + return LCheck(false); + + case kUpStairs: + case kDownStairs: + if (transport->topLeft.v != kStairsTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kStairsTop; + } + break; + case kFloorTrans: + if (transport->topLeft.v != kFloorTransTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kFloorTransTop; + } + break; + case kCeilingTrans: + if (transport->topLeft.v != kCeilingTransTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kCeilingTransTop; + } + break; + case kDoorInLf: + if (transport->topLeft.h != kDoorInLfLeft) + { + anyRepairs = RCheck(true); + transport->topLeft.h = kCeilingTransTop; + } + if (transport->topLeft.v != kDoorInTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kDoorInTop; + } + break; + case kDoorInRt: + if (transport->topLeft.h != kDoorInRtLeft) + { + anyRepairs = RCheck(true); + transport->topLeft.h = kDoorInRtLeft; + } + if (transport->topLeft.v != kDoorInTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kDoorInTop; + } + break; + case kDoorExRt: + if (transport->topLeft.h != kDoorExRtLeft) + { + anyRepairs = RCheck(true); + transport->topLeft.h = kDoorExRtLeft; + } + if (transport->topLeft.v != kDoorExTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kDoorExTop; + } + break; + case kDoorExLf: + if (transport->topLeft.h != kDoorExLfLeft) + { + anyRepairs = RCheck(true); + transport->topLeft.h = kDoorExLfLeft; + } + if (transport->topLeft.v != kDoorExTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kDoorExTop; + } + break; + case kWindowInLf: + if (transport->topLeft.h != kWindowInLfLeft) + { + anyRepairs = RCheck(true); + transport->topLeft.h = kWindowInLfLeft; + } + if (transport->topLeft.v != kWindowInTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kWindowInTop; + } + break; + case kWindowInRt: + if (transport->topLeft.h != kWindowInRtLeft) + { + anyRepairs = RCheck(true); + transport->topLeft.h = kWindowInRtLeft; + } + if (transport->topLeft.v != kWindowInTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kWindowInTop; + } + break; + case kWindowExRt: + if (transport->topLeft.h != kWindowExRtLeft) + { + anyRepairs = RCheck(true); + transport->topLeft.h = kWindowExRtLeft; + } + if (transport->topLeft.v != kWindowExTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kWindowExTop; + } + break; + case kWindowExLf: + if (transport->topLeft.h != kWindowExLfLeft) + { + anyRepairs = RCheck(true); + transport->topLeft.h = kWindowExLfLeft; + } + if (transport->topLeft.v != kWindowExTop) + { + anyRepairs = RCheck(true); + transport->topLeft.v = kWindowExTop; + } + break; + case kInvisTrans: + case kDeluxeTrans: + case kMailboxLf: + case kMailboxRt: + break; + } + + return true; +} + +static bool LegalizeSwitch(houseType *house, size_t roomNum, size_t objectNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + objectType *obj = room->objects + objectNum; + switchType *sw = &obj->data.e; + + if (sw->delay < 0) + { + sw->delay = 0; + anyRepairs = RCheck(true); + } + + bool isSwitch = false; + bool isTrigger = false; + + switch (obj->what) + { + default: + return RCheck(false); + + case kLightSwitch: + case kMachineSwitch: + case kThermostat: + case kPowerSwitch: + case kKnifeSwitch: + case kInvisSwitch: + isSwitch = true; + LegalizeRoomLink(house, sw->where, anyRepairs); + break; + case kTrigger: + case kLgTrigger: + LegalizeRoomLink(house, sw->where, anyRepairs); + break; + case kSoundTrigger: + break; + }; + + if (isSwitch) + { + switch (sw->type) + { + case kToggle: + case kForceOn: + case kForceOff: + break; + default: + anyRepairs = RCheck(true); + sw->type = kToggle; + break; + } + } + + if (isTrigger) + { + if (sw->type != kOneShot) + { + anyRepairs = RCheck(true); + sw->type = kOneShot; + } + } + + LegalizeTopLeft(sw->topLeft, anyRepairs); + + Rect bounds = srcRects[obj->what]; + ZeroRectCorner(&bounds); + QOffsetRect(&bounds, sw->topLeft.h, sw->topLeft.v); + + if (ForceRectInRoomRect(bounds)) + { + anyRepairs = RCheck(true); + sw->topLeft.h = bounds.left; + sw->topLeft.v = bounds.top; + } + + return true; +} + +static bool LegalizeLight(houseType *house, size_t roomNum, size_t objectNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + objectType *obj = room->objects + objectNum; + lightType *light = &obj->data.f; + + LegalizeBoolean(light->initial); + LegalizeBoolean(light->state); + + LegalizeTopLeft(light->topLeft, anyRepairs); + + Rect bounds = srcRects[obj->what]; + ZeroRectCorner(&bounds); + + if (obj->what == kTrackLight || obj->what == kFlourescent) + { + if (light->length < 0) + { + anyRepairs = RCheck(true); + light->length = 0; + } + else if (light->length > kRoomWide) + { + anyRepairs = RCheck(true); + light->length = kRoomWide; + } + + bounds.right = light->length; + } + + QOffsetRect(&bounds, light->topLeft.h, light->topLeft.v); + + if (ForceRectInRoomRect(bounds)) + { + anyRepairs = RCheck(true); + light->topLeft.h = bounds.left; + light->topLeft.v = bounds.top; + } + + switch (obj->what) + { + case kCeilingLight: + if (light->topLeft.v != kCeilingLightTop) + { + anyRepairs = RCheck(true); + light->topLeft.v = kCeilingLightTop; + } + break; + case kHipLamp: + if (light->topLeft.v != kHipLampTop) + { + anyRepairs = RCheck(true); + light->topLeft.v = kHipLampTop; + } + break; + case kDecoLamp: + if (light->topLeft.v != kDecoLampTop) + { + anyRepairs = RCheck(true); + light->topLeft.v = kDecoLampTop; + } + break; + case kFlourescent: + if (light->topLeft.v != kFlourescentTop) + { + anyRepairs = RCheck(true); + light->topLeft.v = kFlourescentTop; + } + break; + case kTrackLight: + if (light->topLeft.v != kTrackLightTop) + { + anyRepairs = RCheck(true); + light->topLeft.v = kTrackLightTop; + } + break; + case kLightBulb: + case kTableLamp: + case kInvisLight: + break; + } + + return true; +} + +static bool LegalizeAppliance(houseType *house, size_t roomNum, size_t objectNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + objectType *obj = room->objects + objectNum; + applianceType *appl = &obj->data.g; + + LegalizeBoolean(appl->initial); + LegalizeBoolean(appl->state); + + LegalizeTopLeft(appl->topLeft, anyRepairs); + + if (obj->what != kCustomPict) + { + Rect bounds = srcRects[obj->what]; + ZeroRectCorner(&bounds); + QOffsetRect(&bounds, appl->topLeft.h, appl->topLeft.v); + + if (ForceRectInRoomRect(bounds)) + { + anyRepairs = RCheck(true); + appl->topLeft.h = bounds.left; + appl->topLeft.v = bounds.top; + } + + switch (obj->what) + { + case kToaster: + { + int maxHeight = bounds.top; + if (appl->height < 0) + { + anyRepairs = RCheck(true); + appl->height = 0; + } + else if (appl->height > maxHeight) + { + anyRepairs = RCheck(true); + appl->height = maxHeight; + } + } + break; + case kShredder: + case kMacPlus: + case kGuitar: + case kTV: + case kCoffee: + case kOutlet: + case kVCR: + case kStereo: + case kMicrowave: + case kCinderBlock: + case kFlowerBox: + case kCDs: + break; + } + } + + return true; +} + +static bool LegalizeEnemy(houseType *house, size_t roomNum, size_t objectNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + objectType *obj = room->objects + objectNum; + enemyType *enemy = &obj->data.h; + + LegalizeBoolean(enemy->initial); + LegalizeBoolean(enemy->state); + + LegalizeTopLeft(enemy->topLeft, anyRepairs); + + Rect bounds = srcRects[obj->what]; + ZeroRectCorner(&bounds); + QOffsetRect(&bounds, enemy->topLeft.h, enemy->topLeft.v); + + if (ForceRectInRoomRect(bounds)) + { + anyRepairs = RCheck(true); + enemy->topLeft.h = bounds.left; + enemy->topLeft.v = bounds.top; + } + + switch (obj->what) + { + case kBalloon: + case kCopterLf: + case kCopterRt: + { + int expectedV = (kTileHigh / 2) - HalfRectTall(&bounds); + if (enemy->topLeft.v != expectedV) + { + anyRepairs = RCheck(true); + enemy->topLeft.v = expectedV; + } + } + break; + case kDartLf: + { + int expectedH = kRoomWide - RectWide(&bounds); + if (enemy->topLeft.h != expectedH) + { + anyRepairs = RCheck(true); + enemy->topLeft.h = expectedH; + } + } + break; + case kDartRt: + if (enemy->topLeft.h != 0) + { + anyRepairs = RCheck(true); + enemy->topLeft.h = 0; + } + break; + case kBall: + case kFish: + { + int maxLength = bounds.top; + if (enemy->length < 0) + { + anyRepairs = RCheck(true); + enemy->length = 0; + } + else if (enemy->length > maxLength) + { + anyRepairs = RCheck(true); + enemy->length = maxLength; + } + } + break; + case kDrip: + { + int maxLength = kTileHigh - bounds.bottom; + if (enemy->length < 0) + { + anyRepairs = RCheck(true); + enemy->length = 0; + } + else if (enemy->length > maxLength) + { + anyRepairs = RCheck(true); + enemy->length = maxLength; + } + } + break; + case kCobweb: + break; + } + + return true; +} + +static bool LegalizeClutter(houseType *house, size_t roomNum, size_t objectNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + objectType *obj = room->objects + objectNum; + clutterType *blower = &obj->data.i; + + PL_NotYetImplemented_TODO("Validate"); + return true; +} + + +static bool LegalizeObject(houseType *house, size_t roomNum, size_t objectNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + objectType *obj = room->objects + objectNum; + + switch (obj->what) + { + default: + obj->what = kObjectIsEmpty; + anyRepairs = RCheck(true); + break; + case kObjectIsEmpty: + break; + + 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: + return LegalizeBlower(house, roomNum, objectNum, anyRepairs); + + 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: + return LegalizeFurniture(house, roomNum, objectNum, anyRepairs); + + 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: + return LegalizeBonus(house, roomNum, objectNum, anyRepairs); + + 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: + return LegalizeTransport(house, roomNum, objectNum, anyRepairs); + + case kLightSwitch: + case kMachineSwitch: + case kThermostat: + case kPowerSwitch: + case kKnifeSwitch: + case kInvisSwitch: + case kTrigger: + case kLgTrigger: + case kSoundTrigger: + return LegalizeSwitch(house, roomNum, objectNum, anyRepairs); + + case kCeilingLight: + case kLightBulb: + case kTableLamp: + case kHipLamp: + case kDecoLamp: + case kFlourescent: + case kTrackLight: + case kInvisLight: + return LegalizeLight(house, roomNum, objectNum, anyRepairs); + + 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: + return LegalizeAppliance(house, roomNum, objectNum, anyRepairs); + + case kBalloon: + case kCopterLf: + case kCopterRt: + case kDartLf: + case kDartRt: + case kBall: + case kDrip: + case kFish: + case kCobweb: + return LegalizeEnemy(house, roomNum, objectNum, anyRepairs); + + 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: + return LegalizeClutter(house, roomNum, objectNum, anyRepairs); + } + + return true; +} + +static bool LegalizeRoom(houseType *house, size_t roomNum, bool &anyRepairs) +{ + roomType *room = house->rooms + roomNum; + if (room->suite == kRoomIsEmpty) + return true; + + if (!LegalizePascalStr(room->name, anyRepairs)) + return LCheck(false); + + LegalizeBoolean(room->visited); + + for (int i = 0; i < kNumTiles; i++) + { + if (room->tiles[i] < 0) + { + room->tiles[i] = 0; + anyRepairs = RCheck(true); + } + else if (room->tiles[i] >= kNumTiles) + { + room->tiles[i] = kNumTiles - 1; + anyRepairs = RCheck(true); + } + } + + // Enforce object type caps + enum CapType + { + CapType_Candle, + CapType_Tiki, + CapType_Coals, + CapType_Pendulum, + CapType_RubberBands, + CapType_Star, + CapType_DynamicObj, + CapType_SoundTrigger, + CapType_UpStairs, + CapType_DownStairs, + CapType_Grease, + + CapType_Count, + }; + + int caps[CapType_Count]; + caps[CapType_Candle] = kMaxCandles; + caps[CapType_Tiki] = kMaxTikis; + caps[CapType_Coals] = kMaxCoals; + caps[CapType_Pendulum] = kMaxPendulums; + caps[CapType_RubberBands] = kMaxRubberBands; + caps[CapType_Star] = kMaxStars; + caps[CapType_DynamicObj] = kMaxDynamicObs; + caps[CapType_SoundTrigger] = kMaxSoundTriggers; + caps[CapType_UpStairs] = kMaxStairs; + caps[CapType_DownStairs] = kMaxStairs; + caps[CapType_Grease] = kMaxGrease; + + int counts[CapType_Count]; + for (int i = 0; i < CapType_Count; i++) + counts[i] = 0; + + for (size_t i = 0; i < kMaxRoomObs; i++) + { + CapType capType = CapType_Count; + + objectType *obj = room->objects + i; + switch (obj->what) + { + case kTaper: + case kCandle: + case kStubby: + capType = CapType_Candle; + break; + case kTiki: + capType = CapType_Tiki; + break; + case kBBQ: + capType = CapType_Coals; + break; + case kCuckoo: + capType = CapType_Pendulum; + break; + case kBands: + capType = CapType_RubberBands; + break; + case kStar: + capType = CapType_Star; + break; + case kSparkle: + case kToaster: + case kMacPlus: + case kTV: + case kCoffee: + case kOutlet: + case kVCR: + case kStereo: + case kMicrowave: + case kBalloon: + case kCopterLf: + case kCopterRt: + case kDartLf: + case kDartRt: + case kBall: + case kDrip: + case kFish: + capType = CapType_DynamicObj; + break; + case kSoundTrigger: + capType = CapType_SoundTrigger; + break; + case kUpStairs: + capType = CapType_UpStairs; + break; + case kDownStairs: + capType = CapType_DownStairs; + break; + case kGreaseLf: + case kGreaseRt: + capType = CapType_Grease; + break; + default: + break; + }; + + if (capType != CapType_Count) + { + if (counts[capType] == caps[capType]) + { + obj->what = kObjectIsEmpty; + anyRepairs = RCheck(true); + } + else + counts[capType]++; + } + } + + // Check all objects + for (size_t i = 0; i < kMaxRoomObs; i++) + { + if (!LegalizeObject(house, roomNum, i, anyRepairs)) + return LCheck(false); + } + + int16_t numObjects = kMaxRoomObs; + for (size_t i = 0; i < kMaxRoomObs; i++) + { + objectType *obj = room->objects + i; + + if (obj->what == kObjectIsEmpty) + numObjects--; + } + + if (numObjects != room->numObjects) + { + anyRepairs = RCheck(true); + room->numObjects = numObjects; + } + + return true; +} + +static bool LegalizeHouse(houseType *house, bool &anyRepairs) +{ + size_t nRooms = house->nRooms; + + if (!LegalizeScores(&house->highScores, anyRepairs)) + return false; + + PL_NotYetImplemented_TODO("Validate initial pos"); + + // Repair room layout + for (size_t i = 0; i < nRooms; i++) + { + if (!LegalizeRoomLayout(house, i, anyRepairs)) + return LCheck(false); + } + + // Repair firstRoom + if (house->firstRoom < 0 || house->firstRoom >= house->nRooms || house->rooms[house->firstRoom].suite == kRoomIsEmpty) + { + if (nRooms != 0) + { + bool repairedOK = false; + for (size_t i = 0; i < nRooms; i++) + { + if (house->rooms[i].suite == kRoomIsEmpty) + continue; + + house->firstRoom = static_cast(i); + repairedOK = true; + anyRepairs = RCheck(true); + } + + if (!repairedOK) + return LCheck(false); + } + } + + for (size_t i = 0; i < nRooms; i++) + { + if (!LegalizeRoom(house, i, anyRepairs)) + return LCheck(false); + } + + return true; +} + +Boolean ReadHouse (GpIOStream *houseStream, bool untrusted) { long byteCount; - PLError_t theErr; + PLError_t theErr; short whichRoom; // There should be no padding remaining the house type @@ -567,6 +1960,21 @@ Boolean ReadHouse (GpIOStream *houseStream) if (thisHouse != nil) thisHouse.Dispose(); + if (byteCount < houseType::kBinaryDataSize) + { + YellowAlert(kYellowHouseDamaged, 1); + return (false); + } + + const size_t roomDataSize = static_cast(byteCount) - houseType::kBinaryDataSize; + if (roomDataSize % sizeof(roomType) != 0) + { + YellowAlert(kYellowHouseDamaged, 2); + return (false); + } + + const size_t roomCountFromDataSize = roomDataSize / sizeof(roomType); + // GP: Correct for padding const size_t alignmentPadding = sizeof(houseType) - sizeof(roomType) - houseType::kBinaryDataSize; @@ -602,6 +2010,24 @@ Boolean ReadHouse (GpIOStream *houseStream) ByteSwapHouse(*thisHouse, static_cast(byteCount), false); numberRooms = (*thisHouse)->nRooms; + if (numberRooms < 0 || static_cast(numberRooms) > roomCountFromDataSize) + { + YellowAlert(kYellowHouseDamaged, 3); + return (false); + } + + bool anyRepairs = false; + if (untrusted) + { + if (!LegalizeHouse(*thisHouse, anyRepairs)) + { + YellowAlert(kYellowHouseDamaged, 4); + return (false); + } + + if (anyRepairs) + YellowAlert(kYellowHouseRepaired, 0); + } #ifdef COMPILEDEMO if (numberRooms != 45) @@ -652,7 +2078,7 @@ Boolean ReadHouse (GpIOStream *houseStream) { } } - + objActive = kNoObjectSelected; ReflectCurrentRoom(true); fileDirty = false; diff --git a/GpApp/HouseLegal.cpp b/GpApp/HouseLegal.cpp index dded8df..2c18927 100644 --- a/GpApp/HouseLegal.cpp +++ b/GpApp/HouseLegal.cpp @@ -129,27 +129,17 @@ Boolean KeepObjectLegal (void) 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 (BlowerTypeHasUpperLimit(theObject->what)) { - if (dist < 36) + if (dist < kUpwardVentMinY) { - theObject->data.a.distance += dist - 36; + theObject->data.a.distance += dist - kUpwardVentMinY; unchanged = false; } } diff --git a/GpApp/Link.cpp b/GpApp/Link.cpp index b7a48c7..cccf8a8 100644 --- a/GpApp/Link.cpp +++ b/GpApp/Link.cpp @@ -42,9 +42,9 @@ short MergeFloorSuite (short floor, short suite) //-------------------------------------------------------------- ExtractFloorSuite -void ExtractFloorSuite (short combo, short *floor, short *suite) +void ExtractFloorSuite (const houseType *house, SInt16 combo, SInt16 *floor, SInt16 *suite) { - if ((*thisHouse)->version < 0x0200) // old floor/suite combo + if (house->version < 0x0200) // old floor/suite combo { *floor = (combo / 100) - kNumUndergroundFloors; *suite = combo % 100; diff --git a/GpApp/Map.cpp b/GpApp/Map.cpp index 44d0fc7..0122e83 100644 --- a/GpApp/Map.cpp +++ b/GpApp/Map.cpp @@ -28,7 +28,6 @@ #define kMapScrollBarWidth 16 #define kHScrollRef 5L #define kVScrollRef 27L -#define kMapGroundValue 56 #define kNewRoomAlert 1004 #define kYesDoNewRoom 1 #define kThumbnailPictID 1010 diff --git a/GpApp/ObjectAdd.cpp b/GpApp/ObjectAdd.cpp index be32d60..e7da40f 100644 --- a/GpApp/ObjectAdd.cpp +++ b/GpApp/ObjectAdd.cpp @@ -16,13 +16,6 @@ #define kNoMoreObjectsAlert 1008 #define kNoMoreSpecialAlert 1028 -#define kMaxSoundTriggers 1 -#define kMaxStairs 1 -#define kMouseholeBottom 295 -#define kFireplaceBottom 297 -#define kManholeSits 322 -#define kGrecoVentTop 303 -#define kSewerBlowerTop 292 short FindEmptyObjectSlot (void); diff --git a/GpApp/ObjectDrawAll.cpp b/GpApp/ObjectDrawAll.cpp index 924950d..9285bbc 100644 --- a/GpApp/ObjectDrawAll.cpp +++ b/GpApp/ObjectDrawAll.cpp @@ -534,7 +534,7 @@ void DrawARoomsObjects (short neighbor, Boolean redraw) OffsetRectRoomRelative(&itsRect, neighbor); if (SectRect(&itsRect, &testRect, &whoCares)) { - ExtractFloorSuite(thisObject.data.e.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisObject.data.e.where, &floor, &suite); room = GetRoomNumber(floor, suite); obj = (short)thisObject.data.e.who; DrawLightSwitch(&itsRect, GetObjectState(room, obj)); @@ -547,7 +547,7 @@ void DrawARoomsObjects (short neighbor, Boolean redraw) OffsetRectRoomRelative(&itsRect, neighbor); if (SectRect(&itsRect, &testRect, &whoCares)) { - ExtractFloorSuite(thisObject.data.e.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisObject.data.e.where, &floor, &suite); room = GetRoomNumber(floor, suite); obj = (short)thisObject.data.e.who; DrawMachineSwitch(&itsRect, GetObjectState(room, obj)); @@ -560,7 +560,7 @@ void DrawARoomsObjects (short neighbor, Boolean redraw) OffsetRectRoomRelative(&itsRect, neighbor); if (SectRect(&itsRect, &testRect, &whoCares)) { - ExtractFloorSuite(thisObject.data.e.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisObject.data.e.where, &floor, &suite); room = GetRoomNumber(floor, suite); obj = (short)thisObject.data.e.who; DrawThermostat(&itsRect, GetObjectState(room, obj)); @@ -573,7 +573,7 @@ void DrawARoomsObjects (short neighbor, Boolean redraw) OffsetRectRoomRelative(&itsRect, neighbor); if (SectRect(&itsRect, &testRect, &whoCares)) { - ExtractFloorSuite(thisObject.data.e.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisObject.data.e.where, &floor, &suite); room = GetRoomNumber(floor, suite); obj = (short)thisObject.data.e.who; DrawPowerSwitch(&itsRect, GetObjectState(room, obj)); @@ -586,7 +586,7 @@ void DrawARoomsObjects (short neighbor, Boolean redraw) OffsetRectRoomRelative(&itsRect, neighbor); if (SectRect(&itsRect, &testRect, &whoCares)) { - ExtractFloorSuite(thisObject.data.e.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisObject.data.e.where, &floor, &suite); room = GetRoomNumber(floor, suite); obj = (short)thisObject.data.e.who; DrawKnifeSwitch(&itsRect, GetObjectState(room, obj)); diff --git a/GpApp/ObjectEdit.cpp b/GpApp/ObjectEdit.cpp index 28225b7..065e1df 100644 --- a/GpApp/ObjectEdit.cpp +++ b/GpApp/ObjectEdit.cpp @@ -1680,6 +1680,24 @@ void DeselectObject (void) #endif } + +//-------------------------------------------------------------- ObjectHasHandle + +Boolean BlowerTypeHasUpperLimit (SInt16 what) +{ + switch (what) + { + case kFloorVent: + case kFloorBlower: + case kTaper: + case kCandle: + case kStubby: + return true; + default: + return false; + } +} + //-------------------------------------------------------------- ObjectHasHandle #ifndef COMPILEDEMO diff --git a/GpApp/ObjectInfo.cpp b/GpApp/ObjectInfo.cpp index bedff3c..1cb7d63 100644 --- a/GpApp/ObjectInfo.cpp +++ b/GpApp/ObjectInfo.cpp @@ -1075,7 +1075,7 @@ void DoSwitchObjectInfo (void) PasStringCopy(PSTR("none"), roomStr); else { - ExtractFloorSuite(thisRoom->objects[objActive].data.e.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisRoom->objects[objActive].data.e.where, &floor, &suite); NumToString((long)floor, roomStr); PasStringConcat(roomStr, PSTR(" / ")); NumToString((long)suite, tempStr); @@ -1196,7 +1196,7 @@ void DoTriggerObjectInfo (void) PasStringCopy(PSTR("none"), roomStr); else { - ExtractFloorSuite(thisRoom->objects[objActive].data.e.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisRoom->objects[objActive].data.e.where, &floor, &suite); NumToString((long)floor, roomStr); PasStringConcat(roomStr, PSTR(" / ")); NumToString((long)suite, tempStr); @@ -1869,7 +1869,7 @@ void DoTransObjectInfo (short what) PasStringCopy(PSTR("none"), roomStr); else { - ExtractFloorSuite(thisRoom->objects[objActive].data.d.where, &floor, &suite); + ExtractFloorSuite(*thisHouse, thisRoom->objects[objActive].data.d.where, &floor, &suite); NumToString((long)floor, roomStr); PasStringConcat(roomStr, PSTR(" / ")); NumToString((long)suite, tempStr); diff --git a/GpApp/ObjectRects.cpp b/GpApp/ObjectRects.cpp index 8e45ce3..19d9e71 100644 --- a/GpApp/ObjectRects.cpp +++ b/GpApp/ObjectRects.cpp @@ -36,6 +36,7 @@ void GetObjectRect (objectPtr who, Rect *itsRect) switch (who->what) { + default: case kObjectIsEmpty: QSetRect(itsRect, 0, 0, 0, 0); break; diff --git a/GpApp/Objects.cpp b/GpApp/Objects.cpp index 3f249ee..d3f61aa 100644 --- a/GpApp/Objects.cpp +++ b/GpApp/Objects.cpp @@ -136,7 +136,7 @@ short GetRoomLinked (objectType *who) compoundRoomNumber = who->data.d.where; if (compoundRoomNumber != -1) // is object linked { - ExtractFloorSuite(compoundRoomNumber, &floor, &suite); + ExtractFloorSuite(*thisHouse, compoundRoomNumber, &floor, &suite); whereLinked = GetRoomNumber(floor, suite); } else @@ -154,7 +154,7 @@ short GetRoomLinked (objectType *who) compoundRoomNumber = who->data.e.where; if (compoundRoomNumber != -1) // is object linked { - ExtractFloorSuite(compoundRoomNumber, &floor, &suite); + ExtractFloorSuite(*thisHouse, compoundRoomNumber, &floor, &suite); whereLinked = GetRoomNumber(floor, suite); } else @@ -352,7 +352,7 @@ void AddTempManholeRect (Rect *manHole) //-------------------------------------------------------------- SetObjectState -Boolean SetObjectState (short room, short object, short action, short local) +Boolean SetObjectState (SInt16 room, SInt16 object, SInt16 action, SInt16 local) { char wasState; Boolean changed = false; diff --git a/GpApp/RectUtils.cpp b/GpApp/RectUtils.cpp index bc3f0ea..a7079a6 100644 --- a/GpApp/RectUtils.cpp +++ b/GpApp/RectUtils.cpp @@ -31,15 +31,17 @@ void FrameWHRect (DrawSurface *surface, short left, short top, short wide, short // This function ensures that a rect's top is less than it's bottomÉ // and that left is less than right. -void NormalizeRect (Rect *theRect) +Boolean NormalizeRect (Rect *theRect) { short tempSide; + Boolean changed = false; if (theRect->left > theRect->right) { tempSide = theRect->left; theRect->left = theRect->right; theRect->right = tempSide; + changed = true; } if (theRect->top > theRect->bottom) @@ -47,7 +49,10 @@ void NormalizeRect (Rect *theRect) tempSide = theRect->top; theRect->top = theRect->bottom; theRect->bottom = tempSide; + changed = true; } + + return changed; } //-------------------------------------------------------------- ZeroRectCorner @@ -198,7 +203,8 @@ Boolean ForceRectInRect (Rect *small, Rect *large) changed = false; - NormalizeRect(small); + if (NormalizeRect(small)) + changed = true; if ((small->bottom - small->top) > (large->bottom - large->top)) { diff --git a/GpApp/RectUtils.h b/GpApp/RectUtils.h index 5affd19..8c3c9eb 100644 --- a/GpApp/RectUtils.h +++ b/GpApp/RectUtils.h @@ -17,7 +17,7 @@ namespace PortabilityLayer void FrameWHRect (short, short, short, short, PortabilityLayer::ResolveCachingColor &color); -void NormalizeRect (Rect *); +Boolean NormalizeRect (Rect *); void ZeroRectCorner (Rect *); void CenterRectOnPoint (Rect *, Point); short HalfRectWide (Rect *);