diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f42bf03
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,19 @@
+*.suo
+*.db
+*.opendb
+*.ipch
+*.pch
+*.user
+*.mcp
+*.obj
+*.log
+*.tlog
+*.lastbuildstate
+*.dll
+*.exe
+*.exp
+*.ilk
+*.lib
+*.pdb
+.vs/*
+Packaged/*
diff --git a/Common.props b/Common.props
new file mode 100644
index 0000000..81ac958
--- /dev/null
+++ b/Common.props
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+ $(SolutionDir)Common;%(AdditionalIncludeDirectories)
+
+
+
+
\ No newline at end of file
diff --git a/Common/CoreDefs.h b/Common/CoreDefs.h
new file mode 100644
index 0000000..7ff9917
--- /dev/null
+++ b/Common/CoreDefs.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#ifndef __PL_COREDEFS_H__
+#define __PL_COREDEFS_H__
+
+#if __cplusplus >= 199711L
+#define PL_IS_CPP11 1
+#else
+#define PL_IS_CPP11 0
+#endif
+
+#if PL_IS_CPP11
+#define PL_DELETED = delete
+#else
+#ifndef nullptr
+#define nullptr 0
+#endif
+
+#ifndef override
+#define override
+#endif
+
+#ifndef final
+#define final
+#endif
+
+#define PL_DELETED
+#endif
+
+
+static const size_t PL_SYSTEM_MEMORY_ALIGNMENT = 16;
+
+
+#endif
diff --git a/GlidePort.sln b/GlidePort.sln
new file mode 100644
index 0000000..8dc0ad4
--- /dev/null
+++ b/GlidePort.sln
@@ -0,0 +1,81 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27130.2020
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hqx2bin", "hqx2bin\hqx2bin.vcxproj", "{45B1B18C-C846-4044-9206-74F58DFC5E88}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PortabilityLayer", "PortabilityLayer\PortabilityLayer.vcxproj", "{6EC62B0F-9353-40A4-A510-3788F1368B33}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MiniRez", "MiniRez\MiniRez.vcxproj", "{2FF15659-5C72-48B8-B55B-3C658E4125B5}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpApp", "GpApp\GpApp.vcxproj", "{6233C3F2-5781-488E-B190-4FA8836F5A77}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpD3D", "GpD3D\GpD3D.vcxproj", "{0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hqx2gp", "hqx2gp\hqx2gp.vcxproj", "{5FDE4822-C771-46A5-B6B2-FD12BACE86BF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {45B1B18C-C846-4044-9206-74F58DFC5E88}.Debug|x64.ActiveCfg = Debug|x64
+ {45B1B18C-C846-4044-9206-74F58DFC5E88}.Debug|x64.Build.0 = Debug|x64
+ {45B1B18C-C846-4044-9206-74F58DFC5E88}.Debug|x86.ActiveCfg = Debug|Win32
+ {45B1B18C-C846-4044-9206-74F58DFC5E88}.Debug|x86.Build.0 = Debug|Win32
+ {45B1B18C-C846-4044-9206-74F58DFC5E88}.Release|x64.ActiveCfg = Release|x64
+ {45B1B18C-C846-4044-9206-74F58DFC5E88}.Release|x64.Build.0 = Release|x64
+ {45B1B18C-C846-4044-9206-74F58DFC5E88}.Release|x86.ActiveCfg = Release|Win32
+ {45B1B18C-C846-4044-9206-74F58DFC5E88}.Release|x86.Build.0 = Release|Win32
+ {6EC62B0F-9353-40A4-A510-3788F1368B33}.Debug|x64.ActiveCfg = Debug|x64
+ {6EC62B0F-9353-40A4-A510-3788F1368B33}.Debug|x64.Build.0 = Debug|x64
+ {6EC62B0F-9353-40A4-A510-3788F1368B33}.Debug|x86.ActiveCfg = Debug|Win32
+ {6EC62B0F-9353-40A4-A510-3788F1368B33}.Debug|x86.Build.0 = Debug|Win32
+ {6EC62B0F-9353-40A4-A510-3788F1368B33}.Release|x64.ActiveCfg = Release|x64
+ {6EC62B0F-9353-40A4-A510-3788F1368B33}.Release|x64.Build.0 = Release|x64
+ {6EC62B0F-9353-40A4-A510-3788F1368B33}.Release|x86.ActiveCfg = Release|Win32
+ {6EC62B0F-9353-40A4-A510-3788F1368B33}.Release|x86.Build.0 = Release|Win32
+ {2FF15659-5C72-48B8-B55B-3C658E4125B5}.Debug|x64.ActiveCfg = Debug|x64
+ {2FF15659-5C72-48B8-B55B-3C658E4125B5}.Debug|x64.Build.0 = Debug|x64
+ {2FF15659-5C72-48B8-B55B-3C658E4125B5}.Debug|x86.ActiveCfg = Debug|Win32
+ {2FF15659-5C72-48B8-B55B-3C658E4125B5}.Debug|x86.Build.0 = Debug|Win32
+ {2FF15659-5C72-48B8-B55B-3C658E4125B5}.Release|x64.ActiveCfg = Release|x64
+ {2FF15659-5C72-48B8-B55B-3C658E4125B5}.Release|x64.Build.0 = Release|x64
+ {2FF15659-5C72-48B8-B55B-3C658E4125B5}.Release|x86.ActiveCfg = Release|Win32
+ {2FF15659-5C72-48B8-B55B-3C658E4125B5}.Release|x86.Build.0 = Release|Win32
+ {6233C3F2-5781-488E-B190-4FA8836F5A77}.Debug|x64.ActiveCfg = Debug|x64
+ {6233C3F2-5781-488E-B190-4FA8836F5A77}.Debug|x64.Build.0 = Debug|x64
+ {6233C3F2-5781-488E-B190-4FA8836F5A77}.Debug|x86.ActiveCfg = Debug|Win32
+ {6233C3F2-5781-488E-B190-4FA8836F5A77}.Debug|x86.Build.0 = Debug|Win32
+ {6233C3F2-5781-488E-B190-4FA8836F5A77}.Release|x64.ActiveCfg = Release|x64
+ {6233C3F2-5781-488E-B190-4FA8836F5A77}.Release|x64.Build.0 = Release|x64
+ {6233C3F2-5781-488E-B190-4FA8836F5A77}.Release|x86.ActiveCfg = Release|Win32
+ {6233C3F2-5781-488E-B190-4FA8836F5A77}.Release|x86.Build.0 = Release|Win32
+ {0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Debug|x64.ActiveCfg = Debug|x64
+ {0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Debug|x64.Build.0 = Debug|x64
+ {0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Debug|x86.ActiveCfg = Debug|Win32
+ {0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Debug|x86.Build.0 = Debug|Win32
+ {0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Release|x64.ActiveCfg = Release|x64
+ {0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Release|x64.Build.0 = Release|x64
+ {0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Release|x86.ActiveCfg = Release|Win32
+ {0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Release|x86.Build.0 = Release|Win32
+ {5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Debug|x64.ActiveCfg = Debug|x64
+ {5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Debug|x64.Build.0 = Debug|x64
+ {5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Debug|x86.ActiveCfg = Debug|Win32
+ {5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Debug|x86.Build.0 = Debug|Win32
+ {5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Release|x64.ActiveCfg = Release|x64
+ {5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Release|x64.Build.0 = Release|x64
+ {5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Release|x86.ActiveCfg = Release|Win32
+ {5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {0D6869A7-07EB-400F-B2AD-48531564555A}
+ EndGlobalSection
+EndGlobal
diff --git a/GlidePort/GlidePort.vcxproj b/GlidePort/GlidePort.vcxproj
new file mode 100644
index 0000000..ea335fd
--- /dev/null
+++ b/GlidePort/GlidePort.vcxproj
@@ -0,0 +1,122 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {69C3CD2A-3114-4181-884A-C09A4C62FBE0}
+ GlidePort
+ 10.0.16299.0
+
+
+
+ Application
+ true
+ v141
+ MultiByte
+
+
+ Application
+ false
+ v141
+ true
+ MultiByte
+
+
+ Application
+ true
+ v141
+ MultiByte
+
+
+ Application
+ false
+ v141
+ true
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GlidePort/GlidePort.vcxproj.filters b/GlidePort/GlidePort.vcxproj.filters
new file mode 100644
index 0000000..f81daba
--- /dev/null
+++ b/GlidePort/GlidePort.vcxproj.filters
@@ -0,0 +1,17 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
\ No newline at end of file
diff --git a/Glider PRO CW5.mcp b/Glider PRO CW5.mcp
deleted file mode 100755
index 85e1daa..0000000
Binary files a/Glider PRO CW5.mcp and /dev/null differ
diff --git a/Glider PRO.mcp b/Glider PRO.mcp
deleted file mode 100755
index 589be91..0000000
Binary files a/Glider PRO.mcp and /dev/null differ
diff --git a/GpApp/About.cpp b/GpApp/About.cpp
new file mode 100644
index 0000000..c063b14
--- /dev/null
+++ b/GpApp/About.cpp
@@ -0,0 +1,258 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// About.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLNumberFormatting.h"
+#include "PLResources.h"
+#include "PLSound.h"
+#include "PLPasStr.h"
+#include "About.h"
+#include "DialogUtils.h"
+#include "Environ.h"
+#include "Externs.h"
+
+
+static void HiLiteOkayButton (void);
+static void UnHiLiteOkayButton (void);
+static void UpdateMainPict (DialogPtr);
+static Boolean AboutFilter (DialogPtr, EventRecord *theEvent, short *hit);
+
+
+static RgnHandle okayButtRgn;
+static Rect okayButtonBounds, mainPICTBounds;
+static Boolean okayButtIsHiLit, clickedDownInOkay;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DoAbout
+// Brings up the About dialog box.
+
+void DoAbout (void)
+{
+ #define kAboutDialogID 150 // res ID of About dialog
+ #define kTextItemVers 2 // item number of version text
+ #define kPictItemMain 4 // item number of main PICT
+
+ DialogPtr aboutDialog;
+ Str255 longVersion;
+ StringPtr messagePtr;
+ VersRecHndl version;
+ Handle itemHandle;
+ short itemType, hit, wasResFile;
+ ModalFilterUPP aboutFilterUPP;
+
+ aboutFilterUPP = NewModalFilterUPP(AboutFilter);
+
+ wasResFile = CurResFile();
+ UseResFile(thisMac.thisResFile);
+
+ aboutDialog = GetNewDialog(kAboutDialogID, nil, (WindowRef)-1L);
+// if (aboutDialog == nil)
+// RedAlert(kErrDialogDidntLoad);
+
+ version = (VersRecHndl)GetResource('vers', 1);
+ if (version != nil)
+ {
+ messagePtr = (**version).shortVersion + 1 + (**version).shortVersion[0];
+
+ BlockMove((Ptr)messagePtr, &longVersion, ((UInt8)*messagePtr) + 1);
+ SetDialogString(aboutDialog, kTextItemVers, longVersion);
+ }
+
+ GetDialogItem(aboutDialog, kOkayButton, &itemType, &itemHandle, &okayButtonBounds);
+ okayButtRgn = NewRgn(); // Create diagonal button region
+ OpenRgn();
+ MoveTo(okayButtonBounds.left + 1, okayButtonBounds.top + 45);
+ Line(44, -44); // These lines define the region
+ Line(16, 16);
+ Line(-44, 44);
+ Line(-16, -16);
+ CloseRgn(okayButtRgn);
+ okayButtIsHiLit = false; // Initially, button is not hilit
+ clickedDownInOkay = false; // Initially, didn't click in okay button
+ GetDialogItem(aboutDialog, kPictItemMain, &itemType, &itemHandle, &mainPICTBounds);
+
+ do // Loop until user wants to exit
+ {
+ ModalDialog(aboutFilterUPP, &hit);
+ }
+ while ((hit != kOkayButton) && (okayButtRgn != nil));
+
+ if (okayButtRgn != nil)
+ DisposeRgn(okayButtRgn); // Clean up!
+ DisposeDialog(aboutDialog);
+ DisposeModalFilterUPP(aboutFilterUPP);
+
+ UseResFile(wasResFile);
+}
+
+//============================================================== Static Functions
+//-------------------------------------------------------------- HiLiteOkayButton
+// Draws my pseudo-button to appear as though it is clicked on.
+
+static void HiLiteOkayButton (void)
+{
+ #define kOkayButtPICTHiLit 151 // res ID of unhilit button PICT
+ PicHandle thePict;
+
+ if (!okayButtIsHiLit)
+ {
+ thePict = GetPicture(kOkayButtPICTHiLit);
+ if (thePict != nil)
+ {
+ DrawPicture(thePict, &okayButtonBounds);
+ ReleaseResource((Handle)thePict);
+
+ okayButtIsHiLit = true;
+ }
+ }
+}
+
+//-------------------------------------------------------------- UnHiLiteOkayButton
+
+// Draws my pseudo-button normal (not clicked on).
+
+static void UnHiLiteOkayButton (void)
+{
+ #define kOkayButtPICTNotHiLit 150 // res ID of hilit button PICT
+ PicHandle thePict;
+
+ if (okayButtIsHiLit)
+ {
+ thePict = GetPicture(kOkayButtPICTNotHiLit);
+ if (thePict != nil)
+ {
+ DrawPicture(thePict, &okayButtonBounds);
+ ReleaseResource((Handle)thePict);
+
+ okayButtIsHiLit = false;
+ }
+ }
+}
+
+//-------------------------------------------------------------- UpdateMainPict
+// Redraws the main graphic in the dialog (in response to an update event).
+
+static void UpdateMainPict (DialogPtr theDial)
+{
+ Str255 theStr, theStr2;
+ long totalSize, contigSize;
+
+ DrawDialog(theDial);
+
+ PasStringCopy(PSTR("Memory: "), theStr); // display free memory
+ PurgeSpace(&totalSize, &contigSize);
+ totalSize /= 1024;
+ NumToString(totalSize, theStr2);
+ PasStringConcat(theStr, theStr2);
+ PasStringConcat(theStr, PSTR("K"));
+ DrawDialogUserText2(theDial, 7, theStr);
+
+ PasStringCopy(PSTR("Screen: "), theStr); // display screen size/depth
+ NumToString((long)(thisMac.screen.right - thisMac.screen.left), theStr2);
+ PasStringConcat(theStr, theStr2);
+ PasStringConcat(theStr, PSTR("x"));
+ NumToString((long)(thisMac.screen.bottom - thisMac.screen.top), theStr2);
+ PasStringConcat(theStr, theStr2);
+ PasStringConcat(theStr, PSTR("x"));
+ NumToString((long)thisMac.isDepth, theStr2);
+ PasStringConcat(theStr, theStr2);
+ DrawDialogUserText2(theDial, 8, theStr);
+}
+
+//-------------------------------------------------------------- AboutFilter
+// Dialog filter for the About dialog.
+
+static Boolean AboutFilter (DialogPtr theDial, EventRecord *theEvent, short *hit)
+{
+ Point mousePt;
+ UInt32 dummyLong;
+ Boolean handledIt;
+
+ if (Button() && clickedDownInOkay)
+ {
+ GetMouse(&mousePt);
+ if(PtInRgn(mousePt, okayButtRgn))
+ HiLiteOkayButton();
+ else
+ UnHiLiteOkayButton();
+ }
+
+ switch (theEvent->what)
+ {
+ case keyDown:
+ switch ((theEvent->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ HiLiteOkayButton();
+ Delay(8, &dummyLong);
+ UnHiLiteOkayButton();
+ *hit = kOkayButton;
+ handledIt = true;
+ break;
+
+ default:
+ handledIt = false;
+ }
+ break;
+
+ case mouseDown:
+ mousePt = theEvent->where;
+ GlobalToLocal(&mousePt);
+ if(PtInRgn(mousePt, okayButtRgn))
+ {
+ clickedDownInOkay = true;
+ handledIt = false;
+ }
+ else
+ handledIt = false;
+ break;
+
+ case mouseUp:
+ mousePt = theEvent->where;
+ GlobalToLocal(&mousePt);
+ if(PtInRgn(mousePt, okayButtRgn) && clickedDownInOkay)
+ {
+ UnHiLiteOkayButton();
+ *hit = kOkayButton;
+ handledIt = true;
+ }
+ else
+ {
+ clickedDownInOkay = false;
+ handledIt = false;
+ }
+ break;
+
+ case updateEvt:
+ if ((WindowPtr)theEvent->message == mainWindow)
+ {
+ SetPort((GrafPtr)mainWindow);
+ BeginUpdate((WindowPtr)theEvent->message);
+ UpdateMainWindow();
+ EndUpdate((WindowPtr)theEvent->message);
+ SetPortDialogPort(theDial);
+ handledIt = true;
+ }
+ else if ((WindowPtr)theEvent->message == (WindowPtr)theDial)
+ {
+ SetPortDialogPort(theDial);
+ BeginUpdate((WindowPtr)theEvent->message);
+ UpdateMainPict(theDial);
+ EndUpdate((WindowPtr)theEvent->message);
+ handledIt = false;
+ }
+ break;
+
+ default:
+ handledIt = false;
+ break;
+ }
+
+ return (handledIt);
+}
+
diff --git a/GpApp/About.h b/GpApp/About.h
new file mode 100644
index 0000000..a90709e
--- /dev/null
+++ b/GpApp/About.h
@@ -0,0 +1,10 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// About.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+void DoAbout (void);
+
+
diff --git a/GpApp/AnimCursor.cpp b/GpApp/AnimCursor.cpp
new file mode 100644
index 0000000..a8cd342
--- /dev/null
+++ b/GpApp/AnimCursor.cpp
@@ -0,0 +1,286 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// AnimCursor.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLResources.h"
+#include "PLBigEndian.h"
+#include "Externs.h"
+#include "Environ.h"
+
+
+#define rAcurID 128
+#define rHandCursorID 1000
+
+
+typedef struct
+{
+ BEInt16_t n;
+ BEInt16_t index;
+ struct
+ {
+ BEInt16_t resID;
+ BEInt16_t reserved;
+ } frame[1];
+} acurRec, *acurPtr, **acurHandle;
+
+typedef struct
+{
+ struct
+ {
+ Handle cursorHdl;
+ } frame[1];
+} compiledAcurRec, *compiledAcurPtr, **compiledAcurHandle;
+
+
+Boolean GetMonoCursors (acurHandle, compiledAcurHandle);
+Boolean GetColorCursors (acurHandle, compiledAcurHandle);
+void InitAnimatedCursor (acurHandle);
+
+
+acurHandle animCursorH = nil;
+compiledAcurHandle compiledAnimCursorH = nil;
+Boolean useColorCursor = false;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- GetMonoCursors
+
+// Loads b&w cursors (for animated beach ball).
+
+Boolean GetMonoCursors (acurHandle ballCursH, compiledAcurHandle compiledBallCursH)
+{
+ short i, j;
+ CursHandle cursHdl;
+
+ if (ballCursH) // Were we passed a legit acur handle?
+ {
+ j = (*ballCursH)->n; // Get number of 'frames' in the acur
+ for (i = 0; i < j; i++) // Start walking the frames
+ {
+ cursHdl = GetCursor((*ballCursH)->frame[i].resID);
+ if (cursHdl == nil) // Did the cursor load? It didn't?...
+ { // Well then, toss what we got.
+ for (j = 0; j < i; j++)
+ DisposeHandle((*compiledBallCursH)->frame[j].cursorHdl);
+ return(false); // And report this to mother.
+ } // However!...
+ else // If cursor loaded ok...
+ { // Detach it from the resource map...
+ DetachResource((Handle)cursHdl); // And assign to our struct
+ (*compiledBallCursH)->frame[i].cursorHdl = (Handle)cursHdl;
+ }
+ }
+ }
+ return(true);
+}
+
+//-------------------------------------------------------------- GetColorCursors
+
+// Loads color cursors (for animated beach ball).
+
+Boolean GetColorCursors (acurHandle ballCursH, compiledAcurHandle compiledBallCursH)
+{
+ short i, j;
+ CCrsrHandle cursHdl;
+ Boolean result = true;
+
+ if (ballCursH)
+ {
+ j = (*ballCursH)->n; // Get the number of cursors
+ HideCursor(); // Hide the cursor
+ for (i = 0; i < j; i++) // Walk through the acur resource
+ {
+ cursHdl = GetCCursor((*ballCursH)->frame[i].resID); // Get the cursor
+ if (cursHdl == nil) // Make sure a real cursor was returned
+ { // If not, trash all cursors loaded
+ for (j = 0; j < i; j++)
+ DisposeCCursor((CCrsrHandle)(*compiledBallCursH)->frame[j].cursorHdl);
+ result = false; // Tell calling proc we failed
+ break; // And break out of the loop
+ }
+ else // But, if the cursor loaded ok
+ { // add it to our list or cursor handles
+ (*compiledBallCursH)->frame[i].cursorHdl = (Handle)cursHdl;
+ SetCCursor((CCrsrHandle)(*compiledBallCursH)->frame[i].cursorHdl);
+ }
+ }
+ InitCursor(); // Show the cursor again (as arrow)
+ }
+ return(result); // Return to calling proc w/ results
+}
+
+//-------------------------------------------------------------- InitAnimatedCursor
+
+// Loads and sets up animated beach ball cursor structures.
+
+void InitAnimatedCursor (acurHandle ballCursH)
+{
+ Boolean useColor;
+ compiledAcurHandle compiledBallCursorH;
+
+ useColor = thisMac.hasColor;
+ if (ballCursH == nil)
+ ballCursH = reinterpret_cast(GetResource('acur', 128));
+ if (ballCursH && ballCursH != animCursorH)
+ {
+ compiledBallCursorH = (compiledAcurHandle)NewHandle(sizeof(compiledAcurRec) * (*ballCursH)->n);
+ if (!compiledBallCursorH)
+ RedAlert(kErrFailedResourceLoad);
+
+ HNoPurge((Handle)ballCursH);
+ MoveHHi((Handle)ballCursH);
+ HLock((Handle)ballCursH);
+ if (useColor)
+ useColor = GetColorCursors(ballCursH, compiledBallCursorH);
+ if (!useColor && !GetMonoCursors(ballCursH, compiledBallCursorH))
+ RedAlert(kErrFailedResourceLoad);
+ DisposCursors();
+
+ animCursorH = ballCursH;
+ compiledAnimCursorH = compiledBallCursorH;
+ useColorCursor = useColor;
+ (*ballCursH)->index = 0;
+ }
+ else
+ RedAlert(kErrFailedResourceLoad);
+}
+
+//-------------------------------------------------------------- LoadCursors
+
+// Just calls the above function. Other code could be added here thoughÉ
+// to add additional cursors.
+
+void LoadCursors (void)
+{
+ InitAnimatedCursor((acurHandle)GetResource('acur', rAcurID));
+}
+
+//-------------------------------------------------------------- DisposCursors
+
+// Disposes of all memory allocated by anaimated beach ball cursors.
+
+void DisposCursors (void)
+{
+ register short i, j;
+
+ if (compiledAnimCursorH != nil)
+ {
+ j = (*animCursorH)->n;
+ if (useColorCursor)
+ {
+ for (i = 0; i < j; i++)
+ {
+ if ((*compiledAnimCursorH)->frame[i].cursorHdl != nil)
+ DisposeCCursor((CCrsrHandle)(*compiledAnimCursorH)->frame[i].cursorHdl);
+ }
+ }
+ else
+ {
+ for (i = 0; i < j; i++)
+ {
+ if ((*compiledAnimCursorH)->frame[i].cursorHdl != nil)
+ DisposeHandle((Handle)(*compiledAnimCursorH)->frame[i].cursorHdl);
+ }
+ }
+ DisposeHandle((Handle)compiledAnimCursorH);
+ compiledAnimCursorH = nil;
+ }
+
+ if (animCursorH != nil)
+ {
+ ReleaseResource((Handle)animCursorH);
+ animCursorH = nil;
+ }
+}
+
+//-------------------------------------------------------------- IncrementCursor
+
+// Advances the beach ball cursor one frame.
+
+void IncrementCursor (void)
+{
+ if (animCursorH == 0)
+ InitAnimatedCursor(nil);
+ if (animCursorH)
+ {
+ (*animCursorH)->index++;
+ (*animCursorH)->index %= (*animCursorH)->n;
+ if (useColorCursor)
+ {
+ SetCCursor((CCrsrHandle)(*compiledAnimCursorH)->
+ frame[(*animCursorH)->index].cursorHdl);
+ }
+ else
+ {
+ SetCursor((CursPtr)*(*compiledAnimCursorH)->
+ frame[(*animCursorH)->index].cursorHdl);
+ }
+ }
+ else
+ SetCursor((CursPtr)*GetCursor(watchCursor));
+}
+
+//-------------------------------------------------------------- DecrementCursor
+
+// Reverses the beach ball cursor one frame.
+
+void DecrementCursor (void)
+{
+ if (animCursorH == 0)
+ InitAnimatedCursor(nil);
+ if (animCursorH)
+ {
+ (*animCursorH)->index--;
+ if (((*animCursorH)->index) < 0)
+ (*animCursorH)->index = ((*animCursorH)->n) - 1;
+ if (useColorCursor)
+ {
+ SetCCursor((CCrsrHandle)(*compiledAnimCursorH)->
+ frame[(*animCursorH)->index].cursorHdl);
+ }
+ else
+ {
+ SetCursor((CursPtr)*(*compiledAnimCursorH)->
+ frame[(*animCursorH)->index].cursorHdl);
+ }
+ }
+ else
+ SetCursor((CursPtr)*GetCursor(watchCursor));
+}
+
+//-------------------------------------------------------------- SpinCursor
+
+// Advances the beach ball cursor the number of frames specified.
+
+void SpinCursor (short incrementIndex)
+{
+ UInt32 dummyLong;
+ short i;
+
+ for (i = 0; i < incrementIndex; i++)
+ {
+ IncrementCursor();
+ Delay(1, &dummyLong);
+ }
+}
+
+//-------------------------------------------------------------- BackSpinCursor
+
+// Reverses the beach ball cursor the number of frames specified.
+
+void BackSpinCursor (short decrementIndex)
+{
+ UInt32 dummyLong;
+ short i;
+
+ for (i = 0; i < decrementIndex; i++)
+ {
+ DecrementCursor();
+ Delay(1, &dummyLong);
+ }
+}
+
diff --git a/GpApp/AppleEvents.cpp b/GpApp/AppleEvents.cpp
new file mode 100644
index 0000000..d4fd275
--- /dev/null
+++ b/GpApp/AppleEvents.cpp
@@ -0,0 +1,202 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// AppleEvents.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLAppleEvents.h"
+#include "Externs.h"
+#include "House.h"
+
+
+#define kNoPrintingAlert 1031
+
+
+OSErr DoOpenAppAE (const AppleEvent *, AppleEvent *, UInt32);
+OSErr DoOpenDocAE (const AppleEvent *, AppleEvent *, UInt32);
+OSErr DoPrintDocAE (const AppleEvent *, AppleEvent *, UInt32);
+OSErr DoQuitAE (const AppleEvent *, AppleEvent *, UInt32);
+OSErr MyGotRequiredParams (const AppleEvent *);
+
+AEEventHandlerUPP openAppAEUPP, openDocAEUPP, printDocAEUPP, quitAEUPP;
+
+
+extern FSSpecPtr theHousesSpecs;
+extern long incrementModeTime;
+extern short thisHouseIndex, splashOriginH, splashOriginV;
+extern Boolean quitting;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DoOpenAppAE
+// Handles an "Open Application" Apple Event.
+
+OSErr DoOpenAppAE (const AppleEvent *theAE, AppleEvent *reply, UInt32 ref)
+{
+ OSErr theErr;
+
+ theErr = MyGotRequiredParams(theAE);
+ return (theErr);
+}
+
+//-------------------------------------------------------------- DoOpenDocAE
+// Handles an "Open Document" Apple Event.
+
+OSErr DoOpenDocAE (const AppleEvent *theAE, AppleEvent *reply, UInt32 ref)
+{
+ FSSpec oneFSS;
+ FInfo finderInfo;
+ AEDescList docList;
+ long itemsInList;
+ Size actualSize;
+ AEKeyword keywd;
+ DescType returnedType;
+ OSErr theErr, whoCares;
+ short i;
+
+ theErr = AEGetParamDesc(theAE, keyDirectObject, typeAEList, &docList);
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowAppleEventErr, theErr);
+ return (theErr);
+ }
+
+ theErr = MyGotRequiredParams(theAE);
+ if (theErr != noErr)
+ {
+ whoCares = AEDisposeDesc(&docList);
+ return (theErr);
+ }
+
+ theErr = AECountItems(&docList, &itemsInList);
+ if (theErr != noErr)
+ {
+ whoCares = AEDisposeDesc(&docList);
+ return (theErr);
+ }
+
+#ifndef COMPILEDEMO
+ for (i = 1; i <= itemsInList; i++)
+ {
+ theErr = AEGetNthPtr(&docList, i, typeFSS, &keywd, &returnedType,
+ &oneFSS, sizeof(oneFSS), &actualSize);
+ if (theErr == noErr)
+ {
+ theErr = FSpGetFInfo(&oneFSS, &finderInfo);
+ if ((theErr == noErr) && (finderInfo.fdType == 'gliH'))
+ AddExtraHouse(&oneFSS);
+ }
+ }
+ if (itemsInList > 0)
+ {
+ theErr = AEGetNthPtr(&docList, 1, typeFSS, &keywd, &returnedType,
+ &oneFSS, sizeof(oneFSS), &actualSize);
+ if (theErr == noErr)
+ {
+ theErr = FSpGetFInfo(&oneFSS, &finderInfo);
+ if ((theErr == noErr) && (finderInfo.fdType == 'gliH'))
+ {
+ whoCares = CloseHouse();
+ PasStringCopy(oneFSS.name, thisHouseName);
+ BuildHouseList();
+ if (OpenHouse())
+ whoCares = ReadHouse();
+ PasStringCopy(theHousesSpecs[thisHouseIndex].name, thisHouseName);
+ OpenCloseEditWindows();
+ incrementModeTime = TickCount() + kIdleSplashTicks;
+ if ((theMode == kSplashMode) || (theMode == kPlayMode))
+ {
+ Rect updateRect;
+
+ SetRect(&updateRect, splashOriginH + 474, splashOriginV + 304, splashOriginH + 474 + 166, splashOriginV + 304 + 12);
+ InvalWindowRect(mainWindow, &updateRect);
+ }
+ }
+ }
+ InitCursor();
+ }
+#endif
+ whoCares = AEDisposeDesc(&docList);
+
+ return theErr;
+}
+
+//-------------------------------------------------------------- DoPrintDocAE
+// Handles a "Print Document" Apple Event.
+
+OSErr DoPrintDocAE (const AppleEvent *theAE, AppleEvent *reply, UInt32 ref)
+{
+ short hitWhat;
+
+// CenterAlert(kNoPrintingAlert);
+ hitWhat = Alert(kNoPrintingAlert, nil);
+
+ return errAEEventNotHandled;
+}
+
+//-------------------------------------------------------------- DoQuitAE
+// Handles a "Quit Application" Apple Event.
+
+OSErr DoQuitAE (const AppleEvent *theAE, AppleEvent *reply, UInt32 ref)
+{
+ OSErr isHuman;
+
+ isHuman = MyGotRequiredParams(theAE);
+ if (isHuman == noErr)
+ quitting = true;
+
+ return isHuman;
+}
+
+//-------------------------------------------------------------- MyGotRequiredParams
+// Have no clue! :)
+
+OSErr MyGotRequiredParams (const AppleEvent *theAE)
+{
+ DescType returnedType;
+ Size actualSize;
+
+ return (AEGetAttributePtr(theAE, keyMissedKeywordAttr, typeWildCard,
+ &returnedType, 0L, 0, &actualSize) == errAEDescNotFound) ? noErr :
+ errAEParamMissed;
+}
+
+//-------------------------------------------------------------- SetUpAppleEvents
+// Initializes all handlers, etc. for dealing with Apple Events.
+
+void SetUpAppleEvents (void)
+{
+ OSErr theErr;
+
+ openAppAEUPP = NewAEEventHandlerProc(DoOpenAppAE);
+ openDocAEUPP = NewAEEventHandlerProc(DoOpenDocAE);
+ printDocAEUPP = NewAEEventHandlerProc(DoPrintDocAE);
+ quitAEUPP = NewAEEventHandlerProc(DoQuitAE);
+
+ theErr = AEInstallEventHandler(kCoreEventClass, // install oapp
+ kAEOpenApplication, openAppAEUPP, 0, false);
+ if (theErr != noErr)
+ YellowAlert(kYellowAppleEventErr, theErr);
+
+ theErr = AEInstallEventHandler(kCoreEventClass, // install odoc
+ kAEOpenDocuments, openDocAEUPP, 0, false);
+ if (theErr != noErr)
+ YellowAlert(kYellowAppleEventErr, theErr);
+
+ theErr = AEInstallEventHandler(kCoreEventClass, // install pdoc
+ kAEPrintDocuments, printDocAEUPP, 0, false);
+ if (theErr != noErr)
+ YellowAlert(kYellowAppleEventErr, theErr);
+
+ theErr = AEInstallEventHandler(kCoreEventClass, // install quit
+ kAEQuitApplication, quitAEUPP, 0, false);
+ if (theErr != noErr)
+ YellowAlert(kYellowAppleEventErr, theErr);
+
+ theErr = AESetInteractionAllowed(kAEInteractWithAll);
+ if (theErr != noErr)
+ YellowAlert(kYellowAppleEventErr, theErr);
+}
+
diff --git a/GpApp/Banner.cpp b/GpApp/Banner.cpp
new file mode 100644
index 0000000..9a393d8
--- /dev/null
+++ b/GpApp/Banner.cpp
@@ -0,0 +1,238 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Banner.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLNumberFormatting.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "MainWindow.h"
+#include "RectUtils.h"
+#include "Room.h"
+#include "Utilities.h"
+
+
+#define kBannerPageTopPICT 1993
+#define kBannerPageBottomPICT 1992
+#define kBannerPageBottomMask 1991
+#define kStarsRemainingPICT 1017
+#define kStarRemainingPICT 1018
+
+
+void DrawBanner (Point *);
+void DrawBannerMessage (Point);
+
+
+short numStarsRemaining;
+Boolean bannerStarCountOn;
+
+extern Rect justRoomsRect;
+extern Boolean quickerTransitions, demoGoing, isUseSecondScreen;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DrawBanner
+// Displays opening banner (when a new game is begun). The banner looksÉ
+// like a sheet of notebook paper. The text printed on it is specifiedÉ
+// by the author of the house.
+
+void DrawBanner (Point *topLeft)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ Rect wholePage, partPage, mapBounds;
+ GWorldPtr tempMap;
+ GWorldPtr tempMask;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&wholePage, 0, 0, 330, 220);
+ mapBounds = thisMac.screen;
+ ZeroRectCorner(&mapBounds);
+ CenterRectInRect(&wholePage, &mapBounds);
+ topLeft->h = wholePage.left;
+ topLeft->v = wholePage.top;
+ partPage = wholePage;
+ partPage.bottom = partPage.top + 190;
+ SetGWorld(workSrcMap, nil);
+ LoadScaledGraphic(kBannerPageTopPICT, &partPage);
+
+ partPage = wholePage;
+ partPage.top = partPage.bottom - 30;
+ mapBounds = partPage;
+ ZeroRectCorner(&mapBounds);
+ theErr = CreateOffScreenGWorld(&tempMap, &mapBounds, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(kBannerPageBottomPICT);
+
+ theErr = CreateOffScreenGWorld(&tempMask, &mapBounds, 1);
+ SetGWorld(tempMask, nil);
+ LoadGraphic(kBannerPageBottomMask);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(tempMask),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &mapBounds, &mapBounds, &partPage);
+ SetPort((GrafPtr)workSrcMap);
+
+ SetGWorld(wasCPort, wasWorld);
+ DisposeGWorld(tempMap);
+ DisposeGWorld(tempMask);
+}
+
+//-------------------------------------------------------------- CountStarsInHouse
+// Goes through the current house and counts the total number of stars within.
+
+short CountStarsInHouse (void)
+{
+ short i, h, numRooms, numStars;
+ char wasState;
+
+ numStars = 0;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ 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 == kStar)
+ numStars++;
+ }
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ return (numStars);
+}
+
+//-------------------------------------------------------------- DrawBannerMessage
+
+// This function prints the author's message acorss the notebook paper banner.
+
+void DrawBannerMessage (Point topLeft)
+{
+ Str255 bannerStr, subStr;
+ short count;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ PasStringCopy((*thisHouse)->banner, bannerStr);
+ HSetState((Handle)thisHouse, wasState);
+
+ TextFont(applFont);
+ TextFace(bold);
+ TextSize(12);
+ ForeColor(blackColor);
+ count = 0;
+ do
+ {
+ GetLineOfText(bannerStr, count, subStr);
+ MoveTo(topLeft.h + 16, topLeft.v + 32 + (count * 20));
+ DrawString(subStr);
+ count++;
+ }
+ while (subStr[0] > 0);
+
+ if (bannerStarCountOn)
+ {
+ if (numStarsRemaining != 1)
+ GetLocalizedString(1, bannerStr);
+ else
+ GetLocalizedString(2, bannerStr);
+
+ NumToString((long)numStarsRemaining, subStr);
+ PasStringConcat(bannerStr, subStr);
+
+ if (numStarsRemaining != 1)
+ GetLocalizedString(3, subStr);
+ else
+ GetLocalizedString(4, subStr);
+ PasStringConcat(bannerStr, subStr);
+
+ ForeColor(redColor);
+ MoveTo(topLeft.h + 16, topLeft.v + 164);
+ DrawString(bannerStr);
+ MoveTo(topLeft.h + 16, topLeft.v + 180);
+ GetLocalizedString(5, subStr);
+ DrawString(subStr);
+ }
+ ForeColor(blackColor);
+}
+
+//-------------------------------------------------------------- BringUpBanner
+// Handles bringing up displaying and disposing of the banner.
+
+void BringUpBanner (void)
+{
+ Rect wholePage;
+ Point topLeft;
+
+ DrawBanner(&topLeft);
+ DrawBannerMessage(topLeft);
+// if (quickerTransitions)
+// DissBitsChunky(&justRoomsRect); // was workSrcRect
+// else
+// DissBits(&justRoomsRect);
+ QSetRect(&wholePage, 0, 0, 330, 220);
+ QOffsetRect(&wholePage, topLeft.h, topLeft.v);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &wholePage, &wholePage, srcCopy, nil);
+
+ if (demoGoing)
+ WaitForInputEvent(4);
+ else
+ WaitForInputEvent(15);
+
+// if (quickerTransitions)
+// DissBitsChunky(&justRoomsRect);
+// else
+// DissBits(&justRoomsRect);
+}
+
+//-------------------------------------------------------------- DisplayStarsRemaining
+// This brings up a small message indicating the number of stars remainingÉ
+// in a house. It comes up when the player gets a star (the game is pausedÉ
+// and the user informed as to how many remain).
+
+void DisplayStarsRemaining (void)
+{
+ Rect src, bounds;
+ Str255 theStr;
+
+ SetPortWindowPort(mainWindow);
+ QSetRect(&bounds, 0, 0, 256, 64);
+ CenterRectInRect(&bounds, &thisMac.screen);
+ QOffsetRect(&bounds, -thisMac.screen.left, -thisMac.screen.top);
+ src = bounds;
+ InsetRect(&src, 64, 32);
+
+ TextFont(applFont);
+ TextFace(bold);
+ TextSize(12);
+ NumToString((long)numStarsRemaining, theStr);
+
+ QOffsetRect(&bounds, 0, -20);
+ if (numStarsRemaining < 2)
+ LoadScaledGraphic(kStarRemainingPICT, &bounds);
+ else
+ {
+ LoadScaledGraphic(kStarsRemainingPICT, &bounds);
+ MoveTo(bounds.left + 102 - (StringWidth(theStr) / 2), bounds.top + 23);
+ ColorText(theStr, 4L);
+ }
+
+ DelayTicks(60);
+ if (WaitForInputEvent(30))
+ RestoreEntireGameScreen();
+ CopyRectWorkToMain(&bounds);
+}
+
diff --git a/GpApp/ColorUtils.cpp b/GpApp/ColorUtils.cpp
new file mode 100644
index 0000000..f7f45b6
--- /dev/null
+++ b/GpApp/ColorUtils.cpp
@@ -0,0 +1,225 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// ColorUtils.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "PLPalettes.h"
+#include "PLPasStr.h"
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- ColorText
+
+// Given a string and a color index (index into the current palette),É
+// this function draws text in that color. It assumes the current port,É
+// the current font, the current pen location, etc.
+
+void ColorText (StringPtr theStr, long color)
+{
+ RGBColor theRGBColor, wasColor;
+
+ GetForeColor(&wasColor);
+ Index2Color(color, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ DrawString(theStr);
+ RGBForeColor(&wasColor);
+}
+
+//-------------------------------------------------------------- ColorRect
+
+// Given a rectangle and color index, this function draws a solidÉ
+// rectangle in that color. Current port, pen mode, etc. assumed.
+
+void ColorRect (Rect *theRect, long color)
+{
+ RGBColor theRGBColor, wasColor;
+
+ GetForeColor(&wasColor);
+ Index2Color(color, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ PaintRect(theRect);
+ RGBForeColor(&wasColor);
+}
+
+//-------------------------------------------------------------- ColorOval
+
+// Given a rectangle and color index, this function draws a solidÉ
+// oval in that color. Current port, pen mode, etc. assumed.
+
+void ColorOval (Rect *theRect, long color)
+{
+ RGBColor theRGBColor, wasColor;
+
+ GetForeColor(&wasColor);
+ Index2Color(color, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ PaintOval(theRect);
+ RGBForeColor(&wasColor);
+}
+
+//-------------------------------------------------------------- ColorRegion
+
+// Given a region and color index, this function draws a solidÉ
+// region in that color. Current port, pen mode, etc. assumed.
+
+void ColorRegion (RgnHandle theRgn, long color)
+{
+ RGBColor theRGBColor, wasColor;
+
+ GetForeColor(&wasColor);
+ Index2Color(color, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ PaintRgn(theRgn);
+ RGBForeColor(&wasColor);
+}
+
+//-------------------------------------------------------------- ColorLine
+
+// Given a the end points for a line and color index, this functionÉ
+// draws a line in that color. Current port, pen mode, etc. assumed.
+
+void ColorLine (short h0, short v0, short h1, short v1, long color)
+{
+ RGBColor theRGBColor, wasColor;
+
+ GetForeColor(&wasColor);
+ Index2Color(color, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ MoveTo(h0, v0);
+ LineTo(h1, v1);
+ RGBForeColor(&wasColor);
+}
+
+//-------------------------------------------------------------- HiliteRect
+
+// Given a rect and two hilite colors, this function frames the top andÉ
+// left edges of the rect with color 1 and frames the bottom and rightÉ
+// sides with color 2. A rect can be made to appear "hi-lit" or "3D"É
+// in this way.
+
+void HiliteRect (Rect *theRect, short color1, short color2)
+{
+ ColorLine(theRect->left, theRect->top, theRect->right - 2,
+ theRect->top, color1);
+ ColorLine(theRect->left, theRect->top, theRect->left,
+ theRect->bottom - 2, color1);
+ ColorLine(theRect->right - 1, theRect->top, theRect->right - 1,
+ theRect->bottom - 2, color2);
+ ColorLine(theRect->left + 1, theRect->bottom - 1, theRect->right - 1,
+ theRect->bottom - 1, color2);
+}
+
+//-------------------------------------------------------------- ColorFrameRect
+
+// Given a rectangle and color index, this function frames aÉ
+// rectangle in that color. Current port, pen mode, etc. assumed.
+
+void ColorFrameRect (Rect *theRect, long color)
+{
+ RGBColor theRGBColor, wasColor;
+
+ GetForeColor(&wasColor);
+ Index2Color(color, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ FrameRect(theRect);
+ RGBForeColor(&wasColor);
+}
+
+//-------------------------------------------------------------- ColorFrameWHRect
+
+// Given a the top-left corner of a rectangle, its width and height,É
+// and a color index, this function frames a rectangle in that color.
+// Current port, pen mode, etc. assumed.
+
+void ColorFrameWHRect (short left, short top, short wide, short high, long color)
+{
+ Rect theRect;
+
+ theRect.left = left;
+ theRect.top = top;
+ theRect.right = left + wide;
+ theRect.bottom = top + high;
+ ColorFrameRect(&theRect, color);
+}
+
+//-------------------------------------------------------------- ColorFrameOval
+
+// Given a rectangle and color index, this function frames anÉ
+// oval in that color. Current port, pen mode, etc. assumed.
+
+void ColorFrameOval (Rect *theRect, long color)
+{
+ RGBColor theRGBColor, wasColor;
+
+ GetForeColor(&wasColor);
+ Index2Color(color, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ FrameOval(theRect);
+ RGBForeColor(&wasColor);
+}
+
+//-------------------------------------------------------------- LtGrayForeColor
+
+// This function finds the closest match to a "light gray" in theÉ
+// current palette and sets the pen color to that.
+
+void LtGrayForeColor (void)
+{
+ RGBColor color;
+
+ color.red = (unsigned short) 0xBFFF;
+ color.green = (unsigned short) 0xBFFF;
+ color.blue = (unsigned short) 0xBFFF;
+
+ RGBForeColor(&color);
+}
+
+//-------------------------------------------------------------- GrayForeColor
+
+// This function finds the closest match to a "medium gray" in theÉ
+// current palette and sets the pen color to that.
+
+void GrayForeColor (void)
+{
+ RGBColor color;
+
+ color.red = (unsigned short) 0x7FFF;
+ color.green = (unsigned short) 0x7FFF;
+ color.blue = (unsigned short) 0x7FFF;
+
+ RGBForeColor(&color);
+}
+
+//-------------------------------------------------------------- DkGrayForeColor
+
+// This function finds the closest match to a "dark gray" in theÉ
+// current palette and sets the pen color to that.
+
+void DkGrayForeColor (void)
+{
+ RGBColor color;
+
+ color.red = (unsigned short) 0x3FFF;
+ color.green = (unsigned short) 0x3FFF;
+ color.blue = (unsigned short) 0x3FFF;
+
+ RGBForeColor(&color);
+}
+
+//-------------------------------------------------------------- RestoreColorsSlam
+
+// This function forces the Macintosh to rebuild the palette. It isÉ
+// called to restore a sense or normality after some serious mungingÉ
+// with the palette.
+
+void RestoreColorsSlam (void)
+{
+ RestoreDeviceClut(nil);
+ PaintBehind(nil, GetGrayRgn());
+ DrawMenuBar();
+}
+
diff --git a/GpApp/Coordinates.cpp b/GpApp/Coordinates.cpp
new file mode 100644
index 0000000..362586c
--- /dev/null
+++ b/GpApp/Coordinates.cpp
@@ -0,0 +1,197 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Coordinates.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLNumberFormatting.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "Marquee.h"
+#include "ObjectEdit.h"
+#include "RectUtils.h"
+
+
+Rect coordWindowRect;
+WindowPtr coordWindow;
+short isCoordH, isCoordV;
+short coordH, coordV, coordD;
+Boolean isCoordOpen;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- SetCoordinateHVD
+
+// Given a horizontal, vertical and distance value, this functionÉ
+// displays these values in the Coordinates window.
+
+void SetCoordinateHVD (short h, short v, short d)
+{
+#ifndef COMPILEDEMO
+ if (h != -2)
+ coordH = h;
+ if (v != -2)
+ coordV = v;
+ if (d != -2)
+ coordD = d;
+ UpdateCoordWindow();
+#endif
+}
+
+//-------------------------------------------------------------- DeltaCoordinateD
+
+// When the user is dragging a handle (such as the height of a blower)É
+// this function can be called and passed the amount by which the userÉ
+// has changed the height (delta). This function then displays it inÉ
+// the Coordinate window.
+
+void DeltaCoordinateD (short d)
+{
+#ifndef COMPILEDEMO
+ coordD = d;
+ UpdateCoordWindow();
+#endif
+}
+
+//-------------------------------------------------------------- UpdateCoordWindow
+
+// Completely redraws and updates the Coordinate window.
+
+void UpdateCoordWindow (void)
+{
+#ifndef COMPILEDEMO
+ Str255 tempStr, numStr;
+ GrafPtr wasPort;
+
+ if (coordWindow == nil)
+ return;
+
+ GetPort(&wasPort);
+ SetPort((GrafPtr)coordWindow);
+ EraseRect(&coordWindowRect);
+
+ PasStringCopy(PSTR("h: "), tempStr);
+ if (coordH != -1)
+ {
+ NumToString((long)coordH, numStr);
+ PasStringConcat(tempStr, numStr);
+ }
+ else
+ PasStringConcat(tempStr, PSTR("-"));
+ MoveTo(5, 12);
+ DrawString(tempStr);
+
+ PasStringCopy(PSTR("v: "), tempStr);
+ if (coordV != -1)
+ {
+ NumToString((long)coordV, numStr);
+ PasStringConcat(tempStr, numStr);
+ }
+ else
+ PasStringConcat(tempStr, PSTR("-"));
+ MoveTo(4, 22);
+ DrawString(tempStr);
+
+ ForeColor(blueColor);
+ PasStringCopy(PSTR("d: "), tempStr);
+ if (coordD != -1)
+ {
+ NumToString((long)coordD, numStr);
+ PasStringConcat(tempStr, numStr);
+ }
+ else
+ PasStringConcat(tempStr, PSTR("-"));
+ MoveTo(5, 32);
+ DrawString(tempStr);
+ ForeColor(blackColor);
+
+ SetPort((GrafPtr)wasPort);
+#endif
+}
+
+//-------------------------------------------------------------- OpenCoordWindow
+// Brings up the Coordinate window.
+
+void OpenCoordWindow (void)
+{
+#ifndef COMPILEDEMO
+ Rect src, dest;
+ Point globalMouse;
+ short direction, dist;
+
+ if (coordWindow == nil)
+ {
+ QSetRect(&coordWindowRect, 0, 0, 50, 38);
+ if (thisMac.hasColor)
+ coordWindow = NewCWindow(nil, &coordWindowRect,
+ PSTR("Tools"), false, kWindoidWDEF, kPutInFront, true, 0L);
+ else
+ coordWindow = NewWindow(nil, &coordWindowRect,
+ PSTR("Tools"), false, kWindoidWDEF, kPutInFront, true, 0L);
+
+ if (coordWindow == nil)
+ RedAlert(kErrNoMemory);
+
+// if (OptionKeyDown())
+// {
+// isCoordH = qd.screenBits.bounds.right - 55;
+// isCoordV = 204;
+// }
+ MoveWindow(coordWindow, isCoordH, isCoordV, true);
+ globalMouse = MyGetGlobalMouse();
+ QSetRect(&src, 0, 0, 1, 1);
+ QOffsetRect(&src, globalMouse.h, globalMouse.v);
+ GetWindowRect(coordWindow, &dest);
+ BringToFront(coordWindow);
+ ShowHide(coordWindow, true);
+// FlagWindowFloating(coordWindow); TEMP - use flaoting windows
+ HiliteAllWindows();
+
+ coordH = -1;
+ coordV = -1;
+ coordD = -1;
+ TextFace(applFont);
+ TextSize(9);
+
+ if (objActive != kNoObjectSelected)
+ {
+ if (ObjectHasHandle(&direction, &dist))
+ coordD = dist;
+ SetCoordinateHVD(theMarquee.bounds.left, theMarquee.bounds.top, coordD);
+ }
+ }
+
+ UpdateCoordinateCheckmark(true);
+#endif
+}
+
+//-------------------------------------------------------------- CloseCoordWindow
+// Closes and disposes of the Coordinate window.
+
+void CloseCoordWindow (void)
+{
+ CloseThisWindow(&coordWindow);
+ UpdateCoordinateCheckmark(false);
+}
+
+//-------------------------------------------------------------- ToggleCoordinateWindow
+// Toggles the Coordinate windows state between open and closed.
+
+void ToggleCoordinateWindow (void)
+{
+#ifndef COMPILEDEMO
+ if (coordWindow == nil)
+ {
+ OpenCoordWindow();
+ isCoordOpen = true;
+ }
+ else
+ {
+ CloseCoordWindow();
+ isCoordOpen = false;
+ }
+#endif
+}
+
diff --git a/Sources/DebugUtilities.c b/GpApp/DebugUtilities.c
old mode 100755
new mode 100644
similarity index 100%
rename from Sources/DebugUtilities.c
rename to GpApp/DebugUtilities.c
diff --git a/GpApp/DialogUtils.cpp b/GpApp/DialogUtils.cpp
new file mode 100644
index 0000000..85e5c00
--- /dev/null
+++ b/GpApp/DialogUtils.cpp
@@ -0,0 +1,807 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// DialogUtils.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLControlDefinitions.h"
+#include "PLLowMem.h"
+#include "PLNumberFormatting.h"
+#include "PLPasStr.h"
+#include "DialogUtils.h"
+#include "Externs.h"
+
+
+#define kActive 0
+#define kInactive 255
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- BringUpDialog
+// Given a dialog pointer and a resource ID, this function brings it upÉ
+// centered, visible, and with the default button outlined.
+
+void BringUpDialog (DialogPtr *theDialog, short dialogID)
+{
+// CenterDialog(dialogID);
+ *theDialog = GetNewDialog(dialogID, nil, kPutInFront);
+ if (*theDialog == nil)
+ RedAlert(kErrDialogDidntLoad);
+ SetPort((GrafPtr)*theDialog);
+ ShowWindow(GetDialogWindow(*theDialog));
+ DrawDefaultButton(*theDialog);
+}
+
+//-------------------------------------------------------------- GetPutDialogCorner
+// Determines the upper left corner coordinates needed to properly centerÉ
+// the standard Mac PutFile dialog (when you save files).
+/*
+void GetPutDialogCorner (Point *theCorner)
+{
+ DialogTHndl dlogHandle;
+ Rect theScreen, dlogBounds;
+ Byte wasState;
+
+ theCorner->h = 64;
+ theCorner->v = 64;
+ theScreen = qd.screenBits.bounds;
+ theScreen.top += LMGetMBarHeight();
+ OffsetRect(&theScreen, -theScreen.left, -theScreen.top);
+
+ dlogHandle = (DialogTHndl)GetResource('DLOG', sfPutDialogID);
+ if (dlogHandle != nil)
+ {
+ wasState = HGetState((Handle)dlogHandle);
+ HLock((Handle)dlogHandle);
+
+ dlogBounds = (**dlogHandle).boundsRect;
+ OffsetRect(&dlogBounds, -dlogBounds.left, -dlogBounds.top);
+
+ theCorner->h = (theScreen.right - dlogBounds.right) / 2;
+ theCorner->v = (theScreen.bottom - dlogBounds.bottom) / 3;
+
+ HSetState((Handle)dlogHandle, wasState);
+ }
+ theCorner->v += LMGetMBarHeight();
+}
+*/
+
+//-------------------------------------------------------------- GetPutDialogCorner
+// Determines the upper left corner coordinates needed to properly centerÉ
+// the standard Mac GetFile dialog (when you open files).
+/*
+void GetGetDialogCorner (Point *theCorner)
+{
+ DialogTHndl dlogHandle;
+ Rect theScreen, dlogBounds;
+ Byte wasState;
+
+ theCorner->h = 64;
+ theCorner->v = 64;
+ theScreen = qd.screenBits.bounds;
+ theScreen.top += LMGetMBarHeight();
+ OffsetRect(&theScreen, -theScreen.left, -theScreen.top);
+
+ dlogHandle = (DialogTHndl)GetResource('DLOG', sfGetDialogID);
+ if (dlogHandle != nil)
+ {
+ wasState = HGetState((Handle)dlogHandle);
+ HLock((Handle)dlogHandle);
+
+ dlogBounds = (**dlogHandle).boundsRect;
+ OffsetRect(&dlogBounds, -dlogBounds.left, -dlogBounds.top);
+
+ theCorner->h = (theScreen.right - dlogBounds.right) / 2;
+ theCorner->v = (theScreen.bottom - dlogBounds.bottom) / 3;
+
+ HSetState((Handle)dlogHandle, wasState);
+ }
+ theCorner->v += LMGetMBarHeight();
+}
+*/
+//-------------------------------------------------------------- CenterDialog
+// Given a resource ID for a dialog, this function properly centers it.
+/*
+void CenterDialog (SInt16 dialogID)
+{
+ DialogTHndl dlogHandle;
+ Rect theScreen, dlogBounds;
+ SInt16 hPos, vPos;
+ Byte wasState;
+
+ theScreen = qd.screenBits.bounds;
+ theScreen.top += LMGetMBarHeight();
+
+ dlogHandle = (DialogTHndl)GetResource('DLOG', dialogID);
+ if (dlogHandle != nil)
+ {
+ wasState = HGetState((Handle)dlogHandle);
+ HLock((Handle)dlogHandle);
+
+ dlogBounds = (**dlogHandle).boundsRect;
+ OffsetRect(&dlogBounds, -dlogBounds.left, -dlogBounds.top);
+
+ hPos = ((theScreen.right - theScreen.left) - dlogBounds.right) / 2;
+ vPos = ((theScreen.bottom - theScreen.top) - dlogBounds.bottom) / 3;
+
+ OffsetRect(&dlogBounds, hPos, vPos + LMGetMBarHeight());
+
+ (**dlogHandle).boundsRect = dlogBounds;
+ HSetState((Handle)dlogHandle, wasState);
+ }
+}
+*/
+//-------------------------------------------------------------- GetDialogRect
+// Determines the bounding rectangle for a given dialog.
+
+void GetDialogRect (Rect *bounds, short dialogID)
+{
+ DialogTHndl dlogHandle;
+ Byte wasState;
+
+ dlogHandle = (DialogTHndl)GetResource('DLOG', dialogID);
+ if (dlogHandle != nil)
+ {
+ wasState = HGetState((Handle)dlogHandle);
+ HLock((Handle)dlogHandle);
+
+ *bounds = (**dlogHandle).boundsRect;
+ HSetState((Handle)dlogHandle, wasState);
+ }
+}
+
+//-------------------------------------------------------------- TrueCenterDialog
+// Places a dialog DEAD CENTER (as opposed to 1/3 of the way down asÉ
+// is common for Mac dialog centering).
+/*
+void TrueCenterDialog (short dialogID)
+{
+ DialogTHndl dlogHandle;
+ Rect theScreen, dlogBounds;
+ short hPos, vPos;
+ Byte wasState;
+
+ theScreen = qd.screenBits.bounds;
+ theScreen.top += LMGetMBarHeight();
+
+ dlogHandle = (DialogTHndl)GetResource('DLOG', dialogID);
+ if (dlogHandle != nil)
+ {
+ wasState = HGetState((Handle)dlogHandle);
+ HLock((Handle)dlogHandle);
+
+ dlogBounds = (**dlogHandle).boundsRect;
+ OffsetRect(&dlogBounds, theScreen.left - dlogBounds.left,
+ theScreen.top - dlogBounds.top);
+
+ hPos = ((theScreen.right - theScreen.left) -
+ (dlogBounds.right - dlogBounds.left)) / 2;
+ vPos = ((theScreen.bottom - theScreen.top) -
+ (dlogBounds.bottom - dlogBounds.top)) / 2;
+
+ OffsetRect(&dlogBounds, hPos, vPos + LMGetMBarHeight());
+
+ (**dlogHandle).boundsRect = dlogBounds;
+ HSetState((Handle)dlogHandle, wasState);
+ }
+}
+*/
+//-------------------------------------------------------------- CenterAlert
+// Given an alert ID, this function properly centers it on the main monitor.
+/*
+void CenterAlert (short alertID)
+{
+ AlertTHndl alertHandle;
+ Rect theScreen, alertRect;
+ short horiOff, vertOff;
+ Byte wasState;
+
+ theScreen = qd.screenBits.bounds;
+ theScreen.top += LMGetMBarHeight();
+
+ alertHandle = (AlertTHndl)GetResource('ALRT', alertID);
+ if (alertHandle != nil)
+ {
+ wasState = HGetState((Handle)alertHandle);
+ HLock((Handle)alertHandle);
+
+ alertRect = (**alertHandle).boundsRect;
+ OffsetRect(&alertRect, -alertRect.left, -alertRect.top);
+
+ horiOff = ((theScreen.right - theScreen.left) - alertRect.right) / 2;
+ vertOff = ((theScreen.bottom - theScreen.top) - alertRect.bottom) / 3;
+
+ OffsetRect(&alertRect, horiOff, vertOff + LMGetMBarHeight());
+
+ (**alertHandle).boundsRect = alertRect;
+ HSetState((Handle)alertHandle, wasState);
+ }
+}
+*/
+//-------------------------------------------------------------- ZoomOutDialogRect
+
+// Given a dialog, this function does the "zoom" animation to make theÉ
+// the dialog appear to expand from nothingness or zoom in at you.
+/*
+void ZoomOutDialogRect (short dialogID)
+{
+ #define kSteps 16
+ #define kZoomDelay 1
+ DialogTHndl dlogHandle;
+ GrafPtr wasPort, tempPort;
+ Rect dlogBounds, zoomRect;
+ UInt32 dummyLong;
+ Byte wasState;
+ short wideStep, highStep, i;
+
+ GetPort(&wasPort);
+
+ tempPort = (GrafPtr)NewPtrClear(sizeof(GrafPort));
+ OpenPort(tempPort);
+
+ dlogHandle = (DialogTHndl)GetResource('DLOG', dialogID);
+ if (dlogHandle != nil)
+ {
+ wasState = HGetState((Handle)dlogHandle);
+ HLock((Handle)dlogHandle);
+ dlogBounds = (**dlogHandle).boundsRect;
+ HSetState((Handle)dlogHandle, wasState);
+ }
+
+ wideStep = ((dlogBounds.right - dlogBounds.left) / 2) / kSteps;
+ highStep = ((dlogBounds.bottom - dlogBounds.top) / 2) / kSteps;
+
+ SetRect(&zoomRect, dlogBounds.left + (wideStep * kSteps),
+ dlogBounds.top + (highStep * kSteps),
+ dlogBounds.right - (wideStep * kSteps),
+ dlogBounds.bottom - (highStep * kSteps));
+ GlobalToLocalRect(&zoomRect);
+
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ PenMode(patXor);
+
+ for (i = 0; i < kSteps; i++)
+ {
+ FrameRect(&zoomRect);
+ Delay(kZoomDelay, &dummyLong);
+ FrameRect(&zoomRect);
+ InsetRect(&zoomRect, -wideStep, -highStep);
+ }
+
+ ClosePort(tempPort);
+
+ SetPort((GrafPtr)wasPort);
+}
+*/
+//-------------------------------------------------------------- ZoomOutAlertRect
+
+// Like the above funciton but zooms out alerts instead of dialogs.
+/*
+void ZoomOutAlertRect (short alertID)
+{
+ #define kSteps 16
+ #define kZoomDelay 1
+ AlertTHndl alertHandle;
+ GrafPtr wasPort, tempPort;
+ Rect alertBounds, zoomRect;
+ UInt32 dummyLong;
+ Byte wasState;
+ short wideStep, highStep, i;
+
+ GetPort(&wasPort);
+
+ tempPort = (GrafPtr)NewPtrClear(sizeof(GrafPort));
+ OpenPort(tempPort);
+
+ alertHandle = (AlertTHndl)GetResource('ALRT', alertID);
+ if (alertHandle != nil)
+ {
+ wasState = HGetState((Handle)alertHandle);
+ HLock((Handle)alertHandle);
+ alertBounds = (**alertHandle).boundsRect;
+ HSetState((Handle)alertHandle, wasState);
+ }
+
+ wideStep = ((alertBounds.right - alertBounds.left) / 2) / kSteps;
+ highStep = ((alertBounds.bottom - alertBounds.top) / 2) / kSteps;
+
+ SetRect(&zoomRect, alertBounds.left + (wideStep * kSteps),
+ alertBounds.top + (highStep * kSteps),
+ alertBounds.right - (wideStep * kSteps),
+ alertBounds.bottom - (highStep * kSteps));
+ GlobalToLocalRect(&zoomRect);
+
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ PenMode(patXor);
+
+ for (i = 0; i < kSteps; i++)
+ {
+ FrameRect(&zoomRect);
+ Delay(kZoomDelay, &dummyLong);
+ FrameRect(&zoomRect);
+ InsetRect(&zoomRect, -wideStep, -highStep);
+ }
+
+ ClosePort(tempPort);
+
+ SetPort((GrafPtr)wasPort);
+}
+*/
+
+//-------------------------------------------------------------- FlashDialogButton
+// Flashes the default dialog button (item = 1) so as to make it appearÉ
+// as though the user clicked on it.
+
+void FlashDialogButton (DialogPtr theDialog, short itemNumber)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ UInt32 dummyLong;
+ short itemType;
+
+ GetDialogItem(theDialog, itemNumber, &itemType, &itemHandle, &itemRect);
+ HiliteControl((ControlHandle)itemHandle, kControlButtonPart);
+ Delay(8, &dummyLong);
+ HiliteControl((ControlHandle)itemHandle, 0);
+}
+
+//-------------------------------------------------------------- DrawDefaultButton
+// Draws a fat outline around the default item (item = 1). This is theÉ
+// item that is selected if the user hits the Return key.
+
+void DrawDefaultButton (DialogPtr theDialog)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, 1, &itemType, &itemHandle, &itemRect);
+ InsetRect(&itemRect, -4, -4);
+ PenSize(3, 3);
+ FrameRoundRect(&itemRect, 16, 16);
+ PenNormal();
+}
+
+//-------------------------------------------------------------- GetDialogString
+// Returns a string from a specific dialog item.
+
+void GetDialogString (DialogPtr theDialog, short item, StringPtr theString)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ GetDialogItemText(itemHandle, theString);
+}
+
+//-------------------------------------------------------------- SetDialogString
+// Sets a specific string to a specific dialog item.
+
+void SetDialogString (DialogPtr theDialog, short item, const PLPasStr &theString)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ SetDialogItemText(itemHandle, theString);
+}
+
+//-------------------------------------------------------------- GetDialogStringLen
+// Returns the length of a dialog item string (text).
+
+short GetDialogStringLen (DialogPtr theDialog, short item)
+{
+ Rect itemRect;
+ Str255 theString;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ GetDialogItemText(itemHandle, theString);
+ return (theString[0]);
+}
+
+//-------------------------------------------------------------- GetDialogItemValue
+// Returns the value or "state" of a dialog item. For checkboxes andÉ
+// radio buttons, this may be a 1 or 0.
+
+void GetDialogItemValue (DialogPtr theDialog, short item, short *theState)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ *theState = GetControlValue((ControlHandle)itemHandle);
+}
+
+//-------------------------------------------------------------- SetDialogItemValue
+// Sets a specific dialogf items value or state (can set or clearÉ
+// checkboxes, radio buttons, etc.).
+
+void SetDialogItemValue (DialogPtr theDialog, short item, short theState)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ SetControlValue((ControlHandle)itemHandle, theState);
+}
+
+//-------------------------------------------------------------- ToggleDialogItemValue
+// If item is a checkbox or radio button, its state is toggled.
+
+void ToggleDialogItemValue (DialogPtr theDialog, short item)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType, theState;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ theState = GetControlValue((ControlHandle)itemHandle);
+ if (theState == 0)
+ theState = 1;
+ else
+ theState = 0;
+ SetControlValue((ControlHandle)itemHandle, theState);
+}
+
+//-------------------------------------------------------------- SetDialogNumToStr
+// Function accepts an integer, converts it to a string and sets aÉ
+// dialog items text to this string.
+
+void SetDialogNumToStr (DialogPtr theDialog, short item, long theNumber)
+{
+ Str255 theString;
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ NumToString(theNumber, theString);
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ SetDialogItemText(itemHandle, theString);
+}
+
+//-------------------------------------------------------------- GetDialogNumFromStr
+// Function extracts the text from a dialog item and converts it to anÉ
+// integer for returning.
+
+void GetDialogNumFromStr (DialogPtr theDialog, short item, long *theNumber)
+{
+ Str255 theString;
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ GetDialogItemText(itemHandle, theString);
+ StringToNum(theString, theNumber);
+}
+
+//-------------------------------------------------------------- GetDialogItemRect
+// Returns the bounding rectangle of the specified dialog item.
+
+void GetDialogItemRect (DialogPtr theDialog, short item, Rect *theRect)
+{
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, theRect);
+}
+
+//-------------------------------------------------------------- SetDialogItemRect
+// Sets the bounding rectangle of the specified dialog item. Used toÉ
+// resize or move a control.
+
+void SetDialogItemRect (DialogPtr theDialog, short item, Rect *theRect)
+{
+ Rect oldRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &oldRect);
+ OffsetRect(&oldRect, theRect->left - oldRect.left, theRect->top - oldRect.top);
+ SetDialogItem(theDialog, item, itemType, itemHandle, &oldRect);
+}
+
+//-------------------------------------------------------------- OffsetDialogItemRect
+// Moves a dialog item by h and v.
+
+void OffsetDialogItemRect (DialogPtr theDialog, short item, short h, short v)
+{
+ Rect oldRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &oldRect);
+ OffsetRect(&oldRect, h, v);
+ SetDialogItem(theDialog, item, itemType, itemHandle, &oldRect);
+}
+
+//-------------------------------------------------------------- SelectFromRadioGroup
+// Assuming a series of consecutively numbered radio buttons, this functionÉ
+// clears the whole range of them but sets the one specified (as thoughÉ
+// the radio buttons are linked and only one can be set at a time).
+
+void SelectFromRadioGroup (DialogPtr dial, short which, short first, short last)
+{
+ Rect iRect;
+ Handle iHandle;
+ short iType, i;
+
+ for (i = first; i <= last; i++)
+ {
+ GetDialogItem(dial, i, &iType, &iHandle, &iRect);
+ SetControlValue((ControlHandle)iHandle, (short)false);
+ }
+
+ GetDialogItem(dial, which, &iType, &iHandle, &iRect);
+ SetControlValue((ControlHandle)iHandle, (short)true);
+}
+
+//-------------------------------------------------------------- AddMenuToPopUp
+// Assigns a menu handle to a pop-up dialog item - thus, giving thatÉ
+// pop-up item something to pop up.
+/*
+void AddMenuToPopUp (DialogPtr theDialog, short whichItem, MenuHandle theMenu)
+{
+ Rect iRect;
+ Handle iHandle;
+ short iType;
+
+ GetDialogItem(theDialog, whichItem, &iType, &iHandle, &iRect);
+ (**(ControlHandle)iHandle).contrlRfCon = (long)theMenu;
+}
+*/
+//-------------------------------------------------------------- GetPopUpMenuValu
+// Returns which item is currently selected in a pop-up menu.
+
+void GetPopUpMenuValue (DialogPtr theDialog, short whichItem, short *value)
+{
+ Rect iRect;
+ Handle iHandle;
+ short iType;
+
+ GetDialogItem(theDialog, whichItem, &iType, &iHandle, &iRect);
+ *value = GetControlValue((ControlHandle)iHandle);
+}
+
+//-------------------------------------------------------------- SetPopUpMenuValue
+// Forces a specific item to be set (as though selected) in a pop-up menu.
+
+void SetPopUpMenuValue (DialogPtr theDialog, short whichItem, short value)
+{
+ Rect iRect;
+ Handle iHandle;
+ short iType;
+
+ GetDialogItem(theDialog, whichItem, &iType, &iHandle, &iRect);
+ SetControlValue((ControlHandle)iHandle, value);
+}
+
+//-------------------------------------------------------------- MyEnableControl
+// "Un-grays" or enables a dialog item (usually a button).
+
+void MyEnableControl (DialogPtr theDialog, short whichItem)
+{
+ Rect iRect;
+ Handle iHandle;
+ short iType;
+
+ GetDialogItem(theDialog, whichItem, &iType, &iHandle, &iRect);
+ HiliteControl((ControlHandle)iHandle, kActive);
+}
+
+//-------------------------------------------------------------- MyDisableControl
+// "Grays out" or disables a dialog item (usually a button).
+
+void MyDisableControl (DialogPtr theDialog, short whichItem)
+{
+ Rect iRect;
+ Handle iHandle;
+ short iType;
+
+ GetDialogItem(theDialog, whichItem, &iType, &iHandle, &iRect);
+ HiliteControl((ControlHandle)iHandle, kInactive);
+}
+
+//-------------------------------------------------------------- DrawDialogUserText
+// Given a string of text and an item, this function draws the stringÉ
+// within the bounding rect of the item. Dialog item assumed to beÉ
+// a "user item" (invisible item with only bounds).
+
+void DrawDialogUserText (DialogPtr dial, short item, StringPtr text, Boolean invert)
+{
+ Rect iRect;
+ Handle iHandle;
+ Str255 newString, stringCopy;
+ short iType, textLong, i, inset;
+
+ TextFont(applFont);
+ TextSize(9);
+
+ PasStringCopy(text, stringCopy);
+ GetDialogItem(dial, item, &iType, &iHandle, &iRect);
+ if ((StringWidth(stringCopy) + 2) > (iRect.right - iRect.left))
+ CollapseStringToWidth(stringCopy, iRect.right - iRect.left - 2);
+ textLong = stringCopy[0];
+ for (i = 0; i < textLong; i++)
+ newString[i] = stringCopy[i + 1];
+
+ OffsetRect(&iRect, 0, 1);
+ EraseRect(&iRect);
+ OffsetRect(&iRect, 0, -1);
+
+ inset = ((iRect.right - iRect.left) - (StringWidth(stringCopy) + 2)) / 2;
+ iRect.left += inset;
+ iRect.right -= inset;
+
+ TETextBox(newString, textLong, &iRect, teCenter);
+ if (invert)
+ {
+ OffsetRect(&iRect, 0, 1);
+ InvertRect(&iRect);
+ }
+}
+
+//-------------------------------------------------------------- DrawDialogUserText
+// Similar to the above function but doesn't call TETextBox(). Instead,É
+// it truncates the string (and appends "É") to the end in order thatÉ
+// the string fits within the dialog item's bounds.
+
+void DrawDialogUserText2 (DialogPtr dial, short item, StringPtr text)
+{
+ Rect iRect;
+ Handle iHandle;
+ Str255 stringCopy;
+ short iType;
+
+ TextFont(applFont);
+ TextSize(9);
+
+ PasStringCopy(text, stringCopy);
+ GetDialogItem(dial, item, &iType, &iHandle, &iRect);
+ if ((StringWidth(stringCopy) + 2) > (iRect.right - iRect.left))
+ CollapseStringToWidth(stringCopy, iRect.right - iRect.left - 2);
+ MoveTo(iRect.left, iRect.bottom);
+ DrawString(stringCopy);
+}
+
+//-------------------------------------------------------------- LoadDialogPICT
+// Draws a 'PICT' specified by ID within the bounds of the specifiedÉ
+// dialog item.
+
+void LoadDialogPICT (DialogPtr theDialog, short item, short theID)
+{
+ Rect iRect;
+ Handle iHandle;
+ PicHandle thePict;
+ short iType;
+
+ GetDialogItem(theDialog, item, &iType, &iHandle, &iRect);
+ thePict = GetPicture(theID);
+ if (thePict)
+ DrawPicture(thePict, &iRect);
+}
+
+//-------------------------------------------------------------- FrameDialogItem
+// Given a dialog item, this function draws a box around it.
+
+void FrameDialogItem (DialogPtr theDialog, short item)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ FrameRect(&itemRect);
+}
+
+//-------------------------------------------------------------- FrameDialogItemC
+// Given a dialog item, this function draws a color (specified) box around it.
+
+void FrameDialogItemC (DialogPtr theDialog, short item, long color)
+{
+ RGBColor theRGBColor, wasColor;
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ GetForeColor(&wasColor);
+ Index2Color(color, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ FrameRect(&itemRect);
+ RGBForeColor(&wasColor);
+}
+
+//-------------------------------------------------------------- FrameOvalDialogItem
+// Given a dialog item, this function draws an oval around it.
+
+void FrameOvalDialogItem (DialogPtr theDialog, short item)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ FrameOval(&itemRect);
+}
+
+//-------------------------------------------------------------- BorderDialogItem
+// Given a dialog item, this function draws any combination of 4 sidesÉ
+// of a box around it. Which sides get drawn is encoded in "sides".
+
+void BorderDialogItem (DialogPtr theDialog, short item, short sides)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ // 1 = left
+ // 2 = top
+ // 4 = bottom
+ // 8 = right ... so 6 = top & bottom, 15 = all 4 sides
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+
+ if (sides >= 8) // 8 = right
+ {
+ MoveTo(itemRect.right, itemRect.top);
+ LineTo(itemRect.right, itemRect.bottom);
+ sides -= 8;
+ }
+ if (sides >= 4) // 4 = bottom
+ {
+ MoveTo(itemRect.left, itemRect.bottom);
+ LineTo(itemRect.right, itemRect.bottom);
+ sides -= 4;
+ }
+ if (sides >= 2) // 2 = top
+ {
+ MoveTo(itemRect.left, itemRect.top - 1);
+ LineTo(itemRect.right, itemRect.top - 1);
+ sides -= 2;
+ }
+ if (sides >= 1) // 1 = left
+ {
+ MoveTo(itemRect.left - 1, itemRect.top);
+ LineTo(itemRect.left - 1, itemRect.bottom);
+ }
+}
+
+//-------------------------------------------------------------- ShadowDialogItem
+// Draws a drop shadow to the right and below a specified dialog item.
+
+void ShadowDialogItem (DialogPtr theDialog, short item, short thickness)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ PenSize(thickness, thickness);
+ MoveTo(itemRect.left + thickness, itemRect.bottom);
+ Line(itemRect.right - itemRect.left - thickness, 0);
+ MoveTo(itemRect.right, itemRect.top + thickness);
+ Line(0, itemRect.bottom - itemRect.top - thickness);
+ PenNormal();
+}
+
+//-------------------------------------------------------------- EraseDialogItem
+// Erases (but doesn't physically remove) a dialog item.
+
+void EraseDialogItem (DialogPtr theDialog, short item)
+{
+ Rect itemRect;
+ Handle itemHandle;
+ short itemType;
+
+ GetDialogItem(theDialog, item, &itemType, &itemHandle, &itemRect);
+ EraseRect(&itemRect);
+}
+
diff --git a/GpApp/DialogUtils.h b/GpApp/DialogUtils.h
new file mode 100644
index 0000000..da0f150
--- /dev/null
+++ b/GpApp/DialogUtils.h
@@ -0,0 +1,47 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// DialogUtils.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLDialogs.h"
+
+
+void BringUpDialog (DialogPtr *theDialog, short dialogID);
+//void GetPutDialogCorner (Point *);
+//void GetGetDialogCorner (Point *);
+//void CenterDialog (short);
+void GetDialogRect (Rect *, short);
+//void TrueCenterDialog (short);
+//void CenterAlert (short);
+//void ZoomOutDialogRect (short);
+//void ZoomOutAlertRect (short);
+void FlashDialogButton (DialogPtr, short);
+void DrawDefaultButton (DialogPtr);
+void GetDialogString (DialogPtr, short, StringPtr);
+void SetDialogString (DialogPtr, short, const PLPasStr&);
+short GetDialogStringLen (DialogPtr, short);
+void GetDialogItemValue (DialogPtr, short, short *);
+void SetDialogItemValue (DialogPtr, short, short);
+void ToggleDialogItemValue (DialogPtr, short);
+void SetDialogNumToStr (DialogPtr, short, long);
+void GetDialogNumFromStr (DialogPtr, short, long *);
+void GetDialogItemRect (DialogPtr, short, Rect *);
+void SetDialogItemRect (DialogPtr, short, Rect *);
+void OffsetDialogItemRect (DialogPtr, short, short, short);
+void SelectFromRadioGroup (DialogPtr, short, short, short);
+//void AddMenuToPopUp (DialogPtr, short, MenuHandle);
+void GetPopUpMenuValue (DialogPtr, short, short *);
+void SetPopUpMenuValue (DialogPtr, short, short);
+void MyEnableControl(DialogPtr, short);
+void MyDisableControl(DialogPtr, short);
+void DrawDialogUserText (DialogPtr, short, StringPtr, Boolean);
+void DrawDialogUserText2 (DialogPtr, short, StringPtr);
+void LoadDialogPICT (DialogPtr, short, short);
+void FrameDialogItem (DialogPtr, short);
+void FrameDialogItemC (DialogPtr, short, long);
+void FrameOvalDialogItem (DialogPtr, short);
+void BorderDialogItem (DialogPtr, short, short);
+void ShadowDialogItem (DialogPtr, short, short);
+void EraseDialogItem (DialogPtr, short);
diff --git a/GpApp/DynamicMaps.cpp b/GpApp/DynamicMaps.cpp
new file mode 100644
index 0000000..33ccde6
--- /dev/null
+++ b/GpApp/DynamicMaps.cpp
@@ -0,0 +1,798 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// DynamicMaps.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Environ.h"
+#include "MainWindow.h"
+#include "Objects.h"
+#include "RectUtils.h"
+#include "Room.h"
+#include "Utilities.h"
+
+
+void BackUpFlames (Rect *, short);
+void BackUpTikiFlames (Rect *, short);
+void BackUpBBQCoals (Rect *, short);
+void BackUpPendulum (Rect *, short);
+void BackUpStar (Rect *, short);
+
+
+sparklePtr sparkles;
+flyingPtPtr flyingPoints;
+flamePtr flames, tikiFlames, bbqCoals;
+pendulumPtr pendulums;
+starPtr theStars;
+shredPtr shreds;
+Rect pointsSrc[15];
+short numSparkles, numFlyingPts, numChimes;
+short numFlames, numSavedMaps, numTikiFlames, numCoals;
+short numPendulums, clockFrame, numStars, numShredded;
+
+
+extern savedType savedMaps[];
+extern Rect flame[], tikiFlame[], coals[], pendulumSrc[];
+extern Rect starSrc[];
+extern short numGrease, numDynamics;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- NilSavedMaps
+// Deletes array of "dyanmics" offscreen pixmaps.
+
+void NilSavedMaps (void)
+{
+ short i;
+
+ for (i = 0; i < kMaxSavedMaps; i++)
+ {
+ if (savedMaps[i].map != nil)
+ {
+ DisposeGWorld(savedMaps[i].map);
+// KillOffScreenPixMap(savedMaps[i].map);
+ savedMaps[i].map = nil;
+ }
+ savedMaps[i].where = -1;
+ savedMaps[i].who = -1;
+ }
+ numSavedMaps = 0;
+}
+
+//-------------------------------------------------------------- BackUpToSavedMap
+// Saves a copy of the room behind an object to an array of pixmaps.
+// Then when the object in question is drawn, there is a copy of theÉ
+// room that it obscured so that, should the player get the object,É
+// it can be made to "disappear".
+
+short BackUpToSavedMap (Rect *theRect, short where, short who)
+{
+ Rect mapRect;
+ OSErr theErr;
+
+ if (numSavedMaps >= kMaxSavedMaps)
+ return(-1);
+
+ mapRect = *theRect;
+ ZeroRectCorner(&mapRect);
+ savedMaps[numSavedMaps].dest = *theRect;
+// CreateOffScreenPixMap(&mapRect, &savedMaps[numSavedMaps].map);
+ theErr = CreateOffScreenGWorld(&savedMaps[numSavedMaps].map, &mapRect, kPreferredDepth);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ GetPortBitMapForCopyBits(savedMaps[numSavedMaps].map),
+ theRect, &mapRect, srcCopy, nil);
+
+ savedMaps[numSavedMaps].where = where;
+ savedMaps[numSavedMaps].who = who;
+ numSavedMaps++;
+
+ return (numSavedMaps - 1); // return array index
+}
+
+//-------------------------------------------------------------- ReBackUpSavedMap
+// This function is similar to the above, but assumes there is alreadyÉ
+// a slot in the pixmap array for the object. It re-copies the backgroundÉ
+// and is needed when the lights in the room go on or off.
+
+short ReBackUpSavedMap (Rect *theRect, short where, short who)
+{
+ Rect mapRect;
+ short i, foundIndex;
+
+ foundIndex = -1;
+
+ for (i = 0; i < numSavedMaps; i++)
+ {
+ if ((savedMaps[i].where == where) && (savedMaps[i].who == who))
+ {
+ foundIndex = i;
+ mapRect = *theRect;
+ ZeroRectCorner(&mapRect);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ GetPortBitMapForCopyBits(savedMaps[foundIndex].map),
+ theRect, &mapRect, srcCopy, nil);
+
+ return (foundIndex);
+ }
+ }
+
+ return (foundIndex);
+}
+
+//-------------------------------------------------------------- RestoreFromSavedMap
+
+// This copies the saved background swatch to the screen - effectivelyÉ
+// covering up or "erasing" the object.
+
+void RestoreFromSavedMap (short where, short who, Boolean doSparkle)
+{
+ Rect mapRect, bounds;
+ short i;
+
+ for (i = 0; i < numSavedMaps; i++)
+ {
+ if ((savedMaps[i].where == where) && (savedMaps[i].who == who) &&
+ (savedMaps[i].map != nil))
+ {
+ mapRect = savedMaps[i].dest;
+ ZeroRectCorner(&mapRect);
+
+ CopyBits(GetPortBitMapForCopyBits(savedMaps[i].map),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &mapRect, &savedMaps[i].dest, srcCopy, nil);
+ CopyBits(GetPortBitMapForCopyBits(savedMaps[i].map),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &mapRect, &savedMaps[i].dest, srcCopy, nil);
+
+ AddRectToWorkRects(&savedMaps[i].dest);
+
+ if (doSparkle)
+ {
+ bounds = savedMaps[i].dest;
+ QOffsetRect(&bounds, -playOriginH, -playOriginV);
+ AddSparkle(&bounds);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ break;
+ }
+ }
+}
+
+//-------------------------------------------------------------- AddSparkle
+
+// This adds a "sparkle" object to the fixed array of sparkles.
+
+void AddSparkle (Rect *theRect)
+{
+ Rect centeredRect;
+ short i;
+
+ if (numSparkles < kMaxSparkles)
+ {
+ theRect->left += playOriginH;
+ theRect->right += playOriginH;
+ theRect->top += playOriginV;
+ theRect->bottom += playOriginV;
+
+ centeredRect = sparkleSrc[0];
+ CenterRectInRect(¢eredRect, theRect);
+
+ for (i = 0; i < kMaxSparkles; i++)
+ if (sparkles[i].mode == -1)
+ {
+ sparkles[i].bounds = centeredRect;
+ sparkles[i].mode = 0;
+ numSparkles++;
+ break;
+ }
+ }
+}
+
+//-------------------------------------------------------------- AddFlyingPoint
+
+// This adds a "flying point" object to the array of flying points.
+
+void AddFlyingPoint (Rect *theRect, short points, short hVel, short vVel)
+{
+ Rect centeredRect;
+ short i;
+
+ if (numFlyingPts < kMaxFlyingPts)
+ {
+ theRect->left += playOriginH;
+ theRect->right += playOriginH;
+ theRect->top += playOriginV;
+ theRect->bottom += playOriginV;
+
+ centeredRect = pointsSrc[0];
+ CenterRectInRect(¢eredRect, theRect);
+
+ for (i = 0; i < kMaxFlyingPts; i++)
+ if (flyingPoints[i].mode == -1)
+ {
+ flyingPoints[i].dest = centeredRect;
+ flyingPoints[i].whole = centeredRect;
+ flyingPoints[i].loops = 0;
+ flyingPoints[i].hVel = hVel;
+ flyingPoints[i].vVel = vVel;
+ switch (points)
+ {
+ case 100:
+ flyingPoints[i].start = 12;
+ flyingPoints[i].stop = 14;
+ break;
+
+ case 250:
+ flyingPoints[i].start = 9;
+ flyingPoints[i].stop = 11;
+ break;
+
+ case 300:
+ flyingPoints[i].start = 6;
+ flyingPoints[i].stop = 8;
+ break;
+
+ case 500:
+ flyingPoints[i].start = 3;
+ flyingPoints[i].stop = 5;
+ break;
+
+ default:
+ flyingPoints[i].start = 0;
+ flyingPoints[i].stop = 2;
+ break;
+ }
+ flyingPoints[i].mode = flyingPoints[i].start;
+ numFlyingPts++;
+ break;
+ }
+ }
+}
+
+//-------------------------------------------------------------- BackUpFlames
+
+// This makes copies of the area of the room behind a flame. The flameÉ
+// graphic can be "copy masked" to this pixmap then and then simpleÉ
+// CopyBits() calls will properly draw the flame on screen with theÉ
+// proper background.
+
+void BackUpFlames (Rect *src, short index)
+{
+ Rect dest;
+ short i;
+
+ QSetRect(&dest, 0, 0, 16, 15);
+ for (i = 0; i < kNumCandleFlames; i++)
+ {
+ // Copy background to map.
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ GetPortBitMapForCopyBits(savedMaps[index].map),
+ src, &dest, srcCopy, nil);
+
+ // Copy flame to map.
+ CopyMask((BitMap *)*GetGWorldPixMap(blowerSrcMap),
+ (BitMap *)*GetGWorldPixMap(blowerMaskMap),
+ GetPortBitMapForCopyBits(savedMaps[index].map),
+ &flame[i], &flame[i], &dest);
+
+
+ QOffsetRect(&dest, 0, 15);
+ }
+}
+
+//-------------------------------------------------------------- ReBackUpFlames
+
+// Like the above function but this is called when the lighting changesÉ
+// in a room (lights go on or off).
+
+void ReBackUpFlames (short where, short who)
+{
+ short i, f;
+
+ for (i = 0; i < numSavedMaps; i++)
+ {
+ if ((savedMaps[i].where == where) && (savedMaps[i].who == who))
+ {
+ for (f = 0; f < numFlames; f++)
+ {
+ if (flames[f].who == i)
+ {
+ BackUpFlames(&flames[f].dest, i);
+ return;
+ }
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- AddCandleFlame
+
+// This adds a candle flame to tha array of flames.
+
+void AddCandleFlame (short where, short who, short h, short v)
+{
+ Rect src, bounds;
+ short savedNum;
+
+ if ((numFlames >= kMaxCandles) || (h < 16) || (v < 15))
+ return;
+
+ QSetRect(&src, 0, 0, 16, 15);
+ QOffsetRect(&src, h - 8, v - 15);
+ if ((thisMac.isDepth == 4) && ((src.left % 2) == 1))
+ {
+ QOffsetRect(&src, -1, 0);
+ if (src.left < 0)
+ QOffsetRect(&src, 2, 0);
+ }
+ QSetRect(&bounds, 0, 0, 16, 15 * kNumCandleFlames);
+ savedNum = BackUpToSavedMap(&bounds, where, who);
+ if (savedNum != -1)
+ {
+ BackUpFlames(&src, savedNum);
+ flames[numFlames].dest = src;
+ flames[numFlames].mode = RandomInt(kNumCandleFlames);
+ QSetRect(&flames[numFlames].src, 0, 0, 16, 15);
+ QOffsetRect(&flames[numFlames].src, 0, flames[numFlames].mode * 15);
+ flames[numFlames].who = savedNum;
+ numFlames++;
+ }
+}
+
+//-------------------------------------------------------------- BackUpTikiFlames
+// This is like the function BackUpFlames() but customized for Tiki torches.
+
+void BackUpTikiFlames (Rect *src, short index)
+{
+ Rect dest;
+ short i;
+
+ QSetRect(&dest, 0, 0, 8, 10);
+ for (i = 0; i < kNumTikiFlames; i++)
+ {
+ // copy background to map
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ GetPortBitMapForCopyBits(savedMaps[index].map),
+ src, &dest, srcCopy, nil);
+
+ // copy flame to map
+ CopyMask((BitMap *)*GetGWorldPixMap(blowerSrcMap),
+ (BitMap *)*GetGWorldPixMap(blowerMaskMap),
+ GetPortBitMapForCopyBits(savedMaps[index].map),
+ &tikiFlame[i], &tikiFlame[i], &dest);
+
+ QOffsetRect(&dest, 0, 10);
+ }
+}
+
+//-------------------------------------------------------------- ReBackUpTikiFlames
+
+// This is like the function ReBackUpFlames() but customized for Tiki torches.
+
+void ReBackUpTikiFlames (short where, short who)
+{
+ short i, f;
+
+ for (i = 0; i < numSavedMaps; i++)
+ {
+ if ((savedMaps[i].where == where) && (savedMaps[i].who == who))
+ {
+ for (f = 0; f < numTikiFlames; f++)
+ {
+ if (tikiFlames[f].who == i)
+ {
+ BackUpTikiFlames(&tikiFlames[f].dest, i);
+ return;
+ }
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- AddTikiFlame
+
+// This adds a tiki flame to the array of tiki flames.
+
+void AddTikiFlame (short where, short who, short h, short v)
+{
+ Rect src, bounds;
+ short savedNum;
+
+ if ((numTikiFlames >= kMaxTikis) || (h < 8) || (v < 10))
+ return;
+
+ QSetRect(&src, 0, 0, 8, 10);
+ if ((thisMac.isDepth == 4) && ((h % 2) == 1))
+ {
+ h--;
+ if (h < 0)
+ h += 2;
+ }
+ QOffsetRect(&src, h, v);
+ QSetRect(&bounds, 0, 0, 8, 10 * kNumTikiFlames);
+ savedNum = BackUpToSavedMap(&bounds, where, who);
+ if (savedNum != -1)
+ {
+ BackUpTikiFlames(&src, savedNum);
+ tikiFlames[numTikiFlames].dest = src;
+ tikiFlames[numTikiFlames].mode = RandomInt(kNumTikiFlames);
+ QSetRect(&tikiFlames[numTikiFlames].src, 0, 0, 8, 10);
+ QOffsetRect(&tikiFlames[numTikiFlames].src, 0,
+ tikiFlames[numTikiFlames].mode * 10);
+ tikiFlames[numTikiFlames].who = savedNum;
+ numTikiFlames++;
+ }
+}
+
+//-------------------------------------------------------------- BackUpBBQCoals
+
+// Another one - but for BBQ coals.
+
+void BackUpBBQCoals (Rect *src, short index)
+{
+ Rect dest;
+ short i;
+
+ QSetRect(&dest, 0, 0, 32, 9);
+ for (i = 0; i < kNumBBQCoals; i++)
+ {
+ // copy background to map
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ GetPortBitMapForCopyBits(savedMaps[index].map),
+ src, &dest, srcCopy, nil);
+
+ // copy flame to map
+ CopyMask((BitMap *)*GetGWorldPixMap(blowerSrcMap),
+ (BitMap *)*GetGWorldPixMap(blowerMaskMap),
+ GetPortBitMapForCopyBits(savedMaps[index].map),
+ &coals[i], &coals[i], &dest);
+
+ QOffsetRect(&dest, 0, 9);
+ }
+}
+
+//-------------------------------------------------------------- ReBackUpBBQCoals
+
+// Sense a pattern here?
+
+void ReBackUpBBQCoals (short where, short who)
+{
+ short i, f;
+
+ for (i = 0; i < numSavedMaps; i++)
+ {
+ if ((savedMaps[i].where == where) && (savedMaps[i].who == who))
+ {
+ for (f = 0; f < numCoals; f++)
+ {
+ if (bbqCoals[f].who == i)
+ {
+ BackUpBBQCoals(&bbqCoals[f].dest, i);
+ return;
+ }
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- AddBBQCoals
+
+// Adds BBQ coals to the array of BBQ coals.
+
+void AddBBQCoals (short where, short who, short h, short v)
+{
+ Rect src, bounds;
+ short savedNum;
+
+ if ((numCoals >= kMaxCoals) || (h < 32) || (v < 9))
+ return;
+
+ QSetRect(&src, 0, 0, 32, 9);
+ if ((thisMac.isDepth == 4) && ((h % 2) == 1))
+ {
+ h--;
+ if (h < 0)
+ h += 2;
+ }
+ QOffsetRect(&src, h, v);
+ QSetRect(&bounds, 0, 0, 32, 9 * kNumBBQCoals);
+ savedNum = BackUpToSavedMap(&bounds, where, who);
+ if (savedNum != -1)
+ {
+ BackUpBBQCoals(&src, savedNum);
+ bbqCoals[numCoals].dest = src;
+ bbqCoals[numCoals].mode = RandomInt(kNumBBQCoals);
+ QSetRect(&bbqCoals[numCoals].src, 0, 0, 32, 9);
+ QOffsetRect(&bbqCoals[numCoals].src, 0, bbqCoals[numCoals].mode * 9);
+ bbqCoals[numCoals].who = savedNum;
+
+ numCoals++;
+ }
+}
+
+//-------------------------------------------------------------- BackUpPendulum
+// Just like many of the previous functions, but for the pendulum on theÉ
+// cuckoo clock.
+
+void BackUpPendulum (Rect *src, short index)
+{
+ Rect dest;
+ short i;
+
+ QSetRect(&dest, 0, 0, 32, 28);
+ for (i = 0; i < kNumPendulums; i++)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ GetPortBitMapForCopyBits(savedMaps[index].map),
+ src, &dest, srcCopy, nil);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ GetPortBitMapForCopyBits(savedMaps[index].map),
+ &pendulumSrc[i], &pendulumSrc[i], &dest);
+
+ QOffsetRect(&dest, 0, 28);
+ }
+}
+
+//-------------------------------------------------------------- ReBackUpPendulum
+
+// Backs up the pendulums in the event of lights going on or off.
+
+void ReBackUpPendulum (short where, short who)
+{
+ short i, f;
+
+ for (i = 0; i < numSavedMaps; i++)
+ {
+ if ((savedMaps[i].where == where) && (savedMaps[i].who == who))
+ {
+ for (f = 0; f < numPendulums; f++)
+ {
+ if (pendulums[f].who == i)
+ {
+ BackUpPendulum(&pendulums[f].dest, i);
+ return;
+ }
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- AddPendulum
+
+// Adds a pendulum to the array of pendulums.
+
+void AddPendulum (short where, short who, short h, short v)
+{
+ Rect src, bounds;
+ short savedNum;
+
+ if ((numPendulums >= kMaxPendulums) || (h < 32) || (v < 28))
+ return;
+
+ clockFrame = 10;
+ QSetRect(&bounds, 0, 0, 32, 28 * kNumPendulums);
+ savedNum = BackUpToSavedMap(&bounds, where, who);
+ if (savedNum != -1)
+ {
+ QSetRect(&src, 0, 0, 32, 28);
+ if ((thisMac.isDepth == 4) && ((h % 2) == 1))
+ {
+ h--;
+ if (h < 0)
+ h += 2;
+ }
+ QOffsetRect(&src, h, v);
+ BackUpPendulum (&src, savedNum);
+ pendulums[numPendulums].dest = src;
+ pendulums[numPendulums].mode = 1;
+ if (RandomInt(2) == 0)
+ pendulums[numPendulums].toOrFro = true;
+ else
+ pendulums[numPendulums].toOrFro = false;
+ pendulums[numPendulums].active = true;
+ QSetRect(&pendulums[numPendulums].src, 0, 0, 32, 28);
+ QOffsetRect(&pendulums[numPendulums].src, 0, 28);
+ pendulums[numPendulums].who = savedNum;
+ pendulums[numPendulums].where = where;
+ pendulums[numPendulums].link = who;
+ numPendulums++;
+ }
+}
+
+//-------------------------------------------------------------- BackUpStar
+
+// Makes a copy of background beneath a star.
+
+void BackUpStar (Rect *src, short index)
+{
+ Rect dest;
+ short i;
+
+ QSetRect(&dest, 0, 0, 32, 31);
+ for (i = 0; i < 6; i++)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ GetPortBitMapForCopyBits(savedMaps[index].map),
+ src, &dest, srcCopy, nil);
+
+ // copy flame to map
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ GetPortBitMapForCopyBits(savedMaps[index].map),
+ &starSrc[i], &starSrc[i], &dest);
+
+ QOffsetRect(&dest, 0, 31);
+ }
+}
+
+//-------------------------------------------------------------- ReBackUpStar
+
+// Re-backs up the stars - in the event of lighting switch.
+
+void ReBackUpStar (short where, short who)
+{
+ short i, f;
+
+ for (i = 0; i < numSavedMaps; i++)
+ {
+ if ((savedMaps[i].where == where) && (savedMaps[i].who == who))
+ {
+ for (f = 0; f < numStars; f++)
+ {
+ if (theStars[f].who == i)
+ {
+ BackUpStar(&theStars[f].dest, i);
+ return;
+ }
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- AddStar
+
+// Adds a star to the star array.
+
+void AddStar (short where, short who, short h, short v)
+{
+ Rect src, bounds;
+ short savedNum;
+
+ if (numStars >= kMaxStars)
+ return;
+
+ QSetRect(&src, 0, 0, 32, 31);
+ if ((thisMac.isDepth == 4) && ((h % 2) == 1))
+ {
+ h--;
+ if (h < 0)
+ h += 2;
+ }
+ QOffsetRect(&src, h, v);
+
+ QSetRect(&bounds, 0, 0, 32, 31 * 6);
+ savedNum = BackUpToSavedMap(&bounds, where, who);
+ if (savedNum != -1)
+ {
+ BackUpStar(&src, savedNum);
+ theStars[numStars].dest = src;
+ theStars[numStars].mode = RandomInt(6);
+ QSetRect(&theStars[numStars].src, 0, 0, 32, 31);
+ QOffsetRect(&theStars[numStars].src, 0, theStars[numStars].mode * 31);
+ theStars[numStars].who = savedNum;
+ theStars[numStars].link = who;
+ theStars[numStars].where = where;
+
+ numStars++;
+ }
+}
+
+//-------------------------------------------------------------- StopPendulum
+
+// Will set a flag to kill a pendulum.
+
+void StopPendulum (short where, short who)
+{
+ short i;
+
+ for (i = 0; i < numPendulums; i++)
+ {
+ if ((pendulums[i].link == who) && (pendulums[i].where == where))
+ pendulums[i].active = false;
+ }
+}
+
+//-------------------------------------------------------------- StopStar
+
+// Will set a flag to kill a star.
+
+void StopStar (short where, short who)
+{
+ short i;
+
+ for (i = 0; i < numStars; i++)
+ {
+ if ((theStars[i].link == who) && (theStars[i].where == where))
+ theStars[i].mode = -1;
+ }
+}
+
+//-------------------------------------------------------------- AddAShreddedGlider
+
+// Adds a shredded glider.
+
+void AddAShreddedGlider (Rect *bounds)
+{
+ if (numShredded > kMaxShredded)
+ return;
+
+ shreds[numShredded].bounds.left = bounds->left + 4;
+ shreds[numShredded].bounds.right = shreds[numShredded].bounds.left + 40;
+ shreds[numShredded].bounds.top = bounds->top + 14;
+ shreds[numShredded].bounds.bottom = shreds[numShredded].bounds.top;
+ shreds[numShredded].frame = 0;
+
+ numShredded++;
+}
+
+//-------------------------------------------------------------- RemoveShreds
+
+// Remves the shredded glider.
+
+void RemoveShreds (void)
+{
+ short largest, who, i;
+
+ largest = 0;
+ who = -1;
+ for (i = 0; i < numShredded; i++)
+ {
+ if (shreds[i].frame > largest)
+ {
+ largest = shreds[i].frame;
+ who = i;
+ }
+ }
+
+ if (who != -1)
+ {
+ if (who == (numShredded - 1))
+ {
+ numShredded--;
+ shreds[who].frame = 0;
+ }
+ else
+ {
+ numShredded--;
+ shreds[who].bounds = shreds[numShredded].bounds;
+ shreds[who].frame = shreds[numShredded].frame;
+ shreds[numShredded].frame = 0;
+ }
+ }
+}
+
+//-------------------------------------------------------------- ZeroFlamesAndTheLike
+
+// Zeroes all counters that indicate the number of flames, pendulums, etc thereÉ
+// are in a room. Called before a room is drawn. As the room is drawn, theÉ
+// above functions are called and the counters incremented as objects of theÉ
+// specified types are drawn.
+
+void ZeroFlamesAndTheLike (void)
+{
+ numFlames = 0;
+ numTikiFlames = 0;
+ numCoals = 0;
+ numPendulums = 0;
+ numGrease = 0;
+ numStars = 0;
+ numShredded = 0;
+ numChimes = 0;
+}
+
diff --git a/Headers/DynamicMaps.h b/GpApp/DynamicMaps.h
old mode 100755
new mode 100644
similarity index 100%
rename from Headers/DynamicMaps.h
rename to GpApp/DynamicMaps.h
diff --git a/GpApp/Dynamics.cpp b/GpApp/Dynamics.cpp
new file mode 100644
index 0000000..d8887e2
--- /dev/null
+++ b/GpApp/Dynamics.cpp
@@ -0,0 +1,776 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Dynamics.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Environ.h"
+#include "MainWindow.h"
+#include "Objects.h"
+#include "RectUtils.h"
+#include "Room.h"
+
+
+#define kShoveVelocity 8
+
+
+Rect breadSrc[kNumBreadPicts];
+
+extern dynaPtr dinahs;
+extern bandPtr bands;
+extern short numBands, tvWithMovieNumber;
+extern Boolean evenFrame, twoPlayerGame, onePlayerLeft, playerDead;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- CheckDynamicCollision
+
+// Checks for a collision betwen the glider and one of the dynamic objects.
+// For example, did the glider hit a flying piece of toast?
+
+void CheckDynamicCollision (short who, gliderPtr thisGlider, Boolean doOffset)
+{
+ Rect dinahRect;
+
+ dinahRect = dinahs[who].dest;
+ if (doOffset)
+ QOffsetRect(&dinahRect, -playOriginH, -playOriginV);
+
+ if (SectGlider(thisGlider, &dinahRect, true))
+ {
+ if ((thisGlider->mode == kGliderNormal) ||
+ (thisGlider->mode == kGliderFaceLeft) ||
+ (thisGlider->mode == kGliderFaceRight) ||
+ (thisGlider->mode == kGliderBurning) ||
+ (thisGlider->mode == kGliderGoingFoil) ||
+ (thisGlider->mode == kGliderLosingFoil))
+ {
+ if ((foilTotal > 0) || (thisGlider->mode == kGliderLosingFoil))
+ {
+ if (IsRectLeftOfRect(&dinahRect, &thisGlider->dest))
+ thisGlider->hDesiredVel = kShoveVelocity;
+ else
+ thisGlider->hDesiredVel = -kShoveVelocity;
+ if (dinahs[who].vVel < 0)
+ thisGlider->vDesiredVel = dinahs[who].vVel;
+ PlayPrioritySound(kFoilHitSound, kFoilHitPriority);
+ if ((evenFrame) && (foilTotal > 0))
+ {
+ foilTotal--;
+ if (foilTotal <= 0)
+ StartGliderFoilLosing(thisGlider);
+ }
+ }
+ else
+ {
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- DidBandHitDynamic
+
+// Checks to see if a rubber band struck a dynamic.
+
+Boolean DidBandHitDynamic (short who)
+{
+ Rect dinahRect;
+ short i;
+ Boolean collided;
+
+ dinahRect = dinahs[who].dest;
+
+ for (i = 0; i < numBands; i++)
+ {
+ if (bands[i].dest.bottom < dinahRect.top)
+ collided = false;
+ else if (bands[i].dest.top > dinahRect.bottom)
+ collided = false;
+ else if (bands[i].dest.right < dinahRect.left)
+ collided = false;
+ else if (bands[i].dest.left > dinahRect.right)
+ collided = false;
+ else
+ collided = true;
+
+ if (collided)
+ break;
+ }
+
+ return (collided);
+}
+
+//-------------------------------------------------------------- RenderToast
+
+// The following handful of functions handle drawing specific "dynamic" objecsts.
+
+void RenderToast (short who)
+{
+ Rect src, dest;
+ short vClip;
+
+ if (dinahs[who].moving)
+ {
+ dest = dinahs[who].dest;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ src = breadSrc[dinahs[who].frame];
+ vClip = dinahs[who].dest.bottom - dinahs[who].hVel;
+ if (vClip > 0)
+ {
+ src.bottom -= vClip;
+ dest.bottom -= vClip;
+ }
+
+ CopyMask((BitMap *)*GetGWorldPixMap(toastSrcMap),
+ (BitMap *)*GetGWorldPixMap(toastMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &src, &dest);
+
+ AddRectToBackRects(&dest);
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ }
+}
+
+//-------------------------------------------------------------- RenderBalloon
+
+void RenderBalloon (short who)
+{
+ Rect src, dest;
+
+ if (dinahs[who].moving)
+ {
+ dest = dinahs[who].dest;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ src = balloonSrc[dinahs[who].frame];
+
+ CopyMask((BitMap *)*GetGWorldPixMap(balloonSrcMap),
+ (BitMap *)*GetGWorldPixMap(balloonMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &src, &dest);
+
+ AddRectToBackRects(&dest);
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ }
+}
+
+//-------------------------------------------------------------- RenderCopter
+
+void RenderCopter (short who)
+{
+ Rect src, dest;
+
+ if (dinahs[who].moving)
+ {
+ dest = dinahs[who].dest;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ src = copterSrc[dinahs[who].frame];
+
+ CopyMask((BitMap *)*GetGWorldPixMap(copterSrcMap),
+ (BitMap *)*GetGWorldPixMap(copterMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &src, &dest);
+
+ AddRectToBackRects(&dest);
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ }
+}
+
+//-------------------------------------------------------------- RenderDart
+
+void RenderDart (short who)
+{
+ Rect src, dest;
+
+ if (dinahs[who].moving)
+ {
+ dest = dinahs[who].dest;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ src = dartSrc[dinahs[who].frame];
+
+ CopyMask((BitMap *)*GetGWorldPixMap(dartSrcMap),
+ (BitMap *)*GetGWorldPixMap(dartMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &src, &dest);
+
+ AddRectToBackRects(&dest);
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ }
+}
+
+//-------------------------------------------------------------- RenderBall
+
+void RenderBall (short who)
+{
+ Rect src, dest;
+
+ dest = dinahs[who].dest;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ src = ballSrc[dinahs[who].frame];
+
+ CopyMask((BitMap *)*GetGWorldPixMap(ballSrcMap),
+ (BitMap *)*GetGWorldPixMap(ballMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &src, &dest);
+
+ AddRectToBackRects(&dest);
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+}
+
+//-------------------------------------------------------------- RenderDrip
+
+void RenderDrip (short who)
+{
+ Rect src, dest;
+
+ dest = dinahs[who].dest;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ src = dripSrc[dinahs[who].frame];
+
+ CopyMask((BitMap *)*GetGWorldPixMap(dripSrcMap),
+ (BitMap *)*GetGWorldPixMap(dripMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &src, &dest);
+
+ AddRectToBackRects(&dest);
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+}
+
+//-------------------------------------------------------------- RenderFish
+
+void RenderFish (short who)
+{
+ Rect src, dest;
+
+ dest = dinahs[who].dest;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ src = fishSrc[dinahs[who].frame];
+
+ if (dinahs[who].moving)
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(fishSrcMap),
+ (BitMap *)*GetGWorldPixMap(fishMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &src, &dest);
+ AddRectToBackRects(&dest);
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(fishSrcMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &dest, srcCopy, nil);
+ AddRectToBackRects(&dest);
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ }
+}
+
+//-------------------------------------------------------------- HandleSparkleObject
+
+// The following handful of functions are called each game frame and handleÉ
+// the movement and state of the various types of dynamic objects.
+
+void HandleSparkleObject (short who)
+{
+ Rect tempRect;
+
+ if (dinahs[who].active) // is it on?
+ {
+ if (dinahs[who].frame <= 0) // is it idle?
+ { // it is idle
+ dinahs[who].timer--;
+ if (dinahs[who].timer <= 0)
+ {
+ dinahs[who].timer = RandomInt(240) + 60;// reset timer
+ dinahs[who].frame = kNumSparkleModes; // time to sparkle
+ tempRect = dinahs[who].dest;
+ AddSparkle(&tempRect);
+ PlayPrioritySound(kMysticSound, kMysticPriority);
+ }
+ }
+ else // it's sparkling
+ dinahs[who].frame--;
+ }
+ else
+ {
+ }
+}
+
+//-------------------------------------------------------------- HandleToast
+
+void HandleToast (short who)
+{
+ Rect dest;
+
+ if (dinahs[who].moving)
+ {
+ if (evenFrame)
+ {
+ dinahs[who].frame++;
+ if (dinahs[who].frame >= kNumBreadPicts)
+ dinahs[who].frame = 0;
+ }
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == theGlider.which)
+ CheckDynamicCollision(who, &theGlider2, false);
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ }
+ else
+ {
+ CheckDynamicCollision(who, &theGlider, false);
+ CheckDynamicCollision(who, &theGlider2, false);
+ }
+ }
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ VOffsetRect(&dinahs[who].dest, dinahs[who].vVel);
+ dinahs[who].whole = dinahs[who].dest;
+ if (dinahs[who].vVel > 0)
+ dinahs[who].whole.top -= dinahs[who].vVel;
+ else
+ dinahs[who].whole.bottom -= dinahs[who].vVel;
+ dinahs[who].vVel++; // falls
+ if (dinahs[who].vVel > dinahs[who].count)
+ {
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ dinahs[who].moving = false;
+ dinahs[who].frame = dinahs[who].timer;
+ PlayPrioritySound(kToastLandSound, kToastLandPriority);
+ }
+ }
+ else
+ {
+ if (dinahs[who].active)
+ dinahs[who].frame--;
+ if (dinahs[who].frame <= 0)
+ {
+ if (dinahs[who].active)
+ {
+ dinahs[who].vVel = (short)-dinahs[who].count;
+ dinahs[who].frame = 0;
+ dinahs[who].moving = true;
+ PlayPrioritySound(kToastLaunchSound, kToastLaunchPriority);
+ }
+ else
+ dinahs[who].frame = dinahs[who].timer;
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleMacPlus
+
+void HandleMacPlus (short who)
+{
+ if (dinahs[who].timer > 0)
+ {
+ dinahs[who].timer--;
+ if (dinahs[who].active)
+ {
+ if (dinahs[who].timer == 0)
+ AddRectToWorkRects(&dinahs[who].dest);
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kMacBeepSound, kMacBeepPriority);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &plusScreen2, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ else if (dinahs[who].timer == 30)
+ PlayPrioritySound(kMacOnSound, kMacOnPriority);
+ }
+ else
+ {
+ if (dinahs[who].timer == 0)
+ AddRectToWorkRects(&dinahs[who].dest);
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kMacOffSound, kMacOffPriority);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &plusScreen1, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleTV
+
+void HandleTV (short who)
+{
+ if (dinahs[who].timer > 0)
+ {
+ dinahs[who].timer--;
+ if (dinahs[who].active)
+ {
+ if (dinahs[who].timer == 0)
+ {
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom) &&
+ (who == tvWithMovieNumber))
+ {
+ }
+ else
+ {
+ AddRectToWorkRects(&dinahs[who].dest);
+ }
+ }
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kTVOnSound, kTVOnPriority);
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom) &&
+ (who == tvWithMovieNumber))
+ {
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &tvScreen2, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ }
+ }
+ else
+ {
+ if (dinahs[who].timer == 0)
+ AddRectToWorkRects(&dinahs[who].dest);
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kTVOffSound, kTVOffPriority);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &tvScreen1, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleCoffee
+
+void HandleCoffee (short who)
+{
+ if (dinahs[who].timer > 0)
+ {
+ dinahs[who].timer--;
+ if (dinahs[who].active)
+ {
+ if (dinahs[who].timer == 0)
+ {
+ AddRectToWorkRects(&dinahs[who].dest);
+ dinahs[who].timer = 200 + RandomInt(200);
+ }
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kMacOnSound, kMacOnPriority);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &coffeeLight2, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ else if (dinahs[who].timer == 100)
+ {
+ PlayPrioritySound(kCoffeeSound, kCoffeePriority);
+ dinahs[who].timer = 200 + RandomInt(200);
+ }
+ }
+ else
+ {
+ if (dinahs[who].timer == 0)
+ AddRectToWorkRects(&dinahs[who].dest);
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kMacOffSound, kMacOffPriority);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &coffeeLight1, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleOutlet
+
+void HandleOutlet (short who)
+{
+ if (dinahs[who].position != 0)
+ {
+ dinahs[who].timer--;
+
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == theGlider.which)
+ CheckDynamicCollision(who, &theGlider2, false);
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ }
+ else
+ {
+ CheckDynamicCollision(who, &theGlider, true);
+ CheckDynamicCollision(who, &theGlider2, true);
+ }
+ }
+ else
+ CheckDynamicCollision(who, &theGlider, true);
+
+ if (dinahs[who].timer <= 0)
+ {
+ dinahs[who].frame = 0;
+ dinahs[who].position = 0;
+ dinahs[who].timer = dinahs[who].count;
+ }
+ else
+ {
+ if ((dinahs[who].timer % 5) == 0)
+ PlayPrioritySound(kZapSound, kZapPriority);
+ dinahs[who].frame++;
+ if (dinahs[who].frame >= kNumOutletPicts)
+ dinahs[who].frame = 1;
+ }
+
+ if ((dinahs[who].position != 0) || (dinahs[who].hVel > 0))
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &outletSrc[dinahs[who].frame],
+ &dinahs[who].dest,
+ srcCopy, nil);
+ }
+ else
+ {
+// SetPort((GrafPtr)workSrcMap);
+ PaintRect(&dinahs[who].dest);
+ }
+ AddRectToWorkRects(&dinahs[who].dest);
+ }
+ else
+ {
+ if (dinahs[who].active)
+ dinahs[who].timer--;
+
+ if (dinahs[who].timer <= 0)
+ {
+ if (dinahs[who].active)
+ {
+ dinahs[who].position = 1;
+ dinahs[who].timer = kLengthOfZap;
+ PlayPrioritySound(kZapSound, kZapPriority);
+ }
+ else
+ dinahs[who].timer = dinahs[who].count;
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleVCR
+
+void HandleVCR (short who)
+{
+ if (dinahs[who].timer > 0)
+ {
+ dinahs[who].timer--;
+ if (dinahs[who].active)
+ {
+ if (dinahs[who].timer == 0)
+ {
+ AddRectToWorkRects(&dinahs[who].dest);
+ dinahs[who].timer = 115;
+ }
+ else if (dinahs[who].timer == 5)
+ PlayPrioritySound(kMacOnSound, kMacOnPriority);
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kVCRSound, kVCRPriority);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &vcrTime2, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ else if (dinahs[who].timer == 100)
+ {
+ AddRectToWorkRects(&dinahs[who].dest);
+ dinahs[who].timer = 115;
+ dinahs[who].frame = 1 - dinahs[who].frame;
+ }
+ else if (dinahs[who].timer == 101)
+ {
+ if (dinahs[who].frame == 0)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &vcrTime2, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &vcrTime1, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ }
+ }
+ else
+ {
+ if (dinahs[who].timer == 0)
+ AddRectToWorkRects(&dinahs[who].dest);
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kMacOffSound, kMacOffPriority);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &vcrTime1, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleStereo
+
+void HandleStereo (short who)
+{
+ if (dinahs[who].timer > 0)
+ {
+ dinahs[who].timer--;
+ if (dinahs[who].active)
+ {
+ if (dinahs[who].timer == 0)
+ {
+ AddRectToWorkRects(&dinahs[who].dest);
+ ToggleMusicWhilePlaying();
+ }
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kMacOnSound, kMacOnPriority);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &stereoLight2, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ }
+ else
+ {
+ if (dinahs[who].timer == 0)
+ {
+ AddRectToWorkRects(&dinahs[who].dest);
+ ToggleMusicWhilePlaying();
+ }
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kMacOffSound, kMacOffPriority);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &stereoLight1, &dinahs[who].dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleMicrowave
+
+void HandleMicrowave (short who)
+{
+ Rect dest;
+
+ if (dinahs[who].timer > 0)
+ {
+ dinahs[who].timer--;
+ if (dinahs[who].active)
+ {
+ if (dinahs[who].timer == 0)
+ AddRectToWorkRects(&dinahs[who].dest);
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kMacOnSound, kMacOnPriority);
+ dest = dinahs[who].dest;
+ dest.right = dest.left + 16;
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOn, &dest,
+ srcCopy, nil);
+ QOffsetRect(&dest, 16, 0);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOn, &dest,
+ srcCopy, nil);
+ QOffsetRect(&dest, 16, 0);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOn, &dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ }
+ else
+ {
+ if (dinahs[who].timer == 0)
+ AddRectToWorkRects(&dinahs[who].dest);
+ else if (dinahs[who].timer == 1)
+ {
+ PlayPrioritySound(kMacOffSound, kMacOffPriority);
+ dest = dinahs[who].dest;
+ dest.right = dest.left + 16;
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOff, &dest,
+ srcCopy, nil);
+ QOffsetRect(&dest, 16, 0);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOff, &dest,
+ srcCopy, nil);
+ QOffsetRect(&dest, 16, 0);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOff, &dest,
+ srcCopy, nil);
+ AddRectToBackRects(&dinahs[who].dest);
+ }
+ }
+ }
+}
+
diff --git a/GpApp/Dynamics2.cpp b/GpApp/Dynamics2.cpp
new file mode 100644
index 0000000..212640f
--- /dev/null
+++ b/GpApp/Dynamics2.cpp
@@ -0,0 +1,589 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Dynamics2.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "RectUtils.h"
+
+
+#define kBalloonStop 8
+#define kBalloonStart 310
+#define kCopterStart 8
+#define kCopterStop 310
+#define kDartVelocity 6
+#define kDartStop 310
+#define kEnemyDropSpeed 8
+
+
+extern dynaPtr dinahs;
+extern short numBands;
+extern Boolean evenFrame, twoPlayerGame, onePlayerLeft, playerDead;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- HandleBalloon
+
+void HandleBalloon (short who)
+{
+ Rect dest;
+
+ if (dinahs[who].moving)
+ {
+ if (dinahs[who].vVel < 0)
+ {
+ if (evenFrame)
+ {
+ dinahs[who].frame++;
+ if (dinahs[who].frame >= 6)
+ dinahs[who].frame = 0;
+ }
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == theGlider.which)
+ CheckDynamicCollision(who, &theGlider2, false);
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ }
+ else
+ {
+ CheckDynamicCollision(who, &theGlider, false);
+ CheckDynamicCollision(who, &theGlider2, false);
+ }
+ }
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+
+ if ((numBands > 0) && (DidBandHitDynamic(who)))
+ {
+ dinahs[who].frame = 6;
+ dinahs[who].vVel = kEnemyDropSpeed;
+ PlayPrioritySound(kPopSound, kPopPriority);
+ }
+ else
+ {
+ VOffsetRect(&dinahs[who].dest, dinahs[who].vVel);
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].whole.bottom -= dinahs[who].vVel;
+ }
+ }
+ else
+ {
+ if (evenFrame)
+ {
+ dinahs[who].frame++;
+ if (dinahs[who].frame >= 8)
+ dinahs[who].frame = 6;
+ }
+
+ VOffsetRect(&dinahs[who].dest, dinahs[who].vVel);
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].whole.top -= dinahs[who].vVel;
+ }
+
+ if ((dinahs[who].dest.top <= kBalloonStop) ||
+ (dinahs[who].dest.bottom >= kBalloonStart))
+ {
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ dest = dinahs[who].dest;
+ AddSparkle(&dest);
+ PlayPrioritySound(kEnemyOutSound, kEnemyOutPriority);
+ dinahs[who].moving = false;
+ dinahs[who].vVel = -2;
+ dinahs[who].timer = dinahs[who].count;
+ dinahs[who].dest.bottom = kBalloonStart;
+ dinahs[who].dest.top = dinahs[who].dest.bottom -
+ RectTall(&balloonSrc[0]);
+ dinahs[who].whole = dinahs[who].dest;
+ }
+ }
+ else // balloon is idle, waiting to appear
+ {
+ if (dinahs[who].active)
+ {
+ dinahs[who].timer--;
+ if (dinahs[who].timer <= 0)
+ {
+ dinahs[who].moving = true;
+ if (dinahs[who].count < kStartSparkle)
+ {
+ dest = dinahs[who].dest;
+ AddSparkle(&dest);
+ PlayPrioritySound(kEnemyInSound, kEnemyInPriority);
+ }
+ }
+ else if (dinahs[who].timer == kStartSparkle)
+ {
+ dest = dinahs[who].dest;
+ AddSparkle(&dest);
+ PlayPrioritySound(kEnemyInSound, kEnemyInPriority);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleCopter
+
+void HandleCopter (short who)
+{
+ Rect dest;
+
+ if (dinahs[who].moving) // is 'copter about?
+ {
+ if (dinahs[who].hVel != 0) // 'copter was not shot
+ {
+ dinahs[who].frame++;
+ if (dinahs[who].frame >= 8)
+ dinahs[who].frame = 0;
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == theGlider.which)
+ CheckDynamicCollision(who, &theGlider2, false);
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ }
+ else
+ {
+ CheckDynamicCollision(who, &theGlider, false);
+ CheckDynamicCollision(who, &theGlider2, false);
+ }
+ }
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ if ((numBands > 0) && (DidBandHitDynamic(who)))
+ {
+ dinahs[who].frame = 8;
+ dinahs[who].hVel = 0;
+ dinahs[who].vVel = kEnemyDropSpeed;
+ PlayPrioritySound(kPaperCrunchSound, kPaperCrunchPriority);
+ }
+ else
+ {
+ HOffsetRect(&dinahs[who].dest, dinahs[who].hVel);
+ VOffsetRect(&dinahs[who].dest, dinahs[who].vVel);
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].whole.top -= dinahs[who].vVel;
+ if (dinahs[who].hVel < 0)
+ dinahs[who].whole.right -= dinahs[who].hVel;
+ else
+ dinahs[who].whole.left -= dinahs[who].hVel;
+ }
+ }
+ else // 'copter was shot
+ {
+ dinahs[who].frame++;
+ if (dinahs[who].frame >= 10)
+ dinahs[who].frame = 8;
+ VOffsetRect(&dinahs[who].dest, dinahs[who].vVel);
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].whole.top -= dinahs[who].vVel;
+ }
+
+ if ((dinahs[who].dest.top <= kCopterStart) ||
+ (dinahs[who].dest.bottom >= kCopterStop))
+ {
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ dest = dinahs[who].dest;
+ AddSparkle(&dest);
+ PlayPrioritySound(kEnemyOutSound, kEnemyOutPriority);
+ dinahs[who].moving = false;
+ dinahs[who].vVel = 2;
+ if (dinahs[who].type == kCopterLf)
+ dinahs[who].hVel = -1;
+ else
+ dinahs[who].hVel = 1;
+ dinahs[who].timer = dinahs[who].count;
+ dinahs[who].dest.top = kCopterStart;
+ dinahs[who].dest.bottom = dinahs[who].dest.top +
+ RectTall(&copterSrc[0]);
+ dinahs[who].dest.left = dinahs[who].position;
+ dinahs[who].dest.right = dinahs[who].dest.left + 32;
+ dinahs[who].whole = dinahs[who].dest;
+ }
+ }
+ else
+ {
+ if (dinahs[who].active)
+ {
+ dinahs[who].timer--;
+ if (dinahs[who].timer <= 0)
+ {
+ dinahs[who].moving = true;
+ if (dinahs[who].count < kStartSparkle)
+ {
+ dest = dinahs[who].dest;
+ AddSparkle(&dest);
+ PlayPrioritySound(kEnemyInSound, kEnemyInPriority);
+ }
+ }
+ else if (dinahs[who].timer == kStartSparkle)
+ {
+ dest = dinahs[who].dest;
+ AddSparkle(&dest);
+ PlayPrioritySound(kEnemyInSound, kEnemyInPriority);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleDart
+
+void HandleDart (short who)
+{
+ Rect dest;
+
+ if (dinahs[who].moving) // Dart has appeared
+ {
+ if (dinahs[who].hVel != 0) // meaning it isn't falling
+ {
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == theGlider.which)
+ CheckDynamicCollision(who, &theGlider2, false);
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ }
+ else
+ {
+ CheckDynamicCollision(who, &theGlider, false);
+ CheckDynamicCollision(who, &theGlider2, false);
+ }
+ }
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ if ((numBands > 0) && (DidBandHitDynamic(who)))
+ {
+ if (dinahs[who].type == kDartLf)
+ dinahs[who].frame = 1;
+ else
+ dinahs[who].frame = 3;
+ dinahs[who].hVel = 0;
+ dinahs[who].vVel = kEnemyDropSpeed;
+ PlayPrioritySound(kPaperCrunchSound, kPaperCrunchPriority);
+ }
+ else
+ {
+ HOffsetRect(&dinahs[who].dest, dinahs[who].hVel);
+ VOffsetRect(&dinahs[who].dest, dinahs[who].vVel);
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].whole.top -= dinahs[who].vVel;
+ if (dinahs[who].hVel < 0)
+ dinahs[who].whole.right -= dinahs[who].hVel;
+ else
+ dinahs[who].whole.left -= dinahs[who].hVel;
+ }
+ }
+ else // dart is falling straight down
+ {
+ VOffsetRect(&dinahs[who].dest, dinahs[who].vVel);
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].whole.top -= dinahs[who].vVel;
+ }
+
+ if ((dinahs[who].dest.left <= 0) ||
+ (dinahs[who].dest.right >= kRoomWide) ||
+ (dinahs[who].dest.bottom >= kDartStop))
+ {
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ dest = dinahs[who].dest;
+ AddSparkle(&dest);
+ PlayPrioritySound(kEnemyOutSound, kEnemyOutPriority);
+ dinahs[who].moving = false;
+ dinahs[who].vVel = 2;
+ if (dinahs[who].type == kDartLf)
+ {
+ dinahs[who].frame = 0;
+ dinahs[who].hVel = -kDartVelocity;
+ dinahs[who].dest.right = kRoomWide;
+ dinahs[who].dest.left = dinahs[who].dest.right -
+ RectWide(&dartSrc[0]);
+ }
+ else
+ {
+ dinahs[who].frame = 2;
+ dinahs[who].hVel = kDartVelocity;
+ dinahs[who].dest.left = 0;
+ dinahs[who].dest.right = dinahs[who].dest.left +
+ RectWide(&dartSrc[0]);
+ }
+ dinahs[who].timer = dinahs[who].count;
+ dinahs[who].dest.top = dinahs[who].position;
+ dinahs[who].dest.bottom = dinahs[who].dest.top +
+ RectTall(&dartSrc[0]);
+ dinahs[who].whole = dinahs[who].dest;
+ }
+ }
+ else
+ {
+ if (dinahs[who].active)
+ {
+ dinahs[who].timer--;
+ if (dinahs[who].timer <= 0)
+ {
+ dinahs[who].moving = true;
+ if (dinahs[who].count < kStartSparkle)
+ {
+ dest = dinahs[who].dest;
+ AddSparkle(&dest);
+ PlayPrioritySound(kEnemyInSound, kEnemyInPriority);
+ }
+ }
+ else if (dinahs[who].timer == kStartSparkle)
+ {
+ dest = dinahs[who].dest;
+ AddSparkle(&dest);
+ PlayPrioritySound(kEnemyInSound, kEnemyInPriority);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleBall
+
+void HandleBall (short who)
+{
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == theGlider.which)
+ CheckDynamicCollision(who, &theGlider2, false);
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ }
+ else
+ {
+ CheckDynamicCollision(who, &theGlider, false);
+ CheckDynamicCollision(who, &theGlider2, false);
+ }
+ }
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+
+ if (dinahs[who].moving) // is ball bouncing?
+ {
+ VOffsetRect(&dinahs[who].dest, dinahs[who].vVel);
+ if (dinahs[who].dest.bottom >= dinahs[who].position) // bounce!
+ {
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].whole.top -= dinahs[who].vVel;
+ dinahs[who].whole.bottom = dinahs[who].position;
+ dinahs[who].dest.bottom = dinahs[who].position;
+ dinahs[who].dest.top = dinahs[who].dest.bottom - 32;
+ if (dinahs[who].active)
+ dinahs[who].vVel = dinahs[who].count;
+ else
+ {
+ dinahs[who].vVel = -((dinahs[who].vVel * 3) / 4);
+ if (dinahs[who].vVel == 0)
+ dinahs[who].moving = false; // stop bounce
+ }
+ if (dinahs[who].whole.bottom < dinahs[who].dest.bottom)
+ dinahs[who].whole.bottom = dinahs[who].dest.bottom;
+ PlayPrioritySound(kBounceSound, kBouncePriority);
+ if (dinahs[who].moving)
+ dinahs[who].frame = 1;
+ }
+ else
+ {
+ dinahs[who].whole = dinahs[who].dest;
+ if (dinahs[who].vVel > 0)
+ dinahs[who].whole.top -= dinahs[who].vVel;
+ else
+ dinahs[who].whole.bottom -= dinahs[who].vVel;
+ if (evenFrame)
+ dinahs[who].vVel++;
+ dinahs[who].frame = 0;
+ }
+ }
+ else
+ {
+ if (dinahs[who].active)
+ {
+ dinahs[who].vVel = dinahs[who].count;
+ dinahs[who].moving = true;
+ evenFrame = true;
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleDrip
+
+void HandleDrip (short who)
+{
+ Rect dest;
+
+ if (dinahs[who].moving)
+ {
+ if (evenFrame)
+ dinahs[who].frame = 9 - dinahs[who].frame;
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == theGlider.which)
+ CheckDynamicCollision(who, &theGlider2, false);
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ }
+ else
+ {
+ CheckDynamicCollision(who, &theGlider, false);
+ CheckDynamicCollision(who, &theGlider2, false);
+ }
+ }
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+
+ VOffsetRect(&dinahs[who].dest, dinahs[who].vVel);
+ if (dinahs[who].dest.bottom >= dinahs[who].position)
+ {
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ dinahs[who].dest.top = dinahs[who].hVel;
+ dinahs[who].dest.bottom = dinahs[who].dest.top + 12;
+ PlayPrioritySound(kDropSound, kDropPriority);
+ dinahs[who].vVel = 0;
+ dinahs[who].timer = dinahs[who].count;
+ dinahs[who].frame = 3;
+ dinahs[who].moving = false;
+ }
+ else
+ {
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].whole.top -= dinahs[who].vVel;
+ if (evenFrame)
+ dinahs[who].vVel++;
+ }
+ }
+ else
+ {
+ if (dinahs[who].active)
+ {
+ dinahs[who].timer--;
+
+ if (dinahs[who].timer == 6)
+ dinahs[who].frame = 0;
+ else if (dinahs[who].timer == 4)
+ dinahs[who].frame = 1;
+ else if (dinahs[who].timer == 2)
+ dinahs[who].frame = 2;
+ else if (dinahs[who].timer <= 0)
+ {
+ VOffsetRect(&dinahs[who].dest, 3);
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].moving = true;
+ dinahs[who].frame = 4;
+ PlayPrioritySound(kDripSound, kDripPriority);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleFish
+
+void HandleFish (short who)
+{
+ Rect dest;
+
+ if (dinahs[who].moving) // fish leaping
+ {
+ if ((dinahs[who].vVel >= 0) && (dinahs[who].frame < 7))
+ dinahs[who].frame++;
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == theGlider.which)
+ CheckDynamicCollision(who, &theGlider2, false);
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+ }
+ else
+ {
+ CheckDynamicCollision(who, &theGlider, false);
+ CheckDynamicCollision(who, &theGlider2, false);
+ }
+ }
+ else
+ CheckDynamicCollision(who, &theGlider, false);
+
+ VOffsetRect(&dinahs[who].dest, dinahs[who].vVel);
+ if (dinahs[who].dest.bottom >= dinahs[who].position) // splash down
+ {
+ dest = dinahs[who].whole;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+ dinahs[who].dest.bottom = dinahs[who].position;
+ dinahs[who].dest.top = dinahs[who].dest.bottom - 16;
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].whole.top -= 2;
+ PlayPrioritySound(kDropSound, kDropPriority);
+ dinahs[who].vVel = dinahs[who].count;
+ dinahs[who].timer = dinahs[who].hVel;
+ dinahs[who].frame = 0;
+ dinahs[who].moving = false;
+ PlayPrioritySound(kFishInSound, kFishInPriority);
+ }
+ else
+ {
+ dinahs[who].whole = dinahs[who].dest;
+ if (dinahs[who].vVel > 0)
+ dinahs[who].whole.top -= dinahs[who].vVel;
+ else
+ dinahs[who].whole.bottom -= dinahs[who].vVel;
+ if (evenFrame)
+ dinahs[who].vVel++;
+ }
+ }
+ else // fish idle
+ {
+ dinahs[who].whole = dinahs[who].dest;
+ if ((dinahs[who].timer & 0x0003) == 0x0003)
+ {
+ dinahs[who].frame++;
+ if (dinahs[who].frame > 3)
+ dinahs[who].frame = 0;
+ if ((dinahs[who].frame == 1) || (dinahs[who].frame == 2))
+ {
+ dinahs[who].dest.top++;
+ dinahs[who].dest.bottom++;
+ dinahs[who].whole.bottom++;
+ }
+ else
+ {
+ dinahs[who].dest.top--;
+ dinahs[who].dest.bottom--;
+ dinahs[who].whole.top--;
+ }
+ }
+ if (dinahs[who].active)
+ {
+ dinahs[who].timer--;
+ if (dinahs[who].timer <= 0) // fish leaps
+ {
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].moving = true;
+ dinahs[who].frame = 4;
+ PlayPrioritySound(kFishOutSound, kFishOutPriority);
+ }
+ }
+ }
+}
+
diff --git a/GpApp/Dynamics3.cpp b/GpApp/Dynamics3.cpp
new file mode 100644
index 0000000..5011153
--- /dev/null
+++ b/GpApp/Dynamics3.cpp
@@ -0,0 +1,555 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Dynamics3.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "RectUtils.h"
+
+
+#define kBalloonStart 310
+#define kCopterStart 8
+#define kDartVelocity 6
+
+
+dynaPtr dinahs;
+short numDynamics;
+
+extern Rect breadSrc[];
+extern short numLights;
+extern Boolean evenFrame;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- HandleDynamics
+
+// This is the master function that calls all the specific handlers above.
+
+void HandleDynamics (void)
+{
+ short i;
+
+ for (i = 0; i < numDynamics; i++)
+ {
+ switch (dinahs[i].type)
+ {
+ case kSparkle:
+ HandleSparkleObject(i);
+ break;
+
+ case kToaster:
+ HandleToast(i);
+ break;
+
+ case kMacPlus:
+ HandleMacPlus(i);
+ break;
+
+ case kTV:
+ HandleTV(i);
+ break;
+
+ case kCoffee:
+ HandleCoffee(i);
+ break;
+
+ case kOutlet:
+ HandleOutlet(i);
+ break;
+
+ case kVCR:
+ HandleVCR(i);
+ break;
+
+ case kStereo:
+ HandleStereo(i);
+ break;
+
+ case kMicrowave:
+ HandleMicrowave(i);
+ break;
+
+ case kBalloon:
+ HandleBalloon(i);
+ break;
+
+ case kCopterLf:
+ case kCopterRt:
+ HandleCopter(i);
+ break;
+
+ case kDartLf:
+ case kDartRt:
+ HandleDart(i);
+ break;
+
+ case kBall:
+ HandleBall(i);
+ break;
+
+ case kDrip:
+ HandleDrip(i);
+ break;
+
+ case kFish:
+ HandleFish(i);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleDynamics
+
+// This is the master function that calls all the various rendering handlersÉ
+// above.
+
+void RenderDynamics (void)
+{
+ short i;
+
+ for (i = 0; i < numDynamics; i++)
+ {
+ switch (dinahs[i].type)
+ {
+ case kToaster:
+ RenderToast(i);
+ break;
+
+ case kBalloon:
+ RenderBalloon(i);
+ break;
+
+ case kCopterLf:
+ case kCopterRt:
+ RenderCopter(i);
+ break;
+
+ case kDartLf:
+ case kDartRt:
+ RenderDart(i);
+ break;
+
+ case kBall:
+ RenderBall(i);
+ break;
+
+ case kDrip:
+ RenderDrip(i);
+ break;
+
+ case kFish:
+ RenderFish(i);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+//-------------------------------------------------------------- ZeroDinahs
+
+// This clears all dynamics - zeros them all out. Used to initialize them.
+
+void ZeroDinahs (void)
+{
+ short i;
+
+ for (i = 0; i < kMaxDynamicObs; i++)
+ {
+ dinahs[i].type = kObjectIsEmpty;
+ QSetRect(&dinahs[i].dest, 0, 0, 0, 0);
+ QSetRect(&dinahs[i].whole, 0, 0, 0, 0);
+ dinahs[i].hVel = 0;
+ dinahs[i].vVel = 0;
+ dinahs[i].count = 0;
+ dinahs[i].frame = 0;
+ dinahs[i].timer = 0;
+ dinahs[i].position = 0;
+ dinahs[i].room = 0;
+ dinahs[i].byte0 = 0;
+ dinahs[i].active = false;
+ }
+ numDynamics = 0;
+}
+
+//-------------------------------------------------------------- AddDynamicObject
+
+// When a room is being drawn, various dynamic objects are pointed here.
+// This function sets up the structures to handle them.
+
+short AddDynamicObject (short what, Rect *where, objectType *who,
+ short room, short index, Boolean isOn)
+{
+ short position, velocity;
+ Boolean lilFrame;
+
+ if (numDynamics >= kMaxDynamicObs)
+ return (-1);
+
+ dinahs[numDynamics].type = what;
+ switch (what)
+ {
+ case kSparkle:
+ dinahs[numDynamics].dest = sparkleSrc[0];
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest, where->left, where->top);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = 0;
+ dinahs[numDynamics].vVel = 0;
+ dinahs[numDynamics].count = 0;
+ dinahs[numDynamics].frame = 0;
+ dinahs[numDynamics].timer = RandomInt(60) + 15;
+ dinahs[numDynamics].position = 0;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kToaster:
+ dinahs[numDynamics].dest = breadSrc[0];
+ CenterRectInRect(&dinahs[numDynamics].dest, where);
+ VOffsetRect(&dinahs[numDynamics].dest,
+ where->top - dinahs[numDynamics].dest.top);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = where->top + 2; // hVel used as clip
+ position = who->data.g.height; // reverse engineer init. vel.
+ velocity = 0;
+ do
+ {
+ velocity++;
+ position -= velocity;
+ }
+ while (position > 0);
+ dinahs[numDynamics].vVel = -velocity;
+ dinahs[numDynamics].count = velocity; // count = initial velocity
+ dinahs[numDynamics].frame = (short)who->data.g.delay * 3;
+ dinahs[numDynamics].timer = dinahs[numDynamics].frame;
+ dinahs[numDynamics].position = 0; // launch/idle state
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kMacPlus:
+ dinahs[numDynamics].dest = plusScreen1;
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest,
+ where->left + playOriginH + 10,
+ where->top + playOriginV + 7);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = 0;
+ dinahs[numDynamics].vVel = 0;
+ dinahs[numDynamics].count = 0;
+ dinahs[numDynamics].frame = 0;
+ dinahs[numDynamics].timer = 0;
+ dinahs[numDynamics].position = 0;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kTV:
+ dinahs[numDynamics].dest = tvScreen1;
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest,
+ where->left + playOriginH + 17,
+ where->top + playOriginV + 10);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = 0;
+ dinahs[numDynamics].vVel = 0;
+ dinahs[numDynamics].count = 0;
+ dinahs[numDynamics].frame = 0;
+ dinahs[numDynamics].timer = 0;
+ dinahs[numDynamics].position = 0;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kCoffee:
+ dinahs[numDynamics].dest = coffeeLight1;
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest,
+ where->left + playOriginH + 32,
+ where->top + playOriginV + 57);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = 0;
+ dinahs[numDynamics].vVel = 0;
+ dinahs[numDynamics].count = 0;
+ dinahs[numDynamics].frame = 0;
+ if (isOn)
+ dinahs[numDynamics].timer = 200;
+ else
+ dinahs[numDynamics].timer = 0;
+ dinahs[numDynamics].position = 0;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kOutlet:
+ dinahs[numDynamics].dest = outletSrc[0];
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest,
+ where->left + playOriginH,
+ where->top + playOriginV);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = numLights;
+ dinahs[numDynamics].vVel = 0;
+ dinahs[numDynamics].count = ((short)who->data.g.delay * 6) / kTicksPerFrame;
+ dinahs[numDynamics].frame = 0;
+ dinahs[numDynamics].timer = dinahs[numDynamics].count;
+ dinahs[numDynamics].position = 0; // launch/idle state
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kVCR:
+ dinahs[numDynamics].dest = vcrTime1;
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest,
+ where->left + playOriginH + 64,
+ where->top + playOriginV + 6);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = 0;
+ dinahs[numDynamics].vVel = 0;
+ dinahs[numDynamics].count = 0;
+ dinahs[numDynamics].frame = 0;
+ if (isOn)
+ dinahs[numDynamics].timer = 115;
+ else
+ dinahs[numDynamics].timer = 0;
+ dinahs[numDynamics].position = 0;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kStereo:
+ dinahs[numDynamics].dest = stereoLight1;
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest,
+ where->left + playOriginH + 56,
+ where->top + playOriginV + 20);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = 0;
+ dinahs[numDynamics].vVel = 0;
+ dinahs[numDynamics].count = 0;
+ dinahs[numDynamics].frame = 0;
+ dinahs[numDynamics].timer = 0;
+ dinahs[numDynamics].position = 0;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kMicrowave:
+ dinahs[numDynamics].dest = microOn;
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest,
+ where->left + playOriginH + 14,
+ where->top + playOriginV + 13);
+ dinahs[numDynamics].dest.right = dinahs[numDynamics].dest.left + 48;
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = 0;
+ dinahs[numDynamics].vVel = 0;
+ dinahs[numDynamics].count = 0;
+ dinahs[numDynamics].frame = 0;
+ dinahs[numDynamics].timer = 0;
+ dinahs[numDynamics].position = 0;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kBalloon:
+ dinahs[numDynamics].dest = balloonSrc[0];
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest, where->left, 0);
+ dinahs[numDynamics].dest.bottom = kBalloonStart;
+ dinahs[numDynamics].dest.top = dinahs[numDynamics].dest.bottom -
+ RectTall(&balloonSrc[0]);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = 0;
+ dinahs[numDynamics].vVel = -2;
+ dinahs[numDynamics].count = ((short)who->data.h.delay * 6) / kTicksPerFrame;
+ dinahs[numDynamics].frame = 0;
+ dinahs[numDynamics].timer = dinahs[numDynamics].count;
+ dinahs[numDynamics].position = 0;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn; // initially idle
+ break;
+
+ case kCopterLf:
+ case kCopterRt:
+ dinahs[numDynamics].dest = copterSrc[0];
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest, where->left, 0);
+ dinahs[numDynamics].dest.top = kCopterStart;
+ dinahs[numDynamics].dest.bottom = dinahs[numDynamics].dest.top +
+ RectTall(&copterSrc[0]);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ if (what == kCopterLf)
+ dinahs[numDynamics].hVel = -1;
+ else
+ dinahs[numDynamics].hVel = 1;
+ dinahs[numDynamics].vVel = 2;
+ dinahs[numDynamics].count = ((short)who->data.h.delay * 6) / kTicksPerFrame;
+ dinahs[numDynamics].frame = 0;
+ dinahs[numDynamics].timer = dinahs[numDynamics].count;
+ dinahs[numDynamics].position = dinahs[numDynamics].dest.left;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn; // initially idle
+ break;
+
+ case kDartLf:
+ case kDartRt:
+ dinahs[numDynamics].dest = dartSrc[0];
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ if (what == kDartLf)
+ {
+ QOffsetRect(&dinahs[numDynamics].dest,
+ kRoomWide - RectWide(&dartSrc[0]), where->top);
+ dinahs[numDynamics].hVel = -kDartVelocity;
+ dinahs[numDynamics].frame = 0;
+ }
+ else
+ {
+ QOffsetRect(&dinahs[numDynamics].dest, 0, where->top);
+ dinahs[numDynamics].hVel = kDartVelocity;
+ dinahs[numDynamics].frame = 2;
+ }
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].vVel = 2;
+ dinahs[numDynamics].count = ((short)who->data.h.delay * 6) / kTicksPerFrame;
+ dinahs[numDynamics].timer = dinahs[numDynamics].count;
+ dinahs[numDynamics].position = dinahs[numDynamics].dest.top;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn; // initially idle
+ break;
+
+ case kBall:
+ dinahs[numDynamics].dest = ballSrc[0];
+ ZeroRectCorner(&dinahs[numDynamics].dest);
+ QOffsetRect(&dinahs[numDynamics].dest,
+ where->left, where->top);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = 0;
+ position = who->data.h.length; // reverse engineer init. vel.
+ velocity = 0;
+ evenFrame = true;
+ lilFrame = true;
+ do
+ {
+ if (lilFrame)
+ velocity++;
+ lilFrame = !lilFrame;
+ position -= velocity;
+ }
+ while (position > 0);
+ dinahs[numDynamics].vVel = -velocity;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].count = -velocity; // count = initial velocity
+ dinahs[numDynamics].frame = 0;
+ dinahs[numDynamics].timer = 0;
+ dinahs[numDynamics].position = dinahs[numDynamics].dest.bottom;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kDrip:
+ dinahs[numDynamics].dest = dripSrc[0];
+ CenterRectInRect(&dinahs[numDynamics].dest, where);
+ VOffsetRect(&dinahs[numDynamics].dest,
+ where->top - dinahs[numDynamics].dest.top);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = dinahs[numDynamics].dest.top; // remember
+ dinahs[numDynamics].vVel = 0;
+ dinahs[numDynamics].count = ((short)who->data.h.delay * 6) / kTicksPerFrame;
+ dinahs[numDynamics].frame = 3;
+ dinahs[numDynamics].timer = dinahs[numDynamics].count;
+ dinahs[numDynamics].position = dinahs[numDynamics].dest.top +
+ who->data.h.length;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ case kFish:
+ dinahs[numDynamics].dest = fishSrc[0];
+ QOffsetRect(&dinahs[numDynamics].dest,
+ where->left + 10, where->top + 8);
+ dinahs[numDynamics].whole = dinahs[numDynamics].dest;
+ dinahs[numDynamics].hVel = ((short)who->data.h.delay * 6) / kTicksPerFrame;
+ position = who->data.g.height; // reverse engineer init. vel.
+ velocity = 0;
+ evenFrame = true;
+ lilFrame = true;
+ do
+ {
+ if (lilFrame)
+ velocity++;
+ lilFrame = !lilFrame;
+ position -= velocity;
+ }
+ while (position > 0);
+ dinahs[numDynamics].vVel = -velocity;
+ dinahs[numDynamics].count = -velocity; // count = initial velocity
+ dinahs[numDynamics].frame = 0;
+ dinahs[numDynamics].timer = dinahs[numDynamics].hVel;
+ dinahs[numDynamics].position = dinahs[numDynamics].dest.bottom;
+ dinahs[numDynamics].room = room;
+ dinahs[numDynamics].byte0 = (Byte)index;
+ dinahs[numDynamics].byte1 = 0;
+ dinahs[numDynamics].moving = false;
+ dinahs[numDynamics].active = isOn;
+ break;
+
+ default:
+ return (-1);
+ break;
+ }
+
+ numDynamics++;
+
+ return (numDynamics - 1);
+}
+
diff --git a/GpApp/Environ.cpp b/GpApp/Environ.cpp
new file mode 100644
index 0000000..6f45c19
--- /dev/null
+++ b/GpApp/Environ.cpp
@@ -0,0 +1,492 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Environ.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLResources.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "HostDisplayDriver.h"
+
+
+#define kSwitchDepthAlert 130
+#define kSetMemoryAlert 180
+#define kLowMemoryAlert 181
+#define kWNETrap 0x60
+#define kSetDepthTrap 0xA2
+#define kUnimpTrap 0x9F
+#define kGestaltTrap 0xAD
+
+#define kDisplay9Inch 1
+#define kDisplay12Inch 2
+#define kDisplay13Inch 3
+
+
+typedef struct
+{
+ short flags;
+ long mem1;
+ long mem2;
+} sizeType;
+
+
+//short GetThisVolumeRefNum (void);
+//long GetThisCurrentDirectoryID (void);
+//Boolean TrapExists (short);
+//Boolean DoWeHaveGestalt (void);
+//Boolean DoWeHaveWNE (void);
+//Boolean DoWeHaveColor (void);
+//Boolean DoWeHaveSystem602 (void);
+//Boolean DoWeHaveSystem605 (void);
+//Boolean DoWeHaveSystem7 (void);
+//Boolean DoWeHaveSoundManager3 (void);
+Boolean DoWeHaveQuickTime (void);
+Boolean DoWeHaveDragManager (void);
+//Boolean CanWeDisplay4Bit (GDHandle);
+//Boolean CanWeDisplay1Bit (GDHandle);
+short HowManyUsableScreens (Boolean, Boolean, Boolean);
+void GetDeviceRect (Rect *);
+Boolean AreWeColorOrGrayscale (void);
+void SwitchDepthOrAbort (void);
+
+
+macEnviron thisMac;
+
+extern short isDepthPref;
+extern Boolean dontLoadMusic, dontLoadSounds;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- GetThisVolumeRefNum
+// Get a hard reference number for the current drive volume this app is on.
+/*
+short GetThisVolumeRefNum (void)
+{
+ OSErr theErr;
+ short vRef;
+
+ theErr = GetVol(nil, &vRef);
+ return (vRef);
+}
+*/
+//-------------------------------------------------------------- GetThisCurrentDirectoryID
+// Get a hard ID number for the current directory volume this app is in.
+/*
+long GetThisCurrentDirectoryID (void)
+{
+ long dirID;
+
+ dirID = LMGetCurDirStore();
+ return (dirID);
+}
+*/
+//-------------------------------------------------------------- TrapExists
+// Returns whether or not a ToolBox trap exists for the users ROMs/System.
+/*
+Boolean TrapExists (short trapNumber)
+{
+ return ((NGetTrapAddress(trapNumber, ToolTrap) !=
+ NGetTrapAddress(kUnimpTrap, ToolTrap)));
+}
+*/
+//-------------------------------------------------------------- DoWeHaveGestalt
+
+// Specifically tests for the availablity of the Gestalt() trap.
+/*
+Boolean DoWeHaveGestalt (void)
+{
+ return (TrapExists(kGestaltTrap));
+}
+*/
+//-------------------------------------------------------------- DoWeHaveWNE
+
+// Specifically tests for the availablity of the WaitNextEvent() trap.
+/*
+Boolean DoWeHaveWNE (void)
+{
+ return (TrapExists(kWNETrap));
+}
+*/
+//-------------------------------------------------------------- DoWeHaveColor
+// Determines if ROMs support Color QuickDraw (monitor not neccessarily color).
+/*
+Boolean DoWeHaveColor (void)
+{
+ SysEnvRec thisWorld;
+
+ SysEnvirons(2, &thisWorld);
+ return (thisWorld.hasColorQD);
+}
+*/
+//-------------------------------------------------------------- DoWeHaveSystem602
+// Determines if the System version is at least 6.0.2 or more recent.
+/*
+Boolean DoWeHaveSystem602 (void)
+{
+ SysEnvRec thisWorld;
+ Boolean haveIt;
+
+ SysEnvirons(2, &thisWorld);
+ if (thisWorld.systemVersion >= 0x0602)
+ haveIt = true;
+ else
+ haveIt = false;
+ return (haveIt);
+}
+*/
+//-------------------------------------------------------------- DoWeHaveSystem605
+// Determines if the System version is at least 6.0.5 or more recent.
+/*
+Boolean DoWeHaveSystem605 (void)
+{
+ SysEnvRec thisWorld;
+ Boolean haveIt;
+
+ SysEnvirons(2, &thisWorld);
+ if (thisWorld.systemVersion >= 0x0605)
+ haveIt = true;
+ else
+ haveIt = false;
+ return (haveIt);
+}
+/
+//-------------------------------------------------------------- DoWeHaveSystem7
+
+// Determines if the System version is at least 7.0.0 or more recent.
+
+Boolean DoWeHaveSystem7 (void)
+{
+ SysEnvRec thisWorld;
+ Boolean haveIt;
+
+ SysEnvirons(2, &thisWorld);
+ if (thisWorld.systemVersion >= 0x0700)
+ haveIt = true;
+ else
+ haveIt = false;
+ return (haveIt);
+}
+
+//-------------------------------------------------------------- DoWeHaveSoundManager3
+// Determines if the Sound Manager version is at least 3.0.0 or more recent.
+/*
+Boolean DoWeHaveSoundManager3 (void)
+{
+// NumVersion version;
+ Boolean hasIt;
+
+ hasIt = true;
+
+ version = SndSoundManagerVersion();
+ hasIt = (version.majorRev >= 3);
+
+ return hasIt;
+}
+*/
+//-------------------------------------------------------------- DoWeHaveQuickTime
+
+Boolean DoWeHaveQuickTime (void)
+{
+ return true;
+}
+
+//-------------------------------------------------------------- DoWeHaveDragManager
+
+Boolean DoWeHaveDragManager (void)
+{
+ return true;
+}
+
+//-------------------------------------------------------------- WhatsOurDepth
+
+// Determines the pixel bit depth for current device (monitor).
+
+short WhatsOurDepth (void)
+{
+ return 8;
+}
+
+void SwitchToDepth (short, Boolean)
+{
+}
+
+//-------------------------------------------------------------- CanWeDisplay4Bit
+// Determines if device (monitor) capable of supporting 4 bit (16 colors/grays).
+/*
+Boolean CanWeDisplay4Bit (GDHandle theDevice)
+{
+ short canDepth;
+ Boolean canDo;
+
+ canDo = false;
+ canDepth = HasDepth(theDevice, 4, 1, 0);
+ if (canDepth != 0)
+ canDo = true;
+
+ return (canDo);
+}
+*/
+//-------------------------------------------------------------- CanWeDisplay1Bit
+// Determines if device (monitor) capable of supporting 1 bit (black & white).
+/*
+Boolean CanWeDisplay1Bit (GDHandle theDevice)
+{
+ short canDepth;
+ Boolean canDo;
+
+ canDo = false;
+ canDepth = HasDepth(theDevice, 1, 1, 0);
+ if (canDepth != 0)
+ canDo = true;
+
+ return (canDo);
+}
+*/
+//-------------------------------------------------------------- HowManyUsableScreens
+
+// Counts the number of monitors that meet the depth criteria passed in.
+
+short HowManyUsableScreens (Boolean use1Bit, Boolean use4Bit, Boolean use8Bit)
+{
+ return 1;
+}
+
+//-------------------------------------------------------------- CheckOurEnvirons
+// Calls all the above functions in order to fill out a sort of "spec sheet"É
+// for the current Mac.
+
+void CheckOurEnvirons (void)
+{
+ thisMac.thisResFile = CurResFile();
+ thisMac.vRefNum = 0; // TEMP
+ thisMac.dirID = 0; // TEMP
+ thisMac.hasGestalt = true; // TEMP
+ thisMac.hasWNE = true; // TEMP
+ thisMac.hasColor = true; // TEMP
+ thisMac.canSwitch = true; // TEMP
+ thisMac.hasSystem7 = true; // TEMP
+ thisMac.hasSM3 = true; // TEMP
+ thisMac.hasQT = DoWeHaveQuickTime();
+ thisMac.hasDrag = DoWeHaveDragManager();
+
+ FindOurDevice();
+ thisMac.can1Bit = true;
+ thisMac.can4Bit = true;
+ thisMac.can8Bit = true;
+ thisMac.numScreens = HowManyUsableScreens(false, true, true);
+ GetDeviceRect(&thisMac.screen);
+
+ thisMac.wasDepth = WhatsOurDepth();
+ thisMac.wasColorOrGray = AreWeColorOrGrayscale();
+}
+
+//-------------------------------------------------------------- ReflectMonitor2Environs
+// Tests second monitor (if available) for specific bit depth capabilities.
+/*
+void ReflectSecondMonitorEnvirons (Boolean use1Bit, Boolean use4Bit, Boolean use8Bit)
+{
+ GDHandle tempGDevice;
+
+ tempGDevice = GetDeviceList();
+ while (tempGDevice != nil)
+ {
+ if (TestDeviceAttribute(tempGDevice, screenDevice))
+ if ((use1Bit && CanWeDisplay1Bit(tempGDevice)) ||
+ (use4Bit && CanWeDisplay4Bit(tempGDevice)) ||
+ (use8Bit && CanWeDisplay8Bit(tempGDevice)))
+ if (!TestDeviceAttribute(tempGDevice, mainScreen))
+ {
+ thisGDevice = tempGDevice;
+ thisMac.can1Bit = CanWeDisplay1Bit(thisGDevice);
+ thisMac.can4Bit = CanWeDisplay4Bit(thisGDevice);
+ thisMac.can8Bit = CanWeDisplay8Bit(thisGDevice);
+ thisMac.wasDepth = WhatsOurDepth();
+ thisMac.wasColorOrGray = AreWeColorOrGrayscale();
+ GetDeviceRect(&thisMac.screen);
+ break;
+ }
+ tempGDevice = GetNextDevice(tempGDevice);
+ }
+}
+*/
+//-------------------------------------------------------------- HandleDepthSwitching
+
+// Handles setting up a monitor's depth to play on.
+
+void HandleDepthSwitching (void)
+{
+ if (thisMac.hasColor)
+ {
+ switch (isDepthPref)
+ {
+ case kSwitchIfNeeded:
+ if ((thisMac.wasDepth != 8) &&
+ ((thisMac.wasDepth != 4) || (thisMac.wasColorOrGray)))
+ SwitchDepthOrAbort();
+ break;
+
+ case kSwitchTo256Colors:
+ if (thisMac.wasDepth != 8)
+ {
+ if (thisMac.can8Bit)
+ SwitchToDepth(8, true);
+ else
+ SwitchDepthOrAbort();
+ }
+ break;
+
+ case kSwitchTo16Grays:
+ if ((thisMac.wasDepth != 4) || (thisMac.wasColorOrGray))
+ {
+ if (thisMac.can4Bit)
+ SwitchToDepth(4, false);
+ else
+ SwitchDepthOrAbort();
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ thisMac.isDepth = WhatsOurDepth();
+}
+
+//-------------------------------------------------------------- RestoreColorDepth
+
+// Restores a monitor to its previous depth when we quit (if we changed it).
+
+void RestoreColorDepth (void)
+{
+ if ((thisMac.hasColor) && ((thisMac.wasDepth != thisMac.isDepth) ||
+ (thisMac.wasColorOrGray != AreWeColorOrGrayscale())))
+ SwitchToDepth(thisMac.wasDepth, true);
+}
+
+//-------------------------------------------------------------- CheckMemorySize
+
+// Tests for a specific amount of memory available. If the required memoryÉ
+// is not available, attempts to turn off various game features (music, etc.)É
+// in order to accomodate the constrained memory available.
+
+void CheckMemorySize (void)
+{
+ #define kBaseBytesNeeded 614400L // 600K Base memory
+ #define kPaddingBytes 204800L // 200K Padding
+ long bytesNeeded, bytesAvail;
+ long soundBytes, musicBytes;
+
+ dontLoadMusic = false;
+ dontLoadSounds = false;
+
+ bytesNeeded = kBaseBytesNeeded; // base memory
+ soundBytes = SoundBytesNeeded(); // sound memory
+ if (soundBytes <= 0L)
+ RedAlert(kErrNoMemory);
+ else
+ bytesNeeded += soundBytes;
+ musicBytes = MusicBytesNeeded(); // music memory
+ if (musicBytes <= 0L)
+ RedAlert(kErrNoMemory);
+ else
+ bytesNeeded += musicBytes;
+ bytesNeeded += 4L * (long)thisMac.screen.bottom; // main screen
+ bytesNeeded += (((long)houseRect.right - (long)houseRect.left) *
+ ((long)houseRect.bottom + 1 - (long)houseRect.top) *
+ (long)thisMac.isDepth) / 8L; // work map
+ bytesNeeded += 4L * (long)houseRect.bottom;
+ bytesNeeded += (((long)houseRect.right - (long)houseRect.left) *
+ ((long)houseRect.bottom + 1 - (long)houseRect.top) *
+ (long)thisMac.isDepth) / 8L; // back map
+ bytesNeeded += 4L * houseRect.bottom;
+ bytesNeeded += (((long)houseRect.right - (long)houseRect.left) * 21 *
+ (long)thisMac.isDepth) / 8L; // scoreboard map
+ bytesNeeded += (6396L * (long)thisMac.isDepth) / 8L; // more scoreboard
+ bytesNeeded += (32112L * (long)thisMac.isDepth) / 8L; // glider map
+ bytesNeeded += (32112L * (long)thisMac.isDepth) / 8L; // glider2 map
+ bytesNeeded += 32064L / 8L; // glider mask
+ bytesNeeded += (912L * (long)thisMac.isDepth) / 8L; // glider shadow
+ bytesNeeded += 864L / 8L; // shadow mask
+ bytesNeeded += (304L * (long)thisMac.isDepth) / 8L; // rubber bands
+ bytesNeeded += 288L / 8L; // bands mask
+ bytesNeeded += (19344L * (long)thisMac.isDepth) / 8L; // blower map
+ bytesNeeded += 19344L / 8L; // blower mask
+ bytesNeeded += (17856L * (long)thisMac.isDepth) / 8L; // furniture map
+ bytesNeeded += 17792L / 8L; // furniture mask
+ bytesNeeded += (33264L * (long)thisMac.isDepth) / 8L; // prizes map
+ bytesNeeded += 33176L / 8L; // prizes mask
+ bytesNeeded += (2904L * (long)thisMac.isDepth) / 8L; // points map
+ bytesNeeded += 2880L / 8L; // points mask
+ bytesNeeded += (1848L * (long)thisMac.isDepth) / 8L; // transport map
+ bytesNeeded += 1792L / 8L; // transport mask
+ bytesNeeded += (3360L * (long)thisMac.isDepth) / 8L; // switches map
+ bytesNeeded += (9144L * (long)thisMac.isDepth) / 8L; // lights map
+ bytesNeeded += 9072L / 8L; // lights mask
+ bytesNeeded += (21600L * (long)thisMac.isDepth) / 8L; // appliances map
+ bytesNeeded += 21520L / 8L; // appliances mask
+ bytesNeeded += (5600L * (long)thisMac.isDepth) / 8L; // toast map
+ bytesNeeded += 5568L / 8L; // toast mask
+ bytesNeeded += (1440L * (long)thisMac.isDepth) / 8L; // shredded map
+ bytesNeeded += 1400L / 8L; // shredded mask
+ bytesNeeded += (5784L * (long)thisMac.isDepth) / 8L; // balloon map
+ bytesNeeded += 5760L / 8L; // balloon mask
+ bytesNeeded += (9632L * (long)thisMac.isDepth) / 8L; // copter map
+ bytesNeeded += 9600L / 8L; // copter mask
+ bytesNeeded += (4928L * (long)thisMac.isDepth) / 8L; // dart map
+ bytesNeeded += 4864L / 8L; // dart mask
+ bytesNeeded += (2080L * (long)thisMac.isDepth) / 8L; // ball map
+ bytesNeeded += 2048L / 8L; // ball mask
+ bytesNeeded += (1168L * (long)thisMac.isDepth) / 8L; // drip map
+ bytesNeeded += 1152L / 8L; // drip mask
+ bytesNeeded += (1224L * (long)thisMac.isDepth) / 8L; // enemy map
+ bytesNeeded += 1188L / 8L; // enemy mask
+ bytesNeeded += (2064L * (long)thisMac.isDepth) / 8L; // fish map
+ bytesNeeded += 2048L / 8L; // fish mask
+ bytesNeeded += (8960L * (long)thisMac.isDepth) / 8L; // clutter map
+ bytesNeeded += 8832L / 8L; // clutter mask
+ bytesNeeded += (23040L * (long)thisMac.isDepth) / 8L; // support map
+ bytesNeeded += (4320L * (long)thisMac.isDepth) / 8L; // angel map
+ bytesNeeded += 4224L / 8L; // angel mask
+ bytesNeeded += sizeof(roomType);
+ bytesNeeded += sizeof(hotObject) * kMaxHotSpots;
+ bytesNeeded += sizeof(sparkleType) * kMaxSparkles;
+ bytesNeeded += sizeof(flyingPtType) * kMaxFlyingPts;
+ bytesNeeded += sizeof(flameType) * kMaxCandles;
+ bytesNeeded += sizeof(flameType) * kMaxTikis;
+ bytesNeeded += sizeof(flameType) * kMaxCoals;
+ bytesNeeded += sizeof(pendulumType) * kMaxPendulums;
+ bytesNeeded += sizeof(savedType) * kMaxSavedMaps;
+ bytesNeeded += sizeof(bandType) * kMaxRubberBands;
+ bytesNeeded += sizeof(greaseType) * kMaxGrease;
+ bytesNeeded += sizeof(starType) * kMaxStars;
+ bytesNeeded += sizeof(shredType) * kMaxShredded;
+ bytesNeeded += sizeof(dynaType) * kMaxDynamicObs;
+ bytesNeeded += sizeof(objDataType) * kMaxMasterObjects;
+ bytesNeeded += kDemoLength; SpinCursor(1);
+
+ bytesAvail = FreeMem(); SpinCursor(1);
+}
+
+void GetDeviceRect(Rect *rect)
+{
+ unsigned int width;
+ unsigned int height;
+ PortabilityLayer::HostDisplayDriver::GetInstance()->GetDisplayResolution(width, height);
+
+ SetRect(rect, 0, 0, static_cast(width), static_cast(height));
+}
+
+Boolean AreWeColorOrGrayscale()
+{
+ // ... As opposed to B&W
+ return true;
+}
+
+void SwitchDepthOrAbort(void)
+{
+}
diff --git a/GpApp/Environ.h b/GpApp/Environ.h
new file mode 100644
index 0000000..b344799
--- /dev/null
+++ b/GpApp/Environ.h
@@ -0,0 +1,37 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Environ.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQuickdraw.h"
+
+
+typedef struct
+{
+ Rect screen, gray;
+ long dirID;
+ short wasDepth, isDepth;
+ short thisResFile;
+ short numScreens;
+ short vRefNum;
+ Boolean can1Bit;
+ Boolean can4Bit;
+ Boolean can8Bit;
+ Boolean wasColorOrGray;
+ Boolean hasWNE;
+ Boolean hasSystem7;
+ Boolean hasColor;
+ Boolean hasGestalt;
+ Boolean canSwitch;
+ Boolean canColor;
+ Boolean hasSM3;
+ Boolean hasQT;
+ Boolean hasDrag;
+} macEnviron;
+
+
+extern macEnviron thisMac;
+
+
diff --git a/GpApp/Events.cpp b/GpApp/Events.cpp
new file mode 100644
index 0000000..fae5158
--- /dev/null
+++ b/GpApp/Events.cpp
@@ -0,0 +1,574 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Events.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLAppleEvents.h"
+#include "PLToolUtils.h"
+#include "PLQuickdraw.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "House.h"
+#include "ObjectEdit.h"
+
+
+short BitchAboutColorDepth (void);
+void HandleMouseEvent (EventRecord *);
+void HandleKeyEvent (EventRecord *);
+void HandleUpdateEvent (EventRecord *);
+void HandleOSEvent (EventRecord *);
+void HandleHighLevelEvent (EventRecord *);
+void HandleIdleTask (void);
+void IncrementMode (void);
+
+
+long lastUp, incrementModeTime;
+UInt32 doubleTime;
+Point lastWhere;
+short idleMode;
+Boolean doAutoDemo, switchedOut;
+
+extern WindowPtr mapWindow, toolsWindow, linkWindow;
+extern WindowPtr menuWindow;
+extern short isEditH, isEditV, isMapH, isMapV, isToolsH, isToolsV;
+extern short isLinkH, isLinkV, isCoordH, isCoordV;
+extern Boolean quitting, isMusicOn, failedMusic;
+extern Boolean autoRoomEdit, newRoomNow, isPlayMusicIdle;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- BitchAboutColorDepth
+// Display a dialog that alerts the user that they have switched the bitÉ
+// depth of the monitor under our noses. They must return it to previous.
+
+short BitchAboutColorDepth (void)
+{
+ #define kColorSwitchedAlert 1042
+ short sheSaid;
+
+// CenterAlert(kColorSwitchedAlert);
+ sheSaid = Alert(kColorSwitchedAlert, nil);
+
+ return (sheSaid);
+}
+
+//-------------------------------------------------------------- HandleMouseEvent
+// Handle a mouse click event.
+
+void HandleMouseEvent (EventRecord *theEvent)
+{
+ WindowPtr whichWindow;
+ long menuChoice, newSize;
+ short thePart, hDelta, vDelta;
+ Boolean isDoubleClick;
+
+ thePart = FindWindow(theEvent->where, &whichWindow);
+
+ switch (thePart)
+ {
+ case inSysWindow:
+// SystemClick(theEvent, whichWindow);
+ break;
+
+ case inMenuBar:
+ menuChoice = MenuSelect(theEvent->where);
+ DoMenuChoice(menuChoice);
+ break;
+
+ case inDrag:
+ DragWindow(whichWindow, theEvent->where, &thisMac.screen);
+ if (whichWindow == mainWindow)
+ {
+ SendBehind(mainWindow, (WindowPtr)0L);
+ GetWindowLeftTop(whichWindow, &isEditH, &isEditV);
+ }
+ else if (whichWindow == mapWindow)
+ GetWindowLeftTop(whichWindow, &isMapH, &isMapV);
+ else if (whichWindow == toolsWindow)
+ GetWindowLeftTop(whichWindow, &isToolsH, &isToolsV);
+ else if (whichWindow == linkWindow)
+ GetWindowLeftTop(whichWindow, &isLinkH, &isLinkV);
+ else if (whichWindow == coordWindow)
+ GetWindowLeftTop(whichWindow, &isCoordH, &isCoordV);
+ HiliteAllWindows();
+ break;
+
+ case inGoAway:
+ if (TrackGoAway(whichWindow,theEvent->where))
+ {
+ if (whichWindow == mapWindow)
+ ToggleMapWindow();
+ else if (whichWindow == toolsWindow)
+ ToggleToolsWindow();
+ else if (whichWindow == linkWindow)
+ CloseLinkWindow();
+ else if (whichWindow == coordWindow)
+ ToggleCoordinateWindow();
+ }
+ break;
+
+ case inGrow:
+ if (whichWindow == mapWindow)
+ {
+ newSize = GrowWindow(mapWindow, theEvent->where, &thisMac.gray);
+ ResizeMapWindow(LoWord(newSize), HiWord(newSize));
+ }
+ break;
+
+ case inZoomIn:
+ case inZoomOut:
+ if (TrackBox(whichWindow, theEvent->where, thePart))
+ ZoomWindow(whichWindow, thePart, true);
+ break;
+
+ case inContent:
+ if (whichWindow == mainWindow)
+ {
+ hDelta = theEvent->where.h - lastWhere.h;
+ if (hDelta < 0)
+ hDelta = -hDelta;
+ vDelta = theEvent->where.v - lastWhere.v;
+ if (vDelta < 0)
+ vDelta = -vDelta;
+ if (((theEvent->when - lastUp) < doubleTime) && (hDelta < 5) &&
+ (vDelta < 5))
+ isDoubleClick = true;
+ else
+ {
+ isDoubleClick = false;
+ lastUp = theEvent->when;
+ lastWhere = theEvent->where;
+ }
+ HandleMainClick(theEvent->where, isDoubleClick);
+ }
+ else if (whichWindow == mapWindow)
+ HandleMapClick(theEvent);
+ else if (whichWindow == toolsWindow)
+ HandleToolsClick(theEvent->where);
+ else if (whichWindow == linkWindow)
+ HandleLinkClick(theEvent->where);
+ break;
+
+ default:
+ break;
+ }
+}
+
+//-------------------------------------------------------------- HandleKeyEvent
+// Handle a key-down event.
+
+void HandleKeyEvent (EventRecord *theEvent)
+{
+ char theChar;
+ Boolean shiftDown, commandDown, optionDown;
+
+ theChar = theEvent->message & charCodeMask;
+ shiftDown = ((theEvent->modifiers & shiftKey) != 0);
+ commandDown = ((theEvent->modifiers & cmdKey) != 0);
+ optionDown = ((theEvent->modifiers & optionKey) != 0);
+
+ if ((commandDown) && (!optionDown))
+ DoMenuChoice(MenuKey(theChar));
+ else
+ {
+ switch (theChar)
+ {
+ case kHelpKeyASCII:
+ break;
+
+ case kPageUpKeyASCII:
+ if (houseUnlocked)
+ PrevToolMode();
+ break;
+
+ case kPageDownKeyASCII:
+ if (houseUnlocked)
+ NextToolMode();
+ break;
+
+#if BUILD_ARCADE_VERSION
+
+ case kLeftArrowKeyASCII:
+ DoOptionsMenu(iHighScores);
+ break;
+
+ case kRightArrowKeyASCII:
+ DoOptionsMenu(iHelp);
+ break;
+
+ case kUpArrowKeyASCII:
+ DoGameMenu(iNewGame);
+ break;
+
+ case kDownArrowKeyASCII:
+ DoGameMenu(iNewGame);
+ break;
+
+#else
+
+ case kLeftArrowKeyASCII:
+ if (houseUnlocked)
+ {
+ if (objActive == kNoObjectSelected)
+ SelectNeighborRoom(kRoomToLeft);
+ else
+ MoveObject(kBumpLeft, shiftDown);
+ }
+ break;
+
+ case kRightArrowKeyASCII:
+ if (houseUnlocked)
+ {
+ if (objActive == kNoObjectSelected)
+ SelectNeighborRoom(kRoomToRight);
+ else
+ MoveObject(kBumpRight, shiftDown);
+ }
+ break;
+
+ case kUpArrowKeyASCII:
+ if (houseUnlocked)
+ {
+ if (objActive == kNoObjectSelected)
+ SelectNeighborRoom(kRoomAbove);
+ else
+ MoveObject(kBumpUp, shiftDown);
+ }
+ break;
+
+ case kDownArrowKeyASCII:
+ if (houseUnlocked)
+ {
+ if (objActive == kNoObjectSelected)
+ SelectNeighborRoom(kRoomBelow);
+ else
+ MoveObject(kBumpDown, shiftDown);
+ }
+ break;
+
+#endif
+
+ case kDeleteKeyASCII:
+ if (houseUnlocked)
+ {
+ if (objActive == kNoObjectSelected)
+ DeleteRoom(true);
+ else
+ DeleteObject();
+ }
+ break;
+
+ case kTabKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ {
+ if (shiftDown)
+ SelectPrevObject();
+ else
+ SelectNextObject();
+ }
+ break;
+
+ case kEscapeKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ DeselectObject();
+ break;
+
+ case kAKeyASCII:
+ case kCapAKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ SetSpecificToolMode(kApplianceMode);
+ break;
+
+ case kBKeyASCII:
+ case kCapBKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ SetSpecificToolMode(kBlowerMode);
+ break;
+
+ case kCKeyASCII:
+ case kCapCKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ SetSpecificToolMode(kClutterMode);
+ break;
+
+ case kEKeyASCII:
+ case kCapEKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ SetSpecificToolMode(kEnemyMode);
+ break;
+
+ case kFKeyASCII:
+ case kCapFKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ SetSpecificToolMode(kFurnitureMode);
+ break;
+
+ case kLKeyASCII:
+ case kCapLKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ SetSpecificToolMode(kLightMode);
+ break;
+
+ case kPKeyASCII:
+ case kCapPKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ SetSpecificToolMode(kBonusMode);
+ break;
+
+ case kSKeyASCII:
+ case kCapSKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ SetSpecificToolMode(kSwitchMode);
+ break;
+
+ case kTKeyASCII:
+ case kCapTKeyASCII:
+ if ((theMode == kEditMode) && (houseUnlocked))
+ SetSpecificToolMode(kTransportMode);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleUpdateEvent
+// Handle an update event.
+
+void HandleUpdateEvent (EventRecord *theEvent)
+{
+ if ((WindowPtr)theEvent->message == mainWindow)
+ {
+ SetPort((GrafPtr)mainWindow);
+ BeginUpdate(mainWindow);
+ UpdateMainWindow();
+ EndUpdate(mainWindow);
+ }
+ else if ((WindowPtr)theEvent->message == mapWindow)
+ {
+ SetPort((GrafPtr)mapWindow);
+ BeginUpdate(mapWindow);
+ UpdateMapWindow();
+ EndUpdate(mapWindow);
+ }
+ else if ((WindowPtr)theEvent->message == toolsWindow)
+ {
+ SetPort((GrafPtr)toolsWindow);
+ BeginUpdate(toolsWindow);
+ UpdateToolsWindow();
+ EndUpdate(toolsWindow);
+ }
+ else if ((WindowPtr)theEvent->message == linkWindow)
+ {
+ SetPort((GrafPtr)linkWindow);
+ BeginUpdate(linkWindow);
+ UpdateLinkWindow();
+ EndUpdate(linkWindow);
+ }
+ else if ((WindowPtr)theEvent->message == coordWindow)
+ {
+ SetPort((GrafPtr)coordWindow);
+ BeginUpdate(coordWindow);
+ UpdateCoordWindow();
+ EndUpdate(coordWindow);
+ }
+ else if ((WindowPtr)theEvent->message == menuWindow)
+ {
+ SetPort((GrafPtr)menuWindow);
+ BeginUpdate(menuWindow);
+ UpdateMenuBarWindow();
+ EndUpdate(menuWindow);
+ }
+}
+
+//-------------------------------------------------------------- HandleOSEvent
+// Handle an OS Event (MultiFinder - user has switched in or out of app).
+
+void HandleOSEvent (EventRecord *theEvent)
+{
+ OSErr theErr;
+ short buttonHit;
+
+ if (theEvent->message & 0x01000000) // suspend or resume event
+ {
+ if (theEvent->message & 0x00000001) // resume event
+ {
+ if (WhatsOurDepth() != thisMac.isDepth)
+ {
+ buttonHit = BitchAboutColorDepth();
+ if (buttonHit == 1) // player wants to Quit
+ {
+#ifndef COMPILEDEMO
+ if (QuerySaveChanges())
+ quitting = true;
+#else
+ quitting = true;
+#endif
+ }
+ else
+ {
+ SwitchToDepth(thisMac.isDepth, thisMac.wasColorOrGray);
+ }
+ }
+ switchedOut = false;
+ InitCursor();
+ if ((isPlayMusicIdle) && (theMode != kEditMode))
+ {
+ theErr = StartMusic();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowNoMusic, theErr);
+ failedMusic = true;
+ }
+ }
+ incrementModeTime = TickCount() + kIdleSplashTicks;
+
+#ifndef COMPILEDEMO
+// if (theMode == kEditMode)
+// SeeIfValidScrapAvailable(true);
+#endif
+ }
+ else // suspend event
+ {
+ switchedOut = true;
+ InitCursor();
+ if ((isMusicOn) && (theMode != kEditMode))
+ StopTheMusic();
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleHighLevelEvent
+// Handle an AppleEvent (Open Document, Quit Application, etc.).
+
+void HandleHighLevelEvent (EventRecord *theEvent)
+{
+ OSErr theErr;
+
+ theErr = AEProcessAppleEvent(theEvent);
+ if ((theErr != noErr) && (theErr != errAEEventNotHandled))
+ YellowAlert(kYellowAppleEventErr, theErr);
+}
+
+//-------------------------------------------------------------- HandleIdleTask
+// Handle some processing during event lulls.
+
+void HandleIdleTask (void)
+{
+ if (theMode == kEditMode)
+ {
+ SetPort((GrafPtr)mainWindow);
+ DoMarquee();
+
+ if ((autoRoomEdit) && (newRoomNow))
+ {
+ if (theMode == kEditMode)
+ DoRoomInfo();
+ newRoomNow = false;
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleEvent
+// "Master" function that tests for events and calls the above functions toÉ
+// handle each event type. Not called during and actual game.
+
+void HandleEvent (void)
+{
+ KeyMap eventKeys;
+ EventRecord theEvent;
+ long sleep = 2;
+ Boolean itHappened = true;
+
+ GetKeys(eventKeys);
+ if ((BitTst(&eventKeys, kCommandKeyMap)) &&
+ (BitTst(&eventKeys, kOptionKeyMap)))
+ {
+ HiliteAllObjects();
+ }
+ else if ((BitTst(&eventKeys, kOptionKeyMap)) && (theMode == kEditMode) &&
+ (houseUnlocked))
+ {
+ EraseSelectedTool();
+ SelectTool(kSelectTool);
+ }
+
+ //if (thisMac.hasWNE)
+ // itHappened = WaitNextEvent(everyEvent, &theEvent, sleep, nil);
+ //else
+ {
+ // SystemTask();
+ itHappened = GetNextEvent(everyEvent, &theEvent);
+ }
+
+ if (itHappened)
+ {
+ switch (theEvent.what)
+ {
+ case mouseDown:
+ HandleMouseEvent(&theEvent);
+ break;
+
+ case keyDown:
+ case autoKey:
+ HandleKeyEvent(&theEvent);
+ break;
+
+ case updateEvt:
+ HandleUpdateEvent(&theEvent);
+ break;
+
+ case osEvt:
+ HandleOSEvent(&theEvent);
+ break;
+
+ case kHighLevelEvent:
+ HandleHighLevelEvent(&theEvent);
+ break;
+ }
+ }
+ else
+ HandleIdleTask();
+
+ if ((theMode == kSplashMode) && doAutoDemo && !switchedOut)
+ {
+ if (TickCount() >= incrementModeTime)
+ DoDemoGame();
+ }
+}
+
+//-------------------------------------------------------------- HiliteAllWindows
+
+// Ugly kludge in order to keep "floating windows" (palettes) on top ofÉ
+// the main window.
+
+void HiliteAllWindows (void)
+{
+ if (mainWindow != nil)
+ HiliteWindow(mainWindow, true);
+ if (mapWindow != nil)
+ HiliteWindow(mapWindow, true);
+ if (toolsWindow != nil)
+ HiliteWindow(toolsWindow, true);
+ if (coordWindow != nil)
+ HiliteWindow(coordWindow, true);
+ if (linkWindow != nil)
+ HiliteWindow(linkWindow, true);
+}
+
+//-------------------------------------------------------------- IgnoreThisClick
+
+// Another inelegant kludge designed to temporarily prevent an unwantedÉ
+// double-click to be registered.
+
+void IgnoreThisClick (void)
+{
+ lastUp -= doubleTime;
+ lastWhere.h = -100;
+ lastWhere.v = -100;
+}
+
diff --git a/GpApp/Externs.h b/GpApp/Externs.h
new file mode 100644
index 0000000..0fb58ab
--- /dev/null
+++ b/GpApp/Externs.h
@@ -0,0 +1,390 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Externs.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#pragma once
+
+
+#include "PLMenus.h"
+
+
+#define kPreferredDepth 8
+
+
+#define kNilPointer 0L
+#define kPutInFront (WindowPtr)-1L
+#define kNormalUpdates TRUE
+#define kOneKilobyte 1024
+#define kOkayButton 1
+#define kCancelButton 2
+#define kControlActive 0
+#define kControlInactive 255
+#define kAsynch TRUE
+#define kSynch FALSE
+
+#define kHomeKeyASCII 0x01
+#define kEnterKeyASCII 0x03
+#define kEndKeyASCII 0x04
+#define kHelpKeyASCII 0x05
+#define kDeleteKeyASCII 0x08
+#define kTabKeyASCII 0x09
+#define kPageUpKeyASCII 0x0B
+#define kPageDownKeyASCII 0x0C
+#define kReturnKeyASCII 0x0D
+#define kFunctionKeyASCII 0x10
+#define kClearKeyASCII 0x1A
+#define kEscapeKeyASCII 0x1B
+#define kLeftArrowKeyASCII 0x1C
+#define kRightArrowKeyASCII 0x1D
+#define kUpArrowKeyASCII 0x1E
+#define kDownArrowKeyASCII 0x1F
+#define kSpaceBarASCII 0x20
+#define kExclamationASCII 0x21
+#define kPlusKeyASCII 0x2B
+#define kMinusKeyASCII 0x2D
+#define k0KeyASCII 0x30
+#define k1KeyASCII 0x31
+#define k2KeyASCII 0x32
+#define k3KeyASCII 0x33
+#define k4KeyASCII 0x34
+#define k5KeyASCII 0x35
+#define k6KeyASCII 0x36
+#define k7KeyASCII 0x37
+#define k8KeyASCII 0x38
+#define k9KeyASCII 0x39
+
+#define kCapAKeyASCII 0x41
+#define kCapBKeyASCII 0x42
+#define kCapCKeyASCII 0x43
+#define kCapDKeyASCII 0x44
+#define kCapEKeyASCII 0x45
+#define kCapFKeyASCII 0x46
+#define kCapGKeyASCII 0x47
+#define kCapHKeyASCII 0x48
+#define kCapIKeyASCII 0x49
+#define kCapJKeyASCII 0x4A
+#define kCapKKeyASCII 0x4B
+#define kCapLKeyASCII 0x4C
+#define kCapMKeyASCII 0x4D
+#define kCapNKeyASCII 0x4E
+#define kCapOKeyASCII 0x4F
+#define kCapPKeyASCII 0x50
+#define kCapQKeyASCII 0x51
+#define kCapRKeyASCII 0x52
+#define kCapSKeyASCII 0x53
+#define kCapTKeyASCII 0x54
+#define kCapUKeyASCII 0x55
+#define kCapVKeyASCII 0x56
+#define kCapWKeyASCII 0x57
+#define kCapXKeyASCII 0x58
+#define kCapYKeyASCII 0x59
+#define kCapZKeyASCII 0x5A
+
+#define kAKeyASCII 0x61
+#define kBKeyASCII 0x62
+#define kCKeyASCII 0x63
+#define kDKeyASCII 0x64
+#define kEKeyASCII 0x65
+#define kFKeyASCII 0x66
+#define kGKeyASCII 0x67
+#define kHKeyASCII 0x68
+#define kIKeyASCII 0x69
+#define kJKeyASCII 0x6A
+#define kKKeyASCII 0x6B
+#define kLKeyASCII 0x6C
+#define kMKeyASCII 0x6D
+#define kNKeyASCII 0x6E
+#define kOKeyASCII 0x6F
+#define kPKeyASCII 0x70
+#define kQKeyASCII 0x71
+#define kRKeyASCII 0x72
+#define kSKeyASCII 0x73
+#define kTKeyASCII 0x74
+#define kUKeyASCII 0x75
+#define kVKeyASCII 0x76
+#define kWKeyASCII 0x77
+#define kXKeyASCII 0x78
+#define kYKeyASCII 0x79
+#define kZKeyASCII 0x7A
+#define kForwardDeleteASCII 0x7F
+
+#define kPlusKeypadMap 66 // key map offset for + on keypad
+#define kMinusKeypadMap 73 // key map offset for - on keypad
+#define kTimesKeypadMap 68 // key map offset for * on keypad
+#define k0KeypadMap 85 // key map offset for 0 on keypad
+#define k1KeypadMap 84 // key map offset for 1 on keypad
+#define k2KeypadMap 83 // key map offset for 2 on keypad
+#define k3KeypadMap 82 // key map offset for 3 on keypad
+#define k4KeypadMap 81 // key map offset for 4 on keypad
+#define k5KeypadMap 80 // key map offset for 5 on keypad
+#define k6KeypadMap 95 // key map offset for 6 on keypad
+#define k7KeypadMap 94 // key map offset for 7 on keypad
+#define k8KeypadMap 92 // key map offset for 8 on keypad
+#define k9KeypadMap 91 // key map offset for 9 on keypad
+
+#define kUpArrowKeyMap 121 // key map offset for up arrow
+#define kDownArrowKeyMap 122 // key map offset for down arrow
+#define kRightArrowKeyMap 123 // key map offset for right arrow
+#define kLeftArrowKeyMap 124 // key map offset for left arrow
+
+#define kAKeyMap 7
+#define kBKeyMap 12
+#define kCKeyMap 15
+#define kDKeyMap 5
+#define kEKeyMap 9
+#define kFKeyMap 4
+#define kGKeyMap 2
+#define kHKeyMap 3
+#define kMKeyMap 41
+#define kNKeyMap 42
+#define kOKeyMap 24
+#define kPKeyMap 36
+#define kQKeyMap 11
+#define kRKeyMap 8
+#define kSKeyMap 6
+#define kTKeyMap 22
+#define kVKeyMap 14
+#define kWKeyMap 10
+#define kXKeyMap 0
+#define kZKeyMap 1
+#define kPeriodKeyMap 40
+#define kCommandKeyMap 48
+#define kEscKeyMap 50
+#define kDeleteKeyMap 52
+#define kSpaceBarMap 54
+#define kTabKeyMap 55
+#define kControlKeyMap 60
+#define kOptionKeyMap 61
+#define kCapsLockKeyMap 62
+#define kShiftKeyMap 63
+
+#define kTabRawKey 0x30 // key map offset for Tab key
+#define kClearRawKey 0x47 // key map offset for Clear key
+#define kF5RawKey 0x60 // key map offset for F5
+#define kF6RawKey 0x61 // key map offset for F6
+#define kF7RawKey 0x62 // key map offset for F7
+#define kF3RawKey 0x63 // key map offset for F3
+#define kF8RawKey 0x64 // key map offset for F8
+#define kF9RawKey 0x65 // key map offset for F9
+#define kF11RawKey 0x67 // key map offset for F11
+#define kF13RawKey 0x69 // key map offset for F13
+#define kF14RawKey 0x6B // key map offset for F14
+#define kF10RawKey 0x6D // key map offset for F10
+#define kF12RawKey 0x6F // key map offset for F12
+#define kF15RawKey 0x71 // key map offset for F15
+#define kF4RawKey 0x76 // key map offset for F4
+#define kF2RawKey 0x78 // key map offset for F2
+#define kF1RawKey 0x7A // key map offset for F1
+
+#define kErrUnnaccounted 1
+#define kErrNoMemory 2
+#define kErrDialogDidntLoad 3
+#define kErrFailedResourceLoad 4
+#define kErrFailedGraphicLoad 5
+#define kErrFailedOurDirect 6
+#define kErrFailedValidation 7
+#define kErrNeedSystem7 8
+#define kErrFailedGetDevice 9
+#define kErrFailedMemoryOperation 10
+#define kErrFailedCatSearch 11
+#define kErrNeedColorQD 12
+#define kErrNeed16Or256Colors 13
+
+#define iAbout 1
+#define iNewGame 1
+#define iTwoPlayer 2
+#define iOpenSavedGame 3
+#define iLoadHouse 5
+#define iQuit 7
+#define iEditor 1
+#define iHighScores 3
+#define iPrefs 4
+#define iHelp 5
+#define iNewHouse 1
+#define iSave 2
+#define iHouse 4
+#define iRoom 5
+#define iObject 6
+#define iCut 8
+#define iCopy 9
+#define iPaste 10
+#define iClear 11
+#define iDuplicate 12
+#define iBringForward 14
+#define iSendBack 15
+#define iGoToRoom 17
+#define iMapWindow 19
+#define iObjectWindow 20
+#define iCoordinateWindow 21
+
+//-------------------------------------------------------------- Structs
+/*
+typedef short SICN[16];
+typedef SICN *SICNList;
+typedef SICNList *SICNHand;
+*/
+
+typedef struct
+{
+ Str32 wasDefaultName;
+ Str15 wasLeftName, wasRightName;
+ Str15 wasBattName, wasBandName;
+ Str15 wasHighName;
+ Str31 wasHighBanner;
+// long encrypted, fakeLong;
+ long wasLeftMap, wasRightMap;
+ long wasBattMap, wasBandMap;
+ short wasVolume;
+ short prefVersion;
+ short wasMaxFiles;
+ short wasEditH, wasEditV;
+ short wasMapH, wasMapV;
+ short wasMapWide, wasMapHigh;
+ short wasToolsH, wasToolsV;
+ short wasLinkH, wasLinkV;
+ short wasCoordH, wasCoordV;
+ short isMapLeft, isMapTop;
+ short wasNumNeighbors;
+ short wasDepthPref;
+ short wasToolGroup;
+ short smWarnings;
+ short wasFloor, wasSuite;
+ Boolean wasZooms, wasMusicOn;
+ Boolean wasAutoEdit, wasDoColorFade;
+ Boolean wasMapOpen, wasToolsOpen;
+ Boolean wasCoordOpen, wasQuickTrans;
+ Boolean wasIdleMusic, wasGameMusic;
+ Boolean wasEscPauseKey;
+ Boolean wasDoAutoDemo, wasScreen2;
+ Boolean wasDoBackground, wasHouseChecks;
+ Boolean wasPrettyMap, wasBitchDialogs;
+} prefsInfo;
+
+//-------------------------------------------------------------- Prototypes
+
+void DoAbout (void); // --- About.c
+
+void LoadCursors (void); // --- AnimCursor.c
+void DisposCursors (void);
+void IncrementCursor (void);
+void DecrementCursor (void);
+void SpinCursor (short);
+void BackSpinCursor (short);
+
+void ColorText (StringPtr, long); // --- ColorUtils.c
+void ColorRect (Rect *, long);
+void ColorOval (Rect *, long);
+void ColorRegion (RgnHandle, long);
+void ColorLine (short, short, short, short, long);
+void HiliteRect (Rect *, short, short);
+void ColorFrameRect (Rect *, long);
+void ColorFrameWHRect (short, short, short, short, long);
+void ColorFrameOval (Rect *, long);
+void LtGrayForeColor (void);
+void GrayForeColor (void);
+void DkGrayForeColor (void);
+void RestoreColorsSlam (void);
+
+void MonitorWait (void); // --- DebugUtils.c
+void DisplayRect (Rect *);
+void FlashRect (Rect *);
+void CheckLegitRect(Rect *, Rect *);
+void DisplayLong (long);
+void DisplayShort (short);
+void FlashLong (long);
+void FlashShort (short);
+void DoBarGraph (short, short, short, short);
+short BetaOkay (void);
+void DebugNum (long);
+void DisplayCTSeed (CGrafPtr);
+void FillScreenRed (void);
+void DumpToResEditFile (Ptr, long);
+
+void HandleEvent (void); // --- Event.c
+void HiliteAllWindows (void);
+void IgnoreThisClick (void);
+
+short WhatsOurDepth (void); // --- Environs.c
+void SwitchToDepth (short, Boolean);
+void CheckOurEnvirons (void);
+//void ReflectSecondMonitorEnvirons (Boolean, Boolean, Boolean);
+void HandleDepthSwitching (void);
+void RestoreColorDepth (void);
+void CheckMemorySize (void);
+void SetAppMemorySize (long);
+
+Boolean CheckFileError (short, const PLPasStr &); // --- File Error.c
+
+Boolean SavePrefs (prefsInfo *, short); // --- Prefs.c
+Boolean LoadPrefs (prefsInfo *, short);
+
+void PasStringCopy (StringPtr, StringPtr); // --- StringUtils.c
+short WhichStringFirst (StringPtr, StringPtr);
+void PasStringCopyNum (StringPtr, StringPtr, short);
+void PasStringConcat (StringPtr, const PLPasStr &);
+void GetLineOfText (StringPtr, short, StringPtr);
+void WrapText (StringPtr, short);
+void GetFirstWordOfString (StringPtr, StringPtr);
+void CollapseStringToWidth (StringPtr, short);
+void GetChooserName (StringPtr);
+StringPtr GetLocalizedString (short, StringPtr);
+
+Point MyGetGlobalMouse (void); // --- Utilities.c
+void ToolBoxInit (void);
+void FindOurDevice (void);
+short RandomInt (short);
+long RandomLong (long);
+void InitRandomLongQUS (void);
+UInt32 RandomLongQUS (void);
+//void CenterAlert (short);
+void RedAlert (short);
+//void CreateOffScreenBitMap (Rect *, GrafPtr *);
+//void CreateOffScreenPixMap (Rect *, CGrafPtr *);
+//void KillOffScreenPixMap (CGrafPtr);
+//void KillOffScreenBitMap (GrafPtr);
+void LoadGraphic (short);
+void LoadScaledGraphic (short, Rect *);
+//void PlotSICN (Rect *, SICNHand, long);
+void LargeIconPlot (Rect *, short);
+void DrawCIcon (short, short, short);
+char KeyMapOffsetFromRawKey (char);
+long LongSquareRoot (long);
+//void HideMenuBarOld (void);
+//void ShowMenuBarOld (void);
+Boolean WaitForInputEvent (short);
+void WaitCommandQReleased (void);
+char GetKeyMapFromMessage (intptr_t);
+void GetKeyName (intptr_t, StringPtr);
+Boolean OptionKeyDown (void);
+long ExtractCTSeed (CGrafPtr);
+//void ForceCTSeed (CGrafPtr, long);
+void DelayTicks (long);
+void UnivGetSoundVolume (short *, Boolean);
+void UnivSetSoundVolume (short, Boolean);
+
+Boolean ValidInstallation (Boolean); // --- Validate.c
+
+void GetWindowLeftTop (WindowPtr, short *, short *); // --- WindowUtils.c
+void GetWindowRect (WindowPtr, Rect *);
+void GetLocalWindowRect (WindowPtr, Rect *);
+//void FlagWindowFloating (WindowPtr);
+//Boolean IsWindowFloating (WindowPtr);
+void OpenMessageWindow (const PLPasStr&);
+void SetMessageWindowMessage (StringPtr);
+void CloseMessageWindow (void);
+void CloseThisWindow (WindowPtr *);
+
+#ifdef powerc
+// extern pascal void SetSoundVol(short level); // for old Sound Manager
+// extern pascal void GetSoundVol(short *level)
+// THREEWORDINLINE(0x4218, 0x10B8, 0x0260);
+#endif
+
+#include "GliderDefines.h"
+#include "GliderStructs.h"
+#include "GliderVars.h"
+#include "GliderProtos.h"
\ No newline at end of file
diff --git a/GpApp/FileError.cpp b/GpApp/FileError.cpp
new file mode 100644
index 0000000..07ac86a
--- /dev/null
+++ b/GpApp/FileError.cpp
@@ -0,0 +1,101 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// FileError.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLNumberFormatting.h"
+#include "PLTextUtils.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+
+
+#define rFileErrorAlert 140
+#define rFileErrorStrings 140
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- CheckFileError
+
+// Given a result code (returned from a previous file operation) thisÉ
+// function cheks to see if the result code is an error and, if it isÉ
+// a common error for which I have a string message, I bring up anÉ
+// alert with the error message. If it is an unusual error, I stillÉ
+// bring up an alert but with "Miscellaneous file error" and theÉ
+// error ID.
+
+Boolean CheckFileError (short resultCode, const PLPasStr &fileName)
+{
+ short dummyInt, stringIndex;
+ Str255 errMessage, errNumString;
+
+ if (resultCode == noErr) // No problems? Then cruise
+ return(true);
+
+ switch (resultCode)
+ {
+ case dirFulErr:
+ stringIndex = 2;
+ break;
+ case dskFulErr:
+ stringIndex = 3;
+ break;
+ case ioErr:
+ stringIndex = 4;
+ break;
+ case bdNamErr:
+ stringIndex = 5;
+ break;
+ case fnOpnErr:
+ stringIndex = 6;
+ break;
+ case mFulErr:
+ stringIndex = 7;
+ break;
+ case tmfoErr:
+ stringIndex = 8;
+ break;
+ case wPrErr:
+ stringIndex = 9;
+ break;
+ case fLckdErr:
+ stringIndex = 10;
+ break;
+ case vLckdErr:
+ stringIndex = 11;
+ break;
+ case fBsyErr:
+ stringIndex = 12;
+ break;
+ case dupFNErr:
+ stringIndex = 13;
+ break;
+ case opWrErr:
+ stringIndex = 14;
+ break;
+ case volOffLinErr:
+ stringIndex = 15;
+ break;
+ case permErr:
+ stringIndex = 16;
+ break;
+ case wrPermErr:
+ stringIndex = 17;
+ break;
+ default:
+ stringIndex = 1;
+ break;
+ }
+ InitCursor();
+
+ GetIndString(errMessage, rFileErrorStrings, stringIndex);
+ NumToString((long)resultCode, errNumString);
+ ParamText(errMessage, errNumString, fileName, PSTR(""));
+
+// CenterAlert(rFileErrorAlert);
+ dummyInt = Alert(rFileErrorAlert, 0L);
+
+ return(false);
+}
diff --git a/GpApp/GameOver.cpp b/GpApp/GameOver.cpp
new file mode 100644
index 0000000..d553cc2
--- /dev/null
+++ b/GpApp/GameOver.cpp
@@ -0,0 +1,508 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// GameOver.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLToolUtils.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "MainWindow.h"
+#include "Objects.h"
+#include "RectUtils.h"
+#include "Utilities.h"
+
+
+#define kNumCountDownFrames 16
+#define kPageFrames 14
+#define kPagesPictID 1990
+#define kPagesMaskID 1989
+#define kLettersPictID 1988
+#define kMilkywayPictID 1021
+
+
+typedef struct
+{
+ Rect dest, was;
+ short frame, counter;
+ Boolean stuck;
+} pageType, *pagePtr;
+
+
+void DoGameOverStarAnimation (void);
+void SetUpFinalScreen (void);
+void InitDiedGameOver (void);
+void HandlePages (void);
+void DrawPages (void);
+
+
+pageType pages[8];
+Rect pageSrcRect, pageSrc[kPageFrames], lettersSrc[8], angelSrcRect;
+RgnHandle roomRgn;
+GWorldPtr pageSrcMap, gameOverSrcMap, angelSrcMap;
+GWorldPtr pageMaskMap, angelMaskMap;
+short countDown, stopPages, pagesStuck;
+Boolean gameOver;
+
+extern Rect justRoomsRect;
+extern short splashOriginH, splashOriginV, numWork2Main;
+extern short numBack2Work;
+extern Boolean playing, shadowVisible, demoGoing;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DoGameOver
+
+// Handles a game over. This is a game over where the player hasÉ
+// completed the house.
+
+void DoGameOver (void)
+{
+ playing = false;
+ SetUpFinalScreen();
+ SetPort((GrafPtr)mainWindow);
+ ColorRect(&mainWindowRect, 244);
+ DoGameOverStarAnimation();
+ if (!TestHighScore())
+ RedrawSplashScreen();
+}
+
+//-------------------------------------------------------------- SetUpFinalScreen
+
+// This sets up the game over screen (again, this function is for whenÉ
+// the player completes the house).
+
+void SetUpFinalScreen (void)
+{
+ Rect tempRect;
+ Str255 tempStr, subStr;
+ short count, offset, i, textDown;
+ char wasState;
+
+ SetPort((GrafPtr)workSrcMap);
+ ColorRect(&workSrcRect, 244);
+ QSetRect(&tempRect, 0, 0, 640, 460);
+ CenterRectInRect(&tempRect, &workSrcRect);
+ LoadScaledGraphic(kMilkywayPictID, &tempRect);
+ textDown = tempRect.top;
+ if (textDown < 0)
+ textDown = 0;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ PasStringCopy((*thisHouse)->trailer, tempStr);
+ HSetState((Handle)thisHouse, wasState);
+
+ count = 0;
+ do
+ {
+ GetLineOfText(tempStr, count, subStr);
+ offset = ((thisMac.screen.right - thisMac.screen.left) -
+ TextWidth(subStr, 1, subStr[0])) / 2;
+ TextFont(applFont);
+ TextFace(bold);
+ TextSize(12);
+ ForeColor(blackColor);
+ MoveTo(offset + 1, textDown + 33 + (count * 20));
+ DrawString(subStr);
+ ForeColor(whiteColor);
+ MoveTo(offset, textDown + 32 + (count * 20));
+ DrawString(subStr);
+ ForeColor(blackColor);
+ count++;
+ }
+ while (subStr[0] > 0);
+
+ CopyRectWorkToBack(&workSrcRect);
+
+ for (i = 0; i < 5; i++) // initialize the falling stars
+ {
+ pages[i].dest = starSrc[0];
+ QOffsetRect(&pages[i].dest,
+ workSrcRect.right + RandomInt(workSrcRect.right / 5) +
+ (workSrcRect.right/ 4) * i,
+ RandomInt(workSrcRect.bottom) - workSrcRect.bottom / 2);
+ pages[i].was = pages[i].dest;
+ pages[i].frame = RandomInt(6);
+ }
+}
+
+//-------------------------------------------------------------- DoGameOverStarAnimation
+
+// This handles the falling stars and the flying angel when a playerÉ
+// completes a house.
+
+void DoGameOverStarAnimation (void)
+{
+ #define kStarFalls 8
+ EventRecord theEvent;
+ KeyMap theKeys;
+ Rect angelDest;
+ long nextLoop;
+ short which, i, count, pass;
+ Boolean noInteruption;
+
+ angelDest = angelSrcRect;
+ QOffsetRect(&angelDest, -96, 0);
+ noInteruption = true;
+ nextLoop = TickCount() + 2;
+ count = 0;
+ pass = 0;
+ FlushEvents(everyEvent, 0);
+
+ while (noInteruption)
+ {
+ if ((angelDest.left % 32) == 0) // add a star
+ {
+ PlayPrioritySound(kMysticSound, kMysticPriority);
+ which = angelDest.left / 32;
+ which = which % 5;
+ ZeroRectCorner(&pages[which].dest);
+ QOffsetRect(&pages[which].dest, angelDest.left, angelDest.bottom);
+ if (count < (which + 1))
+ count = which + 1;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ pages[i].frame++;
+ if (pages[i].frame >= 6)
+ pages[i].frame = 0;
+
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &starSrc[pages[i].frame],
+ &starSrc[pages[i].frame],
+ &pages[i].dest);
+
+ pages[i].was = pages[i].dest;
+ pages[i].was.top -= kStarFalls;
+
+ AddRectToWorkRectsWhole(&pages[i].was);
+ AddRectToBackRects(&pages[i].dest);
+
+ if (pages[i].dest.top < workSrcRect.bottom)
+ QOffsetRect(&pages[i].dest, 0, kStarFalls);
+ }
+
+ if (angelDest.left <= (workSrcRect.right + 2))
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(angelSrcMap),
+ (BitMap *)*GetGWorldPixMap(angelMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &angelSrcRect, &angelSrcRect, &angelDest);
+ angelDest.left -= 2;
+ AddRectToWorkRectsWhole(&angelDest);
+ angelDest.left += 2;
+ AddRectToBackRects(&angelDest);
+ QOffsetRect(&angelDest, 2, 0);
+ pass = 0;
+ }
+
+ CopyRectsQD();
+
+ numWork2Main = 0;
+ numBack2Work = 0;
+
+ do
+ {
+ GetKeys(theKeys);
+ if ((BitTst(&theKeys, kCommandKeyMap)) || (BitTst(&theKeys, kOptionKeyMap)) ||
+ (BitTst(&theKeys, kShiftKeyMap)) || (BitTst(&theKeys, kControlKeyMap)))
+ noInteruption = false;
+ if (GetNextEvent(everyEvent, &theEvent))
+ if ((theEvent.what == mouseDown) || (theEvent.what == keyDown))
+ noInteruption = false;
+ }
+ while (TickCount() < nextLoop);
+ nextLoop = TickCount() + 2;
+
+ if (pass < 80)
+ pass++;
+ else
+ {
+ WaitForInputEvent(5);
+ noInteruption = false;
+ }
+ }
+}
+
+//-------------------------------------------------------------- FlagGameOver
+
+// Called to indicate (flag) that a game is over. Actual game overÉ
+// sequence comes up after a short delay.
+
+void FlagGameOver (void)
+{
+ gameOver = true;
+ countDown = kNumCountDownFrames;
+ SetMusicalMode(kPlayWholeScoreMode);
+}
+
+//-------------------------------------------------------------- InitDiedGameOver
+// This is called when a game is over due to the fact that the playerÉ
+// lost their last glider (died), not due to getting through the entireÉ
+// house. This function initializes the strucures/variables.
+
+void InitDiedGameOver (void)
+{
+ #define kPageSpacing 40
+ #define kPageRightOffset 128
+ #define kPageBackUp 128
+ short i;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&pageSrcRect, 0, 0, 25, 32 * 8);
+ theErr = CreateOffScreenGWorld(&gameOverSrcMap, &pageSrcRect, kPreferredDepth);
+ SetGWorld(gameOverSrcMap, nil);
+ LoadGraphic(kLettersPictID);
+
+ QSetRect(&pageSrcRect, 0, 0, 32, 32 * kPageFrames);
+ theErr = CreateOffScreenGWorld(&pageSrcMap, &pageSrcRect, kPreferredDepth);
+ SetGWorld(pageSrcMap, nil);
+ LoadGraphic(kPagesPictID);
+
+ theErr = CreateOffScreenGWorld(&pageMaskMap, &pageSrcRect, 1);
+ SetGWorld(pageMaskMap, nil);
+ LoadGraphic(kPagesMaskID);
+
+ for (i = 0; i < kPageFrames; i++) // initialize src page rects
+ {
+ QSetRect(&pageSrc[i], 0, 0, 32, 32);
+ QOffsetRect(&pageSrc[i], 0, 32 * i);
+ }
+
+ for (i = 0; i < 8; i++) // initialize dest page rects
+ {
+ QSetRect(&pages[i].dest, 0, 0, 32, 32);
+ CenterRectInRect(&pages[i].dest, &thisMac.screen);
+ QOffsetRect(&pages[i].dest, -thisMac.screen.left, -thisMac.screen.top);
+ if (i < 4)
+ QOffsetRect(&pages[i].dest, -kPageSpacing * (4 - i), 0);
+ else
+ QOffsetRect(&pages[i].dest, kPageSpacing * (i - 3), 0);
+ QOffsetRect(&pages[i].dest, (thisMac.screen.right - thisMac.screen.left) / -2,
+ (thisMac.screen.right - thisMac.screen.left) / -2);
+ if (pages[i].dest.left % 2 == 1)
+ QOffsetRect(&pages[i].dest, 1, 0);
+ pages[i].was = pages[i].dest;
+ pages[i].frame = 0;
+ pages[i].counter = RandomInt(32);
+ pages[i].stuck = false;
+ }
+
+ for (i = 0; i < 8; i++)
+ {
+ QSetRect(&lettersSrc[i], 0, 0, 25, 32);
+ QOffsetRect(&lettersSrc[i], 0, 32 * i);
+ }
+
+ roomRgn = NewRgn();
+ RectRgn(roomRgn, &justRoomsRect);
+ pagesStuck = 0;
+ stopPages = ((thisMac.screen.bottom - thisMac.screen.top) / 2) - 16;
+}
+
+//-------------------------------------------------------------- HandlePages
+
+// This handles the pieces of paper that blow across the screen.
+
+void HandlePages (void)
+{
+ short i;
+
+ for (i = 0; i < 8; i++)
+ {
+ if ((pages[i].dest.bottom + RandomInt(8)) > stopPages)
+ {
+ pages[i].frame = 0;
+ if (!pages[i].stuck)
+ {
+ pages[i].dest.right = pages[i].dest.left + 25;
+ pages[i].stuck = true;
+ pagesStuck++;
+ }
+ }
+ else
+ {
+ if (pages[i].frame == 0)
+ {
+ pages[i].counter--;
+ if (pages[i].counter <= 0)
+ pages[i].frame = 1;
+ }
+ else if (pages[i].frame == 7)
+ {
+ pages[i].counter--;
+ if (pages[i].counter <= 0)
+ {
+ pages[i].frame = 8;
+ if (RandomInt(2) == 0)
+ PlayPrioritySound(kPaper3Sound, kPapersPriority);
+ else
+ PlayPrioritySound(kPaper4Sound, kPapersPriority);
+ }
+ else
+ QOffsetRect(&pages[i].dest, 10, 10);
+ }
+ else
+ {
+ pages[i].frame++;
+ switch (pages[i].frame)
+ {
+ case 5:
+ QOffsetRect(&pages[i].dest, 6, 6);
+ break;
+
+ case 6:
+ QOffsetRect(&pages[i].dest, 8, 8);
+ break;
+
+ case 7:
+ QOffsetRect(&pages[i].dest, 8, 8);
+ pages[i].counter = RandomInt(4) + 4;
+ break;
+
+ case 8:
+ case 9:
+ QOffsetRect(&pages[i].dest, 8, 8);
+ break;
+
+ case 10:
+ QOffsetRect(&pages[i].dest, 6, 6);
+ break;
+
+ case kPageFrames:
+ QOffsetRect(&pages[i].dest, 8, 0);
+ pages[i].frame = 0;
+ pages[i].counter = RandomInt(8) + 8;
+ if (RandomInt(2) == 0)
+ PlayPrioritySound(kPaper1Sound, kPapersPriority);
+ else
+ PlayPrioritySound(kPaper2Sound, kPapersPriority);
+ break;
+ }
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- DrawPages
+
+// This function does the drawing for the pieces of paper that blowÉ
+// across the screen.
+
+void DrawPages (void)
+{
+ short i;
+
+ for (i = 0; i < 8; i++)
+ {
+ if (pages[i].stuck)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(gameOverSrcMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &lettersSrc[i], &pages[i].dest,
+ srcCopy, roomRgn);
+ }
+ else
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(pageSrcMap),
+ (BitMap *)*GetGWorldPixMap(pageMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &pageSrc[pages[i].frame],
+ &pageSrc[pages[i].frame],
+ &pages[i].dest);
+ }
+
+ QUnionSimilarRect(&pages[i].dest, &pages[i].was, &pages[i].was);
+ AddRectToWorkRects(&pages[i].was);
+ AddRectToBackRects(&pages[i].dest);
+
+ CopyRectsQD();
+
+ numWork2Main = 0;
+ numBack2Work = 0;
+
+ pages[i].was = pages[i].dest;
+ }
+}
+
+//-------------------------------------------------------------- DoDiedGameOver
+
+// This is called when a game is over due to the fact that the playerÉ
+// lost their last glider (died), not due to getting through the entireÉ
+// house.
+
+void DoDiedGameOver (void)
+{
+ EventRecord theEvent;
+ KeyMap theKeys;
+ long nextLoop;
+ Boolean userAborted;
+
+ userAborted = false;
+ InitDiedGameOver();
+ CopyRectMainToWork(&workSrcRect);
+ CopyRectMainToBack(&workSrcRect);
+ FlushEvents(everyEvent, 0);
+
+ nextLoop = TickCount() + 2;
+ while (pagesStuck < 8)
+ {
+ HandlePages();
+ DrawPages();
+ do
+ {
+ GetKeys(theKeys);
+ if ((BitTst(&theKeys, kCommandKeyMap)) || (BitTst(&theKeys, kOptionKeyMap)) ||
+ (BitTst(&theKeys, kShiftKeyMap)) || (BitTst(&theKeys, kControlKeyMap)))
+ {
+ pagesStuck = 8;
+ userAborted = true;
+ }
+ if (GetNextEvent(everyEvent, &theEvent))
+ if ((theEvent.what == mouseDown) || (theEvent.what == keyDown))
+ {
+ pagesStuck = 8;
+ userAborted = true;
+ }
+ }
+ while (TickCount() < nextLoop);
+ nextLoop = TickCount() + 2;
+ }
+
+ if (roomRgn != nil)
+ DisposeRgn(roomRgn);
+
+ DisposeGWorld(pageSrcMap);
+ pageSrcMap = nil;
+
+ DisposeGWorld(pageMaskMap);
+ pageMaskMap = nil;
+
+ DisposeGWorld(gameOverSrcMap);
+ gameOverSrcMap = nil;
+ playing = false;
+
+ if (demoGoing)
+ {
+ if (!userAborted)
+ WaitForInputEvent(1);
+ }
+ else
+ {
+ if (!userAborted)
+ WaitForInputEvent(10);
+ TestHighScore();
+ }
+ RedrawSplashScreen();
+}
+
diff --git a/GpApp/GameOver.h b/GpApp/GameOver.h
new file mode 100644
index 0000000..b71723e
--- /dev/null
+++ b/GpApp/GameOver.h
@@ -0,0 +1,12 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// GameOver.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+extern GWorldPtr angelSrcMap;
+extern GWorldPtr angelMaskMap;
diff --git a/GpApp/GliderDefines.h b/GpApp/GliderDefines.h
new file mode 100644
index 0000000..175eb3d
--- /dev/null
+++ b/GpApp/GliderDefines.h
@@ -0,0 +1,625 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// GliderDefines.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+//============================================================== Defines
+
+//#define CREATEDEMODATA
+//#define COMPILEDEMO
+//#define CAREFULDEBUG
+#define COMPILENOCP
+#define COMPILEQT
+#define BUILD_ARCADE_VERSION 1
+
+#define kYellowUnaccounted 1
+#define kYellowFailedResOpen 2
+#define kYellowFailedResAdd 3
+#define kYellowFailedResCreate 4
+#define kYellowNoHouses 5
+#define kYellowNewerVersion 6
+#define kYellowNoBackground 7
+#define kYellowIllegalRoomNum 8
+#define kYellowNoBoundsRes 9
+#define kYellowScrapError 10
+#define kYellowNoMemory 11
+#define kYellowFailedWrite 12
+#define kYellowNoMusic 13
+#define kYellowFailedSound 14
+#define kYellowAppleEventErr 15
+#define kYellowOpenedOldHouse 16
+#define kYellowLostAllHouses 17
+#define kYellowFailedSaveGame 18
+#define kYellowSavedTimeWrong 19
+#define kYellowSavedVersWrong 20
+#define kYellowSavedRoomsWrong 21
+#define kYellowQTMovieNotLoaded 22
+#define kYellowNoRooms 23
+#define kYellowCantOrderLinks 24
+
+#define kSwitchIfNeeded 0
+#define kSwitchTo256Colors 1
+#define kSwitchTo16Grays 2
+
+#define kProdGameScoreMode -4
+#define kKickGameScoreMode -3
+#define kPlayGameScoreMode -2
+#define kPlayWholeScoreMode -1
+#define kPlayChorus 4
+#define kPlayRefrainSparse1 5
+#define kPlayRefrainSparse2 6
+
+#define kHitWallSound 0 // ¥¥¥¥¥¥
+#define kFadeInSound 1 // ¥¥
+#define kFadeOutSound 2 // ¥¥¥¥¥¥
+#define kBeepsSound 3 // ¥¥
+#define kBuzzerSound 4 // ¥¥¥¥¥¥
+#define kDingSound 5 //
+#define kEnergizeSound 6 // ¥¥¥¥¥¥
+#define kFollowSound 7 // ¥¥ ¥¥
+#define kMicrowavedSound 8 // ¥¥ ¥¥
+#define kSwitchSound 9 // ¥¥ ¥¥
+#define kBirdSound 10 // ¥¥¥¥¥¥
+#define kCuckooSound 11 //
+#define kTikSound 12 // ¥¥ ¥¥
+#define kTokSound 13 // ¥¥ ¥¥
+#define kBlowerOn 14 // ¥¥ ¥¥
+#define kBlowerOff 15 // ¥¥ ¥¥
+#define kCaughtFireSound 16 // ¥¥¥¥¥¥
+#define kScoreTikSound 17 //
+#define kThrustSound 18 // ¥¥¥ ¥¥
+#define kFizzleSound 19 // ¥¥¥¥ ¥¥
+#define kFireBandSound 20 // ¥¥ ¥¥ ¥¥
+#define kBandReboundSound 21 // ¥¥ ¥¥¥¥
+#define kGreaseSpillSound 22 // ¥¥ ¥¥¥
+#define kChordSound 23 //
+#define kVCRSound 24 // ¥¥¥¥¥¥¥
+#define kFoilHitSound 25 // ¥¥ ¥¥
+#define kShredSound 26 // ¥¥ ¥¥
+#define kToastLaunchSound 27 // ¥¥ ¥¥
+#define kToastLandSound 28 // ¥¥¥¥¥¥¥
+#define kMacOnSound 29 //
+#define kMacBeepSound 30 //
+#define kMacOffSound 31 //
+#define kTVOnSound 32 //
+#define kTVOffSound 33 // ¥¥¥¥¥¥
+#define kCoffeeSound 34 // ¥¥
+#define kMysticSound 35 // ¥¥¥¥¥¥
+#define kZapSound 36 // ¥¥
+#define kPopSound 37 // ¥¥¥¥¥¥
+#define kEnemyInSound 38 //
+#define kEnemyOutSound 39 // ¥¥¥¥¥¥
+#define kPaperCrunchSound 40 // ¥¥ ¥¥
+#define kBounceSound 41 // ¥¥ ¥¥
+#define kDripSound 42 // ¥¥ ¥¥
+#define kDropSound 43 // ¥¥¥¥¥¥
+#define kFishOutSound 44 //
+#define kFishInSound 45 // ¥¥ ¥¥
+#define kDontExitSound 46 // ¥¥ ¥¥
+#define kSizzleSound 47 // ¥¥ ¥¥
+#define kPaper1Sound 48 // ¥¥ ¥¥
+#define kPaper2Sound 49 // ¥¥¥¥¥¥
+#define kPaper3Sound 50 //
+#define kPaper4Sound 51 // ¥¥¥ ¥¥
+#define kTypingSound 52 // ¥¥¥¥ ¥¥
+#define kCarriageSound 53 // ¥¥ ¥¥ ¥¥
+#define kChord2Sound 54 // ¥¥ ¥¥¥¥
+#define kPhoneRingSound 55 // ¥¥ ¥¥¥
+#define kChime1Sound 56 //
+#define kChime2Sound 57 // ¥¥¥¥¥¥¥
+#define kWebTwangSound 58 // ¥¥ ¥¥
+#define kTransOutSound 59 // ¥¥ ¥¥
+#define kTransInSound 60 // ¥¥ ¥¥
+#define kBonusSound 61 // ¥¥¥¥¥¥¥
+#define kHissSound 62 //
+#define kTriggerSound 63
+
+#define kHitWallPriority 100 // ¥¥¥¥¥¥
+#define kScoreTikPriority 101 // ¥¥
+#define kBandReboundPriority 102 // ¥¥¥¥¥¥
+#define kDontExitPriority 103 // ¥¥
+#define kTikPriority 200 // ¥¥¥¥¥¥
+#define kTokPriority 201 //
+#define kMysticPriority 202 // ¥¥¥¥¥¥
+#define kChime1Priority 203 // ¥¥ ¥¥
+#define kChime2Priority 204 // ¥¥ ¥¥
+#define kThrustPriority 300 // ¥¥ ¥¥
+#define kFireBandPriority 301 // ¥¥¥¥¥¥
+#define kChordPriority 302 //
+#define kVCRPriority 303 // ¥¥ ¥¥
+#define kToastLaunchPriority 304 // ¥¥ ¥¥
+#define kToastLandPriority 305 // ¥¥ ¥¥
+#define kCoffeePriority 306 // ¥¥ ¥¥
+#define kBouncePriority 307 // ¥¥¥¥¥¥
+#define kDripPriority 308 //
+#define kDropPriority 309 // ¥¥¥ ¥¥
+#define kWebTwangPriority 310 // ¥¥¥¥ ¥¥
+#define kHissPriority 311 // ¥¥ ¥¥ ¥¥
+#define kFoilHitPriority 400 // ¥¥ ¥¥¥¥
+#define kMacOnPriority 401 // ¥¥ ¥¥¥
+#define kMacOffPriority 402 //
+#define kMacBeepPriority 403 // ¥¥¥¥¥¥¥
+#define kTVOnPriority 404 // ¥¥ ¥¥
+#define kTVOffPriority 405 // ¥¥ ¥¥
+#define kZapPriority 406 // ¥¥ ¥¥
+#define kPopPriority 407 // ¥¥¥¥¥¥¥
+#define kEnemyInPriority 408 //
+#define kEnemyOutPriority 409 //
+#define kPaperCrunchPriority 410 //
+#define kFishOutPriority 411 //
+#define kFishInPriority 412 //
+#define kSizzlePriority 413
+#define kPhoneRingPriority 500
+#define kSwitchPriority 700
+#define kBlowerOnPriority 701
+#define kBlowerOffPriority 702
+#define kFizzlePriority 703
+#define kBeepsPriority 800
+#define kBuzzerPriority 801
+#define kDingPriority 802
+#define kEnergizePriority 803
+#define kBirdPriority 804
+#define kCuckooPriority 805
+#define kGreaseSpillPriority 806
+#define kPapersPriority 807
+#define kTypingPriority 808
+#define kCarriagePriority 809
+#define kChord2Priority 810
+#define kMicrowavedPriority 811
+#define kBonusPriority 812
+#define kFadeInPriority 900
+#define kFadeOutPriority 901
+#define kCaughtFirePriority 902
+#define kShredPriority 903
+#define kFollowPriority 904
+#define kTransInPriority 905
+#define kTransOutPriority 906
+#define kTriggerPriority 999
+
+#define kArrowCursor 0
+#define kBeamCursor 1
+#define kHandCursor 2
+
+#define kAppleMenuID 128
+#define kGameMenuID 129
+#define kOptionsMenuID 130
+#define kHouseMenuID 131
+
+#define kSplashMode 0
+#define kEditMode 1
+#define kPlayMode 2
+
+#define kIdleSplashMode 0
+#define kIdleDemoMode 1
+#define kIdleSplashTicks 7200L // 2 minutes
+#define kIdleLastMode 1
+
+#define kRoomAbove 1
+#define kRoomBelow 2
+#define kRoomToRight 3
+#define kRoomToLeft 4
+
+#define kBumpUp 1
+#define kBumpDown 2
+#define kBumpRight 3
+#define kBumpLeft 4
+
+#define kAbove 1
+#define kToRight 2
+#define kBelow 3
+#define kToLeft 4
+#define kBottomCorner 5
+#define kTopCorner 6
+
+#define kCentralRoom 0
+#define kNorthRoom 1
+#define kNorthEastRoom 2
+#define kEastRoom 3
+#define kSouthEastRoom 4
+#define kSouthRoom 5
+#define kSouthWestRoom 6
+#define kWestRoom 7
+#define kNorthWestRoom 8
+
+#define kSimpleRoom 2000
+#define kPaneledRoom 2001
+#define kBasement 2002
+#define kChildsRoom 2003
+#define kAsianRoom 2004
+#define kUnfinishedRoom 2005
+#define kSwingersRoom 2006
+#define kBathroom 2007
+#define kLibrary 2008
+#define kGarden 2009
+#define kSkywalk 2010
+#define kDirt 2011
+#define kMeadow 2012
+#define kField 2013
+#define kRoof 2014
+#define kSky 2015
+#define kStratosphere 2016
+#define kStars 2017
+
+#define kMapRoomHeight 20
+#define kMapRoomWidth 32
+
+#define kMaxScores 10
+#define kMaxRoomObs 24
+#define kMaxSparkles 3
+#define kNumSparkleModes 5
+#define kMaxFlyingPts 3
+#define kMaxFlyingPointsLoop 24
+#define kMaxCandles 20
+#define kMaxTikis 8
+#define kMaxCoals 8
+#define kMaxPendulums 8
+#define kMaxHotSpots 56
+#define kMaxSavedMaps 24
+#define kMaxRubberBands 2
+#define kMaxGrease 16
+#define kMaxStars 4
+#define kMaxShredded 4
+#define kMaxDynamicObs 18
+#define kMaxMasterObjects 216 // kMaxRoomObs * 9
+#define kMaxViewWidth 1536
+#define kMaxViewHeight 1026
+
+#define kSelectTool 0
+
+#define kBlowerMode 1
+#define kFurnitureMode 2
+#define kBonusMode 3
+#define kTransportMode 4
+#define kSwitchMode 5
+#define kLightMode 6
+#define kApplianceMode 7
+#define kEnemyMode 8
+#define kClutterMode 9
+
+#define kIgnoreIt 0 // ¥¥¥¥¥¥
+#define kLiftIt 1 // ¥¥ ¥¥
+#define kDropIt 2 // ¥¥¥¥¥¥¥¥
+#define kPushItLeft 3 // ¥¥ ¥¥
+#define kPushItRight 4 // ¥¥ ¥¥
+#define kDissolveIt 5 //
+#define kRewardIt 6 // ¥¥¥¥¥¥
+#define kMoveItUp 7 // ¥¥ ¥¥
+#define kMoveItDown 8 // ¥¥
+#define kSwitchIt 9 // ¥¥ ¥¥
+#define kShredIt 10 // ¥¥¥¥¥¥
+#define kStrumIt 11 //
+#define kTriggerIt 12 // ¥¥¥¥¥¥¥¥
+#define kBurnIt 13 // ¥¥
+#define kSlideIt 14 // ¥¥
+#define kTransportIt 15 // ¥¥
+#define kIgnoreLeftWall 16 // ¥¥
+#define kIgnoreRightWall 17 //
+#define kMailItLeft 18 // ¥¥¥¥¥¥
+#define kMailItRight 19 // ¥¥
+#define kDuctItDown 20 // ¥¥
+#define kDuctItUp 21 // ¥¥
+#define kMicrowaveIt 22 // ¥¥¥¥¥¥
+#define kIgnoreGround 23 //
+#define kBounceIt 24 //
+#define kChimeIt 25 // ¥¥
+#define kWebIt 26 // ¥¥
+#define kSoundIt 27
+
+#define kFloorVent 0x01 // Blowers
+#define kCeilingVent 0x02
+#define kFloorBlower 0x03
+#define kCeilingBlower 0x04
+#define kSewerGrate 0x05
+#define kLeftFan 0x06
+#define kRightFan 0x07
+#define kTaper 0x08
+#define kCandle 0x09
+#define kStubby 0x0A
+#define kTiki 0x0B
+#define kBBQ 0x0C
+#define kInvisBlower 0x0D
+#define kGrecoVent 0x0E
+#define kSewerBlower 0x0F
+#define kLiftArea 0x10
+
+#define kTable 0x11 // Furniture
+#define kShelf 0x12
+#define kCabinet 0x13
+#define kFilingCabinet 0x14
+#define kWasteBasket 0x15
+#define kMilkCrate 0x16
+#define kCounter 0x17
+#define kDresser 0x18
+#define kDeckTable 0x19
+#define kStool 0x1A
+#define kTrunk 0x1B
+#define kInvisObstacle 0x1C
+#define kManhole 0x1D
+#define kBooks 0x1E
+#define kInvisBounce 0x1F
+
+#define kRedClock 0x21 // Prizes
+#define kBlueClock 0x22
+#define kYellowClock 0x23
+#define kCuckoo 0x24
+#define kPaper 0x25
+#define kBattery 0x26
+#define kBands 0x27
+#define kGreaseRt 0x28
+#define kGreaseLf 0x29
+#define kFoil 0x2A
+#define kInvisBonus 0x2B
+#define kStar 0x2C
+#define kSparkle 0x2D
+#define kHelium 0x2E
+#define kSlider 0x2F
+
+#define kUpStairs 0x31 // Transport
+#define kDownStairs 0x32
+#define kMailboxLf 0x33
+#define kMailboxRt 0x34
+#define kFloorTrans 0x35
+#define kCeilingTrans 0x36
+#define kDoorInLf 0x37
+#define kDoorInRt 0x38
+#define kDoorExRt 0x39
+#define kDoorExLf 0x3A
+#define kWindowInLf 0x3B
+#define kWindowInRt 0x3C
+#define kWindowExRt 0x3D
+#define kWindowExLf 0x3E
+#define kInvisTrans 0x3F
+#define kDeluxeTrans 0x40
+
+#define kLightSwitch 0x41 // Switches
+#define kMachineSwitch 0x42
+#define kThermostat 0x43
+#define kPowerSwitch 0x44
+#define kKnifeSwitch 0x45
+#define kInvisSwitch 0x46
+#define kTrigger 0x47
+#define kLgTrigger 0x48
+#define kSoundTrigger 0x49
+
+#define kCeilingLight 0x51 // Lights
+#define kLightBulb 0x52
+#define kTableLamp 0x53
+#define kHipLamp 0x54
+#define kDecoLamp 0x55
+#define kFlourescent 0x56
+#define kTrackLight 0x57
+#define kInvisLight 0x58
+
+#define kShredder 0x61 // Appliances
+#define kToaster 0x62
+#define kMacPlus 0x63
+#define kGuitar 0x64
+#define kTV 0x65
+#define kCoffee 0x66
+#define kOutlet 0x67
+#define kVCR 0x68
+#define kStereo 0x69
+#define kMicrowave 0x6A
+#define kCinderBlock 0x6B
+#define kFlowerBox 0x6C
+#define kCDs 0x6D
+#define kCustomPict 0x6E
+
+#define kBalloon 0x71 // Enemies
+#define kCopterLf 0x72
+#define kCopterRt 0x73
+#define kDartLf 0x74
+#define kDartRt 0x75
+#define kBall 0x76
+#define kDrip 0x77
+#define kFish 0x78
+#define kCobweb 0x79
+
+#define kOzma 0x81 // Clutter
+#define kMirror 0x82
+#define kMousehole 0x83
+#define kFireplace 0x84
+#define kFlower 0x85
+#define kWallWindow 0x86
+#define kBear 0x87
+#define kCalendar 0x88
+#define kVase1 0x89
+#define kVase2 0x8A
+#define kBulletin 0x8B
+#define kCloud 0x8C
+#define kFaucet 0x8D
+#define kRug 0x8E
+#define kChimes 0x8F
+
+#define kNumSrcRects 0x90
+
+#define kTableThick 8
+#define kShelfThick 6
+#define kToggle 0
+#define kForceOn 1
+#define kForceOff 2
+#define kOneShot 3
+#define kNumTrackLights 3
+#define kNumOutletPicts 4
+#define kNumCandleFlames 5
+#define kNumTikiFlames 5
+#define kNumBBQCoals 4
+#define kNumPendulums 3
+#define kNumBreadPicts 6
+#define kNumBalloonFrames 8
+#define kNumCopterFrames 10
+#define kNumDartFrames 4
+#define kNumBallFrames 2
+#define kNumDripFrames 6
+#define kNumFishFrames 8
+#define kNumFlowers 6
+
+#define kNumMarqueePats 7
+#define kObjectNameStrings 1007
+
+#define kSwitchLinkOnly 3
+#define kTriggerLinkOnly 4
+#define kTransportLinkOnly 5
+
+#define kFloorVentTop 305
+#define kCeilingVentTop 8
+#define kFloorBlowerTop 304
+#define kCeilingBlowerTop 5
+#define kSewerGrateTop 303
+#define kCeilingTransTop 6
+#define kFloorTransTop 302
+#define kStairsTop 28
+#define kCounterBottom 304
+#define kDresserBottom 293
+#define kCeilingLightTop 4
+#define kHipLampTop 23
+#define kDecoLampTop 91
+#define kFlourescentTop 12
+#define kTrackLightTop 5
+
+#define kDoorInTop 0
+#define kDoorInLfLeft 0
+#define kDoorInRtLeft 368
+#define kDoorExTop 0
+#define kDoorExLfLeft 0
+#define kDoorExRtLeft 496
+#define kWindowInTop 64
+#define kWindowInLfLeft 0
+#define kWindowInRtLeft 492
+#define kWindowExTop 64
+#define kWindowExLfLeft 0
+#define kWindowExRtLeft 496
+
+#define kNumTiles 8
+#define kTileWide 64
+#define kTileHigh 322
+#define kRoomWide 512 // kNumTiles * kTileWide
+#define kFloorSupportTall 44
+#define kVertLocalOffset 322 // kTileHigh - 39 (was 283, then 295)
+
+#define kCeilingLimit 8
+#define kFloorLimit 312
+#define kRoofLimit 122
+#define kLeftWallLimit 12
+#define kNoLeftWallLimit -24 // 0 - (kGliderWide / 2)
+#define kRightWallLimit 500
+#define kNoRightWallLimit 536 // kRoomWide + (kGliderWide / 2)
+#define kNoCeilingLimit -10
+#define kNoFloorLimit 332
+
+#define kScoreboardHigh 0
+#define kScoreboardLow 1
+#define kScoreboardTall 20
+
+#define kHouseVersion 0x0200
+#define kNewHouseVersion 0x0300
+#define kBaseBackgroundID 2000
+#define kFirstOutdoorBack 2009
+#define kNumBackgrounds 18
+#define kUserBackground 3000
+#define kUserStructureRange 3300
+#define kSplash8BitPICT 1000
+#define kRoomIsEmpty -1
+#define kObjectIsEmpty -1
+#define kNoObjectSelected -1
+#define kInitialGliderSelected -2
+#define kLeftGliderSelected -3
+#define kRightGliderSelected -4
+#define kWindoidWDEF 2048
+#define kWindoidGrowWDEF 2064
+#define kTicksPerFrame 2
+#define kStarPictID 1995
+#define kNumUndergroundFloors 8
+#define kRoomVisitScore 100
+#define kRedClockPoints 100
+#define kBlueClockPoints 300
+#define kYellowClockPoints 500
+#define kCuckooClockPoints 1000
+#define kStarPoints 5000
+#define kRedOrangeColor8 23 // actually, 18
+#define kMaxNumRoomsH 128
+#define kMaxNumRoomsV 64
+#define kStartSparkle 4
+#define kLengthOfZap 30
+
+#define kGliderWide 48
+#define kGliderHigh 20
+#define kHalfGliderWide 24
+#define kGliderBurningHigh 26
+#define kShadowHigh 9
+#define kShadowTop 306
+#define kFaceRight TRUE
+#define kFaceLeft FALSE
+#define kPlayer1 TRUE
+#define kPlayer2 FALSE
+#define kNumGliderSrcRects 31
+#define kNumShadowSrcRects 2
+#define kFirstAboutFaceFrame 18
+#define kLastAboutFaceFrame 20
+#define kWasBurning 2
+#define kLeftFadeOffset 7
+#define kLastFadeSequence 16
+#define kGliderFoil2PictID 3963
+#define kGlider2PictID 3974
+#define kGliderFoilPictID 3976
+#define kGliderPictID 3999
+#define kGliderStartsDown 32
+
+#define kGliderNormal 0 // ¥¥ ¥¥
+#define kGliderFadingIn 1 // ¥¥¥ ¥¥¥
+#define kGliderFadingOut 2 // ¥¥ ¥¥ ¥¥
+#define kGliderGoingUp 3 // ¥¥ ¥¥
+#define kGliderComingUp 4 // ¥¥ ¥¥
+#define kGliderGoingDown 5 //
+#define kGliderComingDown 6 // ¥¥¥¥¥¥
+#define kGliderFaceLeft 7 // ¥¥ ¥¥
+#define kGliderFaceRight 8 // ¥¥ ¥¥
+#define kGliderBurning 9 // ¥¥ ¥¥
+#define kGliderTransporting 10 // ¥¥¥¥¥¥
+#define kGliderDuctingDown 11 //
+#define kGliderDuctingUp 12 // ¥¥¥¥¥¥¥
+#define kGliderDuctingIn 13 // ¥¥ ¥¥
+#define kGliderMailInLeft 14 // ¥¥ ¥¥
+#define kGliderMailOutLeft 15 // ¥¥ ¥¥
+#define kGliderMailInRight 16 // ¥¥¥¥¥¥¥
+#define kGliderMailOutRight 17 //
+#define kGliderGoingFoil 18 // ¥¥¥¥¥¥¥¥
+#define kGliderLosingFoil 19 // ¥¥
+#define kGliderShredding 20 // ¥¥¥¥
+#define kGliderInLimbo 21 // ¥¥
+#define kGliderIdle 22 // ¥¥¥¥¥¥¥¥
+#define kGliderTransportingIn 23
+
+#define kPlayerIsDeadForever -69
+#define kPlayerMailedOut -12
+#define kPlayerDuckedOut -11
+#define kPlayerTransportedOut -10
+#define kPlayerEscapingDownStairs -9
+#define kPlayerEscapingUpStairs -8
+#define kPlayerEscapedDownStairs -7
+#define kPlayerEscapedUpStairs -6
+#define kPlayerEscapedDown -5
+#define kPlayerEscapedUp -4
+#define kPlayerEscapedLeft -3
+#define kPlayerEscapedRight -2
+#define kNoOneEscaped -1
+
+#define kLinkedToOther 0
+#define kLinkedToLeftMailbox 1
+#define kLinkedToRightMailbox 2
+#define kLinkedToCeilingDuct 3
+#define kLinkedToFloorDuct 4
+
+#define kResumeGameMode 0
+#define kNewGameMode 1
+
+#define kNormalTitleMode 0
+#define kEscapedTitleMode 1
+#define kSavingTitleMode 2
+
+#define kScoreboardPictID 1997
+
+#define kDemoLength 6702
diff --git a/GpApp/GliderProtos.h b/GpApp/GliderProtos.h
new file mode 100644
index 0000000..45bfdc5
--- /dev/null
+++ b/GpApp/GliderProtos.h
@@ -0,0 +1,530 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// GliderProtos.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+//-------------------------------------------------------------- Prototypes
+
+void SetUpAppleEvents (void); // --- AppleEvents.c
+
+void BringUpBanner (void); // --- Banner.c
+SInt16 CountStarsInHouse (void);
+void DisplayStarsRemaining (void);
+
+void SetCoordinateHVD (SInt16, SInt16, SInt16); // --- Coordinate.c
+void DeltaCoordinateD (SInt16);
+void UpdateCoordWindow (void);
+void OpenCoordWindow (void);
+void CloseCoordWindow (void);
+void ToggleCoordinateWindow (void);
+
+void NilSavedMaps (void); // --- DynamicMaps.c
+SInt16 BackUpToSavedMap (Rect *, SInt16, SInt16);
+SInt16 ReBackUpSavedMap (Rect *, SInt16, SInt16);
+void RestoreFromSavedMap (SInt16, SInt16, Boolean);
+void AddSparkle (Rect *);
+void AddFlyingPoint (Rect *, SInt16, SInt16, SInt16);
+void ReBackUpFlames (SInt16, SInt16);
+void AddCandleFlame (SInt16, SInt16, SInt16, SInt16);
+void ReBackUpTikiFlames (SInt16, SInt16);
+void AddTikiFlame (SInt16, SInt16, SInt16, SInt16);
+void ReBackUpBBQCoals (SInt16, SInt16);
+void AddBBQCoals (SInt16, SInt16, SInt16, SInt16);
+void ReBackUpPendulum (SInt16, SInt16);
+void AddPendulum (SInt16, SInt16, SInt16, SInt16);
+void ReBackUpStar (SInt16, SInt16);
+void AddStar (SInt16, SInt16, SInt16, SInt16);
+void StopPendulum (SInt16, SInt16);
+void StopStar (SInt16, SInt16);
+void AddAShreddedGlider (Rect *);
+void RemoveShreds (void);
+void ZeroFlamesAndTheLike (void);
+
+void CheckDynamicCollision (SInt16, gliderPtr, Boolean); // --- Dynamics.c
+Boolean DidBandHitDynamic (SInt16);
+void RenderToast (SInt16);
+void RenderBalloon (SInt16);
+void RenderCopter (SInt16);
+void RenderDart (SInt16);
+void RenderBall (SInt16);
+void RenderDrip (SInt16);
+void RenderFish (SInt16);
+void HandleSparkleObject (SInt16);
+void HandleToast (SInt16);
+void HandleMacPlus (SInt16);
+void HandleTV (SInt16);
+void HandleCoffee (SInt16);
+void HandleOutlet (SInt16);
+void HandleVCR (SInt16);
+void HandleStereo (SInt16);
+void HandleMicrowave (SInt16);
+
+void HandleBalloon (SInt16); // --- Dynamics2.c
+void HandleCopter (SInt16);
+void HandleDart (SInt16);
+void HandleBall (SInt16);
+void HandleDrip (SInt16);
+void HandleFish (SInt16);
+
+void HandleDynamics (void); // --- Dynamics3.c
+void RenderDynamics (void);
+void ZeroDinahs (void);
+SInt16 AddDynamicObject (SInt16, Rect *, objectType *, SInt16, SInt16, Boolean);
+
+void DoGameOver (void); // --- GameOver.c
+void FlagGameOver (void);
+void DoDiedGameOver (void);
+
+void HandleGrease (void); // --- Grease.c
+SInt16 ReBackUpGrease (SInt16, SInt16);
+SInt16 AddGrease (SInt16, SInt16, SInt16, SInt16, SInt16, Boolean);
+void SpillGrease (SInt16, SInt16);
+void RedrawAllGrease (void);
+
+void DoHighScores (void); // --- HighScores.c
+void SortHighScores (void);
+void ZeroHighScores (void);
+void ZeroAllButHighestScore (void);
+Boolean TestHighScore (void);
+Boolean WriteScoresToDisk (void);
+Boolean ReadScoresFromDisk (void);
+
+Boolean CreateNewHouse (void); // --- House.c
+Boolean InitializeEmptyHouse (void);
+SInt16 RealRoomNumberCount (void);
+SInt16 GetFirstRoomNumber (void);
+void WhereDoesGliderBegin (Rect *, SInt16);
+Boolean HouseHasOriginalPicts (void);
+SInt16 CountHouseLinks (void);
+void GenerateLinksList (void);
+void SortRoomsObjects (SInt16);
+void SortHouseObjects (void);
+SInt16 CountRoomsVisited (void);
+void GenerateRetroLinks (void);
+void DoGoToDialog (void);
+void ConvertHouseVer1To2 (void);
+void ShiftWholeHouse (SInt16);
+
+void DoHouseInfo (void); // --- HouseInfo.c
+
+Boolean OpenHouse (void); // --- HouseIO.c
+Boolean OpenSpecificHouse (FSSpec *);
+Boolean SaveHouseAs (void);
+Boolean ReadHouse (void);
+Boolean WriteHouse (Boolean);
+Boolean CloseHouse (void);
+void OpenHouseResFork (void);
+void CloseHouseResFork (void);
+Boolean QuerySaveChanges (void);
+void YellowAlert (SInt16, SInt16);
+
+Boolean KeepObjectLegal (void); // --- HouseLegal.c
+void CheckHouseForProblems (void);
+
+Boolean SectGlider (gliderPtr, Rect *, Boolean); // --- Interactions.c
+void HandleSwitches (hotPtr);
+void HandleInteraction (void);
+void FlagStillOvers (gliderPtr);
+
+void InitializeMenus (void); // --- InterfaceInit.c
+void GetExtraCursors (void);
+void VariableInit (void);
+
+void GetDemoInput (gliderPtr); // --- Input.c
+void GetInput (gliderPtr);
+
+SInt16 MergeFloorSuite (SInt16, SInt16); // --- Link.c
+void ExtractFloorSuite (SInt16, SInt16 *, SInt16 *);
+void UpdateLinkControl (void);
+void UpdateLinkWindow (void);
+void OpenLinkWindow (void);
+void CloseLinkWindow (void);
+void HandleLinkClick (Point);
+
+void RedrawSplashScreen (void); // --- MainWindow.c
+void UpdateMainWindow (void);
+void UpdateMenuBarWindow (void);
+void OpenMainWindow (void);
+void CloseMainWindow (void);
+void ZoomBetweenWindows (void);
+void UpdateEditWindowTitle (void);
+void HandleMainClick (Point, Boolean);
+//void WashColorIn (void);
+
+void CenterMapOnRoom (SInt16, SInt16); // --- Map.c
+Boolean ThisRoomVisibleOnMap (void);
+void FindNewActiveRoomRect (void);
+void FlagMapRoomsForUpdate (void);
+void UpdateMapWindow (void);
+void ResizeMapWindow (SInt16, SInt16);
+void OpenMapWindow (void);
+void CloseMapWindow (void);
+void ToggleMapWindow (void);
+void HandleMapClick (EventRecord *);
+void MoveRoom (Point);
+
+void DoMarquee (void); // --- Marquee.c
+void StartMarquee (Rect *);
+void StartMarqueeHandled (Rect *, SInt16, SInt16);
+void StopMarquee (void);
+void PauseMarquee (void);
+void ResumeMarquee (void);
+void DragOutMarqueeRect (Point, Rect *);
+void DragMarqueeRect (Point, Rect *, Boolean, Boolean);
+void DragMarqueeHandle (Point, SInt16 *);
+void DragMarqueeCorner (Point, SInt16 *, SInt16 *, Boolean);
+Boolean MarqueeHasHandles (SInt16 *, SInt16 *);
+Boolean PtInMarqueeHandle (Point);
+void SetMarqueeGliderRect (SInt16, SInt16);
+void InitMarquee (void);
+
+void UpdateClipboardMenus (void); // --- Menu.c
+void DoAppleMenu (SInt16);
+void DoGameMenu (SInt16);
+void DoOptionsMenu (SInt16);
+void DoHouseMenu (SInt16);
+void DoMenuChoice (long);
+void UpdateMenus (Boolean);
+void UpdateMapCheckmark (Boolean);
+void UpdateToolsCheckmark (Boolean);
+void UpdateCoordinateCheckmark (Boolean);
+#ifdef COMPILEDEMO
+void DoNotInDemo (void);
+#endif
+void OpenCloseEditWindows (void);
+
+void StartGliderFadingIn (gliderPtr); // --- Modes.c
+void StartGliderTransportingIn (gliderPtr);
+void StartGliderFadingOut (gliderPtr);
+void StartGliderGoingUpStairs (gliderPtr);
+void StartGliderGoingDownStairs (gliderPtr);
+void StartGliderMailingIn (gliderPtr, Rect *, hotPtr);
+void StartGliderMailingOut (gliderPtr);
+void StartGliderDuctingDown (gliderPtr, Rect *, hotPtr);
+void StartGliderDuctingUp (gliderPtr, Rect *, hotPtr);
+void StartGliderDuctingIn (gliderPtr);
+void StartGliderTransporting (gliderPtr, hotPtr);
+void FlagGliderNormal (gliderPtr);
+void FlagGliderShredding (gliderPtr, Rect *);
+void FlagGliderBurning (gliderPtr);
+void FlagGliderFaceLeft (gliderPtr);
+void FlagGliderFaceRight (gliderPtr);
+void FlagGliderInLimbo (gliderPtr, Boolean);
+void UndoGliderLimbo (gliderPtr);
+void ToggleGliderFacing (gliderPtr);
+void InsureGliderFacingRight (gliderPtr);
+void InsureGliderFacingLeft (gliderPtr);
+void ReadyGliderForTripUpStairs (gliderPtr);
+void ReadyGliderForTripDownStairs (gliderPtr);
+void StartGliderFoilGoing (gliderPtr);
+void StartGliderFoilLosing (gliderPtr);
+void TagGliderIdle (gliderPtr);
+
+OSErr StartMusic (void); // --- Music.c
+void StopTheMusic (void);
+void ToggleMusicWhilePlaying (void);
+void SetMusicalMode (SInt16);
+void InitMusic (void);
+void KillMusic (void);
+long MusicBytesNeeded (void);
+void TellHerNoMusic (void);
+
+Boolean AddNewObject (Point, SInt16, Boolean); // --- ObjectAdd.c
+SInt16 FindObjectSlotInRoom (SInt16);
+Boolean DoesRoomNumHaveObject (SInt16, SInt16);
+void ShoutNoMoreObjects (void);
+
+void DrawSimpleBlowers (SInt16, Rect *); // --- ObjectDraw.c
+void DrawTiki (Rect *, SInt16);
+void DrawInvisibleBlower (Rect *);
+void DrawLiftArea (Rect *);
+void DrawTable (Rect *, SInt16);
+void DrawShelf (Rect *);
+void DrawCabinet (Rect *);
+void DrawSimpleFurniture (SInt16, Rect *);
+void DrawCounter (Rect *);
+void DrawDresser (Rect *);
+void DrawDeckTable (Rect *, SInt16);
+void DrawStool (Rect *, SInt16);
+void DrawInvisObstacle (Rect *);
+void DrawInvisBounce (Rect *);
+void DrawRedClock (Rect *);
+void DrawBlueClock (Rect *);
+void DrawYellowClock (Rect *);
+void DrawCuckoo (Rect *);
+void DrawSimplePrizes (SInt16, Rect *);
+void DrawGreaseRt (Rect *, SInt16, Boolean);
+void DrawGreaseLf (Rect *, SInt16, Boolean);
+void DrawFoil (Rect *);
+void DrawInvisBonus (Rect *);
+void DrawSlider (Rect *);
+
+void DrawMailboxLeft (Rect *, SInt16); // --- ObjectDraw2.c
+void DrawMailboxRight (Rect *, SInt16);
+void DrawSimpleTransport (SInt16, Rect *);
+void DrawInvisTransport (Rect *);
+void DrawLightSwitch (Rect *, Boolean);
+void DrawMachineSwitch (Rect *, Boolean);
+void DrawThermostat (Rect *, Boolean);
+void DrawPowerSwitch (Rect *, Boolean);
+void DrawKnifeSwitch (Rect *, Boolean);
+void DrawInvisibleSwitch (Rect *);
+void DrawTrigger (Rect *);
+void DrawSoundTrigger (Rect *);
+void DrawSimpleLight (SInt16, Rect *);
+void DrawFlourescent (Rect *);
+void DrawSimpleAppliance (SInt16, Rect *);
+void DrawMacPlus (Rect *, Boolean, Boolean);
+void DrawTrackLight (Rect *);
+void DrawInvisLight (Rect *);
+void DrawTV (Rect *, Boolean, Boolean);
+void DrawCoffee (Rect *, Boolean, Boolean);
+void DrawOutlet (Rect *);
+void DrawVCR (Rect *, Boolean, Boolean);
+void DrawStereo (Rect *, Boolean, Boolean);
+void DrawMicrowave (Rect *, Boolean, Boolean);
+void DrawBalloon (Rect *);
+void DrawCopter (Rect *);
+void DrawDart (Rect *, SInt16);
+void DrawBall (SInt16, Rect *);
+void DrawFish (SInt16, Rect *);
+void DrawDrip (Rect *);
+void DrawMirror (Rect *);
+void DrawSimpleClutter (SInt16, Rect *);
+void DrawFlower (Rect *, SInt16);
+void DrawWallWindow (Rect *);
+void DrawCalendar (Rect *);
+void DrawBulletin (Rect *);
+void DrawPictObject (SInt16, Rect *);
+void DrawPictWithMaskObject (SInt16, Rect *);
+void DrawPictSansWhiteObject (SInt16, Rect *);
+void DrawCustPictSansWhite (SInt16, Rect *);
+
+void DrawARoomsObjects (SInt16, Boolean); // --- ObjectDrawAll.c
+
+void DoSelectionClick (Point, Boolean); // --- ObjectEdit.c
+void DoNewObjectClick (Point);
+void DeleteObject (void);
+void DuplicateObject (void);
+void MoveObject (SInt16, Boolean);
+void DeselectObject (void);
+Boolean ObjectHasHandle (SInt16 *, SInt16 *);
+void HandleBlowerGlider (void);
+void SelectNextObject (void);
+void SelectPrevObject (void);
+void GetThisRoomsObjRects (void);
+void DrawThisRoomsObjects (void);
+void HiliteAllObjects (void);
+void GoToObjectInRoom (SInt16, SInt16, SInt16);
+void GoToObjectInRoomNum (SInt16, SInt16);
+
+void DoObjectInfo (void); // --- ObjectInfo.c
+
+void GetObjectRect (objectPtr, Rect *); // --- ObjectRects.c
+SInt16 CreateActiveRects (SInt16);
+SInt16 VerticalRoomOffset (SInt16);
+void OffsetRectRoomRelative (Rect *, SInt16);
+SInt16 GetUpStairsRightEdge (void);
+SInt16 GetDownStairsLeftEdge (void);
+
+SInt16 GetRoomLinked (objectType *); // --- Objects.c
+Boolean ObjectIsLinkTransport (objectType *);
+Boolean ObjectIsLinkSwitch (objectType *);
+void ListAllLocalObjects (void);
+Boolean SetObjectState (SInt16, SInt16, SInt16, SInt16);
+Boolean GetObjectState (SInt16, SInt16);
+void BringSendFrontBack (Boolean);
+Boolean IsThisValid (SInt16, SInt16);
+void AddTempManholeRect (Rect *);
+
+void NewGame (SInt16); // --- Play.c
+void DoDemoGame (void);
+void HideGlider (gliderPtr);
+void StrikeChime (void);
+void RestoreEntireGameScreen (void);
+
+void HandleGlider (gliderPtr); // --- Player.c
+void FinishGliderUpStairs (gliderPtr);
+void FinishGliderDownStairs (gliderPtr);
+void FinishGliderDuctingIn (gliderPtr);
+void DeckGliderInFoil (gliderPtr);
+void RemoveFoilFromGlider (gliderPtr);
+void OffsetGlider (gliderPtr, SInt16);
+void OffAMortal (gliderPtr);
+
+void AddRectToWorkRects (Rect *); // --- Render.c
+void AddRectToBackRects (Rect *);
+void AddRectToWorkRectsWhole (Rect *);
+void RenderGlider (gliderPtr, Boolean);
+void CopyRectsQD (void);
+void DirectWork2Main8 (Rect *);
+void DirectBack2Work8 (Rect *);
+void DirectGeneric2Work8 (long, long, Rect *, Rect *);
+void DirectWork2Main4 (Rect *);
+void DirectBack2Work4 (Rect *);
+void DirectGeneric2Work4 (long, long, Rect *, Rect *);
+void CopyRectsAssm (void);
+void DirectFillBack8 (Rect *, Byte);
+void DirectFillWork8 (Rect *, Byte);
+void DirectFillBack4 (Rect *, Byte);
+void DirectFillWork4 (Rect *, Byte);
+void RenderFrame (void);
+void InitGarbageRects (void);
+void CopyRectBackToWork (Rect *);
+void CopyRectWorkToBack (Rect *);
+void CopyRectWorkToMain (Rect *);
+void CopyRectMainToWork (Rect *);
+void CopyRectMainToBack (Rect *);
+void AddToMirrorRegion (Rect *);
+void ZeroMirrorRegion (void);
+
+void SetInitialTiles (SInt16, Boolean); // --- Room.c
+Boolean CreateNewRoom (SInt16, SInt16);
+void DoRoomInfo (void);
+void ReadyBackground (SInt16, SInt16 *);
+void ReflectCurrentRoom (Boolean);
+void CopyRoomToThisRoom (SInt16);
+void CopyThisRoomToRoom (void);
+void ForceThisRoom (SInt16);
+Boolean RoomExists (SInt16, SInt16, SInt16 *);
+Boolean RoomNumExists (SInt16);
+void DeleteRoom (Boolean);
+SInt16 DoesNeighborRoomExist (SInt16);
+void SelectNeighborRoom (SInt16);
+SInt16 GetNeighborRoomNumber (SInt16);
+Boolean GetRoomFloorSuite (SInt16, SInt16 *, SInt16 *);
+SInt16 GetRoomNumber (SInt16, SInt16);
+Boolean IsRoomAStructure (SInt16);
+void DetermineRoomOpenings (void);
+SInt16 GetOriginalBounding (SInt16);
+SInt16 GetNumberOfLights (SInt16);
+Boolean IsShadowVisible (void);
+Boolean DoesRoomHaveFloor (void);
+Boolean DoesRoomHaveCeiling (void);
+
+void ReadyLevel (void); // --- RoomGraphics.c
+void DrawLocale (void);
+void RedrawRoomLighting (void);
+
+Boolean PictIDExists (SInt16); // --- RoomInfo.c
+
+void HandleBands (void); // --- RubberBands.c
+Boolean AddBand (gliderPtr, SInt16, SInt16, Boolean);
+void KillAllBands (void);
+
+void SaveGame2 (void); // --- SavedGames.c
+Boolean OpenSavedGame (void);
+void SaveGame (Boolean);
+
+void RefreshScoreboard (SInt16); // --- Scoreboard.c
+void HandleDynamicScoreboard (void);
+void QuickGlidersRefresh (void);
+void QuickScoreRefresh (void);
+void QuickBatteryRefresh (Boolean);
+void QuickBandsRefresh (Boolean);
+void QuickFoilRefresh (Boolean);
+void HandleScore (void);
+void AdjustScoreboardHeight (void);
+void BlackenScoreboard (void);
+
+//void PutRoomScrap (void); // --- Scrap.c
+//void PutObjectScrap (void);
+void GetRoomScrap (void);
+void GetObjectScrap (void);
+//void SeeIfValidScrapAvailable (Boolean);
+Boolean HasDragManager (void);
+//Boolean DragRoom (EventRecord *, Rect *, SInt16);
+
+void DoLoadHouse (void); // --- SelectHouse.c
+void BuildHouseList (void);
+void AddExtraHouse (FSSpec *);
+
+void DoSettingsMain (void); // --- Settings.c
+
+void PlayPrioritySound (SInt16, SInt16); // --- Sound.c
+void FlushAnyTriggerPlaying (void);
+void PlaySound0 (SInt16, SInt16);
+void PlaySound1 (SInt16, SInt16);
+void PlaySound2 (SInt16, SInt16);
+OSErr LoadTriggerSound (SInt16);
+void DumpTriggerSound (void);
+void InitSound (void);
+void KillSound (void);
+long SoundBytesNeeded (void);
+void TellHerNoSounds (void);
+void BitchAboutSM3 (void);
+
+void InitScoreboardMap (void); // --- StructuresInit.c
+void InitGliderMap (void);
+void InitBlowers (void);
+void InitFurniture (void);
+void InitPrizes (void);
+void InitTransports (void);
+void InitSwitches (void);
+void InitLights (void);
+void InitAppliances (void);
+void InitEnemies (void);
+
+void CreateOffscreens (void); // --- StructuresInit2.c
+void CreatePointers (void);
+void InitSrcRects (void);
+
+void UpdateToolsWindow (void); // --- Tools.c
+void EraseSelectedTool (void);
+void SelectTool (SInt16);
+void OpenToolsWindow (void);
+void CloseToolsWindow (void);
+void ToggleToolsWindow (void);
+void HandleToolsClick (Point);
+void NextToolMode (void);
+void PrevToolMode (void);
+void SetSpecificToolMode (SInt16);
+
+SInt16 WhatAreWeLinkedTo (SInt16, Byte); // --- Transit.c
+void ReadyGliderFromTransit (gliderPtr, SInt16);
+void MoveRoomToRoom (gliderPtr, SInt16);
+void TransportRoomToRoom (gliderPtr);
+void MoveDuctToDuct (gliderPtr);
+void MoveMailToMail (gliderPtr);
+void ForceKillGlider (void);
+void FollowTheLeader (void);
+
+void PourScreenOn (Rect *); // --- Transitions.c
+void WipeScreenOn (SInt16, Rect *);
+void DumpScreenOn (Rect *);
+//void DissBits (Rect *);
+//void DissBitsChunky (Rect *);
+//void FillColorNoise (Rect *);
+//void FillSnow (Rect *);
+
+void ToggleToaster (SInt16); // --- Trip.c
+void ToggleMacPlus (SInt16);
+void ToggleTV (SInt16);
+void ToggleCoffee (SInt16);
+void ToggleOutlet (SInt16);
+void ToggleVCR (SInt16);
+void ToggleStereos (SInt16);
+void ToggleMicrowave (SInt16);
+void ToggleBalloon (SInt16);
+void ToggleCopter (SInt16);
+void ToggleDart (SInt16);
+void ToggleBall (SInt16);
+void ToggleDrip (SInt16);
+void ToggleFish (SInt16);
+void TriggerSwitch (SInt16);
+void TriggerToast (SInt16);
+void TriggerOutlet (SInt16);
+void TriggerDrip (SInt16);
+void TriggerFish (SInt16);
+void TriggerBalloon (SInt16);
+void TriggerCopter (SInt16);
+void TriggerDart (SInt16);
+void UpdateOutletsLighting (SInt16, SInt16);
+
+void ArmTrigger (hotPtr); // --- Triggers.c
+void HandleTriggers (void);
+void ZeroTriggers (void);
+
diff --git a/GpApp/GliderStructs.h b/GpApp/GliderStructs.h
new file mode 100644
index 0000000..3c569ba
--- /dev/null
+++ b/GpApp/GliderStructs.h
@@ -0,0 +1,347 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// GliderStructs.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+typedef struct
+{
+ Point topLeft; // 4
+ short distance; // 2
+ Boolean initial; // 1
+ Boolean state; // 1 F. lf. dn. rt. up
+ Byte vector; // 1 | x | x | x | x | 8 | 4 | 2 | 1 |
+ Byte tall; // 1
+} blowerType; // total = 10
+
+typedef struct
+{
+ Rect bounds; // 8
+ short pict; // 2
+} furnitureType; // total = 10
+
+typedef struct
+{
+ Point topLeft; // 4
+ short length; // 2 grease spill
+ short points; // 2 invis bonus
+ Boolean state; // 1
+ Boolean initial; // 1
+} bonusType; // total = 10
+
+typedef struct
+{
+ Point topLeft; // 4
+ short tall; // 2 invis transport
+ short where; // 2
+ Byte who; // 1
+ Byte wide; // 1
+} transportType; // total = 10
+
+typedef struct
+{
+ Point topLeft; // 4
+ short delay; // 2
+ short where; // 2
+ Byte who; // 1
+ Byte type; // 1
+} switchType; // total = 10
+
+typedef struct
+{
+ Point topLeft; // 4
+ short length; // 2
+ Byte byte0; // 1
+ Byte byte1; // 1
+ Boolean initial; // 1
+ Boolean state; // 1
+} lightType; // total = 10
+
+typedef struct
+{
+ Point topLeft; // 4
+ short height; // 2 toaster, pict ID
+ Byte byte0; // 1
+ Byte delay; // 1
+ Boolean initial; // 1
+ Boolean state; // 1
+} applianceType; // total = 10
+
+typedef struct
+{
+ Point topLeft; // 4
+ short length; // 2
+ Byte delay; // 1
+ Byte byte0; // 1
+ Boolean initial; // 1
+ Boolean state; // 1
+} enemyType; // total = 10
+
+typedef struct
+{
+ Rect bounds; // 8
+ short pict; // 2
+} clutterType; // total = 10
+
+typedef struct
+{
+ short what; // 2
+ union
+ {
+ blowerType a;
+ furnitureType b;
+ bonusType c;
+ transportType d;
+ switchType e;
+ lightType f;
+ applianceType g;
+ enemyType h;
+ clutterType i;
+ } data; // 10
+} objectType, *objectPtr; // total = 12
+
+typedef struct
+{
+ Str31 banner; // 32 = 32
+ Str15 names[kMaxScores]; // 16 * 10 = 160
+ Int32 scores[kMaxScores]; // 4 * 10 = 40
+ UInt32 timeStamps[kMaxScores]; // 4 * 10 = 40
+ short levels[kMaxScores]; // 2 * 10 = 20
+} scoresType; // total = 292
+
+typedef struct
+{
+ short version; // 2
+ short wasStarsLeft; // 2
+ UInt32 timeStamp; // 4
+ Point where; // 4
+ Int32 score; // 4
+ Int32 unusedLong; // 4
+ Int32 unusedLong2; // 4
+ short energy; // 2
+ short bands; // 2
+ short roomNumber; // 2
+ short gliderState; // 2
+ short numGliders; // 2
+ short foil; // 2
+ short unusedShort; // 2
+ Boolean facing; // 1
+ Boolean showFoil; // 1
+} gameType; // total = 40
+
+typedef struct
+{
+ short unusedShort; // 2
+ Byte unusedByte; // 1
+ Boolean visited; // 1
+ objectType objects[kMaxRoomObs]; // 24 * 12
+} savedRoom, *saveRoomPtr; // total = 292
+
+typedef struct
+{
+ FSSpec house; // 70
+ short version; // 2
+ short wasStarsLeft; // 2
+ long timeStamp; // 4
+ Point where; // 4
+ long score; // 4
+ long unusedLong; // 4
+ long unusedLong2; // 4
+ short energy; // 2
+ short bands; // 2
+ short roomNumber; // 2
+ short gliderState; // 2
+ short numGliders; // 2
+ short foil; // 2
+ short nRooms; // 2
+ Boolean facing; // 1
+ Boolean showFoil; // 1
+ savedRoom savedData[1]; // 4
+} game2Type, *gamePtr; // total = 114
+
+typedef struct
+{
+ Str27 name; // 28
+ short bounds; // 2
+ Byte leftStart; // 1
+ Byte rightStart; // 1
+ Byte unusedByte; // 1
+ Boolean visited; // 1
+ short background; // 2
+ short tiles[kNumTiles]; // 2 * 8
+ short floor, suite; // 2 + 2
+ short openings; // 2
+ short numObjects; // 2
+ objectType objects[kMaxRoomObs]; // 24 * 12
+} roomType, *roomPtr; // total = 348
+
+typedef struct
+{
+ short version; // 2
+ short unusedShort; // 2
+ long timeStamp; // 4
+ long flags; // 4 (bit 0 = wardBit)
+ Point initial; // 4
+ Str255 banner; // 256
+ Str255 trailer; // 256
+ scoresType highScores; // 292
+ gameType savedGame; // 40
+ Boolean hasGame; // 1
+ Boolean unusedBoolean; // 1
+ short firstRoom; // 2
+ short nRooms; // 2
+ roomType rooms[1]; // 348 * nRooms
+} houseType, *housePtr, **houseHand; // total = 866 +
+
+typedef struct
+{
+ Rect src, mask, dest, whole;
+ Rect destShadow, wholeShadow;
+ Rect clip, enteredRect;
+ Int32 leftKey, rightKey;
+ Int32 battKey, bandKey;
+ short hVel, vVel;
+ short wasHVel, wasVVel;
+ short vDesiredVel, hDesiredVel;
+ short mode, frame, wasMode;
+ Boolean facing, tipped;
+ Boolean sliding, ignoreLeft, ignoreRight;
+ Boolean fireHeld, which;
+ Boolean heldLeft, heldRight;
+ Boolean dontDraw, ignoreGround;
+} gliderType, *gliderPtr;
+
+typedef struct
+{
+ Rect bounds;
+ short action;
+ short who;
+ Boolean isOn, stillOver;
+ Boolean doScrutinize;
+} hotObject, *hotPtr;
+
+typedef struct
+{
+ Rect dest;
+ GWorldPtr map;
+ short where;
+ short who;
+} savedType, *savedPtr;
+
+typedef struct
+{
+ Rect bounds;
+ short mode;
+} sparkleType, *sparklePtr;
+
+typedef struct
+{
+ Rect dest, whole;
+ short start;
+ short stop;
+ short mode;
+ short loops;
+ short hVel, vVel;
+} flyingPtType, *flyingPtPtr;
+
+typedef struct
+{
+ Rect dest, src;
+ short mode;
+ short who;
+} flameType, *flamePtr;
+
+typedef struct
+{
+ Rect dest, src;
+ short mode, where;
+ short who, link;
+ Boolean toOrFro, active;
+} pendulumType, *pendulumPtr;
+
+typedef struct
+{
+ Boolean left;
+ Boolean top;
+ Boolean right;
+ Boolean bottom;
+} boundsType, *boundsPtr, **boundsHand;
+
+typedef struct
+{
+ Rect dest;
+ short mode, count;
+ short hVel, vVel;
+} bandType, *bandPtr;
+
+typedef struct
+{
+ short srcRoom, srcObj;
+ short destRoom, destObj;
+} linksType, *linksPtr;
+
+typedef struct
+{
+ Rect dest;
+ short mapNum, mode;
+ short who, where;
+ short start, stop;
+ short frame, hotNum;
+ Boolean isRight;
+} greaseType, *greasePtr;
+
+typedef struct
+{
+ Rect dest, src;
+ short mode, who;
+ short link, where;
+} starType, *starPtr;
+
+typedef struct
+{
+ Rect bounds;
+ short frame;
+} shredType, *shredPtr;
+
+typedef struct
+{
+ Rect dest;
+ Rect whole;
+ short hVel, vVel;
+ short type, count;
+ short frame, timer;
+ short position, room;
+ Byte byte0, byte1;
+ Boolean moving, active;
+} dynaType, *dynaPtr;
+
+typedef struct
+{
+ short roomNum; // room # object in (real number)
+ short objectNum; // obj. # in house (real number)
+ short roomLink; // room # object linked to (if any)
+ short objectLink; // obj. # object linked to (if any)
+ short localLink; // index in master list if exists
+ short hotNum; // index into active rects (if any)
+ short dynaNum; // index into dinahs (if any)
+ objectType theObject; // actual object data
+} objDataType, *objDataPtr;
+
+typedef struct
+{
+ Int32 frame;
+ char key;
+ char padding;
+} demoType, *demoPtr;
+
+typedef struct
+{
+ short room;
+ short object;
+} retroLink, *retroLinkPtr;
+
+
diff --git a/GpApp/GliderVars.h b/GpApp/GliderVars.h
new file mode 100644
index 0000000..5c5285e
--- /dev/null
+++ b/GpApp/GliderVars.h
@@ -0,0 +1,59 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// GliderVars.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLMovies.h"
+
+
+extern Rect blowerSrcRect;
+extern Rect flame[], tikiFlame[];
+extern Rect coals[];
+extern Rect furnitureSrcRect;
+extern Rect tableSrc, shelfSrc, hingeSrc, handleSrc, knobSrc;
+extern Rect leftFootSrc, rightFootSrc, deckSrc;
+extern Rect bonusSrcRect;
+extern Rect pointsSrcRect;
+extern Rect starSrc[], sparkleSrc[];
+extern Rect digits[], pendulumSrc[], greaseSrcRt[], greaseSrcLf[];
+extern Rect transSrcRect;
+extern Rect switchSrcRect;
+extern Rect lightSwitchSrc[], machineSwitchSrc[], thermostatSrc[];
+extern Rect powerSrc[], knifeSwitchSrc[];
+extern Rect lightSrcRect;
+extern Rect flourescentSrc1, flourescentSrc2;
+extern Rect trackLightSrc[];
+extern Rect applianceSrcRect, toastSrcRect, shredSrcRect; // Appliances
+extern Rect plusScreen1, plusScreen2, tvScreen1, tvScreen2;
+extern Rect coffeeLight1, coffeeLight2, vcrTime1, vcrTime2;
+extern Rect stereoLight1, stereoLight2, microOn, microOff;
+extern Rect outletSrc[];
+extern Rect balloonSrcRect, copterSrcRect, dartSrcRect; // Enemies
+extern Rect ballSrcRect, dripSrcRect, enemySrcRect;
+extern Rect fishSrcRect;
+extern Rect balloonSrc[], copterSrc[], dartSrc[];
+extern Rect ballSrc[], dripSrc[], fishSrc[];
+extern Rect clutterSrcRect;
+extern Rect flowerSrc[];
+extern Rect *srcRects;
+
+extern Movie theMovie;
+extern Rect movieRect;
+extern Boolean hasMovie, tvInRoom;
+
+extern gliderType theGlider, theGlider2;
+extern objDataPtr masterObjects;
+extern Rect workSrcRect;
+extern Rect backSrcRect;
+extern Rect mainWindowRect, houseRect;
+extern houseHand thisHouse;
+extern roomPtr thisRoom;
+extern WindowPtr mainWindow, coordWindow;
+extern long theScore;
+extern short playOriginH, playOriginV;
+extern short thisRoomNumber, theMode, batteryTotal, bandsTotal;
+extern short foilTotal, mortals, numMasterObjects, previousRoom;
+extern Boolean fileDirty, gameDirty, showFoil, doZooms, isPlayMusicGame;
+
diff --git a/GpApp/GpApp.props b/GpApp/GpApp.props
new file mode 100644
index 0000000..b82aa3f
--- /dev/null
+++ b/GpApp/GpApp.props
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+ GP_APP_DLL;GP_APP_DLL_EXPORT;%(PreprocessorDefinitions)
+
+
+
+
\ No newline at end of file
diff --git a/GpApp/GpApp.vcxproj b/GpApp/GpApp.vcxproj
new file mode 100644
index 0000000..b492b47
--- /dev/null
+++ b/GpApp/GpApp.vcxproj
@@ -0,0 +1,204 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {6233C3F2-5781-488E-B190-4FA8836F5A77}
+ GpApp
+ 10.0.17763.0
+
+
+
+ Application
+ true
+ v141
+ MultiByte
+
+
+ Application
+ false
+ v141
+ true
+ MultiByte
+
+
+ DynamicLibrary
+ true
+ v141
+ MultiByte
+
+
+ DynamicLibrary
+ false
+ v141
+ true
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {6ec62b0f-9353-40a4-a510-3788f1368b33}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GpApp/GpApp.vcxproj.filters b/GpApp/GpApp.vcxproj.filters
new file mode 100644
index 0000000..10d281f
--- /dev/null
+++ b/GpApp/GpApp.vcxproj.filters
@@ -0,0 +1,214 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/GpApp/GpAppInterface.cpp b/GpApp/GpAppInterface.cpp
new file mode 100644
index 0000000..cf166ab
--- /dev/null
+++ b/GpApp/GpAppInterface.cpp
@@ -0,0 +1,57 @@
+#include "GpAppInterface.h"
+
+#include "DisplayDeviceManager.h"
+#include "HostFileSystem.h"
+#include "HostDisplayDriver.h"
+#include "HostSystemServices.h"
+
+int gpAppMain();
+
+class GpAppInterfaceImpl final : public GpAppInterface
+{
+public:
+ int ApplicationMain() override;
+ void PL_IncrementTickCounter(uint32_t count) override;
+ void PL_HostFileSystem_SetInstance(PortabilityLayer::HostFileSystem *instance) override;
+ void PL_HostDisplayDriver_SetInstance(PortabilityLayer::HostDisplayDriver *instance) override;
+ void PL_HostSystemServices_SetInstance(PortabilityLayer::HostSystemServices *instance) override;
+ void PL_InstallHostSuspendHook(PortabilityLayer::HostSuspendHook_t hook, void *context) override;
+};
+
+
+int GpAppInterfaceImpl::ApplicationMain()
+{
+ return gpAppMain();
+}
+
+void GpAppInterfaceImpl::PL_IncrementTickCounter(uint32_t count)
+{
+ PortabilityLayer::DisplayDeviceManager::GetInstance()->IncrementTickCount(count);
+}
+
+void GpAppInterfaceImpl::PL_HostFileSystem_SetInstance(PortabilityLayer::HostFileSystem *instance)
+{
+ PortabilityLayer::HostFileSystem::SetInstance(instance);
+}
+
+void GpAppInterfaceImpl::PL_HostDisplayDriver_SetInstance(PortabilityLayer::HostDisplayDriver *instance)
+{
+ PortabilityLayer::HostDisplayDriver::SetInstance(instance);
+}
+
+void GpAppInterfaceImpl::PL_HostSystemServices_SetInstance(PortabilityLayer::HostSystemServices *instance)
+{
+ PortabilityLayer::HostSystemServices::SetInstance(instance);
+}
+
+void GpAppInterfaceImpl::PL_InstallHostSuspendHook(PortabilityLayer::HostSuspendHook_t hook, void *context)
+{
+ PortabilityLayer::InstallHostSuspendHook(hook, context);
+}
+
+static GpAppInterfaceImpl gs_application;
+
+extern "C" GpAppInterface *GpAppInterface_Get()
+{
+ return &gs_application;
+}
diff --git a/GpApp/Grease.cpp b/GpApp/Grease.cpp
new file mode 100644
index 0000000..8a04045
--- /dev/null
+++ b/GpApp/Grease.cpp
@@ -0,0 +1,302 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Grease.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Environ.h"
+#include "MainWindow.h"
+#include "Objects.h"
+#include "RectUtils.h"
+#include "Room.h"
+
+
+#define kGreaseIdle 0
+#define kGreaseFalling 1
+#define kGreaseSpreading 2
+#define kGreaseSpiltIdle 3
+
+
+void BackupGrease (Rect *, short, Boolean);
+
+
+greasePtr grease;
+short numGrease;
+
+extern hotPtr hotSpots;
+extern savedType savedMaps[];
+extern Point shieldPt;
+extern Rect greaseSrcRt[], greaseSrcLf[], shieldRect;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- HandleGrease
+
+// Goes through all grease objects currently on screen and handlesÉ
+// them. If they're upright, nothing happens, but if they're inÉ
+// the course of falling or spilling, this function will handleÉ
+// advancing the spill, etc.
+
+void HandleGrease (void)
+{
+ Rect src;
+ short i;
+
+ if (numGrease == 0)
+ return;
+
+ for (i = 0; i < numGrease; i++)
+ {
+ if (grease[i].mode == kGreaseFalling)
+ {
+ grease[i].frame++;
+ if (grease[i].frame >= 3) // grease completely tipped
+ {
+ grease[i].frame = 3;
+ grease[i].mode = kGreaseSpreading;
+ hotSpots[grease[i].hotNum].action = kSlideIt;
+ hotSpots[grease[i].hotNum].isOn = true;
+ if (grease[i].isRight)
+ QSetRect(&src, 0, -2, 2, 0);
+ else
+ QSetRect(&src, -2, -2, 0, 0);
+ QOffsetRect(&src, -playOriginH, -playOriginV);
+ QOffsetRect(&src, grease[i].start, grease[i].dest.bottom);
+ hotSpots[grease[i].hotNum].bounds = src;
+ }
+
+ QSetRect(&src, 0, 0, 32, 27);
+ QOffsetRect(&src, 0, grease[i].frame * 27);
+ CopyBits((BitMap *)*GetGWorldPixMap(savedMaps[grease[i].mapNum].map),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &grease[i].dest,
+ srcCopy, nil);
+ CopyBits((BitMap *)*GetGWorldPixMap(savedMaps[grease[i].mapNum].map),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &src, &grease[i].dest,
+ srcCopy, nil);
+
+ AddRectToWorkRects(&grease[i].dest);
+ if (grease[i].isRight)
+ QOffsetRect(&grease[i].dest, 2, 0);
+ else
+ QOffsetRect(&grease[i].dest, -2, 0);
+ }
+ else if (grease[i].mode == kGreaseSpreading)
+ {
+ if (grease[i].isRight)
+ {
+ QSetRect(&src, 0, -2, 2, 0);
+ QOffsetRect(&src, grease[i].start, grease[i].dest.bottom);
+ grease[i].start += 2;
+ hotSpots[grease[i].hotNum].bounds.right += 2;
+ }
+ else
+ {
+ QSetRect(&src, -2, -2, 0, 0);
+ QOffsetRect(&src, grease[i].start, grease[i].dest.bottom);
+ grease[i].start -= 2;
+ hotSpots[grease[i].hotNum].bounds.left -= 2;
+ }
+
+ {
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ SetGWorld(backSrcMap, nil);
+ PaintRect(&src);
+
+ SetGWorld(workSrcMap, nil);
+ PaintRect(&src);
+ AddRectToWorkRects(&src);
+
+ SetGWorld(wasCPort, wasWorld);
+ }
+
+ if (grease[i].isRight)
+ {
+ if (grease[i].start >= grease[i].stop)
+ grease[i].mode = kGreaseSpiltIdle;
+ }
+ else
+ {
+ if (grease[i].start <= grease[i].stop)
+ grease[i].mode = kGreaseSpiltIdle;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- BackupGrease
+// This makes copies of the region of the screen the grease is aboutÉ
+// to be drawn to. It is called in the "set up" when a player hasÉ
+// just entered a new room. The "grease jar falling over" animationÉ
+// is set up here.
+
+void BackupGrease (Rect *src, short index, Boolean isRight)
+{
+ Rect dest;
+ short i;
+
+ QSetRect(&dest, 0, 0, 32, 27);
+ for (i = 0; i < 4; i++)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ (BitMap *)*GetGWorldPixMap(savedMaps[index].map),
+ src, &dest, srcCopy, nil);
+
+ if (isRight)
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(savedMaps[index].map),
+ &greaseSrcRt[i], &greaseSrcRt[i], &dest);
+ QOffsetRect(src, 2, 0);
+ }
+ else
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(savedMaps[index].map),
+ &greaseSrcLf[i], &greaseSrcLf[i], &dest);
+ QOffsetRect(src, -2, 0);
+ }
+ QOffsetRect(&dest, 0, 27);
+ }
+
+}
+
+//-------------------------------------------------------------- ReBackUpGrease
+// Just like th eabove function but it is called while the player isÉ
+// active in a room and has changed the lighting situation (like turnedÉ
+// off or on the lights). It assumes certain data strucutures areÉ
+// already declared from an earlier call to the above funciton.
+
+short ReBackUpGrease (short where, short who)
+{
+ Rect src;
+ short i;
+
+ for (i = 0; i < numGrease; i++)
+ {
+ if ((grease[i].where == where) && (grease[i].who == who))
+ {
+ if ((grease[i].mode == kGreaseIdle) || (grease[i].mode == kGreaseFalling))
+ {
+ src = grease[i].dest;
+ BackupGrease(&src, grease[i].mapNum, grease[i].isRight);
+ }
+ return (i);
+ }
+ }
+
+ return (-1);
+}
+
+//-------------------------------------------------------------- AddGrease
+
+// Called when a new room is being set up during a game. This addsÉ
+// another jar of grease to the queue of jars to be handled.
+
+short AddGrease (short where, short who, short h, short v,
+ short distance, Boolean isRight)
+{
+ Rect src, bounds;
+ short savedNum;
+
+ if (numGrease >= kMaxGrease)
+ return (-1);
+
+ QSetRect(&src, 0, 0, 32, 27);
+ QOffsetRect(&src, h, v);
+
+ QSetRect(&bounds, 0, 0, 32, 27 * 4);
+ savedNum = BackUpToSavedMap(&bounds, where, who);
+ if (savedNum != -1)
+ {
+ BackupGrease (&src, savedNum, isRight);
+ if (isRight)
+ QOffsetRect(&src, -8, 0);
+ else
+ QOffsetRect(&src, 8, 0);
+ grease[numGrease].who = who;
+ grease[numGrease].where = where;
+ grease[numGrease].dest = src;
+ grease[numGrease].mapNum = savedNum;
+ grease[numGrease].mode = kGreaseIdle;
+ grease[numGrease].frame = -1;
+ if (isRight)
+ {
+ grease[numGrease].isRight = true;
+ grease[numGrease].start = src.right + 4;
+ grease[numGrease].stop = src.right + distance;
+ }
+ else
+ {
+ grease[numGrease].isRight = false;
+ grease[numGrease].start = src.left - 4;
+ grease[numGrease].stop = src.left - distance;
+ }
+ numGrease++;
+
+ return (numGrease - 1);
+ }
+ else
+ return (-1);
+}
+
+//-------------------------------------------------------------- SpillGrease
+
+// A player has knocked a jar of grease over - this function flags that.
+
+void SpillGrease (short who, short index)
+{
+ if (grease[who].mode == kGreaseIdle)
+ {
+ grease[who].mode = kGreaseFalling;
+ grease[who].hotNum = index;
+ PlayPrioritySound(kGreaseSpillSound, kGreaseSpillPriority);
+ }
+}
+
+//-------------------------------------------------------------- RedrawAllGrease
+// Called to redraw all the black lines of spilt grease.
+
+void RedrawAllGrease (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ Rect src;
+ short i;
+
+ if (numGrease == 0)
+ return;
+
+ for (i = 0; i < numGrease; i++)
+ {
+ src = hotSpots[grease[i].hotNum].bounds;
+ if ((grease[i].where == thisRoomNumber) &&
+ ((src.bottom - src.top) == 2) &&
+ (grease[i].mode != kGreaseIdle))
+ {
+ QOffsetRect(&src, playOriginH, playOriginV);
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ SetGWorld(backSrcMap, nil);
+ PaintRect(&src);
+
+ SetGWorld(workSrcMap, nil);
+ PaintRect(&src);
+ AddRectToWorkRects(&src);
+
+ SetGWorld(wasCPort, wasWorld);
+ }
+ }
+}
+
diff --git a/GpApp/HighScores.cpp b/GpApp/HighScores.cpp
new file mode 100644
index 0000000..d59df57
--- /dev/null
+++ b/GpApp/HighScores.cpp
@@ -0,0 +1,856 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// HighScores.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLFolders.h"
+#include "PLNumberFormatting.h"
+#include "PLScript.h"
+#include "PLSound.h"
+#include "PLStringCompare.h"
+#include "DialogUtils.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "House.h"
+#include "MainWindow.h"
+#include "RectUtils.h"
+#include "Utilities.h"
+
+
+#define kHighScoresPictID 1994
+#define kHighScoresMaskID 1998
+#define kHighNameDialogID 1020
+#define kHighBannerDialogID 1021
+#define kHighNameItem 2
+#define kNameNCharsItem 5
+#define kHighBannerItem 2
+#define kBannerScoreNCharsItem 5
+
+
+void DrawHighScores (void);
+void UpdateNameDialog (DialogPtr);
+Boolean NameFilter (DialogPtr, EventRecord *, short *);
+void GetHighScoreName (short);
+void UpdateBannerDialog (DialogPtr);
+Boolean BannerFilter (DialogPtr, EventRecord *, short *);
+void GetHighScoreBanner (void);
+Boolean CreateScoresFolder (long *);
+Boolean FindHighScoresFolder (short *, long *);
+Boolean OpenHighScoresFile (FSSpec *, short *);
+
+
+Str31 highBanner;
+Str15 highName;
+short lastHighScore;
+Boolean keyStroke;
+
+extern short splashOriginH, splashOriginV;
+extern Boolean quickerTransitions, resumedSavedGame;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DoHighScores
+// Handles fading in and cleaning up the high scores screen.
+
+void DoHighScores (void)
+{
+ Rect tempRect;
+
+ SpinCursor(3);
+ SetPort((GrafPtr)workSrcMap);
+ PaintRect(&workSrcRect);
+ QSetRect(&tempRect, 0, 0, 640, 480);
+ QOffsetRect(&tempRect, splashOriginH, splashOriginV);
+ LoadScaledGraphic(kStarPictID, &tempRect);
+// if (quickerTransitions)
+// DissBitsChunky(&workSrcRect);
+// else
+// DissBits(&workSrcRect);
+ SpinCursor(3);
+ SetPort((GrafPtr)workSrcMap);
+ DrawHighScores();
+ SpinCursor(3);
+// if (quickerTransitions)
+// DissBitsChunky(&workSrcRect);
+// else
+// DissBits(&workSrcRect);
+ InitCursor();
+ DelayTicks(60);
+ WaitForInputEvent(30);
+
+ RedrawSplashScreen();
+}
+
+//-------------------------------------------------------------- DrawHighScores
+// Draws the actual scores on the screen.
+
+#define kScoreSpacing 18
+#define kScoreWide 352
+#define kKimsLifted 4
+
+void DrawHighScores (void)
+{
+ GWorldPtr tempMap, tempMask;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+ houseType *thisHousePtr;
+ Rect tempRect, tempRect2;
+ Str255 tempStr;
+ short scoreLeft, bannerWidth, i, dropIt;
+ char wasState;
+
+ scoreLeft = ((thisMac.screen.right - thisMac.screen.left) - kScoreWide) / 2;
+ dropIt = 129 + splashOriginV;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&tempRect, 0, 0, 332, 30);
+ theErr = CreateOffScreenGWorld(&tempMap, &tempRect, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(kHighScoresPictID);
+
+ theErr = CreateOffScreenGWorld(&tempMask, &tempRect, 1);
+ SetGWorld(tempMask, nil);
+ LoadGraphic(kHighScoresMaskID);
+
+ tempRect2 = tempRect;
+ QOffsetRect(&tempRect2, scoreLeft + (kScoreWide - 332) / 2, dropIt - 60);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(tempMask),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &tempRect, &tempRect, &tempRect2);
+
+ DisposeGWorld(tempMap);
+ DisposeGWorld(tempMask);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ TextFont(applFont);
+ TextFace(bold);
+ TextSize(14);
+
+ PasStringCopy(PSTR("¥ "), tempStr);
+ PasStringConcat(tempStr, thisHouseName);
+ PasStringConcat(tempStr, PSTR(" ¥"));
+ MoveTo(scoreLeft + ((kScoreWide - StringWidth(tempStr)) / 2) - 1, dropIt - 66);
+ ForeColor(blackColor);
+ DrawString(tempStr);
+ MoveTo(scoreLeft + ((kScoreWide - StringWidth(tempStr)) / 2), dropIt - 65);
+ ForeColor(cyanColor);
+ DrawString(tempStr);
+ ForeColor(blackColor);
+
+ TextFont(applFont);
+ TextFace(bold);
+ TextSize(12);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+ // message for score #1
+ PasStringCopy(thisHousePtr->highScores.banner, tempStr);
+ bannerWidth = StringWidth(tempStr);
+ ForeColor(blackColor);
+ MoveTo(scoreLeft + (kScoreWide - bannerWidth) / 2, dropIt - kKimsLifted);
+ DrawString(tempStr);
+ ForeColor(yellowColor);
+ MoveTo(scoreLeft + (kScoreWide - bannerWidth) / 2, dropIt - kKimsLifted - 1);
+ DrawString(tempStr);
+
+ QSetRect(&tempRect, 0, 0, bannerWidth + 8, kScoreSpacing);
+ QOffsetRect(&tempRect, scoreLeft - 3 + (kScoreWide - bannerWidth) / 2,
+ dropIt + 5 - kScoreSpacing - kKimsLifted);
+ ForeColor(blackColor);
+ FrameRect(&tempRect);
+ QOffsetRect(&tempRect, -1, -1);
+ ForeColor(yellowColor);
+ FrameRect(&tempRect);
+
+ for (i = 0; i < kMaxScores; i++)
+ {
+ if (thisHousePtr->highScores.scores[i] > 0L)
+ {
+ SpinCursor(1);
+ NumToString((long)i + 1L, tempStr); // draw placing number
+ ForeColor(blackColor);
+ if (i == 0)
+ MoveTo(scoreLeft + 1, dropIt - kScoreSpacing - kKimsLifted);
+ else
+ MoveTo(scoreLeft + 1, dropIt + (i * kScoreSpacing));
+ DrawString(tempStr);
+ if (i == lastHighScore)
+ ForeColor(whiteColor);
+ else
+ ForeColor(cyanColor);
+ if (i == 0)
+ MoveTo(scoreLeft + 0, dropIt - 1 - kScoreSpacing - kKimsLifted);
+ else
+ MoveTo(scoreLeft + 0, dropIt - 1 + (i * kScoreSpacing));
+ DrawString(tempStr);
+ // draw high score name
+ PasStringCopy(thisHousePtr->highScores.names[i], tempStr);
+ ForeColor(blackColor);
+ if (i == 0)
+ MoveTo(scoreLeft + 31, dropIt - kScoreSpacing - kKimsLifted);
+ else
+ MoveTo(scoreLeft + 31, dropIt + (i * kScoreSpacing));
+ DrawString(tempStr);
+ if (i == lastHighScore)
+ ForeColor(whiteColor);
+ else
+ ForeColor(yellowColor);
+ if (i == 0)
+ MoveTo(scoreLeft + 30, dropIt - 1 - kScoreSpacing - kKimsLifted);
+ else
+ MoveTo(scoreLeft + 30, dropIt - 1 + (i * kScoreSpacing));
+ DrawString(tempStr);
+ // draw level number
+ NumToString(thisHousePtr->highScores.levels[i], tempStr);
+ ForeColor(blackColor);
+ if (i == 0)
+ MoveTo(scoreLeft + 161, dropIt - kScoreSpacing - kKimsLifted);
+ else
+ MoveTo(scoreLeft + 161, dropIt + (i * kScoreSpacing));
+ DrawString(tempStr);
+ if (i == lastHighScore)
+ ForeColor(whiteColor);
+ else
+ ForeColor(yellowColor);
+ if (i == 0)
+ MoveTo(scoreLeft + 160, dropIt - 1 - kScoreSpacing - kKimsLifted);
+ else
+ MoveTo(scoreLeft + 160, dropIt - 1 + (i * kScoreSpacing));
+ DrawString(tempStr);
+ // draw word "rooms"
+ if (thisHousePtr->highScores.levels[i] == 1)
+ GetLocalizedString(6, tempStr);
+ else
+ GetLocalizedString(7, tempStr);
+ ForeColor(blackColor);
+ if (i == 0)
+ MoveTo(scoreLeft + 193, dropIt - kScoreSpacing - kKimsLifted);
+ else
+ MoveTo(scoreLeft + 193, dropIt + (i * kScoreSpacing));
+ DrawString(tempStr);
+ ForeColor(cyanColor);
+ if (i == 0)
+ MoveTo(scoreLeft + 192, dropIt - 1 - kScoreSpacing - kKimsLifted);
+ else
+ MoveTo(scoreLeft + 192, dropIt - 1 + (i * kScoreSpacing));
+ DrawString(tempStr);
+ // draw high score points
+ NumToString(thisHousePtr->highScores.scores[i], tempStr);
+ ForeColor(blackColor);
+ if (i == 0)
+ MoveTo(scoreLeft + 291, dropIt - kScoreSpacing - kKimsLifted);
+ else
+ MoveTo(scoreLeft + 291, dropIt + (i * kScoreSpacing));
+ DrawString(tempStr);
+ if (i == lastHighScore)
+ ForeColor(whiteColor);
+ else
+ ForeColor(yellowColor);
+ if (i == 0)
+ MoveTo(scoreLeft + 290, dropIt - 1 - kScoreSpacing - kKimsLifted);
+ else
+ MoveTo(scoreLeft + 290, dropIt - 1 + (i * kScoreSpacing));
+ DrawString(tempStr);
+ }
+ }
+
+ ForeColor(blueColor);
+ TextFont(applFont);
+ TextFace(bold);
+ TextSize(9);
+ MoveTo(scoreLeft + 80, dropIt - 1 + (10 * kScoreSpacing));
+ GetLocalizedString(8, tempStr);
+ DrawString(tempStr);
+
+ ForeColor(blackColor);
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- SortHighScores
+// This does a simple sort of the high scores.
+
+void SortHighScores (void)
+{
+ scoresType tempScores;
+ houseType *thisHousePtr;
+ long greatest;
+ short i, h, which;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ for (h = 0; h < kMaxScores; h++)
+ {
+ greatest = -1L;
+ which = -1;
+ for (i = 0; i < kMaxScores; i++)
+ {
+ if (thisHousePtr->highScores.scores[i] > greatest)
+ {
+ greatest = thisHousePtr->highScores.scores[i];
+ which = i;
+ }
+ }
+ if (which != -1)
+ {
+ PasStringCopy(thisHousePtr->highScores.names[which], tempScores.names[h]);
+ tempScores.scores[h] = thisHousePtr->highScores.scores[which];
+ tempScores.timeStamps[h] = thisHousePtr->highScores.timeStamps[which];
+ tempScores.levels[h] = thisHousePtr->highScores.levels[which];
+ thisHousePtr->highScores.scores[which] = -1L;
+ }
+ }
+ PasStringCopy(thisHousePtr->highScores.banner, tempScores.banner);
+ thisHousePtr->highScores = tempScores;
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- ZeroHighScores
+// This funciton goes through and resets or "zeros" all high scores.
+
+void ZeroHighScores (void)
+{
+ houseType *thisHousePtr;
+ short i;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ PasStringCopy(thisHouseName, thisHousePtr->highScores.banner);
+ for (i = 0; i < kMaxScores; i++)
+ {
+ PasStringCopy(PSTR("--------------"), thisHousePtr->highScores.names[i]);
+ thisHousePtr->highScores.scores[i] = 0L;
+ thisHousePtr->highScores.timeStamps[i] = 0L;
+ thisHousePtr->highScores.levels[i] = 0;
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- ZeroAllButHighestScore
+// Like the above, but this function preserves the highest score.
+
+void ZeroAllButHighestScore (void)
+{
+ houseType *thisHousePtr;
+ short i;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ for (i = 1; i < kMaxScores; i++)
+ {
+ PasStringCopy(PSTR("--------------"), thisHousePtr->highScores.names[i]);
+ thisHousePtr->highScores.scores[i] = 0L;
+ thisHousePtr->highScores.timeStamps[i] = 0L;
+ thisHousePtr->highScores.levels[i] = 0;
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- TestHighScore
+// This function is called after a game ends in order to test theÉ
+// current high score against the high score list. It returns trueÉ
+// if the player is on the high score list now.
+
+Boolean TestHighScore (void)
+{
+ houseType *thisHousePtr;
+ short placing, i;
+ char wasState;
+
+ if (resumedSavedGame)
+ return (false);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ lastHighScore = -1;
+ placing = -1;
+
+ for (i = 0; i < kMaxScores; i++)
+ {
+ if (theScore > thisHousePtr->highScores.scores[i])
+ {
+ placing = i;
+ lastHighScore = i;
+ break;
+ }
+ }
+
+ if (placing != -1)
+ {
+ FlushEvents(everyEvent, 0);
+ GetHighScoreName(placing + 1);
+ PasStringCopy(highName, thisHousePtr->highScores.names[kMaxScores - 1]);
+ if (placing == 0)
+ {
+ GetHighScoreBanner();
+ PasStringCopy(highBanner, thisHousePtr->highScores.banner);
+ }
+ thisHousePtr->highScores.scores[kMaxScores - 1] = theScore;
+ GetDateTime(&thisHousePtr->highScores.timeStamps[kMaxScores - 1]);
+ thisHousePtr->highScores.levels[kMaxScores - 1] = CountRoomsVisited();
+ SortHighScores();
+ gameDirty = true;
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ if (placing != -1)
+ {
+ DoHighScores();
+ return (true);
+ }
+ else
+ return (false);
+}
+
+//-------------------------------------------------------------- UpdateNameDialog
+// Redraws the "Enter High Score Name" dialog.
+
+void UpdateNameDialog (DialogPtr theDialog)
+{
+ short nChars;
+
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+
+ nChars = GetDialogStringLen(theDialog, kHighNameItem);
+ SetDialogNumToStr(theDialog, kNameNCharsItem, (long)nChars);
+}
+
+//-------------------------------------------------------------- NameFilter
+// Dialog filter for the "Enter High Score Name" dialog.
+
+Boolean NameFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ short nChars;
+
+ if (keyStroke)
+ {
+ nChars = GetDialogStringLen(dial, kHighNameItem);
+ SetDialogNumToStr(dial, kNameNCharsItem, (long)nChars);
+ keyStroke = false;
+ }
+
+ switch (event->what)
+ {
+ case keyDown:
+ keyStroke = true;
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ PlayPrioritySound(kCarriageSound, kCarriagePriority);
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kTabKeyASCII:
+ SelectDialogItemText(dial, kHighNameItem, 0, 1024);
+ return(false);
+ break;
+
+ default:
+ PlayPrioritySound(kTypingSound, kTypingPriority);
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateNameDialog(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- GetHighScoreName
+// Brings up a dialog to get player's name (due to a high score).
+
+void GetHighScoreName (short place)
+{
+ DialogPtr theDial;
+ Str255 scoreStr, placeStr, tempStr;
+ short item;
+ Boolean leaving;
+ ModalFilterUPP nameFilterUPP;
+
+ nameFilterUPP = NewModalFilterUPP(NameFilter);
+
+ InitCursor();
+ NumToString(theScore, scoreStr);
+ NumToString((long)place, placeStr);
+ ParamText(scoreStr, placeStr, thisHouseName, PSTR(""));
+ PlayPrioritySound(kEnergizeSound, kEnergizePriority);
+ BringUpDialog(&theDial, kHighNameDialogID);
+ FlushEvents(everyEvent, 0);
+ SetDialogString(theDial, kHighNameItem, highName);
+ SelectDialogItemText(theDial, kHighNameItem, 0, 1024);
+ leaving = false;
+
+ while (!leaving)
+ {
+ ModalDialog(nameFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogString(theDial, kHighNameItem, tempStr);
+ PasStringCopyNum(tempStr, highName, 15);
+ leaving = true;
+ }
+ }
+
+ DisposeDialog(theDial);
+ DisposeModalFilterUPP(nameFilterUPP);
+}
+
+//-------------------------------------------------------------- UpdateBannerDialog
+// Redraws the "Enter Message" dialog.
+
+void UpdateBannerDialog (DialogPtr theDialog)
+{
+ short nChars;
+
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+
+ nChars = GetDialogStringLen(theDialog, kHighBannerItem);
+ SetDialogNumToStr(theDialog, kBannerScoreNCharsItem, (long)nChars);
+}
+
+//-------------------------------------------------------------- BannerFilter
+// Dialog filter for the "Enter Message" dialog.
+
+Boolean BannerFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ short nChars;
+
+ if (keyStroke)
+ {
+ nChars = GetDialogStringLen(dial, kHighBannerItem);
+ SetDialogNumToStr(dial, kBannerScoreNCharsItem, (long)nChars);
+ keyStroke = false;
+ }
+
+ switch (event->what)
+ {
+
+ case keyDown:
+ keyStroke = true;
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ PlayPrioritySound(kCarriageSound, kCarriagePriority);
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kTabKeyASCII:
+ SelectDialogItemText(dial, kHighBannerItem, 0, 1024);
+ return(false);
+ break;
+
+ default:
+ PlayPrioritySound(kTypingSound, kTypingPriority);
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateBannerDialog(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- GetHighScoreBanner
+// A player who gets the #1 slot gets to enter a short message (thatÉ
+// appears across the top of the high scores list). This dialogÉ
+// gets that message.
+
+void GetHighScoreBanner (void)
+{
+ DialogPtr theDial;
+ Str255 tempStr;
+ short item;
+ Boolean leaving;
+ ModalFilterUPP bannerFilterUPP;
+
+ bannerFilterUPP = NewModalFilterUPP(BannerFilter);
+
+ PlayPrioritySound(kEnergizeSound, kEnergizePriority);
+ BringUpDialog(&theDial, kHighBannerDialogID);
+ SetDialogString(theDial, kHighBannerItem, highBanner);
+ SelectDialogItemText(theDial, kHighBannerItem, 0, 1024);
+ leaving = false;
+
+ while (!leaving)
+ {
+ ModalDialog(bannerFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogString(theDial, kHighBannerItem, tempStr);
+ PasStringCopyNum(tempStr, highBanner, 31);
+ leaving = true;
+ }
+ }
+
+ DisposeDialog(theDial);
+ DisposeModalFilterUPP(bannerFilterUPP);
+}
+
+//-------------------------------------------------------------- CreateScoresFolder
+
+Boolean CreateScoresFolder (long *scoresDirID)
+{
+ FSSpec scoresSpec;
+ long prefsDirID;
+ OSErr theErr;
+ short volRefNum;
+
+ theErr = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
+ &volRefNum, &prefsDirID);
+ if (!CheckFileError(theErr, PSTR("Prefs Folder")))
+ return (false);
+
+ theErr = FSMakeFSSpec(volRefNum, prefsDirID, PSTR("G-PRO Scores Ä"), &scoresSpec);
+
+ theErr = FSpDirCreate(&scoresSpec, smSystemScript, scoresDirID);
+ if (!CheckFileError(theErr, PSTR("High Scores Folder")))
+ return (false);
+
+ return (true);
+}
+
+//-------------------------------------------------------------- FindHighScoresFolder
+
+Boolean FindHighScoresFolder (short *volRefNum, long *scoresDirID)
+{
+ CInfoPBRec theBlock;
+ Str255 nameString;
+ long prefsDirID;
+ OSErr theErr;
+ short count;
+ Boolean foundIt;
+
+ theErr = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
+ volRefNum, &prefsDirID);
+ if (!CheckFileError(theErr, PSTR("Prefs Folder")))
+ return (false);
+
+ PasStringCopy(PSTR("G-PRO Scores Ä"), nameString);
+ count = 1;
+ foundIt = false;
+
+ theBlock.dirInfo.ioCompletion = nil;
+ theBlock.dirInfo.ioVRefNum = *volRefNum;
+ theBlock.dirInfo.ioNamePtr = nameString;
+
+ while ((theErr == noErr) && (!foundIt))
+ {
+ theBlock.dirInfo.ioFDirIndex = count;
+ theBlock.dirInfo.ioDrDirID = prefsDirID;
+ theErr = PBGetCatInfo(&theBlock, false);
+ if (theErr == noErr)
+ {
+ if ((theBlock.dirInfo.ioFlAttrib & 0x10) == 0x10)
+ {
+ if (EqualString(theBlock.dirInfo.ioNamePtr, PSTR("G-PRO Scores Ä"),
+ true, true))
+ {
+ foundIt = true;
+ *scoresDirID = theBlock.dirInfo.ioDrDirID;
+ }
+ }
+ count++;
+ }
+ }
+
+ if (theErr == fnfErr)
+ {
+ if (CreateScoresFolder(scoresDirID))
+ return (true);
+ else
+ return (false);
+ }
+ else
+ return (true);
+}
+
+//-------------------------------------------------------------- OpenHighScoresFile
+
+Boolean OpenHighScoresFile (FSSpec *scoreSpec, short *scoresRefNum)
+{
+ OSErr theErr;
+
+ theErr = FSpOpenDF(scoreSpec, fsCurPerm, scoresRefNum);
+ if (theErr == fnfErr)
+ {
+ theErr = FSpCreate(scoreSpec, 'ozm5', 'gliS', smSystemScript);
+ if (!CheckFileError(theErr, PSTR("New High Scores File")))
+ return (false);
+ theErr = FSpOpenDF(scoreSpec, fsCurPerm, scoresRefNum);
+ if (!CheckFileError(theErr, PSTR("High Score")))
+ return (false);
+ }
+ else if (!CheckFileError(theErr, PSTR("High Score")))
+ return (false);
+
+ return (true);
+}
+
+//-------------------------------------------------------------- WriteScoresToDisk
+
+Boolean WriteScoresToDisk (void)
+{
+ scoresType *theScores;
+ FSSpec scoreSpec;
+ long dirID, byteCount;
+ OSErr theErr;
+ short volRefNum, scoresRefNum;
+ char wasState;
+
+ if (!FindHighScoresFolder(&volRefNum, &dirID))
+ {
+ SysBeep(1);
+ return (false);
+ }
+
+ theErr = FSMakeFSSpec(volRefNum, dirID, thisHouseName, &scoreSpec);
+ if (!OpenHighScoresFile(&scoreSpec, &scoresRefNum))
+ {
+ SysBeep(1);
+ return (false);
+ }
+
+ theErr = SetFPos(scoresRefNum, fsFromStart, 0L);
+ if (!CheckFileError(theErr, PSTR("High Scores File")))
+ {
+ theErr = FSClose(scoresRefNum);
+ return(false);
+ }
+
+ byteCount = sizeof(scoresType);
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ theScores = &((*thisHouse)->highScores);
+
+ theErr = FSWrite(scoresRefNum, &byteCount, (Ptr)theScores);
+ if (!CheckFileError(theErr, PSTR("High Scores File")))
+ {
+ HSetState((Handle)thisHouse, wasState);
+ theErr = FSClose(scoresRefNum);
+ return(false);
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ theErr = SetEOF(scoresRefNum, byteCount);
+ if (!CheckFileError(theErr, PSTR("High Scores File")))
+ {
+ theErr = FSClose(scoresRefNum);
+ return(false);
+ }
+
+ theErr = FSClose(scoresRefNum);
+ if (!CheckFileError(theErr, PSTR("High Scores File")))
+ return(false);
+
+ return (true);
+}
+
+//-------------------------------------------------------------- ReadScoresFromDisk
+
+Boolean ReadScoresFromDisk (void)
+{
+ scoresType *theScores;
+ FSSpec scoreSpec;
+ long dirID, byteCount;
+ OSErr theErr;
+ short volRefNum, scoresRefNum;
+ char wasState;
+
+ if (!FindHighScoresFolder(&volRefNum, &dirID))
+ {
+ SysBeep(1);
+ return (false);
+ }
+
+ theErr = FSMakeFSSpec(volRefNum, dirID, thisHouseName, &scoreSpec);
+ if (!OpenHighScoresFile(&scoreSpec, &scoresRefNum))
+ {
+ SysBeep(1);
+ return (false);
+ }
+
+ theErr = GetEOF(scoresRefNum, &byteCount);
+ if (!CheckFileError(theErr, PSTR("High Scores File")))
+ {
+ theErr = FSClose(scoresRefNum);
+ return (false);
+ }
+
+ theErr = SetFPos(scoresRefNum, fsFromStart, 0L);
+ if (!CheckFileError(theErr, PSTR("High Scores File")))
+ {
+ theErr = FSClose(scoresRefNum);
+ return (false);
+ }
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ theScores = &((*thisHouse)->highScores);
+
+ theErr = FSRead(scoresRefNum, &byteCount, theScores);
+ if (!CheckFileError(theErr, PSTR("High Scores File")))
+ {
+ HSetState((Handle)thisHouse, wasState);
+ theErr = FSClose(scoresRefNum);
+ return (false);
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ theErr = FSClose(scoresRefNum);
+ if (!CheckFileError(theErr, PSTR("High Scores File")))
+ return(false);
+
+ return (true);
+}
+
diff --git a/GpApp/House.cpp b/GpApp/House.cpp
new file mode 100644
index 0000000..ec0abbe
--- /dev/null
+++ b/GpApp/House.cpp
@@ -0,0 +1,860 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// House.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+#include "PLAppleEvents.h"
+#include "PLNavigation.h"
+#include "PLNumberFormatting.h"
+#include "PLPasStr.h"
+#include "PLResources.h"
+#include "PLSound.h"
+#include "DialogUtils.h"
+#include "Externs.h"
+#include "House.h"
+#include "RectUtils.h"
+
+
+#define kGoToDialogID 1043
+
+
+void UpdateGoToDialog (DialogPtr);
+Boolean GoToFilter (DialogPtr, EventRecord *, short *);
+
+
+houseHand thisHouse;
+linksPtr linksList;
+Str32 thisHouseName;
+short srcLocations[kMaxRoomObs];
+short destLocations[kMaxRoomObs];
+short wasFloor, wasSuite;
+retroLink retroLinkList[kMaxRoomObs];
+Boolean houseUnlocked;
+
+
+extern gameType smallGame;
+extern short numberRooms, mapLeftRoom, mapTopRoom, numStarsRemaining;
+extern Boolean houseOpen, noRoomAtAll;
+extern Boolean twoPlayerGame, wardBitSet, phoneBitSet;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- CreateNewHouse
+// Called to create a new house file.
+
+#ifndef COMPILEDEMO
+Boolean CreateNewHouse (void)
+{
+ AEKeyword theKeyword;
+ DescType actualType;
+ Size actualSize;
+ NavReplyRecord theReply;
+ NavDialogOptions dialogOptions;
+ FSSpec tempSpec;
+ FSSpec theSpec;
+ OSErr theErr;
+
+ theErr = NavGetDefaultDialogOptions(&dialogOptions);
+ theErr = NavPutFile(nil, &theReply, &dialogOptions, nil, 'gliH', 'ozm5', nil);
+ if (theErr == userCanceledErr)
+ return false;
+ if (!theReply.validRecord)
+ return (false);
+
+ theErr = AEGetNthPtr(&(theReply.selection), 1, typeFSS, &theKeyword,
+ &actualType, &theSpec, sizeof(FSSpec), &actualSize);
+
+ if (theReply.replacing)
+ {
+ theErr = FSMakeFSSpec(theSpec.vRefNum, theSpec.parID,
+ theSpec.name, &tempSpec);
+ if (!CheckFileError(theErr, theSpec.name))
+ return (false);
+
+ theErr = FSpDelete(&tempSpec);
+ if (!CheckFileError(theErr, theSpec.name))
+ return (false);
+ }
+
+ if (houseOpen)
+ {
+ if (!CloseHouse())
+ return (false);
+ }
+
+ theErr = FSpCreate(&theSpec, 'ozm5', 'gliH', theReply.keyScript);
+ if (!CheckFileError(theErr, PSTR("New House")))
+ return (false);
+ HCreateResFile(theSpec.vRefNum, theSpec.parID, theSpec.name);
+ if (ResError() != noErr)
+ YellowAlert(kYellowFailedResCreate, ResError());
+
+ PasStringCopy(theSpec.name, thisHouseName);
+ AddExtraHouse(&theSpec);
+ BuildHouseList();
+ InitCursor();
+ if (!OpenHouse())
+ return (false);
+
+ return (true);
+}
+#endif
+
+//-------------------------------------------------------------- InitializeEmptyHouse
+
+// Initializes all the structures for an empty (new) house.
+
+#ifndef COMPILEDEMO
+Boolean InitializeEmptyHouse (void)
+{
+ houseType *thisHousePtr;
+ Str255 tempStr;
+
+ if (thisHouse != nil)
+ DisposeHandle((Handle)thisHouse);
+
+ thisHouse = (houseHand)NewHandle(sizeof(houseType));
+
+ if (thisHouse == nil)
+ {
+ YellowAlert(kYellowUnaccounted, 1);
+ return (false);
+ }
+
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ thisHousePtr->version = kHouseVersion;
+ thisHousePtr->firstRoom = -1;
+ thisHousePtr->timeStamp = 0L;
+ thisHousePtr->flags = 0L;
+ thisHousePtr->initial.h = 32;
+ thisHousePtr->initial.v = 32;
+ ZeroHighScores();
+
+ GetLocalizedString(11, tempStr);
+ PasStringCopy(tempStr, thisHousePtr->banner);
+ GetLocalizedString(12, tempStr);
+ PasStringCopy(tempStr, thisHousePtr->trailer);
+ thisHousePtr->hasGame = false;
+ thisHousePtr->nRooms = 0;
+
+ wardBitSet = false;
+ phoneBitSet = false;
+
+ HUnlock((Handle)thisHouse);
+
+ numberRooms = 0;
+ mapLeftRoom = 60;
+ mapTopRoom = 50;
+ thisRoomNumber = kRoomIsEmpty;
+ previousRoom = -1;
+ houseUnlocked = true;
+ OpenMapWindow();
+ UpdateMapWindow();
+ noRoomAtAll = true;
+ fileDirty = true;
+ UpdateMenus(false);
+ ReflectCurrentRoom(true);
+
+ return (true);
+}
+#endif
+
+//-------------------------------------------------------------- RealRoomNumberCount
+
+// Returns the real number of rooms in a house (some rooms may stillÉ
+// be place-holders - they were deleted earlier and are flagged asÉ
+// deleted but still occupy space in the file).
+
+short RealRoomNumberCount (void)
+{
+ short realRoomCount, i;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ realRoomCount = (*thisHouse)->nRooms;
+ if (realRoomCount != 0)
+ {
+ for (i = 0; i < (*thisHouse)->nRooms; i++)
+ {
+ if ((*thisHouse)->rooms[i].suite == kRoomIsEmpty)
+ realRoomCount--;
+ }
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ return (realRoomCount);
+}
+
+//-------------------------------------------------------------- GetFirstRoomNumber
+
+// Returns the room number (indicee into house file) of the room whereÉ
+// the player is to begin.
+
+short GetFirstRoomNumber (void)
+{
+ short firstRoom;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ if ((*thisHouse)->nRooms <= 0)
+ {
+ firstRoom = -1;
+ noRoomAtAll = true;
+ }
+ else
+ {
+ firstRoom = (*thisHouse)->firstRoom;
+ if ((firstRoom >= (*thisHouse)->nRooms) || (firstRoom < 0))
+ firstRoom = 0;
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ return (firstRoom);
+}
+
+//-------------------------------------------------------------- WhereDoesGliderBegin
+
+// Returns a rectangle indicating where in the first room the player'sÉ
+// glider is to appear.
+
+void WhereDoesGliderBegin (Rect *theRect, short mode)
+{
+ Point initialPt;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ if (mode == kResumeGameMode)
+ initialPt = smallGame.where;
+ else if (mode == kNewGameMode)
+ initialPt = (*thisHouse)->initial;
+
+ HSetState((Handle)thisHouse, wasState);
+ QSetRect(theRect, 0, 0, kGliderWide, kGliderHigh);
+ QOffsetRect(theRect, initialPt.h, initialPt.v);
+}
+
+//-------------------------------------------------------------- HouseHasOriginalPicts
+
+// Returns true is the current house has custom artwork imbedded.
+
+Boolean HouseHasOriginalPicts (void)
+{
+ short nPicts;
+
+ nPicts = Count1Resources('PICT');
+ return (nPicts > 0);
+}
+
+//-------------------------------------------------------------- CountHouseLinks
+
+// Counts up the number of linked objects in a house.
+
+short CountHouseLinks (void)
+{
+ houseType *thisHousePtr;
+ short numRooms, numLinks;
+ short r, i, what;
+ char wasState;
+
+ numLinks = 0;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+ numRooms = thisHousePtr->nRooms;
+
+ for (r = 0; r < numRooms; r++)
+ {
+ for (i = 0; i < kMaxRoomObs; i++)
+ {
+ what = thisHousePtr->rooms[r].objects[i].what;
+ switch (what)
+ {
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ if (thisHousePtr->rooms[r].objects[i].data.e.where != -1)
+ numLinks++;
+ break;
+
+ case kMailboxLf:
+ case kMailboxRt:
+ case kFloorTrans:
+ case kCeilingTrans:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ if (thisHousePtr->rooms[r].objects[i].data.d.where != -1)
+ numLinks++;
+ break;
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ return (numLinks);
+}
+
+//-------------------------------------------------------------- GenerateLinksList
+
+// Generates a list of all objects that have links and what roomsÉ
+// and objects they are linked to. It is called in order to preserveÉ
+// the links if the objects or rooms in a house are to be shuffledÉ
+// around.
+
+#ifndef COMPILEDEMO
+void GenerateLinksList (void)
+{
+ houseType *thisHousePtr;
+ objectType thisObject;
+ short numLinks, numRooms, r, i, what;
+ short floor, suite, roomLinked, objectLinked;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+ numRooms = thisHousePtr->nRooms;
+
+ numLinks = 0;
+
+ for (r = 0; r < numRooms; r++)
+ {
+ for (i = 0; i < kMaxRoomObs; i++)
+ {
+ what = thisHousePtr->rooms[r].objects[i].what;
+ switch (what)
+ {
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ thisObject = thisHousePtr->rooms[r].objects[i];
+ if (thisObject.data.e.where != -1)
+ {
+ ExtractFloorSuite(thisObject.data.e.where, &floor, &suite);
+ roomLinked = GetRoomNumber(floor, suite);
+ objectLinked = (short)thisObject.data.e.who;
+ linksList[numLinks].srcRoom = r;
+ linksList[numLinks].srcObj = i;
+ linksList[numLinks].destRoom = roomLinked;
+ linksList[numLinks].destObj = objectLinked;
+ numLinks++;
+ }
+ break;
+
+ case kMailboxLf:
+ case kMailboxRt:
+ case kFloorTrans:
+ case kCeilingTrans:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ thisObject = thisHousePtr->rooms[r].objects[i];
+ if (thisObject.data.d.where != -1)
+ {
+ ExtractFloorSuite(thisObject.data.d.where, &floor, &suite);
+ roomLinked = GetRoomNumber(floor, suite);
+ objectLinked = (short)thisObject.data.d.who;
+ linksList[numLinks].srcRoom = r;
+ linksList[numLinks].srcObj = i;
+ linksList[numLinks].destRoom = roomLinked;
+ linksList[numLinks].destObj = objectLinked;
+ numLinks++;
+ }
+ break;
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+#endif
+
+//-------------------------------------------------------------- SortRoomObjects
+
+// I'm a little fuzzy on what this does.
+
+#ifndef COMPILEDEMO
+void SortRoomsObjects (short which)
+{
+ short probe, probe2, room, obj;
+ Boolean busy, looking;
+
+ busy = true;
+ probe = 0;
+
+ do
+ {
+ if ((*thisHouse)->rooms[which].objects[probe].what == kObjectIsEmpty)
+ {
+ looking = true;
+ probe2 = probe + 1; // begin by looking at the next object
+ do
+ {
+ if ((*thisHouse)->rooms[which].objects[probe2].what != kObjectIsEmpty)
+ {
+ (*thisHouse)->rooms[which].objects[probe] =
+ (*thisHouse)->rooms[which].objects[probe2];
+ (*thisHouse)->rooms[which].objects[probe2].what = kObjectIsEmpty;
+ if (srcLocations[probe2] != -1)
+ linksList[srcLocations[probe2]].srcObj = probe;
+ if (destLocations[probe2] != -1)
+ {
+ linksList[destLocations[probe2]].destObj = probe;
+ room = linksList[destLocations[probe2]].srcRoom;
+ obj = linksList[destLocations[probe2]].srcObj;
+ (*thisHouse)->rooms[room].objects[obj].data.e.who = static_cast(probe);
+ }
+ fileDirty = true;
+ looking = false;
+ }
+ probe2++;
+ if ((probe2 >= kMaxRoomObs) && (looking))
+ {
+ looking = false;
+ busy = false;
+ }
+ }
+ while (looking);
+ }
+ probe++;
+ if (probe >= (kMaxRoomObs - 1))
+ busy = false;
+ }
+ while (busy);
+}
+#endif
+
+//-------------------------------------------------------------- SortHouseObjects
+
+// I'm a little fuzzy on what this does exactly either.
+
+#ifndef COMPILEDEMO
+void SortHouseObjects (void)
+{
+ houseType *thisHousePtr;
+ short numLinks, numRooms, r, i, l;
+ char wasState;
+
+ SpinCursor(3);
+
+ CopyThisRoomToRoom();
+
+ numLinks = CountHouseLinks();
+ if (numLinks == 0)
+ return;
+
+ linksList = nil;
+ linksList = (linksPtr)NewPtr(sizeof(linksType) * numLinks);
+ if (linksList == nil)
+ RedAlert(kErrNoMemory);
+
+ GenerateLinksList();
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+ numRooms = thisHousePtr->nRooms;
+
+ for (r = 0; r < numRooms; r++)
+ {
+ for (i = 0; i < kMaxRoomObs; i++) // initialize arrays
+ {
+ srcLocations[i] = -1;
+ destLocations[i] = -1;
+ }
+
+ for (i = 0; i < kMaxRoomObs; i++) // walk object list
+ {
+ for (l = 0; l < numLinks; l++) // walk link list
+ {
+ if ((linksList[l].srcRoom == r) && (linksList[l].srcObj == i))
+ srcLocations[i] = l;
+ if ((linksList[l].destRoom == r) && (linksList[l].destObj == i))
+ destLocations[i] = l;
+ }
+ }
+ SortRoomsObjects(r);
+
+ if ((r & 0x0007) == 0x0007)
+ IncrementCursor();
+ }
+
+ SpinCursor(3);
+ HSetState((Handle)thisHouse, wasState);
+ if (linksList != nil)
+ DisposePtr((Ptr)linksList);
+ ForceThisRoom(thisRoomNumber);
+}
+#endif
+
+//-------------------------------------------------------------- CountRoomsVisited
+
+// Goes through and counts the number of rooms a player has been to inÉ
+// the current game.
+
+short CountRoomsVisited (void)
+{
+ houseType *thisHousePtr;
+ short numRooms, r, count;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+ numRooms = thisHousePtr->nRooms;
+ count = 0;
+
+ for (r = 0; r < numRooms; r++)
+ {
+ if (thisHousePtr->rooms[r].visited)
+ count++;
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+ return (count);
+}
+
+//-------------------------------------------------------------- GenerateRetroLinks
+
+// Walk entire house looking for objects which are linked to objectsÉ
+// in the current room.
+
+void GenerateRetroLinks (void)
+{
+ houseType *thisHousePtr;
+ objectType thisObject;
+ short i, r, numRooms, floor, suite;
+ short what, roomLinked, objectLinked;
+ char wasState;
+
+ for (i = 0; i < kMaxRoomObs; i++) // Initialize array.
+ retroLinkList[i].room = -1;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+ numRooms = thisHousePtr->nRooms;
+
+ for (r = 0; r < numRooms; r++)
+ {
+ for (i = 0; i < kMaxRoomObs; i++)
+ {
+ what = thisHousePtr->rooms[r].objects[i].what;
+ switch (what)
+ {
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ thisObject = thisHousePtr->rooms[r].objects[i];
+ if (thisObject.data.e.where != -1)
+ {
+ ExtractFloorSuite(thisObject.data.e.where, &floor, &suite);
+ roomLinked = GetRoomNumber(floor, suite);
+ if (roomLinked == thisRoomNumber)
+ {
+ objectLinked = (short)thisObject.data.e.who;
+ if (retroLinkList[objectLinked].room == -1)
+ {
+ retroLinkList[objectLinked].room = r;
+ retroLinkList[objectLinked].object = i;
+ }
+ }
+ }
+ break;
+
+ case kMailboxLf:
+ case kMailboxRt:
+ case kFloorTrans:
+ case kCeilingTrans:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ thisObject = thisHousePtr->rooms[r].objects[i];
+ if (thisObject.data.d.where != -1)
+ {
+ ExtractFloorSuite(thisObject.data.d.where, &floor, &suite);
+ roomLinked = GetRoomNumber(floor, suite);
+ if (roomLinked == thisRoomNumber)
+ {
+ objectLinked = (short)thisObject.data.d.who;
+ if (retroLinkList[objectLinked].room == -1)
+ {
+ retroLinkList[objectLinked].room = r;
+ retroLinkList[objectLinked].object = i;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- UpdateGoToDialog
+// Redraws the "Go To Room..." dialog.
+
+void UpdateGoToDialog (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 10, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- GoToFilter
+// Dialog filter for the "Go To Room..." dialog.
+
+Boolean GoToFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateGoToDialog(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoGoToDialog
+
+// "Go To Room..." dialog.
+
+ void DoGoToDialog (void)
+ {
+ #define kGoToFirstButt 2
+ #define kGoToPrevButt 3
+ #define kGoToFSButt 4
+ #define kFloorEditText 5
+ #define kSuiteEditText 6
+ DialogPtr theDialog;
+ long tempLong;
+ short item, roomToGoTo;
+ Boolean leaving, canceled;
+ ModalFilterUPP goToFilterUPP;
+
+ goToFilterUPP = NewModalFilterUPP(GoToFilter);
+ BringUpDialog(&theDialog, kGoToDialogID);
+
+ if (GetFirstRoomNumber() == thisRoomNumber)
+ MyDisableControl(theDialog, kGoToFirstButt);
+ if ((!RoomNumExists(previousRoom)) || (previousRoom == thisRoomNumber))
+ MyDisableControl(theDialog, kGoToPrevButt);
+
+ SetDialogNumToStr(theDialog, kFloorEditText, (long)wasFloor);
+ SetDialogNumToStr(theDialog, kSuiteEditText, (long)wasSuite);
+ SelectDialogItemText(theDialog, kFloorEditText, 0, 1024);
+
+ leaving = false;
+ canceled = false;
+
+ while (!leaving)
+ {
+ ModalDialog(goToFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ roomToGoTo = -1;
+ canceled = true;
+ leaving = true;
+ }
+ else if (item == kGoToFirstButt)
+ {
+ roomToGoTo = GetFirstRoomNumber();
+ leaving = true;
+ }
+ else if (item == kGoToPrevButt)
+ {
+ roomToGoTo = previousRoom;
+ leaving = true;
+ }
+ else if (item == kGoToFSButt)
+ {
+ GetDialogNumFromStr(theDialog, kFloorEditText, &tempLong);
+ wasFloor = (short)tempLong;
+ GetDialogNumFromStr(theDialog, kSuiteEditText, &tempLong);
+ wasSuite = (short)tempLong;
+ roomToGoTo = GetRoomNumber(wasFloor, wasSuite);
+ leaving = true;
+ }
+ }
+
+ DisposeDialog(theDialog);
+ DisposeModalFilterUPP(goToFilterUPP);
+
+ if (!canceled)
+ {
+ if (RoomNumExists(roomToGoTo))
+ {
+ DeselectObject();
+ CopyRoomToThisRoom(roomToGoTo);
+ ReflectCurrentRoom(false);
+ }
+ else
+ SysBeep(1);
+ }
+}
+
+//-------------------------------------------------------------- ConvertHouseVer1To2
+
+// This function goes through an old version 1 house and converts itÉ
+// to version 2.
+
+void ConvertHouseVer1To2 (void)
+{
+ Str255 roomStr, message;
+ short wasRoom, floor, suite;
+ short i, h, numRooms;
+ char wasState;
+
+ CopyThisRoomToRoom();
+ wasRoom = thisRoomNumber;
+ GetLocalizedString(13, message);
+ OpenMessageWindow(message);
+
+ SpinCursor(3);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ numRooms = (*thisHouse)->nRooms;
+ for (i = 0; i < numRooms; i++)
+ {
+ if ((*thisHouse)->rooms[i].suite != kRoomIsEmpty)
+ {
+ NumToString((long)i, roomStr);
+ GetLocalizedString(14, message);
+ PasStringConcat(message, roomStr);
+ SetMessageWindowMessage(message);
+ SpinCursor(1);
+
+ ForceThisRoom(i);
+ for (h = 0; h < kMaxRoomObs; h++)
+ {
+ switch (thisRoom->objects[h].what)
+ {
+ case kMailboxLf:
+ case kMailboxRt:
+ case kFloorTrans:
+ case kCeilingTrans:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ if (thisRoom->objects[h].data.d.where != -1)
+ {
+ ExtractFloorSuite(thisRoom->objects[h].data.d.where, &floor, &suite);
+ floor += kNumUndergroundFloors;
+ thisRoom->objects[h].data.d.where = MergeFloorSuite(floor, suite);
+ }
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ if (thisRoom->objects[h].data.e.where != -1)
+ {
+ ExtractFloorSuite(thisRoom->objects[h].data.e.where, &floor, &suite);
+ floor += kNumUndergroundFloors;
+ thisRoom->objects[h].data.e.where = MergeFloorSuite(floor, suite);
+ }
+ break;
+ }
+ }
+ CopyThisRoomToRoom();
+ }
+ }
+
+ (*thisHouse)->version = kHouseVersion;
+ HSetState((Handle)thisHouse, wasState);
+
+ InitCursor();
+ CloseMessageWindow();
+ ForceThisRoom(wasRoom);
+}
+
+//-------------------------------------------------------------- ShiftWholeHouse
+
+void ShiftWholeHouse (short howFar)
+{
+ short wasRoom;
+ short i, h, numRooms;
+ char wasState;
+
+ OpenMessageWindow(PSTR("Shifting Whole HouseÉ"));
+ SpinCursor(3);
+
+ CopyThisRoomToRoom();
+ wasRoom = thisRoomNumber;
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ numRooms = (*thisHouse)->nRooms;
+
+ for (i = 0; i < numRooms; i++)
+ {
+ if ((*thisHouse)->rooms[i].suite != kRoomIsEmpty)
+ {
+ SpinCursor(1);
+
+ ForceThisRoom(i);
+ for (h = 0; h < kMaxRoomObs; h++)
+ {
+ }
+ CopyThisRoomToRoom();
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+ ForceThisRoom(wasRoom);
+
+ InitCursor();
+ CloseMessageWindow();
+}
+
diff --git a/GpApp/House.h b/GpApp/House.h
new file mode 100644
index 0000000..51a39c7
--- /dev/null
+++ b/GpApp/House.h
@@ -0,0 +1,12 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// House.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLMacTypes.h"
+
+
+extern Str32 thisHouseName;
+extern Boolean houseUnlocked;
diff --git a/GpApp/HouseIO.cpp b/GpApp/HouseIO.cpp
new file mode 100644
index 0000000..9114376
--- /dev/null
+++ b/GpApp/HouseIO.cpp
@@ -0,0 +1,707 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// HouseIO.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLAliases.h"
+#include "PLMovies.h"
+#include "PLResources.h"
+#include "PLStringCompare.h"
+#include "PLTextUtils.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "House.h"
+#include "ObjectEdit.h"
+
+
+#define kSaveChangesAlert 1002
+#define kSaveChanges 1
+#define kDiscardChanges 2
+
+
+void LoopMovie (void);
+void OpenHouseMovie (void);
+void CloseHouseMovie (void);
+Boolean IsFileReadOnly (FSSpec *);
+
+
+Movie theMovie;
+Rect movieRect;
+short houseRefNum, houseResFork, wasHouseVersion;
+Boolean houseOpen, fileDirty, gameDirty;
+Boolean changeLockStateOfHouse, saveHouseLocked, houseIsReadOnly;
+Boolean hasMovie, tvInRoom;
+
+extern FSSpecPtr theHousesSpecs;
+extern short thisHouseIndex, tvWithMovieNumber;
+extern short numberRooms, housesFound;
+extern Boolean noRoomAtAll, quitting, wardBitSet;
+extern Boolean phoneBitSet, bannerStarCountOn;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- LoopMovie
+
+void LoopMovie (void)
+{
+ Handle theLoop;
+ UserData theUserData;
+ short theCount;
+
+ theLoop = NewHandle(sizeof(long));
+ (** (long **) theLoop) = 0;
+ theUserData = GetMovieUserData(theMovie);
+ theCount = CountUserDataType(theUserData, 'LOOP');
+ while (theCount--)
+ {
+ RemoveUserData(theUserData, 'LOOP', 1);
+ }
+ AddUserData(theUserData, theLoop, 'LOOP');
+}
+
+//-------------------------------------------------------------- OpenHouseMovie
+
+void OpenHouseMovie (void)
+{
+#ifdef COMPILEQT
+ TimeBase theTime;
+ FSSpec theSpec;
+ FInfo finderInfo;
+ Handle spaceSaver;
+ OSErr theErr;
+ short movieRefNum;
+ Boolean dataRefWasChanged;
+
+ if (thisMac.hasQT)
+ {
+ theSpec = theHousesSpecs[thisHouseIndex];
+ PasStringConcat(theSpec.name, PSTR(".mov"));
+
+ theErr = FSpGetFInfo(&theSpec, &finderInfo);
+ if (theErr != noErr)
+ return;
+
+ theErr = OpenMovieFile(&theSpec, &movieRefNum, fsCurPerm);
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowQTMovieNotLoaded, theErr);
+ return;
+ }
+
+ theErr = NewMovieFromFile(&theMovie, movieRefNum, nil, theSpec.name,
+ newMovieActive, &dataRefWasChanged);
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowQTMovieNotLoaded, theErr);
+ theErr = CloseMovieFile(movieRefNum);
+ return;
+ }
+ theErr = CloseMovieFile(movieRefNum);
+
+ spaceSaver = NewHandle(307200L);
+ if (spaceSaver == nil)
+ {
+ YellowAlert(kYellowQTMovieNotLoaded, 749);
+ CloseHouseMovie();
+ return;
+ }
+
+ GoToBeginningOfMovie(theMovie);
+ theErr = LoadMovieIntoRam(theMovie,
+ GetMovieTime(theMovie, 0L), GetMovieDuration(theMovie), 0);
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowQTMovieNotLoaded, theErr);
+ DisposeHandle(spaceSaver);
+ CloseHouseMovie();
+ return;
+ }
+ DisposeHandle(spaceSaver);
+
+ theErr = PrerollMovie(theMovie, 0, 0x000F0000);
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowQTMovieNotLoaded, theErr);
+ CloseHouseMovie();
+ return;
+ }
+
+ theTime = GetMovieTimeBase(theMovie);
+ SetTimeBaseFlags(theTime, loopTimeBase);
+ SetMovieMasterTimeBase(theMovie, theTime, nil);
+ LoopMovie();
+
+ GetMovieBox(theMovie, &movieRect);
+
+ hasMovie = true;
+ }
+#endif
+}
+
+//-------------------------------------------------------------- CloseHouseMovie
+
+void CloseHouseMovie (void)
+{
+#ifdef COMPILEQT
+ OSErr theErr;
+
+ if ((thisMac.hasQT) && (hasMovie))
+ {
+ theErr = LoadMovieIntoRam(theMovie,
+ GetMovieTime(theMovie, 0L), GetMovieDuration(theMovie), flushFromRam);
+ DisposeMovie(theMovie);
+ }
+#endif
+ hasMovie = false;
+}
+
+//-------------------------------------------------------------- OpenHouse
+// Opens a house (whatever current selection is). Returns true if all went well.
+
+Boolean OpenHouse (void)
+{
+ OSErr theErr;
+ Boolean targetIsFolder, wasAliased;
+
+ if (houseOpen)
+ {
+ if (!CloseHouse())
+ return(false);
+ }
+ if ((housesFound < 1) || (thisHouseIndex == -1))
+ return(false);
+
+ theErr = ResolveAliasFile(&theHousesSpecs[thisHouseIndex], true,
+ &targetIsFolder, &wasAliased);
+ if (!CheckFileError(theErr, thisHouseName))
+ return (false);
+
+ #ifdef COMPILEDEMO
+ if (!EqualString(theHousesSpecs[thisHouseIndex].name, "\pDemo House", false, true))
+ return (false);
+ #endif
+
+ houseIsReadOnly = IsFileReadOnly(&theHousesSpecs[thisHouseIndex]);
+
+ theErr = FSpOpenDF(&theHousesSpecs[thisHouseIndex], fsCurPerm, &houseRefNum);
+ if (!CheckFileError(theErr, thisHouseName))
+ return (false);
+
+ houseOpen = true;
+ OpenHouseResFork();
+
+ hasMovie = false;
+ tvInRoom = false;
+ tvWithMovieNumber = -1;
+ OpenHouseMovie();
+
+ return (true);
+}
+
+//-------------------------------------------------------------- OpenSpecificHouse
+// Opens the specific house passed in.
+
+#ifndef COMPILEDEMO
+Boolean OpenSpecificHouse (FSSpec *specs)
+{
+ short i;
+ Boolean itOpened;
+
+ if ((housesFound < 1) || (thisHouseIndex == -1))
+ return (false);
+
+ itOpened = true;
+
+ for (i = 0; i < housesFound; i++)
+ {
+ if ((theHousesSpecs[i].vRefNum == specs->vRefNum) &&
+ (theHousesSpecs[i].parID == specs->parID) &&
+ (EqualString(theHousesSpecs[i].name, specs->name, false, true)))
+ {
+ thisHouseIndex = i;
+ PasStringCopy(theHousesSpecs[thisHouseIndex].name, thisHouseName);
+ if (OpenHouse())
+ itOpened = ReadHouse();
+ else
+ itOpened = false;
+ break;
+ }
+ }
+
+ return (itOpened);
+}
+#endif
+
+//-------------------------------------------------------------- SaveHouseAs
+
+#ifndef COMPILEDEMO
+Boolean SaveHouseAs (void)
+{
+ // TEMP - fix this later -- use NavServices (see House.c)
+/*
+ StandardFileReply theReply;
+ FSSpec oldHouse;
+ OSErr theErr;
+ Boolean noProblems;
+ Str255 tempStr;
+
+ noProblems = true;
+
+ GetLocalizedString(15, tempStr);
+ StandardPutFile(tempStr, thisHouseName, &theReply);
+ if (theReply.sfGood)
+ {
+ oldHouse = theHousesSpecs[thisHouseIndex];
+
+ CloseHouseResFork(); // close this house file
+ theErr = FSClose(houseRefNum);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, "\pPreferences");
+ return(false);
+ }
+ // create new house file
+ theErr = FSpCreate(&theReply.sfFile, 'ozm5', 'gliH', theReply.sfScript);
+ if (!CheckFileError(theErr, theReply.sfFile.name))
+ return (false);
+ HCreateResFile(theReply.sfFile.vRefNum, theReply.sfFile.parID,
+ theReply.sfFile.name);
+ if (ResError() != noErr)
+ YellowAlert(kYellowFailedResCreate, ResError());
+ PasStringCopy(theReply.sfFile.name, thisHouseName);
+ // open new house data fork
+ theErr = FSpOpenDF(&theReply.sfFile, fsRdWrPerm, &houseRefNum);
+ if (!CheckFileError(theErr, thisHouseName))
+ return (false);
+
+ houseOpen = true;
+
+ noProblems = WriteHouse(false); // write out house data
+ if (!noProblems)
+ return(false);
+
+ BuildHouseList();
+ if (OpenSpecificHouse(&theReply.sfFile)) // open new house again
+ {
+ }
+ else
+ {
+ if (OpenSpecificHouse(&oldHouse))
+ {
+ YellowAlert(kYellowOpenedOldHouse, 0);
+ }
+ else
+ {
+ YellowAlert(kYellowLostAllHouses, 0);
+ noProblems = false;
+ }
+ }
+ }
+
+
+ return (noProblems);
+ */
+ return false;
+}
+#endif
+
+//-------------------------------------------------------------- ReadHouse
+// With a house open, this function reads in the actual bits of dataÉ
+// into memory.
+
+Boolean ReadHouse (void)
+{
+ long byteCount;
+ OSErr theErr;
+ short whichRoom;
+
+ if (!houseOpen)
+ {
+ YellowAlert(kYellowUnaccounted, 2);
+ return (false);
+ }
+
+ if (gameDirty || fileDirty)
+ {
+ if (houseIsReadOnly)
+ {
+ if (!WriteScoresToDisk())
+ {
+ YellowAlert(kYellowFailedWrite, 0);
+ return(false);
+ }
+ }
+ else if (!WriteHouse(false))
+ return(false);
+ }
+
+ theErr = GetEOF(houseRefNum, &byteCount);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, thisHouseName);
+ return(false);
+ }
+
+ #ifdef COMPILEDEMO
+ if (byteCount != 16526L)
+ return (false);
+ #endif
+
+ if (thisHouse != nil)
+ DisposeHandle((Handle)thisHouse);
+
+ thisHouse = (houseHand)NewHandle(byteCount);
+ if (thisHouse == nil)
+ {
+ YellowAlert(kYellowNoMemory, 10);
+ return(false);
+ }
+ MoveHHi((Handle)thisHouse);
+
+ theErr = SetFPos(houseRefNum, fsFromStart, 0L);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, thisHouseName);
+ return(false);
+ }
+
+ HLock((Handle)thisHouse);
+ theErr = FSRead(houseRefNum, &byteCount, *thisHouse);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, thisHouseName);
+ HUnlock((Handle)thisHouse);
+ return(false);
+ }
+
+ numberRooms = (*thisHouse)->nRooms;
+ #ifdef COMPILEDEMO
+ if (numberRooms != 45)
+ return (false);
+ #endif
+ if ((numberRooms < 1) || (byteCount == 0L))
+ {
+ numberRooms = 0;
+ noRoomAtAll = true;
+ YellowAlert(kYellowNoRooms, 0);
+ HUnlock((Handle)thisHouse);
+ return(false);
+ }
+
+ wasHouseVersion = (*thisHouse)->version;
+ if (wasHouseVersion >= kNewHouseVersion)
+ {
+ YellowAlert(kYellowNewerVersion, 0);
+ HUnlock((Handle)thisHouse);
+ return(false);
+ }
+
+ houseUnlocked = (((*thisHouse)->timeStamp & 0x00000001) == 0);
+ #ifdef COMPILEDEMO
+ if (houseUnlocked)
+ return (false);
+ #endif
+ changeLockStateOfHouse = false;
+ saveHouseLocked = false;
+
+ whichRoom = (*thisHouse)->firstRoom;
+ #ifdef COMPILEDEMO
+ if (whichRoom != 0)
+ return (false);
+ #endif
+
+ wardBitSet = (((*thisHouse)->flags & 0x00000001) == 0x00000001);
+ phoneBitSet = (((*thisHouse)->flags & 0x00000002) == 0x00000002);
+ bannerStarCountOn = (((*thisHouse)->flags & 0x00000004) == 0x00000000);
+
+ HUnlock((Handle)thisHouse);
+
+ noRoomAtAll = (RealRoomNumberCount() == 0);
+ thisRoomNumber = -1;
+ previousRoom = -1;
+ if (!noRoomAtAll)
+ CopyRoomToThisRoom(whichRoom);
+
+ if (houseIsReadOnly)
+ {
+ houseUnlocked = false;
+ if (ReadScoresFromDisk())
+ {
+ }
+ }
+
+ objActive = kNoObjectSelected;
+ ReflectCurrentRoom(true);
+ gameDirty = false;
+ fileDirty = false;
+ UpdateMenus(false);
+
+ return (true);
+}
+
+//-------------------------------------------------------------- WriteHouse
+// This function writes out the house data to disk.
+
+Boolean WriteHouse (Boolean checkIt)
+{
+ UInt32 timeStamp;
+ long byteCount;
+ OSErr theErr;
+
+ if (!houseOpen)
+ {
+ YellowAlert(kYellowUnaccounted, 4);
+ return (false);
+ }
+
+ theErr = SetFPos(houseRefNum, fsFromStart, 0L);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, thisHouseName);
+ return(false);
+ }
+
+ CopyThisRoomToRoom();
+
+ if (checkIt)
+ CheckHouseForProblems();
+
+ HLock((Handle)thisHouse);
+ byteCount = GetHandleSize((Handle)thisHouse);
+
+ if (fileDirty)
+ {
+ GetDateTime(&timeStamp);
+ timeStamp &= 0x7FFFFFFF;
+
+ if (changeLockStateOfHouse)
+ houseUnlocked = !saveHouseLocked;
+
+ if (houseUnlocked) // house unlocked
+ timeStamp &= 0x7FFFFFFE;
+ else
+ timeStamp |= 0x00000001;
+ (*thisHouse)->timeStamp = (long)timeStamp;
+ (*thisHouse)->version = wasHouseVersion;
+ }
+
+ theErr = FSWrite(houseRefNum, &byteCount, *thisHouse);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, thisHouseName);
+ HUnlock((Handle)thisHouse);
+ return(false);
+ }
+
+ theErr = SetEOF(houseRefNum, byteCount);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, thisHouseName);
+ HUnlock((Handle)thisHouse);
+ return(false);
+ }
+
+ HUnlock((Handle)thisHouse);
+
+ if (changeLockStateOfHouse)
+ {
+ changeLockStateOfHouse = false;
+ ReflectCurrentRoom(true);
+ }
+
+ gameDirty = false;
+ fileDirty = false;
+ UpdateMenus(false);
+ return (true);
+}
+
+//-------------------------------------------------------------- CloseHouse
+// This function closes the current house that is open.
+
+Boolean CloseHouse (void)
+{
+ OSErr theErr;
+
+ if (!houseOpen)
+ return (true);
+
+ if (gameDirty)
+ {
+ if (houseIsReadOnly)
+ {
+ if (!WriteScoresToDisk())
+ YellowAlert(kYellowFailedWrite, 0);
+ }
+ else if (!WriteHouse(theMode == kEditMode))
+ YellowAlert(kYellowFailedWrite, 0);
+ }
+ else if (fileDirty)
+ {
+#ifndef COMPILEDEMO
+ if (!QuerySaveChanges()) // false signifies user canceled
+ return(false);
+#endif
+ }
+
+ CloseHouseResFork();
+ CloseHouseMovie();
+
+ theErr = FSClose(houseRefNum);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, thisHouseName);
+ return(false);
+ }
+
+ houseOpen = false;
+
+ return (true);
+}
+
+//-------------------------------------------------------------- OpenHouseResFork
+// Opens the resource fork of the current house that is open.
+
+void OpenHouseResFork (void)
+{
+ if (houseResFork == -1)
+ {
+ houseResFork = FSpOpenResFile(&theHousesSpecs[thisHouseIndex], fsCurPerm);
+ if (houseResFork == -1)
+ YellowAlert(kYellowFailedResOpen, ResError());
+ else
+ UseResFile(houseResFork);
+ }
+}
+
+//-------------------------------------------------------------- CloseHouseResFork
+// Closes the resource fork of the current house that is open.
+
+void CloseHouseResFork (void)
+{
+ if (houseResFork != -1)
+ {
+ CloseResFile(houseResFork);
+ houseResFork = -1;
+ }
+}
+
+//-------------------------------------------------------------- QuerySaveChanges
+// If changes were made, this function will present the user with aÉ
+// dialog asking them if they would like to save the changes.
+
+#ifndef COMPILEDEMO
+Boolean QuerySaveChanges (void)
+{
+ short hitWhat;
+ Boolean whoCares;
+
+ if (!fileDirty)
+ return(true);
+
+ InitCursor();
+// CenterAlert(kSaveChangesAlert);
+ ParamText(thisHouseName, PSTR(""), PSTR(""), PSTR(""));
+ hitWhat = Alert(kSaveChangesAlert, nil);
+ if (hitWhat == kSaveChanges)
+ {
+ if (wasHouseVersion < kHouseVersion)
+ ConvertHouseVer1To2();
+ wasHouseVersion = kHouseVersion;
+ if (WriteHouse(true))
+ return (true);
+ else
+ return (false);
+ }
+ else if (hitWhat == kDiscardChanges)
+ {
+ fileDirty = false;
+ if (!quitting)
+ {
+ whoCares = CloseHouse();
+ if (OpenHouse())
+ whoCares = ReadHouse();
+ }
+ UpdateMenus(false);
+ return (true);
+ }
+ else
+ return (false);
+}
+#endif
+
+//-------------------------------------------------------------- YellowAlert
+// This is a dialog used to present an error code and explanationÉ
+// to the user when a non-lethal error has occurred. Ideally, ofÉ
+// course, this never is called.
+
+void YellowAlert (short whichAlert, short identifier)
+{
+ #define kYellowAlert 1006
+ Str255 errStr, errNumStr;
+ short whoCares;
+
+ InitCursor();
+
+ GetIndString(errStr, kYellowAlert, whichAlert);
+ NumToString((long)identifier, errNumStr);
+
+// CenterAlert(kYellowAlert);
+ ParamText(errStr, errNumStr, PSTR(""), PSTR(""));
+
+ whoCares = Alert(kYellowAlert, nil);
+}
+
+//-------------------------------------------------------------- IsFileReadOnly
+
+Boolean IsFileReadOnly (FSSpec *theSpec)
+{
+ return false;
+ /*
+ Str255 tempStr;
+ ParamBlockRec theBlock;
+ HParamBlockRec hBlock;
+ VolumeParam *volPtr;
+ OSErr theErr;
+
+ volPtr = (VolumeParam *)&theBlock;
+ volPtr->ioCompletion = nil;
+ volPtr->ioVolIndex = 0;
+ volPtr->ioNamePtr = tempStr;
+ volPtr->ioVRefNum = theSpec->vRefNum;
+
+ theErr = PBGetVInfo(&theBlock, false);
+ if (CheckFileError(theErr, "\pRead/Write"))
+ {
+ if (((volPtr->ioVAtrb & 0x0080) == 0x0080) ||
+ ((volPtr->ioVAtrb & 0x8000) == 0x8000))
+ return (true); // soft/hard locked bits
+ else
+ {
+ hBlock.fileParam.ioCompletion = nil;
+ hBlock.fileParam.ioVRefNum = theSpec->vRefNum;
+ hBlock.fileParam.ioFVersNum = 0;
+ hBlock.fileParam.ioFDirIndex = 0;
+ hBlock.fileParam.ioNamePtr = theSpec->name;
+ hBlock.fileParam.ioDirID = theSpec->parID;
+
+ theErr = PBHGetFInfo(&hBlock, false);
+ if (CheckFileError(theErr, "\pRead/Write"))
+ {
+ if ((hBlock.fileParam.ioFlAttrib & 0x0001) == 0x0001)
+ return (true);
+ else
+ return (false);
+ }
+ else
+ return (false);
+ }
+ }
+ else
+ return (false);
+ */
+}
+
diff --git a/GpApp/HouseInfo.cpp b/GpApp/HouseInfo.cpp
new file mode 100644
index 0000000..67d7301
--- /dev/null
+++ b/GpApp/HouseInfo.cpp
@@ -0,0 +1,344 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// HouseInfo.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLNumberFormatting.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "DialogUtils.h"
+
+
+#define kHouseInfoDialogID 1001
+#define kBannerTextItem 4
+#define kLockHouseButton 6
+#define kClearScoresButton 9
+#define kTrailerTextItem 11
+#define kNoPhoneCheck 14
+#define kBannerNCharsItem 15
+#define kTrailerNCharsItem 16
+#define kHouseSizeItem 18
+#define kLockHouseAlert 1029
+#define kZeroScoresAlert 1032
+
+
+long CountTotalHousePoints (void);
+void UpdateHouseInfoDialog (DialogPtr);
+Boolean HouseFilter (DialogPtr, EventRecord *, short *);
+Boolean WarnLockingHouse (void);
+void HowToZeroScores (void);
+
+
+Str255 banner, trailer;
+Rect houseEditText1, houseEditText2;
+short houseCursorIs;
+Boolean keyHit, tempPhoneBit;
+
+extern Cursor beamCursor;
+extern Boolean noRoomAtAll, changeLockStateOfHouse, saveHouseLocked;
+extern Boolean phoneBitSet;
+
+#ifndef COMPILEDEMO
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- CountTotalHousePoints
+
+// The following functions all handle the "House Info" dialog in the editor.
+
+long CountTotalHousePoints (void)
+{
+ long pointTotal;
+ short numRooms, h, i;
+ char wasState;
+
+ pointTotal = (long)RealRoomNumberCount() * (long)kRoomVisitScore;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ numRooms = (*thisHouse)->nRooms;
+ for (i = 0; i < numRooms; i++)
+ {
+ if ((*thisHouse)->rooms[i].suite != kRoomIsEmpty)
+ {
+ for (h = 0; h < kMaxRoomObs; h++)
+ {
+ switch ((*thisHouse)->rooms[i].objects[h].what)
+ {
+ case kRedClock:
+ pointTotal += kRedClockPoints;
+ break;
+
+ case kBlueClock:
+ pointTotal += kBlueClockPoints;
+ break;
+
+ case kYellowClock:
+ pointTotal += kYellowClockPoints;
+ break;
+
+ case kCuckoo:
+ pointTotal += kCuckooClockPoints;
+ break;
+
+ case kStar:
+ pointTotal += kStarPoints;
+ break;
+
+ case kInvisBonus:
+ pointTotal += (*thisHouse)->rooms[i].objects[h].data.c.points;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ return (pointTotal);
+}
+
+//-------------------------------------------------------------- UpdateHouseInfoDialog
+
+void UpdateHouseInfoDialog (DialogPtr theDialog)
+{
+ short nChars;
+
+ DrawDialog(theDialog);
+ nChars = GetDialogStringLen(theDialog, kBannerTextItem);
+ SetDialogNumToStr(theDialog, kBannerNCharsItem, (long)nChars);
+ nChars = GetDialogStringLen(theDialog, kTrailerTextItem);
+ SetDialogNumToStr(theDialog, kTrailerNCharsItem, (long)nChars);
+ SetDialogNumToStr(theDialog, kHouseSizeItem, CountTotalHousePoints());
+ FrameDialogItemC(theDialog, 10, kRedOrangeColor8);
+ SetDialogItemValue(theDialog, kNoPhoneCheck, (short)tempPhoneBit);
+}
+
+//-------------------------------------------------------------- HouseFilter
+
+Boolean HouseFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ Point mouseIs;
+ short nChars;
+
+ if (keyHit)
+ {
+ nChars = GetDialogStringLen(dial, kBannerTextItem);
+ SetDialogNumToStr(dial, kBannerNCharsItem, (long)nChars);
+ nChars = GetDialogStringLen(dial, kTrailerTextItem);
+ SetDialogNumToStr(dial, kTrailerNCharsItem, (long)nChars);
+ keyHit = false;
+ }
+
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ default:
+ keyHit = true;
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case mouseUp:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateHouseInfoDialog(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ mouseIs = event->where;
+ GlobalToLocal(&mouseIs);
+ if ((PtInRect(mouseIs, &houseEditText1)) ||
+ (PtInRect(mouseIs, &houseEditText2)))
+ {
+ if (houseCursorIs != kBeamCursor)
+ {
+ SetCursor(&beamCursor);
+ houseCursorIs = kBeamCursor;
+ }
+ }
+ else
+ {
+ if (houseCursorIs != kArrowCursor)
+ {
+ InitCursor();
+ houseCursorIs = kArrowCursor;
+ }
+ }
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoHouseInfo
+
+void DoHouseInfo (void)
+{
+ DialogPtr houseInfoDialog;
+ Str255 versStr, loVers, nRoomsStr;
+ long h, v;
+ short item, numRooms, version;
+ char wasState;
+ Boolean leaving;
+ ModalFilterUPP houseFilterUPP;
+
+ houseFilterUPP = NewModalFilterUPP(HouseFilter);
+ tempPhoneBit = phoneBitSet;
+
+ wasState = HGetState((Handle)thisHouse);
+ numRooms = RealRoomNumberCount();
+ HLock((Handle)thisHouse);
+ PasStringCopy((*thisHouse)->banner, banner);
+ PasStringCopy((*thisHouse)->trailer, trailer);
+ version = (*thisHouse)->version;
+ if (!noRoomAtAll)
+ {
+ h = (long)(*thisHouse)->rooms[(*thisHouse)->firstRoom].suite;
+ v = (long)(*thisHouse)->rooms[(*thisHouse)->firstRoom].floor;
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ NumToString((long)version >> 8, versStr); // Convert version to two stringsÉ
+ NumToString((long)version % 0x0100, loVers); // the 1's and 1/10th's part.
+ NumToString((long)numRooms, nRoomsStr); // Number of rooms -> string.
+
+ ParamText(versStr, loVers, nRoomsStr, PSTR(""));
+
+// CenterDialog(kHouseInfoDialogID);
+ houseInfoDialog = GetNewDialog(kHouseInfoDialogID, nil, kPutInFront);
+ if (houseInfoDialog == nil)
+ RedAlert(kErrDialogDidntLoad);
+ SetPort((GrafPtr)houseInfoDialog);
+ ShowWindow(GetDialogWindow(houseInfoDialog));
+
+ SetDialogString(houseInfoDialog, kBannerTextItem, banner);
+ SetDialogString(houseInfoDialog, kTrailerTextItem, trailer);
+ SelectDialogItemText(houseInfoDialog, kBannerTextItem, 0, 1024);
+ GetDialogItemRect(houseInfoDialog, kBannerTextItem, &houseEditText1);
+ GetDialogItemRect(houseInfoDialog, kTrailerTextItem, &houseEditText2);
+ houseCursorIs = kArrowCursor;
+ leaving = false;
+
+ while (!leaving)
+ {
+ ModalDialog(houseFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogString(houseInfoDialog, kBannerTextItem, banner);
+ GetDialogString(houseInfoDialog, kTrailerTextItem, trailer);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ PasStringCopyNum(banner, (*thisHouse)->banner, 255);
+ PasStringCopyNum(trailer, (*thisHouse)->trailer, 255);
+ if (tempPhoneBit != phoneBitSet)
+ {
+ phoneBitSet = tempPhoneBit;
+ if (phoneBitSet)
+ (*thisHouse)->flags = (*thisHouse)->flags | 0x00000002;
+ else
+ (*thisHouse)->flags = (*thisHouse)->flags & 0xFFFFDFFD;
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ }
+ else if (item == kCancelButton)
+ leaving = true;
+ else if (item == kLockHouseButton)
+ {
+ if (WarnLockingHouse())
+ {
+ changeLockStateOfHouse = true;
+ saveHouseLocked = true;
+ fileDirty = true;
+ UpdateMenus(false);
+ }
+ }
+ else if (item == kClearScoresButton)
+ HowToZeroScores();
+ else if (item == kNoPhoneCheck)
+ {
+ tempPhoneBit = !tempPhoneBit;
+ SetDialogItemValue(houseInfoDialog, kNoPhoneCheck, (short)tempPhoneBit);
+ }
+ }
+ InitCursor();
+ DisposeDialog(houseInfoDialog);
+ DisposeModalFilterUPP(houseFilterUPP);
+}
+
+//-------------------------------------------------------------- WarnLockingHouse
+
+Boolean WarnLockingHouse (void)
+{
+ short hitWhat;
+
+// CenterAlert(kLockHouseAlert);
+ hitWhat = Alert(kLockHouseAlert, nil);
+
+ return (hitWhat == 1);
+}
+
+//-------------------------------------------------------------- HowToZeroScores
+
+void HowToZeroScores (void)
+{
+ short hitWhat;
+
+// CenterAlert(kZeroScoresAlert);
+ hitWhat = Alert(kZeroScoresAlert, nil);
+
+ switch (hitWhat)
+ {
+ case 2: // zero all
+ ZeroHighScores();
+ fileDirty = true;
+ UpdateMenus(false);
+ break;
+
+ case 3: // zero all but highest
+ ZeroAllButHighestScore();
+ fileDirty = true;
+ UpdateMenus(false);
+ break;
+ }
+}
+
+#endif
+
diff --git a/GpApp/HouseLegal.cpp b/GpApp/HouseLegal.cpp
new file mode 100644
index 0000000..ac8e711
--- /dev/null
+++ b/GpApp/HouseLegal.cpp
@@ -0,0 +1,1219 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// 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)
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ 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;
+ HSetState((Handle)thisHouse, wasState);
+ 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;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ WrapText((*thisHouse)->banner, 40);
+ WrapText((*thisHouse)->trailer, 64);
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- ValidateNumberOfRooms
+
+// Makes sure the number of room count and actual number of rooms match.
+
+void ValidateNumberOfRooms (void)
+{
+ long countedRooms, reportsRooms;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ reportsRooms = (long)(*thisHouse)->nRooms;
+ countedRooms = (GetHandleSize((Handle)thisHouse) -
+ sizeof(houseType)) / sizeof(roomType);
+ if (reportsRooms != countedRooms)
+ {
+ (*thisHouse)->nRooms = (short)countedRooms;
+ numberRooms = (*thisHouse)->nRooms;
+ houseErrors++;
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- 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;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ 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]++;
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ 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;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ 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);
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- 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;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ 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);
+ HUnlock((Handle)thisHouse); // resize house handle (shrink)
+ SetHandleSize((Handle)thisHouse, newSize);
+ if (MemError() != noErr) // problem?
+ {
+ ForeColor(redColor);
+ GetLocalizedString(16, message);
+ SetMessageWindowMessage(message);
+ }
+ HLock((Handle)thisHouse); // reflect new room count
+ (*thisHouse)->nRooms -= count;
+ numberRooms = (*thisHouse)->nRooms;
+ }
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- ValidateRoomNumbers
+
+// Error check - ensures that the floor and suite numbers are within legal ranges.
+
+void ValidateRoomNumbers (void)
+{
+ short i, numRooms;
+ char wasState;
+ Str255 message;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ 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);
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- CountUntitledRooms
+
+// Returns the number of rooms left "Untitled".
+
+void CountUntitledRooms (void)
+{
+ short i, numRooms;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ numRooms = (*thisHouse)->nRooms;
+ for (i = 0; i < numRooms; i++)
+ {
+ if (((*thisHouse)->rooms[i].suite != kRoomIsEmpty) &&
+ (EqualString((*thisHouse)->rooms[i].name, PSTR("Untitled Room"), false, true)))
+ houseErrors++;
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- CheckRoomNameLength
+
+// Error check - ensures the length of the room name is legal.
+
+void CheckRoomNameLength (void)
+{
+ short i, numRooms;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ 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++;
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- MakeSureNumObjectsJives
+
+// Error check - ensures the actual count of objects equals number of objects.
+
+void MakeSureNumObjectsJives (void)
+{
+ short i, h, numRooms, count;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ 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;
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- KeepAllObjectsLegal
+
+// Repeatedly calls KeepObjectLegal() on ALL objects in a house. Wow!
+
+void KeepAllObjectsLegal (void)
+{
+ short i, h, numRooms;
+ char wasState;
+ Str255 message;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ 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();
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- 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;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ 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);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+#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
+}
+
diff --git a/GpApp/Input.cpp b/GpApp/Input.cpp
new file mode 100644
index 0000000..76ce835
--- /dev/null
+++ b/GpApp/Input.cpp
@@ -0,0 +1,399 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Input.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLToolUtils.h"
+#include "PLDialogs.h"
+#include "Externs.h"
+#include "MainWindow.h"
+#include "RectUtils.h"
+
+
+#define kNormalThrust 5
+#define kHyperThrust 8
+#define kHeliumLift 4
+#define kEscPausePictID 1015
+#define kTabPausePictID 1016
+#define kSavingGameDial 1042
+
+
+void LogDemoKey (char);
+void DoCommandKey (void);
+void DoPause (void);
+void DoBatteryEngaged (gliderPtr);
+void DoHeliumEngaged (gliderPtr);
+Boolean QuerySaveGame (void);
+
+
+demoPtr demoData;
+KeyMap theKeys;
+DialogPtr saveDial;
+short demoIndex, batteryFrame;
+Boolean isEscPauseKey, paused, batteryWasEngaged;
+
+extern long gameFrame;
+extern short otherPlayerEscaped;
+extern Boolean quitting, playing, onePlayerLeft, twoPlayerGame, demoGoing;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- LogDemoKey
+
+void LogDemoKey (char keyIs)
+{
+ demoData[demoIndex].frame = gameFrame;
+ demoData[demoIndex].key = keyIs;
+ demoIndex++;
+}
+
+//-------------------------------------------------------------- DoCommandKey
+
+void DoCommandKey (void)
+{
+ if (BitTst(&theKeys, kQKeyMap))
+ {
+ playing = false;
+ paused = false;
+ if ((!twoPlayerGame) && (!demoGoing))
+ {
+ if (QuerySaveGame())
+ SaveGame2(); // New save game.
+ }
+ }
+ else if ((BitTst(&theKeys, kSKeyMap)) && (!twoPlayerGame))
+ {
+ RefreshScoreboard(kSavingTitleMode);
+ SaveGame2(); // New save game.
+ HideCursor();
+ CopyRectWorkToMain(&workSrcRect);
+ RefreshScoreboard(kNormalTitleMode);
+ }
+}
+
+//-------------------------------------------------------------- DoPause
+
+void DoPause (void)
+{
+ Rect bounds;
+
+ SetPort((GrafPtr)mainWindow);
+ QSetRect(&bounds, 0, 0, 214, 54);
+ CenterRectInRect(&bounds, &houseRect);
+ if (isEscPauseKey)
+ LoadScaledGraphic(kEscPausePictID, &bounds);
+ else
+ LoadScaledGraphic(kTabPausePictID, &bounds);
+
+ do
+ {
+ GetKeys(theKeys);
+ }
+ while ((isEscPauseKey && BitTst(&theKeys, kEscKeyMap)) ||
+ (!isEscPauseKey && BitTst(&theKeys, kTabKeyMap)));
+
+ paused = true;
+ while (paused)
+ {
+ GetKeys(theKeys);
+ if ((isEscPauseKey && BitTst(&theKeys, kEscKeyMap)) ||
+ (!isEscPauseKey && BitTst(&theKeys, kTabKeyMap)))
+ paused = false;
+ else if (BitTst(&theKeys, kCommandKeyMap))
+ DoCommandKey();
+ }
+
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &bounds, &bounds, srcCopy, nil);
+
+ do
+ {
+ GetKeys(theKeys);
+ }
+ while ((isEscPauseKey && BitTst(&theKeys, kEscKeyMap)) ||
+ (!isEscPauseKey && BitTst(&theKeys, kTabKeyMap)));
+}
+
+//-------------------------------------------------------------- DoBatteryEngaged
+
+void DoBatteryEngaged (gliderPtr thisGlider)
+{
+ if (thisGlider->facing == kFaceLeft)
+ {
+ if (thisGlider->tipped)
+ thisGlider->hVel += kHyperThrust;
+ else
+ thisGlider->hVel -= kHyperThrust;
+ }
+ else
+ {
+ if (thisGlider->tipped)
+ thisGlider->hVel -= kHyperThrust;
+ else
+ thisGlider->hVel += kHyperThrust;
+ }
+
+ batteryTotal--;
+
+ if (batteryTotal == 0)
+ {
+ QuickBatteryRefresh(false);
+ PlayPrioritySound(kFizzleSound, kFizzlePriority);
+ }
+ else
+ {
+ if (!batteryWasEngaged)
+ batteryFrame = 0;
+ if (batteryFrame == 0)
+ PlayPrioritySound(kThrustSound, kThrustPriority);
+ batteryFrame++;
+ if (batteryFrame >= 4)
+ batteryFrame = 0;
+ batteryWasEngaged = true;
+ }
+}
+
+//-------------------------------------------------------------- DoHeliumEngaged
+
+void DoHeliumEngaged (gliderPtr thisGlider)
+{
+ thisGlider->vDesiredVel = -kHeliumLift;
+ batteryTotal++;
+
+ if (batteryTotal == 0)
+ {
+ QuickBatteryRefresh(false);
+ PlayPrioritySound(kFizzleSound, kFizzlePriority);
+ batteryWasEngaged = false;
+ }
+ else
+ {
+ if (!batteryWasEngaged)
+ batteryFrame = 0;
+ if (batteryFrame == 0)
+ PlayPrioritySound(kHissSound, kHissPriority);
+ batteryFrame++;
+ if (batteryFrame >= 4)
+ batteryFrame = 0;
+ batteryWasEngaged = true;
+ }
+}
+
+//-------------------------------------------------------------- GetDemoInput
+
+ void GetDemoInput (gliderPtr thisGlider)
+ {
+ if (thisGlider->which == kPlayer1)
+ {
+ GetKeys(theKeys);
+
+#if BUILD_ARCADE_VERSION
+
+ if ((BitTst(&theKeys, thisGlider->leftKey)) ||
+ (BitTst(&theKeys, thisGlider->rightKey)) ||
+ (BitTst(&theKeys, thisGlider->battKey)) ||
+ (BitTst(&theKeys, thisGlider->bandKey)))
+ {
+ playing = false;
+ paused = false;
+ }
+
+#else
+
+ if (BitTst(&theKeys, kCommandKeyMap))
+ DoCommandKey();
+
+#endif
+ }
+
+ if (thisGlider->mode == kGliderBurning)
+ {
+ if (thisGlider->facing == kFaceLeft)
+ thisGlider->hDesiredVel -= kNormalThrust;
+ else
+ thisGlider->hDesiredVel += kNormalThrust;
+ }
+ else
+ {
+ thisGlider->heldLeft = false;
+ thisGlider->heldRight = false;
+ thisGlider->tipped = false;
+
+ if (gameFrame == (long)demoData[demoIndex].frame)
+ {
+ switch (demoData[demoIndex].key)
+ {
+ case 0: // left key
+ thisGlider->hDesiredVel += kNormalThrust;
+ thisGlider->tipped = (thisGlider->facing == kFaceLeft);
+ thisGlider->heldRight = true;
+ thisGlider->fireHeld = false;
+ break;
+
+ case 1: // right key
+ thisGlider->hDesiredVel -= kNormalThrust;
+ thisGlider->tipped = (thisGlider->facing == kFaceRight);
+ thisGlider->heldLeft = true;
+ thisGlider->fireHeld = false;
+ break;
+
+ case 2: // battery key
+ if (batteryTotal > 0)
+ DoBatteryEngaged(thisGlider);
+ else
+ DoHeliumEngaged(thisGlider);
+ thisGlider->fireHeld = false;
+ break;
+
+ case 3: // rubber band key
+ if (!thisGlider->fireHeld)
+ {
+ if (AddBand(thisGlider, thisGlider->dest.left + 24,
+ thisGlider->dest.top + 10, thisGlider->facing))
+ {
+ bandsTotal--;
+ if (bandsTotal <= 0)
+ QuickBandsRefresh(false);
+
+ thisGlider->fireHeld = true;
+ }
+ }
+ break;
+ }
+
+ demoIndex++;
+ }
+ else
+ thisGlider->fireHeld = false;
+
+ if ((isEscPauseKey && BitTst(&theKeys, kEscKeyMap)) ||
+ (!isEscPauseKey && BitTst(&theKeys, kTabKeyMap)))
+ {
+ DoPause();
+ }
+ }
+ }
+
+//-------------------------------------------------------------- GetInput
+
+void GetInput (gliderPtr thisGlider)
+{
+ if (thisGlider->which == kPlayer1)
+ {
+ GetKeys(theKeys);
+ if (BitTst(&theKeys, kCommandKeyMap))
+ DoCommandKey();
+ }
+
+ if (thisGlider->mode == kGliderBurning)
+ {
+ if (thisGlider->facing == kFaceLeft)
+ thisGlider->hDesiredVel -= kNormalThrust;
+ else
+ thisGlider->hDesiredVel += kNormalThrust;
+ }
+ else
+ {
+ thisGlider->heldLeft = false;
+ thisGlider->heldRight = false;
+ if (BitTst(&theKeys, thisGlider->rightKey)) // right key
+ {
+ #ifdef CREATEDEMODATA
+ LogDemoKey(0);
+ #endif
+ if (BitTst(&theKeys, thisGlider->leftKey))
+ {
+ ToggleGliderFacing(thisGlider);
+ thisGlider->heldLeft = true;
+ }
+ else
+ {
+ thisGlider->hDesiredVel += kNormalThrust;
+ thisGlider->tipped = (thisGlider->facing == kFaceLeft);
+ thisGlider->heldRight = true;
+ }
+ }
+ else if (BitTst(&theKeys, thisGlider->leftKey)) // left key
+ {
+ #ifdef CREATEDEMODATA
+ LogDemoKey(1);
+ #endif
+ thisGlider->hDesiredVel -= kNormalThrust;
+ thisGlider->tipped = (thisGlider->facing == kFaceRight);
+ thisGlider->heldLeft = true;
+ }
+ else
+ thisGlider->tipped = false;
+
+ if ((BitTst(&theKeys, thisGlider->battKey)) && (batteryTotal != 0) &&
+ (thisGlider->mode == kGliderNormal))
+ {
+ #ifdef CREATEDEMODATA
+ LogDemoKey(2);
+ #endif
+ if (batteryTotal > 0)
+ DoBatteryEngaged(thisGlider);
+ else
+ DoHeliumEngaged(thisGlider);
+ }
+ else
+ batteryWasEngaged = false;
+
+ if ((BitTst(&theKeys, thisGlider->bandKey)) && (bandsTotal > 0) &&
+ (thisGlider->mode == kGliderNormal))
+ {
+ #ifdef CREATEDEMODATA
+ LogDemoKey(3);
+ #endif
+ if (!thisGlider->fireHeld)
+ {
+ if (AddBand(thisGlider, thisGlider->dest.left + 24,
+ thisGlider->dest.top + 10, thisGlider->facing))
+ {
+ bandsTotal--;
+ if (bandsTotal <= 0)
+ QuickBandsRefresh(false);
+
+ thisGlider->fireHeld = true;
+ }
+ }
+ }
+ else
+ thisGlider->fireHeld = false;
+
+ if ((otherPlayerEscaped != kNoOneEscaped) &&
+ (BitTst(&theKeys, kDeleteKeyMap)) &&
+ (thisGlider->which) && (!onePlayerLeft))
+ {
+ ForceKillGlider();
+ }
+
+ if ((isEscPauseKey && BitTst(&theKeys, kEscKeyMap)) ||
+ (!isEscPauseKey && BitTst(&theKeys, kTabKeyMap)))
+ {
+ DoPause();
+ }
+ }
+}
+
+//-------------------------------------------------------------- QuerySaveGame
+
+Boolean QuerySaveGame (void)
+{
+ #define kSaveGameAlert 1041
+ #define kYesSaveGameButton 1
+ short hitWhat;
+
+ InitCursor();
+ FlushEvents(everyEvent, 0);
+// CenterAlert(kSaveGameAlert);
+ hitWhat = Alert(kSaveGameAlert, nil);
+ if (hitWhat == kYesSaveGameButton)
+ return (true);
+ else
+ return (false);
+}
+
diff --git a/GpApp/Interactions.cpp b/GpApp/Interactions.cpp
new file mode 100644
index 0000000..739cd9d
--- /dev/null
+++ b/GpApp/Interactions.cpp
@@ -0,0 +1,1777 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Interactions.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "RectUtils.h"
+
+
+#define kFloorVentLift -6
+#define kCeilingVentDrop 8
+#define kFanStrength 12
+#define kBatterySupply 50 // about 2 rooms worth of thrust
+#define kHeliumSupply 150
+#define kBandsSupply 8
+#define kFoilSupply 8
+
+
+Boolean GliderHitTop (gliderPtr, Rect *);
+Boolean GliderInRect (gliderPtr, Rect *);
+void BounceGlider (gliderPtr, Rect *);
+void CheckEscapeUpTwo (gliderPtr);
+void CheckEscapeUp (gliderPtr);
+void CheckEscapeDownTwo (gliderPtr);
+void CheckEscapeDown (gliderPtr);
+void CheckRoofCollision (gliderPtr);
+void CheckEscapeLeftTwo (gliderPtr);
+void CheckEscapeLeft (gliderPtr);
+void CheckEscapeRightTwo (gliderPtr);
+void CheckEscapeRight (gliderPtr);
+void CheckGliderInRoom (gliderPtr);
+void HandleRewards (gliderPtr, hotPtr);
+void HandleMicrowaveAction (hotPtr, gliderPtr);
+void HandleHotSpotCollision (gliderPtr, hotPtr, short);
+void CheckForHotSpots (void);
+void WebGlider (gliderPtr, Rect *);
+
+
+short otherPlayerEscaped, activeRectEscaped;
+
+extern hotPtr hotSpots;
+extern short nHotSpots, leftThresh, rightThresh, thisTiles[];
+extern short localNumbers[], thisBackground, numStarsRemaining;
+extern Boolean leftOpen, rightOpen, topOpen, bottomOpen, evenFrame;
+extern Boolean twoPlayerGame, newState, onePlayerLeft, playerDead;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- GliderHitSides
+
+Boolean GliderHitTop (gliderPtr thisGlider, Rect *theRect)
+{
+ Rect glideBounds;
+ short offset;
+ Boolean hitTop;
+
+ glideBounds.left = thisGlider->dest.left + 5;
+ glideBounds.top = thisGlider->dest.top + 5;
+ glideBounds.right = thisGlider->dest.right - 5;
+ glideBounds.bottom = thisGlider->dest.bottom - 5;
+
+ glideBounds.left -= thisGlider->wasHVel;
+ glideBounds.right -= thisGlider->wasHVel;
+
+ if (theRect->bottom < glideBounds.top)
+ hitTop = false;
+ else if (theRect->top > glideBounds.bottom)
+ hitTop = false;
+ else if (theRect->right < glideBounds.left)
+ hitTop = false;
+ else if (theRect->left > glideBounds.right)
+ hitTop = false;
+ else
+ hitTop = true;
+
+ if (!hitTop)
+ {
+ PlayPrioritySound(kFoilHitSound, kFoilHitPriority);
+ foilTotal--;
+ if (foilTotal <= 0)
+ StartGliderFoilLosing(thisGlider);
+
+ glideBounds.left += thisGlider->wasHVel;
+ glideBounds.right += thisGlider->wasHVel;
+ if (thisGlider->hVel > 0)
+ offset = 2 + glideBounds.right - theRect->left;
+ else
+ offset = 2 + glideBounds.left - theRect->right;
+
+ thisGlider->hVel = -thisGlider->hVel - offset;
+ }
+
+ return (hitTop);
+}
+
+//-------------------------------------------------------------- SectGlider
+
+Boolean SectGlider (gliderPtr thisGlider, Rect *theRect, Boolean scrutinize)
+{
+ Rect glideBounds;
+ Boolean itHit;
+
+ glideBounds = thisGlider->dest;
+ if (thisGlider->mode == kGliderBurning)
+ glideBounds.top += 6;
+
+ if (scrutinize)
+ {
+ glideBounds.left += 5;
+ glideBounds.top += 5;
+ glideBounds.right -= 5;
+ glideBounds.bottom -= 5;
+ }
+
+ if (theRect->bottom < glideBounds.top)
+ itHit = false;
+ else if (theRect->top > glideBounds.bottom)
+ itHit = false;
+ else if (theRect->right < glideBounds.left)
+ itHit = false;
+ else if (theRect->left > glideBounds.right)
+ itHit = false;
+ else
+ itHit = true;
+
+ return (itHit);
+}
+
+//-------------------------------------------------------------- GliderInRect
+
+Boolean GliderInRect (gliderPtr thisGlider, Rect *theRect)
+{
+ Rect glideBounds;
+
+ glideBounds = thisGlider->dest;
+
+ if (glideBounds.top < theRect->top)
+ return (false);
+ else if (glideBounds.bottom > theRect->bottom)
+ return (false);
+ else if (glideBounds.left < theRect->left)
+ return (false);
+ else if (glideBounds.right > theRect->right)
+ return (false);
+ else
+ return (true);
+}
+
+//-------------------------------------------------------------- BounceGlider
+
+void BounceGlider (gliderPtr thisGlider, Rect *theRect)
+{
+ Rect glideBounds;
+
+ glideBounds = thisGlider->dest;
+ if ((theRect->right - glideBounds.left) < (glideBounds.right - theRect->left))
+ thisGlider->hVel = theRect->right - glideBounds.left;
+ else
+ thisGlider->hVel = theRect->left - glideBounds.right;
+ if (foilTotal > 0)
+ PlayPrioritySound(kFoilHitSound, kFoilHitPriority);
+ else
+ PlayPrioritySound(kHitWallSound, kHitWallPriority);
+}
+
+//-------------------------------------------------------------- CheckEscapeUpTwo
+
+void CheckEscapeUpTwo (gliderPtr thisGlider)
+{
+ short offset, leftTile, rightTile;
+
+ if (topOpen)
+ {
+ if (thisGlider->dest.top < kNoCeilingLimit)
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ otherPlayerEscaped = kPlayerEscapedUp;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ else if (otherPlayerEscaped == kPlayerEscapedUp)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveRoomToRoom(thisGlider, kAbove);
+ }
+ else
+ {
+ PlayPrioritySound(kDontExitSound, kDontExitPriority);
+ offset = kNoCeilingLimit - thisGlider->dest.top;
+ thisGlider->vVel = -thisGlider->vVel + offset;
+ }
+ }
+ }
+ else if (thisBackground == kDirt)
+ {
+ leftTile = thisGlider->dest.left >> 6; // Ö 64
+ rightTile = thisGlider->dest.right >> 6; // Ö 64
+
+ if ((leftTile >= 0) && (leftTile < 8) &&
+ (rightTile >= 0) && (rightTile < 8))
+ {
+ if (((thisTiles[leftTile] == 5) ||
+ (thisTiles[leftTile] == 6)) &&
+ ((thisTiles[rightTile] == 5) ||
+ (thisTiles[rightTile] == 6)))
+ {
+ if (thisGlider->dest.top < kNoCeilingLimit)
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ otherPlayerEscaped = kPlayerEscapedUp;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ else if (otherPlayerEscaped == kPlayerEscapedUp)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveRoomToRoom(thisGlider, kAbove);
+ }
+ else
+ {
+ PlayPrioritySound(kDontExitSound, kDontExitPriority);
+ offset = kNoCeilingLimit - thisGlider->dest.top;
+ thisGlider->vVel = -thisGlider->vVel + offset;
+ }
+ }
+ }
+ else
+ thisGlider->vVel = kCeilingLimit - thisGlider->dest.top;
+ }
+ else
+ thisGlider->vVel = kCeilingLimit - thisGlider->dest.top;
+ }
+ else
+ thisGlider->vVel = kCeilingLimit - thisGlider->dest.top;
+}
+
+//-------------------------------------------------------------- CheckEscapeUp
+
+void CheckEscapeUp (gliderPtr thisGlider)
+{
+ short leftTile, rightTile;
+
+ if (topOpen)
+ {
+ if (thisGlider->dest.top < kNoCeilingLimit)
+ {
+ MoveRoomToRoom(thisGlider, kAbove);
+ }
+ }
+ else if (thisBackground == kDirt)
+ {
+ leftTile = thisGlider->dest.left >> 6; // Ö 64
+ rightTile = thisGlider->dest.right >> 6; // Ö 64
+
+ if ((leftTile >= 0) && (leftTile < 8) &&
+ (rightTile >= 0) && (rightTile < 8))
+ {
+ if (((thisTiles[leftTile] == 5) ||
+ (thisTiles[leftTile] == 6)) &&
+ ((thisTiles[rightTile] == 5) ||
+ (thisTiles[rightTile] == 6)))
+ {
+ if (thisGlider->dest.top < kNoCeilingLimit)
+ MoveRoomToRoom(thisGlider, kAbove);
+ }
+ else
+ thisGlider->vVel = kCeilingLimit - thisGlider->dest.top;
+ }
+ else
+ thisGlider->vVel = kCeilingLimit - thisGlider->dest.top;
+ }
+ else
+ thisGlider->vVel = kCeilingLimit - thisGlider->dest.top;
+}
+
+//-------------------------------------------------------------- CheckEscapeDownTwo
+
+void CheckEscapeDownTwo (gliderPtr thisGlider)
+{
+ short offset, leftTile, rightTile;
+
+ if (bottomOpen)
+ {
+ if (thisGlider->dest.bottom > kNoFloorLimit)
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ otherPlayerEscaped = kPlayerEscapedDown;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ else if (otherPlayerEscaped == kPlayerEscapedDown)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ else
+ {
+ PlayPrioritySound(kDontExitSound, kDontExitPriority);
+ offset = kNoFloorLimit - thisGlider->dest.bottom;
+ thisGlider->vVel = -thisGlider->vVel + offset;
+ }
+ }
+ }
+ else if (thisBackground == kDirt)
+ {
+ leftTile = thisGlider->dest.left >> 6; // Ö 64
+ rightTile = thisGlider->dest.right >> 6; // Ö 64
+
+ if ((leftTile >= 0) && (leftTile < 8) &&
+ (rightTile >= 0) && (rightTile < 8))
+ {
+ if (((thisTiles[leftTile] == 2) ||
+ (thisTiles[leftTile] == 3)) &&
+ ((thisTiles[rightTile] == 2) ||
+ (thisTiles[rightTile] == 3)))
+ {
+ if (thisGlider->dest.bottom > kNoFloorLimit)
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ otherPlayerEscaped = kPlayerEscapedDown;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ else if (otherPlayerEscaped == kPlayerEscapedDown)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ else
+ {
+ PlayPrioritySound(kDontExitSound, kDontExitPriority);
+ offset = kNoFloorLimit - thisGlider->dest.bottom;
+ thisGlider->vVel = -thisGlider->vVel + offset;
+ }
+ }
+ }
+ else
+ {
+ if (thisGlider->ignoreGround)
+ {
+ if (thisGlider->dest.bottom > kNoFloorLimit)
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ else
+ {
+ thisGlider->vVel = kFloorLimit - thisGlider->dest.bottom;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (thisGlider->ignoreGround)
+ {
+ if (thisGlider->dest.bottom > kNoFloorLimit)
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ else
+ {
+ thisGlider->vVel = kFloorLimit - thisGlider->dest.bottom;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+}
+
+//-------------------------------------------------------------- CheckEscapeDown
+
+void CheckEscapeDown (gliderPtr thisGlider)
+{
+ short leftTile, rightTile;
+
+ if (bottomOpen)
+ {
+ if (thisGlider->dest.bottom > kNoFloorLimit)
+ {
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ }
+ else if (thisBackground == kDirt)
+ {
+ leftTile = thisGlider->dest.left >> 6; // Ö 64
+ rightTile = thisGlider->dest.right >> 6; // Ö 64
+
+ if ((leftTile >= 0) && (leftTile < 8) && (rightTile >= 0) && (rightTile < 8))
+ {
+ if (((thisTiles[leftTile] == 2) || (thisTiles[leftTile] == 3)) &&
+ ((thisTiles[rightTile] == 2) || (thisTiles[rightTile] == 3)))
+ {
+ if (thisGlider->dest.bottom > kNoFloorLimit)
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ else
+ {
+ if (thisGlider->ignoreGround)
+ {
+ if (thisGlider->dest.bottom > kNoFloorLimit)
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ else
+ {
+ thisGlider->vVel = kFloorLimit - thisGlider->dest.bottom;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+ }
+ else
+ {
+ if (thisGlider->ignoreGround)
+ {
+ if (thisGlider->dest.bottom > kNoFloorLimit)
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ else
+ {
+ thisGlider->vVel = kFloorLimit - thisGlider->dest.bottom;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+ }
+ else
+ {
+ if (thisGlider->ignoreGround)
+ {
+ if (thisGlider->dest.bottom > kNoFloorLimit)
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ else
+ {
+ thisGlider->vVel = kFloorLimit - thisGlider->dest.bottom;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+}
+
+//-------------------------------------------------------------- CheckRoofCollision
+
+void CheckRoofCollision (gliderPtr thisGlider)
+{
+ short offset, tileOver;
+
+ offset = (thisGlider->dest.left + kHalfGliderWide) >> 6; // Ö 64
+ if ((offset >= 0) && (offset <= 7) && (!thisGlider->sliding))
+ {
+ tileOver = thisTiles[offset];
+ if (tileOver == 1)
+ {
+ if (((thisGlider->dest.left + kHalfGliderWide) - (offset << 6)) >
+ (250 - thisGlider->dest.bottom))
+ {
+ thisGlider->vVel = kFloorLimit - thisGlider->dest.bottom;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+ else if (tileOver == 2)
+ {
+ if (((thisGlider->dest.left + kHalfGliderWide) - (offset << 6)) >
+ (186 - thisGlider->dest.bottom))
+ {
+ thisGlider->vVel = kFloorLimit - thisGlider->dest.bottom;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+ else if (tileOver == 5)
+ {
+ if ((64 - ((thisGlider->dest.left + kHalfGliderWide) - (offset << 6))) >
+ (186 - thisGlider->dest.bottom))
+ {
+ thisGlider->vVel = kFloorLimit - thisGlider->dest.bottom;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+ else if (tileOver == 6)
+ {
+ if ((64 - ((thisGlider->dest.left + kHalfGliderWide) - (offset << 6))) >
+ (250 - thisGlider->dest.bottom))
+ {
+ thisGlider->vVel = kFloorLimit - thisGlider->dest.bottom;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+ else
+ {
+ thisGlider->vVel = kFloorLimit - thisGlider->dest.bottom;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+}
+
+//-------------------------------------------------------------- CheckEscapeLeftTwo
+
+void CheckEscapeLeftTwo (gliderPtr thisGlider)
+{
+ short offset;
+
+ if (leftThresh == kLeftWallLimit)
+ {
+ if (thisGlider->ignoreLeft)
+ {
+ if (thisGlider->dest.left < kNoLeftWallLimit)
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ otherPlayerEscaped = kPlayerEscapedLeft;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ else if (otherPlayerEscaped == kPlayerEscapedLeft)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveRoomToRoom(thisGlider, kToLeft);
+ }
+ else
+ {
+ PlayPrioritySound(kDontExitSound, kDontExitPriority);
+ offset = kNoLeftWallLimit - thisGlider->dest.left;
+ thisGlider->hVel = -thisGlider->hVel + offset;
+ }
+ }
+ }
+ else
+ {
+ if (foilTotal > 0)
+ PlayPrioritySound(kFoilHitSound, kFoilHitPriority);
+ else
+ PlayPrioritySound(kHitWallSound, kHitWallPriority);
+ offset = kLeftWallLimit - thisGlider->dest.left;
+ thisGlider->hVel = -thisGlider->hVel + offset;
+ }
+ }
+ else
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ otherPlayerEscaped = kPlayerEscapedLeft;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ else if (otherPlayerEscaped == kPlayerEscapedLeft)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveRoomToRoom(thisGlider, kToLeft);
+ }
+ else
+ {
+ PlayPrioritySound(kDontExitSound, kDontExitPriority);
+ offset = kNoLeftWallLimit - thisGlider->dest.left;
+ thisGlider->hVel = -thisGlider->hVel + offset;
+ }
+ }
+}
+
+//-------------------------------------------------------------- CheckEscapeLeft
+
+void CheckEscapeLeft (gliderPtr thisGlider)
+{
+ short offset;
+
+ if (leftThresh == kLeftWallLimit)
+ {
+ if (thisGlider->ignoreLeft)
+ {
+ if (thisGlider->dest.left < kNoLeftWallLimit)
+ MoveRoomToRoom(thisGlider, kToLeft);
+ }
+ else
+ {
+ if (foilTotal > 0)
+ PlayPrioritySound(kFoilHitSound, kFoilHitPriority);
+ else
+ PlayPrioritySound(kHitWallSound, kHitWallPriority);
+ offset = kLeftWallLimit - thisGlider->dest.left;
+ thisGlider->hVel = -thisGlider->hVel + offset;
+ }
+ }
+ else
+ MoveRoomToRoom(thisGlider, kToLeft);
+}
+
+//-------------------------------------------------------------- CheckEscapeRightTwo
+
+void CheckEscapeRightTwo (gliderPtr thisGlider)
+{
+ short offset;
+
+ if (rightThresh == kRightWallLimit)
+ {
+ if (thisGlider->ignoreRight)
+ {
+ if (thisGlider->dest.right > kNoRightWallLimit)
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ otherPlayerEscaped = kPlayerEscapedRight;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ else if (otherPlayerEscaped == kPlayerEscapedRight)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveRoomToRoom(thisGlider, kToRight);
+ }
+ else
+ {
+ PlayPrioritySound(kDontExitSound, kDontExitPriority);
+ offset = kNoRightWallLimit - thisGlider->dest.right;
+ thisGlider->hVel = -thisGlider->hVel + offset;
+ }
+ }
+ }
+ else
+ {
+ if (foilTotal > 0)
+ PlayPrioritySound(kFoilHitSound, kFoilHitPriority);
+ else
+ PlayPrioritySound(kHitWallSound, kHitWallPriority);
+ offset = kRightWallLimit - thisGlider->dest.right;
+ thisGlider->hVel = -thisGlider->hVel + offset;
+ }
+ }
+ else
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ otherPlayerEscaped = kPlayerEscapedRight;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ else if (otherPlayerEscaped == kPlayerEscapedRight)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveRoomToRoom(thisGlider, kToRight);
+ }
+ else
+ {
+ PlayPrioritySound(kDontExitSound, kDontExitPriority);
+ offset = kNoRightWallLimit - thisGlider->dest.right;
+ thisGlider->hVel = -thisGlider->hVel + offset;
+ }
+ }
+}
+
+//-------------------------------------------------------------- CheckEscapeRight
+
+void CheckEscapeRight (gliderPtr thisGlider)
+{
+ short offset;
+
+ if (rightThresh == kRightWallLimit)
+ {
+ if (thisGlider->ignoreRight)
+ {
+ if (thisGlider->dest.right > kNoRightWallLimit)
+ MoveRoomToRoom(thisGlider, kToRight);
+ }
+ else
+ {
+ if (foilTotal > 0)
+ PlayPrioritySound(kFoilHitSound, kFoilHitPriority);
+ else
+ PlayPrioritySound(kHitWallSound, kHitWallPriority);
+ offset = kRightWallLimit - thisGlider->dest.right;
+ thisGlider->hVel = -thisGlider->hVel + offset;
+ }
+ }
+ else
+ MoveRoomToRoom(thisGlider, kToRight);
+}
+
+//-------------------------------------------------------------- CheckGliderInRoom
+
+void CheckGliderInRoom (gliderPtr thisGlider)
+{
+ if ((thisGlider->mode == kGliderNormal) ||
+ (thisGlider->mode == kGliderFaceLeft) ||
+ (thisGlider->mode == kGliderFaceRight) ||
+ (thisGlider->mode == kGliderBurning))
+ {
+ if (thisGlider->dest.top < kCeilingLimit)
+ {
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if ((twoPlayerGame) && (!onePlayerLeft))
+ CheckEscapeUpTwo(thisGlider);
+ else
+ CheckEscapeUp(thisGlider);
+ }
+ else if (thisGlider->dest.bottom > kFloorLimit)
+ {
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if ((twoPlayerGame) && (!onePlayerLeft))
+ CheckEscapeDownTwo(thisGlider);
+ else
+ CheckEscapeDown(thisGlider);
+ }
+ else if ((thisBackground == kRoof) && (thisGlider->dest.bottom > kRoofLimit))
+ CheckRoofCollision(thisGlider);
+
+ if (thisGlider->dest.left < leftThresh)
+ {
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if((twoPlayerGame) && (!onePlayerLeft))
+ CheckEscapeLeftTwo(thisGlider);
+ else
+ CheckEscapeLeft(thisGlider);
+ }
+ else if (thisGlider->dest.right > rightThresh)
+ {
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if ((twoPlayerGame) && (!onePlayerLeft))
+ CheckEscapeRightTwo(thisGlider);
+ else
+ CheckEscapeRight(thisGlider);
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleRewards
+
+void HandleRewards (gliderPtr thisGlider, hotPtr who)
+{
+ Rect bounds;
+ short whoLinked, points;
+
+ whoLinked = who->who;
+ bounds = who->bounds;
+
+ switch (masterObjects[whoLinked].theObject.what)
+ {
+ case kRedClock:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kBeepsSound, kBeepsPriority);
+ RestoreFromSavedMap(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, false);
+ AddFlyingPoint(&bounds, 100, thisGlider->hVel / 2, thisGlider->vVel / 2);
+ thisGlider->hVel /= 4;
+ thisGlider->vVel /= 4;
+ theScore += kRedClockPoints;
+ RedrawAllGrease();
+ }
+ who->isOn = false;
+ break;
+
+ case kBlueClock:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kBuzzerSound, kBuzzerPriority);
+ RestoreFromSavedMap(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, false);
+ AddFlyingPoint(&bounds, 300, thisGlider->hVel / 2, thisGlider->vVel / 2);
+ thisGlider->hVel /= 4;
+ thisGlider->vVel /= 4;
+ theScore += kBlueClockPoints;
+ RedrawAllGrease();
+ }
+ who->isOn = false;
+ break;
+
+ case kYellowClock:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kDingSound, kDingPriority);
+ RestoreFromSavedMap(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, false);
+ AddFlyingPoint(&bounds, 500, thisGlider->hVel / 2, thisGlider->vVel / 2);
+ thisGlider->hVel /= 4;
+ thisGlider->vVel /= 4;
+ theScore += kYellowClockPoints;
+ RedrawAllGrease();
+ }
+ who->isOn = false;
+ break;
+
+ case kCuckoo:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kCuckooSound, kCuckooPriority);
+ RestoreFromSavedMap(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, false);
+ StopPendulum(thisRoomNumber, masterObjects[whoLinked].objectNum);
+ AddFlyingPoint(&bounds, 1000, thisGlider->hVel / 2, thisGlider->vVel / 2);
+ thisGlider->hVel /= 4;
+ thisGlider->vVel /= 4;
+ theScore += kCuckooClockPoints;
+ RedrawAllGrease();
+ }
+ who->isOn = false;
+ break;
+
+ case kPaper:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kEnergizeSound, kEnergizePriority);
+ RestoreFromSavedMap(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, false);
+ AddSparkle(&bounds);
+ thisGlider->hVel /= 2;
+ thisGlider->vVel /= 2;
+ mortals++;
+ if ((twoPlayerGame) && (!onePlayerLeft))
+ mortals++;
+ QuickGlidersRefresh();
+ RedrawAllGrease();
+ }
+ who->isOn = false;
+ break;
+
+ case kBattery:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kEnergizeSound, kEnergizePriority);
+ RestoreFromSavedMap(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, false);
+ AddSparkle(&bounds);
+ thisGlider->hVel /= 2;
+ thisGlider->vVel /= 2;
+ if (batteryTotal > 0) // positive number means battery power
+ batteryTotal += kBatterySupply;
+ else // negative number means helium gas
+ batteryTotal = kBatterySupply;
+ if ((twoPlayerGame) && (!onePlayerLeft))
+ batteryTotal += kBatterySupply;
+ QuickBatteryRefresh(false);
+ RedrawAllGrease();
+ }
+ who->isOn = false;
+ break;
+
+ case kBands:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kEnergizeSound, kEnergizePriority);
+ RestoreFromSavedMap(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, false);
+ AddSparkle(&bounds);
+ thisGlider->hVel /= 2;
+ thisGlider->vVel /= 2;
+ bandsTotal += kBandsSupply;
+ if ((twoPlayerGame) && (!onePlayerLeft))
+ bandsTotal += kBandsSupply;
+ QuickBandsRefresh(false);
+ RedrawAllGrease();
+ }
+ who->isOn = false;
+ break;
+
+ case kGreaseRt:
+ case kGreaseLf:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ SpillGrease(masterObjects[whoLinked].dynaNum,
+ masterObjects[whoLinked].hotNum);
+ who->isOn = false;
+ break;
+
+ case kFoil:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kEnergizeSound, kEnergizePriority);
+ RestoreFromSavedMap(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, false);
+ AddSparkle(&bounds);
+ thisGlider->hVel /= 2;
+ thisGlider->vVel /= 2;
+ foilTotal += kFoilSupply;
+ if ((twoPlayerGame) && (!onePlayerLeft))
+ foilTotal += kFoilSupply;
+ StartGliderFoilGoing(thisGlider);
+ RedrawAllGrease();
+ }
+ who->isOn = false;
+ break;
+
+ case kInvisBonus:
+ points = masterObjects[whoLinked].theObject.data.c.points;
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kBonusSound, kBonusPriority);
+ AddFlyingPoint(&bounds, points, thisGlider->hVel / 2, thisGlider->vVel / 2);
+ thisGlider->hVel /= 4;
+ thisGlider->vVel /= 4;
+ theScore += points;
+ }
+ who->isOn = false;
+ break;
+
+ case kStar:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kEnergizeSound, kEnergizePriority);
+ RestoreFromSavedMap(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, false);
+ AddSparkle(&bounds);
+ StopStar(thisRoomNumber, masterObjects[whoLinked].objectNum);
+ numStarsRemaining--;
+ if (numStarsRemaining <= 0)
+ FlagGameOver();
+ else
+ DisplayStarsRemaining();
+ RedrawAllGrease();
+ theScore += kStarPoints;
+ }
+ who->isOn = false;
+ break;
+
+ case kSparkle:
+ break;
+
+ case kHelium:
+ if (SetObjectState(thisRoomNumber, masterObjects[whoLinked].objectNum,
+ 0, whoLinked))
+ {
+ PlayPrioritySound(kEnergizeSound, kEnergizePriority);
+ RestoreFromSavedMap(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, false);
+ AddSparkle(&bounds);
+ thisGlider->hVel /= 2;
+ thisGlider->vVel /= 2;
+ if (batteryTotal < 0) // if negative, it is already helium gas
+ batteryTotal -= kHeliumSupply;
+ else // if positive, it is battery power
+ batteryTotal = -kHeliumSupply;
+ if ((twoPlayerGame) && (!onePlayerLeft))
+ batteryTotal -= kHeliumSupply;
+ QuickBatteryRefresh(false);
+ RedrawAllGrease();
+ }
+ who->isOn = false;
+ break;
+
+ case kSlider:
+ break;
+ }
+}
+
+//-------------------------------------------------------------- HandleSwitches
+
+void HandleSwitches (hotPtr who)
+{
+ Rect newRect, bounds;
+ short whoLinked, roomLinked, objectLinked, linkIndex;
+
+ if (who->stillOver)
+ return;
+
+ whoLinked = who->who; // what is switch's obj. #
+ roomLinked = masterObjects[whoLinked].roomLink;
+ objectLinked = masterObjects[whoLinked].objectLink;
+ linkIndex = masterObjects[whoLinked].localLink;
+ // change state of linked obj.
+ if (SetObjectState(roomLinked, objectLinked,
+ masterObjects[whoLinked].theObject.data.e.type, linkIndex))
+ {
+ newRect = who->bounds;
+ QOffsetRect(&newRect, playOriginH, playOriginV);
+ switch (masterObjects[whoLinked].theObject.what)
+ {
+ case kLightSwitch:
+ PlayPrioritySound(kSwitchSound, kSwitchPriority);
+ DrawLightSwitch(&newRect, newState);
+ break;
+
+ case kMachineSwitch:
+ PlayPrioritySound(kSwitchSound, kSwitchPriority);
+ DrawMachineSwitch(&newRect, newState);
+ break;
+
+ case kThermostat:
+ PlayPrioritySound(kSwitchSound, kSwitchPriority);
+ DrawThermostat(&newRect, newState);
+ break;
+
+ case kPowerSwitch:
+ PlayPrioritySound(kSwitchSound, kSwitchPriority);
+ DrawPowerSwitch(&newRect, newState);
+ break;
+
+ case kKnifeSwitch:
+ PlayPrioritySound(kSwitchSound, kSwitchPriority);
+ DrawKnifeSwitch(&newRect, newState);
+ break;
+
+ case kInvisSwitch:
+ break;
+ }
+ CopyRectBackToWork(&newRect);
+ AddRectToWorkRects(&newRect);
+
+ if (linkIndex != -1)
+ {
+ switch (masterObjects[linkIndex].theObject.what)
+ {
+ case kRedClock:
+ case kBlueClock:
+ case kYellowClock:
+ case kPaper:
+ case kBattery:
+ case kBands:
+ case kFoil:
+ case kStar:
+ case kHelium:
+ RestoreFromSavedMap(roomLinked, objectLinked, true);
+ AddSparkle(&bounds);
+ break;
+
+ case kCuckoo:
+ RestoreFromSavedMap(roomLinked, objectLinked, true);
+ StopPendulum(roomLinked, objectLinked);
+ break;
+
+ case kGreaseRt:
+ case kGreaseLf:
+ SpillGrease(masterObjects[linkIndex].dynaNum,
+ masterObjects[linkIndex].hotNum);
+ break;
+
+ case kInvisBonus:
+ case kSlider:
+ break;
+
+ case kDeluxeTrans:
+ break;
+
+ case kSoundTrigger:
+ PlayPrioritySound(kTriggerSound, kTriggerPriority);
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kTrackLight:
+ case kInvisLight:
+ RedrawRoomLighting();
+ break;
+
+ case kShredder:
+ break;
+
+ case kToaster:
+ ToggleToaster(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kMacPlus:
+ ToggleMacPlus(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kGuitar:
+ PlayPrioritySound(kChordSound, kChordPriority);
+ break;
+
+ case kTV:
+ ToggleTV(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kCoffee:
+ ToggleCoffee(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kOutlet:
+ ToggleOutlet(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kVCR:
+ ToggleVCR(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kStereo:
+ ToggleStereos(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kMicrowave:
+ ToggleMicrowave(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kBalloon:
+ ToggleBalloon(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kCopterLf:
+ case kCopterRt:
+ ToggleCopter(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kDartLf:
+ case kDartRt:
+ ToggleDart(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kBall:
+ ToggleBall(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kDrip:
+ ToggleDrip(masterObjects[linkIndex].dynaNum);
+ break;
+
+ case kFish:
+ ToggleFish(masterObjects[linkIndex].dynaNum);
+ break;
+ }
+ }
+ }
+
+ who->stillOver = true;
+}
+
+//-------------------------------------------------------------- HandleMicrowaveAction
+
+void HandleMicrowaveAction (hotPtr who, gliderPtr thisGlider)
+{
+ short whoLinked, kills;
+ Boolean killed;
+
+ if (who->stillOver)
+ return;
+
+ killed = false;
+ whoLinked = who->who; // what is microwave's obj. #
+ if (masterObjects[whoLinked].theObject.data.g.state)
+ {
+ kills = (short)masterObjects[whoLinked].theObject.data.g.byte0;
+ if (((kills & 0x0001) == 0x0001) && (bandsTotal > 0))
+ {
+ bandsTotal = 0;
+ killed = true;
+ QuickBandsRefresh(false);
+ }
+ if (((kills & 0x0002) == 0x0002) && (batteryTotal != 0))
+ {
+ batteryTotal = 0;
+ killed = true;
+ QuickBatteryRefresh(false);
+ }
+ if (((kills & 0x0004) == 0x0004) && (foilTotal > 0))
+ {
+ foilTotal = 0;
+ killed = true;
+ StartGliderFoilLosing(thisGlider);
+ }
+ }
+
+ if (killed)
+ PlayPrioritySound(kMicrowavedSound, kMicrowavedPriority);
+}
+
+//-------------------------------------------------------------- HandleHotSpotCollision
+
+void HandleHotSpotCollision (gliderPtr thisGlider, hotPtr who, short index)
+{
+ switch (who->action)
+ {
+ case kLiftIt:
+ thisGlider->vDesiredVel = kFloorVentLift;
+ break;
+
+ case kDropIt:
+ thisGlider->vDesiredVel = kCeilingVentDrop;
+ break;
+
+ case kPushItLeft:
+ thisGlider->hDesiredVel += -kFanStrength;
+ break;
+
+ case kPushItRight:
+ thisGlider->hDesiredVel += kFanStrength;
+ break;
+
+ case kDissolveIt:
+ if (thisGlider->mode != kGliderFadingOut)
+ {
+ if ((foilTotal > 0) || (thisGlider->mode == kGliderLosingFoil))
+ {
+ if (GliderHitTop(thisGlider, &(who->bounds)))
+ {
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else
+ {
+ if (foilTotal > 0)
+ {
+ foilTotal--;
+ if (foilTotal <= 0)
+ StartGliderFoilLosing(thisGlider);
+ }
+ }
+ }
+ else
+ {
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ }
+ break;
+
+ case kRewardIt:
+ HandleRewards(thisGlider, who);
+ break;
+
+ case kMoveItUp:
+ if (!thisGlider->heldRight && GliderInRect(thisGlider, &who->bounds))
+ {
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if ((twoPlayerGame) && (!onePlayerLeft))
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ if ((thisGlider->mode != kGliderGoingUp) &&
+ (thisGlider->mode != kGliderInLimbo))
+ {
+ otherPlayerEscaped = kPlayerEscapingUpStairs;
+ RefreshScoreboard(kEscapedTitleMode);
+ StartGliderGoingUpStairs(thisGlider);
+ }
+ }
+ else if (otherPlayerEscaped == kPlayerEscapedUpStairs)
+ {
+ if ((thisGlider->mode != kGliderGoingUp) &&
+ (thisGlider->mode != kGliderInLimbo))
+ {
+ StartGliderGoingUpStairs(thisGlider);
+ }
+ }
+ }
+ else
+ StartGliderGoingUpStairs(thisGlider);
+ }
+ break;
+
+ case kMoveItDown:
+ if (!thisGlider->heldLeft && GliderInRect(thisGlider, &who->bounds))
+ {
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if ((twoPlayerGame) && (!onePlayerLeft))
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ if ((thisGlider->mode != kGliderGoingDown) &&
+ (thisGlider->mode != kGliderInLimbo))
+ {
+ otherPlayerEscaped = kPlayerEscapingDownStairs;
+ RefreshScoreboard(kEscapedTitleMode);
+ StartGliderGoingDownStairs(thisGlider);
+ }
+ }
+ else if (otherPlayerEscaped == kPlayerEscapedDownStairs)
+ {
+ if ((thisGlider->mode != kGliderGoingDown) &&
+ (thisGlider->mode != kGliderInLimbo))
+ {
+ StartGliderGoingDownStairs(thisGlider);
+ }
+ }
+ }
+ else
+ StartGliderGoingDownStairs(thisGlider);
+ }
+ break;
+
+ case kSwitchIt:
+ HandleSwitches(who);
+ break;
+
+ case kShredIt:
+ if ((thisGlider->mode != kGliderShredding) &&
+ (GliderInRect(thisGlider, &who->bounds)))
+ {
+ if ((foilTotal > 0) || (thisGlider->mode == kGliderLosingFoil))
+ {
+ PlayPrioritySound(kFoilHitSound, kFoilHitPriority);
+ if (foilTotal > 0)
+ {
+ foilTotal--;
+ if (foilTotal <= 0)
+ StartGliderFoilLosing(thisGlider);
+ }
+ }
+ else
+ FlagGliderShredding(thisGlider, &who->bounds);
+ }
+ break;
+
+ case kStrumIt:
+ if (!who->stillOver)
+ {
+ PlayPrioritySound(kChordSound, kChordPriority);
+ who->stillOver = true;
+ }
+ break;
+
+ case kTriggerIt:
+ case kLgTrigger:
+ ArmTrigger(who);
+ break;
+
+ case kBurnIt:
+ if ((thisGlider->mode != kGliderBurning) &&
+ (thisGlider->mode != kGliderFadingOut))
+ {
+ if ((foilTotal > 0) || (thisGlider->mode == kGliderLosingFoil))
+ {
+ thisGlider->vDesiredVel = kFloorVentLift;
+ if (foilTotal > 0)
+ {
+ PlayPrioritySound(kSizzleSound, kSizzlePriority);
+ foilTotal--;
+ if (foilTotal <= 0)
+ StartGliderFoilLosing(thisGlider);
+ }
+ }
+ else
+ FlagGliderBurning(thisGlider);
+ }
+ break;
+
+ case kSlideIt:
+ thisGlider->sliding = true;
+ thisGlider->vVel = who->bounds.top - thisGlider->dest.bottom;
+ break;
+
+ case kTransportIt:
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if ((GliderInRect(thisGlider, &who->bounds)) &&
+ (thisGlider->mode != kGliderTransporting) &&
+ (thisGlider->mode != kGliderFadingOut))
+ {
+ if ((twoPlayerGame) && (!onePlayerLeft))
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ if (thisGlider->mode != kGliderInLimbo)
+ {
+ activeRectEscaped = index;
+ StartGliderTransporting(thisGlider, who);
+ }
+ }
+ else if (otherPlayerEscaped == kPlayerTransportedOut)
+ {
+ if ((thisGlider->mode != kGliderInLimbo) &&
+ (activeRectEscaped == index))
+ {
+ StartGliderTransporting(thisGlider, who);
+ }
+ }
+ }
+ else
+ StartGliderTransporting(thisGlider, who);
+ }
+ break;
+
+ case kIgnoreLeftWall:
+ thisGlider->ignoreLeft = true;
+ break;
+
+ case kIgnoreRightWall:
+ thisGlider->ignoreRight = true;
+ break;
+
+ case kMailItLeft: // mailbox open to right
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if ((GliderInRect(thisGlider, &who->bounds)) &&
+ (thisGlider->mode != kGliderMailOutRight) &&
+ (thisGlider->mode != kGliderMailInLeft) &&
+ (thisGlider->mode != kGliderFadingOut) &&
+ (((thisGlider->facing == kFaceRight) && (!thisGlider->tipped)) ||
+ ((thisGlider->facing == kFaceLeft) && (thisGlider->tipped))))
+ {
+ if ((twoPlayerGame) && (!onePlayerLeft)) // two gliders to handle
+ {
+ if (otherPlayerEscaped == kNoOneEscaped) // other glider in room
+ {
+ if (thisGlider->mode != kGliderInLimbo) // this glider is active
+ {
+ activeRectEscaped = index;
+ StartGliderMailingIn(thisGlider, &who->bounds, who);
+ thisGlider->mode = kGliderMailInLeft;
+ }
+ }
+ else if (otherPlayerEscaped == kPlayerMailedOut)
+ { // other glider left here
+ if ((thisGlider->mode != kGliderInLimbo) &&
+ (activeRectEscaped == index))
+ { // []_ <--G
+ StartGliderMailingIn(thisGlider, &who->bounds, who);
+ thisGlider->mode = kGliderMailInLeft;
+ }
+ }
+ }
+ else // only 1 glider in game
+ {
+ StartGliderMailingIn(thisGlider, &who->bounds, who);
+ thisGlider->mode = kGliderMailInLeft;
+ }
+ }
+ break;
+
+ case kMailItRight: // mailbox open to left
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if ((GliderInRect(thisGlider, &who->bounds)) &&
+ (thisGlider->mode != kGliderMailOutLeft) &&
+ (thisGlider->mode != kGliderMailInRight) &&
+ (thisGlider->mode != kGliderFadingOut) &&
+ (((thisGlider->facing == kFaceRight) && (thisGlider->tipped)) ||
+ ((thisGlider->facing == kFaceLeft) && (!thisGlider->tipped))))
+ {
+ if ((twoPlayerGame) && (!onePlayerLeft))
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ if (thisGlider->mode != kGliderInLimbo)
+ {
+ activeRectEscaped = index;
+ StartGliderMailingIn(thisGlider, &who->bounds, who);
+ thisGlider->mode = kGliderMailInRight;
+ }
+ }
+ else if (otherPlayerEscaped == kPlayerMailedOut)
+ {
+ if ((thisGlider->mode != kGliderInLimbo) &&
+ (activeRectEscaped == index))
+ {
+ StartGliderMailingIn(thisGlider, &who->bounds, who);
+ thisGlider->mode = kGliderMailInRight;
+ }
+ }
+ }
+ else
+ {
+ StartGliderMailingIn(thisGlider, &who->bounds, who);
+ thisGlider->mode = kGliderMailInRight;
+ }
+ }
+ break;
+
+ case kDuctItDown:
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if ((GliderInRect(thisGlider, &who->bounds)) &&
+ (thisGlider->mode != kGliderDuctingDown) &&
+ (thisGlider->mode != kGliderFadingOut))
+ {
+ if ((twoPlayerGame) && (!onePlayerLeft))
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ if (thisGlider->mode != kGliderInLimbo)
+ {
+ activeRectEscaped = index;
+ StartGliderDuctingDown(thisGlider, &who->bounds, who);
+ }
+ }
+ else if (otherPlayerEscaped == kPlayerDuckedOut)
+ {
+ if ((thisGlider->mode != kGliderInLimbo) &&
+ (activeRectEscaped == index))
+ StartGliderDuctingDown(thisGlider, &who->bounds, who);
+ }
+ }
+ else
+ StartGliderDuctingDown(thisGlider, &who->bounds, who);
+ }
+ break;
+
+ case kDuctItUp:
+ if (thisGlider->mode == kGliderBurning)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ else if ((GliderInRect(thisGlider, &who->bounds)) &&
+ (thisGlider->mode != kGliderDuctingUp) &&
+ (thisGlider->mode != kGliderDuctingIn) &&
+ (thisGlider->mode != kGliderFadingOut) &&
+ (!who->stillOver))
+ {
+ if ((twoPlayerGame) && (!onePlayerLeft))
+ {
+ if (otherPlayerEscaped == kNoOneEscaped)
+ {
+ if (thisGlider->mode != kGliderInLimbo)
+ {
+ activeRectEscaped = index;
+ StartGliderDuctingUp(thisGlider, &who->bounds, who);
+ }
+ }
+ else if (otherPlayerEscaped == kPlayerDuckedOut)
+ {
+ if ((thisGlider->mode != kGliderInLimbo) &&
+ (activeRectEscaped == index))
+ StartGliderDuctingUp(thisGlider, &who->bounds, who);
+ }
+ }
+ else
+ {
+ StartGliderDuctingUp(thisGlider, &who->bounds, who);
+ who->stillOver = true;
+ }
+ }
+ break;
+
+ case kMicrowaveIt:
+ if (GliderInRect(thisGlider, &who->bounds))
+ HandleMicrowaveAction(who, thisGlider);
+ break;
+
+ case kIgnoreGround:
+ thisGlider->ignoreGround = true;
+ break;
+
+ case kBounceIt:
+ BounceGlider(thisGlider, &who->bounds);
+ break;
+
+ case kChimeIt:
+ if (!who->stillOver)
+ {
+ StrikeChime();
+ who->stillOver = true;
+ }
+ break;
+
+ case kWebIt:
+ if ((GliderInRect(thisGlider, &who->bounds)) &&
+ (thisGlider->mode != kGliderBurning))
+ WebGlider(thisGlider, &who->bounds);
+ else if ((thisGlider->mode == kGliderBurning) &&
+ (GliderInRect(thisGlider, &who->bounds)))
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ break;
+
+ case kSoundIt:
+ if (!who->stillOver)
+ {
+ PlayPrioritySound(kTriggerSound, kTriggerPriority);
+ who->stillOver = true;
+ }
+ break;
+ }
+}
+
+//-------------------------------------------------------------- CheckForHotSpots
+
+void CheckForHotSpots (void)
+{
+ short i;
+ Boolean hitObject;
+
+ for (i = 0; i < nHotSpots; i++)
+ {
+ if (hotSpots[i].isOn)
+ {
+ if (twoPlayerGame)
+ {
+ hitObject = false;
+ if (SectGlider(&theGlider, &hotSpots[i].bounds,
+ hotSpots[i].doScrutinize))
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == kPlayer2)
+ {
+ HandleHotSpotCollision(&theGlider, &hotSpots[i], i);
+ hitObject = true;
+ }
+ }
+ else
+ {
+ HandleHotSpotCollision(&theGlider, &hotSpots[i], i);
+ hitObject = true;
+ }
+ }
+
+ if (SectGlider(&theGlider2, &hotSpots[i].bounds,
+ hotSpots[i].doScrutinize))
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == kPlayer1)
+ {
+ HandleHotSpotCollision(&theGlider2, &hotSpots[i], i);
+ hitObject = true;
+ }
+ }
+ else
+ {
+ HandleHotSpotCollision(&theGlider2, &hotSpots[i], i);
+ hitObject = true;
+ }
+ }
+ if (!hitObject)
+ hotSpots[i].stillOver = false;
+ }
+ else
+ {
+ if (SectGlider(&theGlider, &hotSpots[i].bounds,
+ hotSpots[i].doScrutinize))
+ HandleHotSpotCollision(&theGlider, &hotSpots[i], i);
+ else
+ hotSpots[i].stillOver = false;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- HandleInteraction
+
+void HandleInteraction (void)
+{
+ CheckForHotSpots();
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == kPlayer1)
+ CheckGliderInRoom(&theGlider2);
+ else
+ CheckGliderInRoom(&theGlider);
+ }
+ else
+ {
+ CheckGliderInRoom(&theGlider);
+ CheckGliderInRoom(&theGlider2);
+ }
+ }
+ else
+ CheckGliderInRoom(&theGlider);
+}
+
+//-------------------------------------------------------------- FlagStillOvers
+
+void FlagStillOvers (gliderPtr thisGlider)
+{
+ short i;
+
+ for (i = 0; i < nHotSpots; i++)
+ {
+ if (hotSpots[i].isOn)
+ {
+ if (SectGlider(thisGlider, &hotSpots[i].bounds,
+ hotSpots[i].doScrutinize))
+ hotSpots[i].stillOver = true;
+ else
+ hotSpots[i].stillOver = false;
+ }
+ else
+ hotSpots[i].stillOver = false;
+ }
+}
+
+//-------------------------------------------------------------- WebGlider
+
+void WebGlider (gliderPtr thisGlider, Rect *webBounds)
+{
+ #define kKillWebbedGlider 150
+ short hDist, vDist;
+
+ if ((thisGlider->mode == kGliderBurning) && (GliderInRect(thisGlider, webBounds)))
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ return;
+ }
+
+ hDist = ((webBounds->right - thisGlider->dest.right) +
+ (webBounds->left - thisGlider->dest.left)) >> 3;
+ vDist = ((webBounds->bottom - thisGlider->dest.bottom) +
+ (webBounds->top - thisGlider->dest.top)) >> 3;
+
+ if (thisGlider->hDesiredVel != 0)
+ {
+ if (evenFrame)
+ {
+ thisGlider->hVel = hDist;
+ thisGlider->vVel = vDist;
+ PlayPrioritySound(kWebTwangSound, kWebTwangPriority);
+ }
+ }
+ else
+ {
+ thisGlider->hDesiredVel = 0;
+ thisGlider->vDesiredVel = 0;
+ }
+
+ thisGlider->wasMode++;
+ if (thisGlider->wasMode >= kKillWebbedGlider)
+ {
+ thisGlider->wasMode = 0;
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+}
+
diff --git a/GpApp/InterfaceInit.cpp b/GpApp/InterfaceInit.cpp
new file mode 100644
index 0000000..0ca097c
--- /dev/null
+++ b/GpApp/InterfaceInit.cpp
@@ -0,0 +1,220 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// InterfaceInit.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Environ.h"
+#include "Map.h"
+#include "RectUtils.h"
+#include "Tools.h"
+
+
+#define kHandCursorID 128
+#define kVertCursorID 129
+#define kHoriCursorID 130
+#define kDiagCursorID 131
+
+
+extern RgnHandle mirrorRgn;
+extern WindowPtr mapWindow, toolsWindow, linkWindow;
+extern WindowPtr menuWindow;
+extern Rect shieldRect, boardSrcRect, localRoomsDest[];
+extern CursHandle handCursorH, beamCursorH, vertCursorH, horiCursorH;
+extern CursHandle diagCursorH;
+extern Cursor handCursor, beamCursor, vertCursor, horiCursor;
+extern Cursor diagCursor;
+extern MenuHandle appleMenu, gameMenu, optionsMenu, houseMenu;
+extern Point shieldPt;
+extern long incrementModeTime;
+extern UInt32 doubleTime;
+extern short fadeInSequence[], idleMode;
+extern short toolSelected, lastBackground, wasFlower, numExtraHouses;
+extern short houseResFork, lastHighScore, maxFiles, willMaxFiles;
+extern Boolean quitting, playing, fadeGraysOut;
+extern Boolean houseOpen, newRoomNow, evenFrame, menusUp, demoGoing;
+extern Boolean twoPlayerGame, paused, hasMirror, splashDrawn;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- InitializeMenus
+
+// The menus are loaded from disk and the menu bar set up and drawn.
+
+void InitializeMenus (void)
+{
+ appleMenu = GetMenu(kAppleMenuID);
+ if (appleMenu == nil)
+ RedAlert(kErrFailedResourceLoad);
+ AppendResMenu(appleMenu, 'DRVR');
+ InsertMenu(appleMenu, 0);
+
+ gameMenu = GetMenu(kGameMenuID);
+ if (gameMenu == nil)
+ RedAlert(kErrFailedResourceLoad);
+ InsertMenu(gameMenu, 0);
+
+ optionsMenu = GetMenu(kOptionsMenuID);
+ if (optionsMenu == nil)
+ RedAlert(kErrFailedResourceLoad);
+ InsertMenu(optionsMenu, 0);
+
+ menusUp = true;
+ DrawMenuBar();
+
+ houseMenu = GetMenu(kHouseMenuID);
+ if (houseMenu == nil)
+ RedAlert(kErrFailedResourceLoad);
+
+ UpdateMenus(false);
+}
+
+//-------------------------------------------------------------- GetExtraCursors
+
+// Extra cursors (custom cursors) like the "hand" and various roomÉ
+// editing cursors are loaded up.
+
+void GetExtraCursors (void)
+{
+ handCursorH = GetCursor(kHandCursorID);
+ if (handCursorH == nil)
+ RedAlert(kErrFailedResourceLoad);
+ HLock((Handle)handCursorH);
+ handCursor = **handCursorH;
+
+ beamCursorH = GetCursor(iBeamCursor);
+ if (beamCursorH == nil)
+ RedAlert(kErrFailedResourceLoad);
+ HLock((Handle)beamCursorH);
+ beamCursor = **beamCursorH;
+
+ vertCursorH = GetCursor(kVertCursorID);
+ if (vertCursorH == nil)
+ RedAlert(kErrFailedResourceLoad);
+ HLock((Handle)vertCursorH);
+ vertCursor = **vertCursorH;
+
+ horiCursorH = GetCursor(kHoriCursorID);
+ if (horiCursorH == nil)
+ RedAlert(kErrFailedResourceLoad);
+ HLock((Handle)horiCursorH);
+ horiCursor = **horiCursorH;
+
+ diagCursorH = GetCursor(kDiagCursorID);
+ if (diagCursorH == nil)
+ RedAlert(kErrFailedResourceLoad);
+ HLock((Handle)diagCursorH);
+ diagCursor = **diagCursorH;
+}
+
+//-------------------------------------------------------------- VariableInit
+
+// All the simple interface variables are intialized here - Booleans,É
+// shorts, a few Rects, etc.
+
+void VariableInit (void)
+{
+ short i;
+
+ shieldPt.h = 0;
+ shieldPt.v = 0;
+ shieldRect = thisMac.screen;
+
+ menusUp = false;
+ quitting = false;
+ houseOpen = false;
+ newRoomNow = false;
+ playing = false;
+ evenFrame = false;
+ if (thisMac.isDepth == 8)
+ fadeGraysOut = true;
+ else
+ fadeGraysOut = false;
+ twoPlayerGame = false;
+ paused = false;
+ hasMirror = false;
+ demoGoing = false;
+// scrapIsARoom = true;
+ splashDrawn = false;
+
+#ifndef COMPILEDEMO
+// SeeIfValidScrapAvailable(false);
+#endif
+
+ theGlider.which = kPlayer1;
+ theGlider2.leftKey = kControlKeyMap;
+ theGlider2.rightKey = kCommandKeyMap;
+ theGlider2.battKey = kOptionKeyMap;
+ theGlider2.bandKey = kShiftKeyMap;
+ theGlider2.which = kPlayer2;
+
+ theMode = kSplashMode;
+ thisRoomNumber = 0;
+ previousRoom = -1;
+ toolSelected = kSelectTool;
+ houseResFork = -1;
+ lastBackground = kBaseBackgroundID;
+ wasFlower = RandomInt(kNumFlowers);
+ lastHighScore = -1;
+ idleMode = kIdleSplashMode;
+ incrementModeTime = TickCount() + kIdleSplashTicks;
+ willMaxFiles = maxFiles;
+ numExtraHouses = 0;
+
+ fadeInSequence[0] = 4; // 4
+ fadeInSequence[1] = 5;
+ fadeInSequence[2] = 6;
+ fadeInSequence[3] = 7;
+ fadeInSequence[4] = 5; // 5
+ fadeInSequence[5] = 6;
+ fadeInSequence[6] = 7;
+ fadeInSequence[7] = 8;
+ fadeInSequence[8] = 6; // 6
+ fadeInSequence[9] = 7;
+ fadeInSequence[10] = 8;
+ fadeInSequence[11] = 9;
+ fadeInSequence[12] = 7; // 7
+ fadeInSequence[13] = 8;
+ fadeInSequence[14] = 9;
+ fadeInSequence[15] = 10;
+
+ doubleTime = GetDblTime();
+
+ mirrorRgn = nil;
+ mainWindow = nil;
+ mapWindow = nil;
+ toolsWindow = nil;
+ linkWindow = nil;
+ coordWindow = nil;
+ toolSrcMap = nil;
+ nailSrcMap = nil;
+ menuWindow = nil;
+
+ houseRect = thisMac.screen;
+ houseRect.bottom -= kScoreboardTall;
+ if (houseRect.right > kMaxViewWidth)
+ houseRect.right = kMaxViewWidth;
+ if (houseRect.bottom > kMaxViewHeight)
+ houseRect.bottom = kMaxViewHeight;
+
+ playOriginH = (RectWide(&thisMac.screen) - kRoomWide) / 2;
+ playOriginV = (RectTall(&thisMac.screen) - kTileHigh) / 2;
+
+ for (i = 0; i < 9; i++)
+ {
+ QSetRect(&localRoomsDest[i], 0, 0, kRoomWide, kTileHigh);
+ QOffsetRect(&localRoomsDest[i], playOriginH, playOriginV);
+ }
+ QOffsetRect(&localRoomsDest[kNorthRoom], 0, -kVertLocalOffset);
+ QOffsetRect(&localRoomsDest[kNorthEastRoom], kRoomWide, -kVertLocalOffset);
+ QOffsetRect(&localRoomsDest[kEastRoom], kRoomWide, 0);
+ QOffsetRect(&localRoomsDest[kSouthEastRoom], kRoomWide, kVertLocalOffset);
+ QOffsetRect(&localRoomsDest[kSouthRoom], 0, kVertLocalOffset);
+ QOffsetRect(&localRoomsDest[kSouthWestRoom], -kRoomWide, kVertLocalOffset);
+ QOffsetRect(&localRoomsDest[kWestRoom], -kRoomWide, 0);
+ QOffsetRect(&localRoomsDest[kNorthWestRoom], -kRoomWide, -kVertLocalOffset);
+}
+
diff --git a/GpApp/Link.cpp b/GpApp/Link.cpp
new file mode 100644
index 0000000..0bb9171
--- /dev/null
+++ b/GpApp/Link.cpp
@@ -0,0 +1,397 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Link.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+#include "PLControlDefinitions.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "ObjectEdit.h"
+#include "RectUtils.h"
+
+
+#define kLinkControlID 130
+#define kUnlinkControlID 131
+
+
+void DoLink (void);
+void DoUnlink (void);
+
+
+Rect linkWindowRect;
+ControlHandle linkControl, unlinkControl;
+WindowPtr linkWindow;
+short isLinkH, isLinkV, linkRoom, linkType;
+Byte linkObject;
+Boolean isLinkOpen, linkerIsSwitch;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- MergeFloorSuite
+
+short MergeFloorSuite (short floor, short suite)
+{
+ return ((suite * 100) + floor);
+}
+
+//-------------------------------------------------------------- ExtractFloorSuite
+
+void ExtractFloorSuite (short combo, short *floor, short *suite)
+{
+ if ((*thisHouse)->version < 0x0200) // old floor/suite combo
+ {
+ *floor = (combo / 100) - kNumUndergroundFloors;
+ *suite = combo % 100;
+ }
+ else
+ {
+ *suite = combo / 100;
+ *floor = (combo % 100) - kNumUndergroundFloors;
+ }
+}
+
+//-------------------------------------------------------------- UpdateLinkControl
+
+void UpdateLinkControl (void)
+{
+#ifndef COMPILEDEMO
+ if (linkWindow == nil)
+ return;
+
+ switch (linkType)
+ {
+ case kSwitchLinkOnly:
+ if (objActive == kNoObjectSelected)
+ HiliteControl(linkControl, kControlInactive);
+ else
+ switch (thisRoom->objects[objActive].what)
+ {
+ case kFloorVent:
+ case kCeilingVent:
+ case kFloorBlower:
+ case kCeilingBlower:
+ case kSewerGrate:
+ case kLeftFan:
+ case kRightFan:
+ case kInvisBlower:
+ case kGrecoVent:
+ case kSewerBlower:
+ case kLiftArea:
+ case kRedClock:
+ case kBlueClock:
+ case kYellowClock:
+ case kCuckoo:
+ case kPaper:
+ case kBattery:
+ case kBands:
+ case kFoil:
+ case kInvisBonus:
+ case kHelium:
+ case kDeluxeTrans:
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kTrackLight:
+ case kInvisLight:
+ case kShredder:
+ 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:
+ HiliteControl(linkControl, kControlActive);
+ break;
+
+ default:
+ HiliteControl(linkControl, kControlInactive);
+ break;
+ }
+ break;
+
+ case kTriggerLinkOnly:
+ if (objActive == kNoObjectSelected)
+ HiliteControl(linkControl, kControlInactive);
+ else
+ switch (thisRoom->objects[objActive].what)
+ {
+ case kGreaseRt:
+ case kGreaseLf:
+ case kToaster:
+ case kGuitar:
+ case kCoffee:
+ case kOutlet:
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kDartLf:
+ case kDartRt:
+ case kDrip:
+ case kFish:
+ HiliteControl(linkControl, kControlActive);
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ if (linkRoom == thisRoomNumber)
+ HiliteControl(linkControl, kControlActive);
+ break;
+
+ default:
+ HiliteControl(linkControl, kControlInactive);
+ break;
+ }
+ break;
+
+ case kTransportLinkOnly:
+ if (objActive == kNoObjectSelected)
+ HiliteControl(linkControl, kControlInactive);
+ else
+ switch (thisRoom->objects[objActive].what)
+ {
+ case kMailboxLf:
+ case kMailboxRt:
+ case kCeilingTrans:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ case kInvisLight:
+ case kOzma:
+ case kMirror:
+ case kFireplace:
+ case kWallWindow:
+ case kCalendar:
+ case kBulletin:
+ case kCloud:
+ HiliteControl(linkControl, kControlActive);
+ break;
+
+ default:
+ HiliteControl(linkControl, kControlInactive);
+ break;
+ }
+ break;
+ }
+#endif
+}
+
+//-------------------------------------------------------------- UpdateLinkWindow
+
+void UpdateLinkWindow (void)
+{
+#ifndef COMPILEDEMO
+ if (linkWindow == nil)
+ return;
+
+ SetPortWindowPort(linkWindow);
+ DrawControls(linkWindow);
+ UpdateLinkControl();
+#endif
+}
+
+//-------------------------------------------------------------- OpenLinkWindow
+
+void OpenLinkWindow (void)
+{
+#ifndef COMPILEDEMO
+ Rect src, dest;
+ Point globalMouse;
+
+ if (linkWindow == nil)
+ {
+ QSetRect(&linkWindowRect, 0, 0, 129, 30);
+ if (thisMac.hasColor)
+ linkWindow = NewCWindow(nil, &linkWindowRect,
+ PSTR("Link"), false, kWindoidWDEF, kPutInFront, true, 0L);
+ else
+ linkWindow = NewWindow(nil, &linkWindowRect,
+ PSTR("Link"), false, kWindoidWDEF, kPutInFront, true, 0L);
+
+ MoveWindow(linkWindow, isLinkH, isLinkV, true);
+ globalMouse = MyGetGlobalMouse();
+ QSetRect(&src, 0, 0, 1, 1);
+ QOffsetRect(&src, globalMouse.h, globalMouse.v);
+ GetWindowRect(linkWindow, &dest);
+ BringToFront(linkWindow);
+ ShowHide(linkWindow, true);
+// FlagWindowFloating(linkWindow); TEMP - use flaoting windows
+ HiliteAllWindows();
+
+ linkControl = GetNewControl(kLinkControlID, linkWindow);
+ if (linkControl == nil)
+ RedAlert(kErrFailedResourceLoad);
+
+ unlinkControl = GetNewControl(kUnlinkControlID, linkWindow);
+ if (unlinkControl == nil)
+ RedAlert(kErrFailedResourceLoad);
+
+ linkRoom = -1;
+ linkObject = 255;
+
+ isLinkOpen = true;
+ }
+#endif
+}
+
+//-------------------------------------------------------------- CloseLinkWindow
+
+void CloseLinkWindow (void)
+{
+#ifndef COMPILEDEMO
+ if (linkWindow != nil)
+ DisposeWindow(linkWindow);
+
+ linkWindow = nil;
+ isLinkOpen = false;
+#endif
+}
+
+//-------------------------------------------------------------- DoLink
+
+#ifndef COMPILEDEMO
+void DoLink (void)
+{
+ short floor, suite;
+ char wasState;
+
+ if (GetRoomFloorSuite(thisRoomNumber, &floor, &suite))
+ {
+ floor += kNumUndergroundFloors;
+ if (thisRoomNumber == linkRoom)
+ {
+ if (linkerIsSwitch)
+ {
+ thisRoom->objects[linkObject].data.e.where =
+ MergeFloorSuite(floor, suite);
+ thisRoom->objects[linkObject].data.e.who =
+ objActive;
+ }
+ else
+ {
+ thisRoom->objects[linkObject].data.d.where =
+ MergeFloorSuite(floor, suite);
+ thisRoom->objects[linkObject].data.d.who =
+ objActive;
+ }
+ }
+ else
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ if (linkerIsSwitch)
+ {
+ (*thisHouse)->rooms[linkRoom].objects[linkObject].data.e.where =
+ MergeFloorSuite(floor, suite);
+ (*thisHouse)->rooms[linkRoom].objects[linkObject].data.e.who =
+ objActive;
+ }
+ else // linker is transport
+ {
+ (*thisHouse)->rooms[linkRoom].objects[linkObject].data.d.where =
+ MergeFloorSuite(floor, suite);
+ (*thisHouse)->rooms[linkRoom].objects[linkObject].data.d.who =
+ objActive;
+ }
+ HSetState((Handle)thisHouse, wasState);
+ }
+ fileDirty = true;
+ UpdateMenus(false);
+ CloseLinkWindow();
+ }
+}
+#endif
+
+//-------------------------------------------------------------- DoUnlink
+
+#ifndef COMPILEDEMO
+void DoUnlink (void)
+{
+ char wasState;
+
+ if (thisRoomNumber == linkRoom)
+ {
+ if (linkerIsSwitch)
+ {
+ thisRoom->objects[linkObject].data.e.where = -1;
+ thisRoom->objects[linkObject].data.e.who = 255;
+ }
+ else
+ {
+ thisRoom->objects[linkObject].data.d.where = -1;
+ thisRoom->objects[linkObject].data.d.who = 255;
+ }
+ }
+ else
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ if (linkerIsSwitch)
+ {
+ (*thisHouse)->rooms[linkRoom].objects[linkObject].data.e.where = -1;
+ (*thisHouse)->rooms[linkRoom].objects[linkObject].data.e.who = 255;
+ }
+ else
+ {
+ (*thisHouse)->rooms[linkRoom].objects[linkObject].data.d.where = -1;
+ (*thisHouse)->rooms[linkRoom].objects[linkObject].data.d.who = 255;
+ }
+ HSetState((Handle)thisHouse, wasState);
+ }
+ fileDirty = true;
+ UpdateMenus(false);
+ CloseLinkWindow();
+}
+#endif
+
+//-------------------------------------------------------------- HandleLinkClick
+
+void HandleLinkClick (Point wherePt)
+{
+#ifndef COMPILEDEMO
+ ControlHandle theControl;
+ short part;
+
+ if (linkWindow == nil)
+ return;
+
+ SetPortWindowPort(linkWindow);
+ GlobalToLocal(&wherePt);
+
+ part = FindControl(wherePt, linkWindow, &theControl);
+ if ((theControl != nil) && (part != 0))
+ {
+ part = TrackControl(theControl, wherePt, nil);
+ if (part != 0)
+ {
+ if (theControl == linkControl)
+ DoLink();
+ else if (theControl == unlinkControl)
+ DoUnlink();
+
+ if (thisRoomNumber == linkRoom)
+ CopyThisRoomToRoom();
+ GenerateRetroLinks();
+ }
+ }
+#endif
+}
+
diff --git a/GpApp/Main.cpp b/GpApp/Main.cpp
new file mode 100644
index 0000000..2abae42
--- /dev/null
+++ b/GpApp/Main.cpp
@@ -0,0 +1,389 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Glider PRO 1.0.4
+// by john calhoun
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLApplication.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "House.h"
+
+
+#define kPrefsVersion 0x0034
+
+
+void ReadInPrefs (void);
+void WriteOutPrefs (void);
+int main(int argc, const char **argv);
+
+
+short isVolume, wasVolume;
+short isDepthPref, dataResFile, numSMWarnings;
+Boolean quitting, doZooms, quickerTransitions, isUseSecondScreen;
+
+
+extern Str31 highBanner;
+extern Str15 leftName, rightName, batteryName, bandName;
+extern Str15 highName;
+//extern long encryptedNumber;
+extern short maxFiles, numNeighbors, houseRefNum, willMaxFiles;
+extern short isEditH, isEditV, isMapH, isMapV;
+extern short isToolsH, isToolsV, isCoordH, isCoordV;
+extern short isLinkH, isLinkV, toolMode, mapLeftRoom, mapTopRoom;
+extern short mapRoomsWide, mapRoomsHigh, wasFloor, wasSuite;
+extern Boolean isMusicOn, isSoundOn, isPlayMusicIdle, isHouseChecks;
+extern Boolean houseOpen, isDoColorFade, isEscPauseKey;
+extern Boolean autoRoomEdit, doAutoDemo, doBackground;
+extern Boolean isMapOpen, isToolsOpen, isCoordOpen;
+extern Boolean doPrettyMap, doBitchDialogs;
+//extern Boolean didValidation;
+
+//============================================================== Functions
+//-------------------------------------------------------------- ReadInPrefs
+
+// Called only once when game launches - reads in the preferences savedÉ
+// from the last time Glider PRO was launched. If no prefs are found,É
+// it assigns default settings.
+
+void ReadInPrefs (void)
+{
+ prefsInfo thePrefs;
+
+ if (LoadPrefs(&thePrefs, kPrefsVersion))
+ {
+#ifdef COMPILEDEMO
+ PasStringCopy("\pDemo House", thisHouseName);
+#else
+ PasStringCopy(thePrefs.wasDefaultName, thisHouseName);
+#endif
+ PasStringCopy(thePrefs.wasLeftName, leftName);
+ PasStringCopy(thePrefs.wasRightName, rightName);
+ PasStringCopy(thePrefs.wasBattName, batteryName);
+ PasStringCopy(thePrefs.wasBandName, bandName);
+ PasStringCopy(thePrefs.wasHighName, highName);
+ PasStringCopy(thePrefs.wasHighBanner, highBanner);
+ theGlider.leftKey = thePrefs.wasLeftMap;
+ theGlider.rightKey = thePrefs.wasRightMap;
+ theGlider.battKey = thePrefs.wasBattMap;
+ theGlider.bandKey = thePrefs.wasBandMap;
+#ifndef COMPILEDEMO
+#ifndef COMPILENOCP
+ encryptedNumber = thePrefs.encrypted;
+#endif // COMPILENOCP
+#endif // COMPILEDEMO
+ isVolume = thePrefs.wasVolume;
+ isDepthPref = thePrefs.wasDepthPref;
+ isMusicOn = thePrefs.wasMusicOn;
+ doZooms = thePrefs.wasZooms;
+ quickerTransitions = thePrefs.wasQuickTrans;
+ isDoColorFade = thePrefs.wasDoColorFade;
+ isPlayMusicIdle = thePrefs.wasIdleMusic;
+ isPlayMusicGame = thePrefs.wasGameMusic;
+ isHouseChecks = thePrefs.wasHouseChecks;
+ maxFiles = thePrefs.wasMaxFiles;
+ if ((maxFiles < 12) || (maxFiles > 500))
+ maxFiles = 12;
+ isEditH = thePrefs.wasEditH;
+ isEditV = thePrefs.wasEditV;
+ isMapH = thePrefs.wasMapH;
+ isMapV = thePrefs.wasMapV;
+ mapRoomsWide = thePrefs.wasMapWide;
+ mapRoomsHigh = thePrefs.wasMapHigh;
+ isToolsH = thePrefs.wasToolsH;
+ isToolsV = thePrefs.wasToolsV;
+ isLinkH = thePrefs.wasLinkH;
+ isLinkV = thePrefs.wasLinkV;
+ isCoordH = thePrefs.wasCoordH;
+ isCoordV = thePrefs.wasCoordV;
+ mapLeftRoom = thePrefs.isMapLeft;
+ mapTopRoom = thePrefs.isMapTop;
+ wasFloor = thePrefs.wasFloor;
+ wasSuite = thePrefs.wasSuite;
+ numSMWarnings = thePrefs.smWarnings;
+ autoRoomEdit = thePrefs.wasAutoEdit;
+ isMapOpen = thePrefs.wasMapOpen;
+ isToolsOpen = thePrefs.wasToolsOpen;
+ isCoordOpen = thePrefs.wasCoordOpen;
+ numNeighbors = thePrefs.wasNumNeighbors;
+ toolMode = thePrefs.wasToolGroup;
+ doAutoDemo = thePrefs.wasDoAutoDemo;
+ isEscPauseKey = thePrefs.wasEscPauseKey;
+ isUseSecondScreen = thePrefs.wasScreen2;
+ if (thisMac.numScreens < 2)
+ isUseSecondScreen = false;
+ doBackground = thePrefs.wasDoBackground;
+ doPrettyMap = thePrefs.wasPrettyMap;
+ doBitchDialogs = thePrefs.wasBitchDialogs;
+ }
+ else
+ {
+#ifdef COMPILEDEMO
+ PasStringCopy("\pDemo House", thisHouseName);
+#else
+ PasStringCopy(PSTR("Slumberland"), thisHouseName);
+#endif
+ PasStringCopy(PSTR("lf arrow"), leftName);
+ PasStringCopy(PSTR("rt arrow"), rightName);
+ PasStringCopy(PSTR("dn arrow"), batteryName);
+ PasStringCopy(PSTR("up arrow"), bandName);
+ PasStringCopy(PSTR("Your Name"), highName);
+ PasStringCopy(PSTR("Your Message Here"), highBanner);
+ theGlider.leftKey = kLeftArrowKeyMap;
+ theGlider.rightKey = kRightArrowKeyMap;
+ theGlider.battKey = kDownArrowKeyMap;
+ theGlider.bandKey = kUpArrowKeyMap;
+
+ UnivGetSoundVolume(&isVolume, thisMac.hasSM3);
+ if (isVolume < 1)
+ isVolume = 1;
+ else if (isVolume > 3)
+ isVolume = 3;
+
+ isDepthPref = kSwitchIfNeeded;
+ isSoundOn = true;
+ isMusicOn = true;
+ isPlayMusicIdle = true;
+ isPlayMusicGame = true;
+ isHouseChecks = true;
+ doZooms = true;
+ quickerTransitions = false;
+ numNeighbors = 9;
+ isDoColorFade = true;
+ maxFiles = 48;
+ willMaxFiles = 48;
+ isEditH = 3;
+ isEditV = 41;
+ isMapH = 3;
+// isMapV = qd.screenBits.bounds.bottom - 100;
+ isMapV = 100;
+ mapRoomsWide = 15;
+ mapRoomsHigh = 4;
+// isToolsH = qd.screenBits.bounds.right - 120;
+ isToolsH = 100;
+ isToolsV = 35;
+ isLinkH = 50;
+ isLinkV = 80;
+// isCoordH = qd.screenBits.bounds.right - 55;
+ isCoordH = 50;
+ isCoordV = 204;
+ mapLeftRoom = 60;
+ mapTopRoom = 50;
+ wasFloor = 0;
+ wasSuite = 0;
+ numSMWarnings = 0;
+ autoRoomEdit = true;
+ isMapOpen = true;
+ isToolsOpen = true;
+ isCoordOpen = false;
+ toolMode = kBlowerMode;
+ doAutoDemo = true;
+ isEscPauseKey = false;
+ isUseSecondScreen = false;
+ doBackground = false;
+ doPrettyMap = false;
+ doBitchDialogs = true;
+ }
+
+ if ((numNeighbors > 1) && (thisMac.screen.right <= 512))
+ numNeighbors = 1;
+
+ UnivGetSoundVolume(&wasVolume, thisMac.hasSM3);
+ UnivSetSoundVolume(isVolume, thisMac.hasSM3);
+
+ if (isVolume == 0)
+ isSoundOn = false;
+ else
+ isSoundOn = true;
+}
+
+//-------------------------------------------------------------- WriteOutPrefs
+
+// Called just before Glider PRO quits. This function writes outÉ
+// the user preferences to disk.
+
+void WriteOutPrefs (void)
+{
+ prefsInfo thePrefs;
+
+ UnivGetSoundVolume(&isVolume, thisMac.hasSM3);
+
+#ifdef COMPILEDEMO
+ PasStringCopy("\pDemo House", thePrefs.wasDefaultName);
+#else
+ PasStringCopy(thisHouseName, thePrefs.wasDefaultName);
+#endif
+ PasStringCopy(leftName, thePrefs.wasLeftName);
+ PasStringCopy(rightName, thePrefs.wasRightName);
+ PasStringCopy(batteryName, thePrefs.wasBattName);
+ PasStringCopy(bandName, thePrefs.wasBandName);
+ PasStringCopy(highName, thePrefs.wasHighName);
+ PasStringCopy(highBanner, thePrefs.wasHighBanner);
+ thePrefs.wasLeftMap = theGlider.leftKey;
+ thePrefs.wasRightMap = theGlider.rightKey;
+ thePrefs.wasBattMap = theGlider.battKey;
+ thePrefs.wasBandMap = theGlider.bandKey;
+#ifndef COMPILEDEMO
+#ifndef COMPILENOCP
+ thePrefs.encrypted = encryptedNumber;
+ thePrefs.fakeLong = Random();
+#endif // COMPILENOCP
+#endif // COMPILEDEMO
+ thePrefs.wasVolume = isVolume;
+ thePrefs.wasDepthPref = isDepthPref;
+ thePrefs.wasMusicOn = isMusicOn;
+ thePrefs.wasZooms = doZooms;
+ thePrefs.wasQuickTrans = quickerTransitions;
+ thePrefs.wasDoColorFade = isDoColorFade;
+ thePrefs.wasIdleMusic = isPlayMusicIdle;
+ thePrefs.wasGameMusic = isPlayMusicGame;
+ thePrefs.wasHouseChecks = isHouseChecks;
+ thePrefs.wasMaxFiles = willMaxFiles;
+ thePrefs.wasEditH = isEditH;
+ thePrefs.wasEditV = isEditV;
+ thePrefs.wasMapH = isMapH;
+ thePrefs.wasMapV = isMapV;
+ thePrefs.wasMapWide = mapRoomsWide;
+ thePrefs.wasMapHigh = mapRoomsHigh;
+ thePrefs.wasToolsH = isToolsH;
+ thePrefs.wasToolsV = isToolsV;
+ thePrefs.isMapLeft = mapLeftRoom;
+ thePrefs.isMapTop = mapTopRoom;
+ thePrefs.wasFloor = wasFloor;
+ thePrefs.wasSuite = wasSuite;
+ thePrefs.wasLinkH = isLinkH;
+ thePrefs.wasLinkV = isLinkV;
+ thePrefs.wasCoordH = isCoordH;
+ thePrefs.wasCoordV = isCoordV;
+ thePrefs.smWarnings = numSMWarnings;
+ thePrefs.wasAutoEdit = autoRoomEdit;
+ thePrefs.wasMapOpen = isMapOpen;
+ thePrefs.wasToolsOpen = isToolsOpen;
+ thePrefs.wasCoordOpen = isCoordOpen;
+ thePrefs.wasNumNeighbors = numNeighbors;
+ thePrefs.wasToolGroup = toolMode;
+ thePrefs.wasDoAutoDemo = doAutoDemo;
+ thePrefs.wasEscPauseKey = isEscPauseKey;
+ thePrefs.wasScreen2 = isUseSecondScreen;
+ thePrefs.wasDoBackground = doBackground;
+ thePrefs.wasPrettyMap = doPrettyMap;
+ thePrefs.wasBitchDialogs = doBitchDialogs;
+
+ if (!SavePrefs(&thePrefs, kPrefsVersion))
+ SysBeep(1);
+
+ UnivSetSoundVolume(wasVolume, thisMac.hasSM3);
+}
+
+//-------------------------------------------------------------- main
+// Here is main(). The first function called when Glider PRO comes up.
+
+int gpAppMain()
+{
+// long wasSeed;
+ long theErr;
+ OSErr fileErr;
+ Boolean whoCares, copyGood;
+
+ PL_Init();
+
+ ToolBoxInit();
+ CheckOurEnvirons();
+ if (!thisMac.hasColor)
+ RedAlert(kErrNeedColorQD);
+ if (!thisMac.hasSystem7)
+ RedAlert(kErrNeedSystem7);
+ if (thisMac.numScreens == 0)
+ RedAlert(kErrNeed16Or256Colors);
+// dataResFile = OpenResFile("\pMermaid");
+ SetUpAppleEvents();
+ LoadCursors();
+ ReadInPrefs();
+
+#if defined COMPILEDEMO
+ copyGood = true;
+#elif defined COMPILENOCP
+// didValidation = false;
+ copyGood = true;
+#else
+ didValidation = false;
+ copyGood = ValidInstallation(true);
+ if (!copyGood)
+ encryptedNumber = 0L;
+ else if (didValidation)
+ WriteOutPrefs(); SpinCursor(3);
+#endif
+
+// if ((thisMac.numScreens > 1) && (isUseSecondScreen))
+// ReflectSecondMonitorEnvirons(false, true, true);
+ HandleDepthSwitching();
+ VariableInit(); SpinCursor(2);
+ CheckMemorySize();
+ GetExtraCursors(); SpinCursor(2);
+ InitMarquee();
+ CreatePointers(); SpinCursor(2);
+ InitSrcRects();
+ CreateOffscreens(); SpinCursor(2);
+ OpenMainWindow();
+
+ if (thisMac.hasQT)
+ {
+ theErr = EnterMovies();
+ if (theErr != noErr)
+ thisMac.hasQT = false;
+ }
+
+ InitSound(); SpinCursor(2);
+ InitMusic(); SpinCursor(2);
+ BuildHouseList();
+ if (OpenHouse())
+ whoCares = ReadHouse();
+
+ PlayPrioritySound(kBirdSound, kBirdPriority);
+ DelayTicks(6);
+ InitializeMenus(); InitCursor();
+
+#if BUILD_ARCADE_VERSION
+// HideMenuBarOld();
+#endif
+
+// if ((isDoColorFade) && (thisMac.isDepth == 8))
+// {
+// wasSeed = ExtractCTSeed((CGrafPtr)mainWindow);
+// WashColorIn();
+// ForceCTSeed((CGrafPtr)mainWindow, wasSeed);
+// }
+// if ((!thisMac.hasSM3) && (numSMWarnings < 3))
+// {
+// numSMWarnings++;
+// BitchAboutSM3();
+// }
+
+ while (!quitting) // this is the main loop
+ HandleEvent();
+/*
+#if BUILD_ARCADE_VERSION
+ ShowMenuBarOld();
+#endif
+*/
+ KillMusic();
+ KillSound();
+ if (houseOpen)
+ {
+ if (!CloseHouse())
+ {
+ CloseHouseResFork();
+ fileErr = FSClose(houseRefNum);
+ houseOpen = false;
+ }
+ }
+ WriteOutPrefs();
+ RestoreColorDepth();
+ PL_DEAD(FlushEvents(everyEvent, 0));
+// theErr = LoadScrap();
+
+ return 0;
+}
+
diff --git a/GpApp/MainWindow.cpp b/GpApp/MainWindow.cpp
new file mode 100644
index 0000000..88f2b46
--- /dev/null
+++ b/GpApp/MainWindow.cpp
@@ -0,0 +1,602 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// MainWindow.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLNumberFormatting.h"
+#include "PLToolUtils.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "House.h"
+#include "RectUtils.h"
+
+
+#define kMainWindowID 128
+#define kEditWindowID 129
+#define kMenuWindowID 130
+
+
+void DrawOnSplash (void);
+void SetPaletteToGrays (void);
+void HardDrawMainWindow (void);
+void RestoreColorsSlam (void);
+
+
+CTabHandle theCTab;
+PixMapHandle thePMap;
+ColorSpec * wasColors;
+ColorSpec * newColors;
+CursHandle handCursorH, beamCursorH, vertCursorH, horiCursorH;
+CursHandle diagCursorH;
+Cursor handCursor, beamCursor, vertCursor, horiCursor;
+Cursor diagCursor;
+Rect workSrcRect;
+GWorldPtr workSrcMap;
+Rect mainWindowRect;
+WindowPtr mainWindow, menuWindow;
+short isEditH, isEditV;
+short playOriginH, playOriginV;
+short splashOriginH, splashOriginV;
+short theMode;
+Boolean fadeGraysOut, isDoColorFade, splashDrawn;
+
+extern GDHandle thisGDevice;
+extern short toolSelected;
+extern Boolean noRoomAtAll, isUseSecondScreen;
+extern Boolean quickerTransitions, houseIsReadOnly;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DrawOnSplash
+
+// Draws additional text on top of splash screen.
+
+void DrawOnSplash (void)
+{
+ Str255 houseLoadedStr;
+
+ PasStringCopy(PSTR("House: "), houseLoadedStr);
+ PasStringConcat(houseLoadedStr, thisHouseName);
+ if ((thisMac.hasQT) && (hasMovie))
+ PasStringConcat(houseLoadedStr, PSTR(" (QT)"));
+ TextSize(9);
+ TextFace(1);
+ TextFont(applFont);
+ MoveTo(splashOriginH + 436, splashOriginV + 314);
+ if (thisMac.isDepth == 4)
+ {
+ ForeColor(whiteColor);
+ DrawString(houseLoadedStr);
+ ForeColor(blackColor);
+ }
+ else
+ {
+ if (houseIsReadOnly)
+ ColorText(houseLoadedStr, 5L);
+ else
+ ColorText(houseLoadedStr, 28L);
+ }
+
+ #if defined(powerc) || defined(__powerc)
+ TextSize(12);
+ TextFace(0);
+ TextFont(systemFont);
+ ForeColor(blackColor);
+ MoveTo(splashOriginH + 5, splashOriginV + 457);
+ DrawString("\pPowerPC Native!");
+ ForeColor(whiteColor);
+ MoveTo(splashOriginH + 4, splashOriginV + 456);
+ DrawString("\pPowerPC Native!");
+ ForeColor(blackColor);
+ #endif
+}
+
+//-------------------------------------------------------------- RedrawSplashScreen
+
+void RedrawSplashScreen (void)
+{
+ Rect tempRect;
+
+ SetPort((GrafPtr)workSrcMap);
+ PaintRect(&workSrcRect);
+ QSetRect(&tempRect, 0, 0, 640, 460);
+ QOffsetRect(&tempRect, splashOriginH, splashOriginV);
+ LoadScaledGraphic(kSplash8BitPICT, &tempRect);
+ DrawOnSplash();
+ SetPortWindowPort(mainWindow);
+// if (quickerTransitions)
+// DissBitsChunky(&workSrcRect);
+// else
+// DissBits(&workSrcRect);
+ CopyRectMainToWork(&workSrcRect);
+}
+
+//-------------------------------------------------------------- UpdateMainWindow
+
+// Redraws the main window (depends on mode were in - splash, editing, playing).
+
+void UpdateMainWindow (void)
+{
+ Rect tempRect;
+ RgnHandle dummyRgn;
+
+ dummyRgn = NewRgn();
+ SetPortWindowPort(mainWindow);
+
+ if (theMode == kEditMode)
+ {
+ PauseMarquee();
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &mainWindowRect, &mainWindowRect, srcCopy,
+ GetPortVisibleRegion(GetWindowPort(mainWindow), dummyRgn));
+ ResumeMarquee();
+ }
+ else if ((theMode == kSplashMode) || (theMode == kPlayMode))
+ {
+ SetPort((GrafPtr)workSrcMap);
+ PaintRect(&workSrcRect);
+ QSetRect(&tempRect, 0, 0, 640, 460);
+ QOffsetRect(&tempRect, splashOriginH, splashOriginV);
+ LoadScaledGraphic(kSplash8BitPICT, &tempRect);
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &workSrcRect, &mainWindowRect, srcCopy,
+ GetPortVisibleRegion(GetWindowPort(mainWindow), dummyRgn));
+ SetPortWindowPort(mainWindow);
+
+ DrawOnSplash();
+ }
+
+ DisposeRgn(dummyRgn);
+ splashDrawn = true;
+}
+
+//-------------------------------------------------------------- UpdateMenuBarWindow
+// Ugly kludge to cover over the menu bar when playing game on 2nd monitor.
+
+void UpdateMenuBarWindow (void)
+{
+ Rect bounds;
+
+ if (menuWindow == nil)
+ return;
+
+ GetLocalWindowRect(menuWindow, &bounds);
+ PaintRect(&bounds);
+}
+
+//-------------------------------------------------------------- OpenMainWindow
+// Opens up the main window (how it does this depends on mode were in).
+
+void OpenMainWindow (void)
+{
+// long wasSeed;
+ short whichRoom;
+
+ if (mainWindow != nil)
+ {
+ YellowAlert(kYellowUnaccounted, 6);
+ return;
+ }
+
+ if (theMode == kEditMode)
+ {
+ if (menuWindow != nil)
+ DisposeWindow(menuWindow);
+ menuWindow = nil;
+
+ QSetRect(&mainWindowRect, 0, 0, 512, 322);
+ mainWindow = GetNewCWindow(kEditWindowID, nil, kPutInFront);
+ SizeWindow(mainWindow, mainWindowRect.right,
+ mainWindowRect.bottom, false);
+
+ if (OptionKeyDown())
+ {
+ isEditH = 3;
+ isEditV = 41;
+ }
+ MoveWindow(mainWindow, isEditH, isEditV, true);
+ ShowWindow(mainWindow);
+ SetPortWindowPort(mainWindow);
+ ClipRect(&mainWindowRect);
+ ForeColor(blackColor);
+ BackColor(whiteColor);
+
+ whichRoom = GetFirstRoomNumber();
+ CopyRoomToThisRoom(whichRoom);
+ ReflectCurrentRoom(false);
+ }
+ else
+ {
+ if (menuWindow == nil)
+ {
+ menuWindow = GetNewCWindow(kMenuWindowID, nil, kPutInFront);
+ SizeWindow(menuWindow, RectWide(&thisMac.screen), 20, false);
+ MoveWindow(menuWindow, thisMac.screen.left,
+ thisMac.screen.top, true);
+ ShowWindow(menuWindow);
+ }
+ mainWindowRect = thisMac.screen;
+ ZeroRectCorner(&mainWindowRect);
+ mainWindowRect.bottom -= 20; // thisMac.menuHigh
+ mainWindow = GetNewCWindow(kMainWindowID, nil, kPutInFront);
+ SizeWindow(mainWindow, mainWindowRect.right - mainWindowRect.left,
+ mainWindowRect.bottom - mainWindowRect.top, false);
+ MoveWindow(mainWindow, thisMac.screen.left,
+ thisMac.screen.top + 20, true); // thisMac.menuHigh
+ ShowWindow(mainWindow);
+ SetPortWindowPort(mainWindow);
+ ClipRect(&mainWindowRect);
+// CopyRgn(mainWindow->clipRgn, mainWindow->visRgn);
+ ForeColor(blackColor);
+ BackColor(whiteColor);
+ PaintRect(&mainWindowRect);
+
+ splashOriginH = ((thisMac.screen.right - thisMac.screen.left) - 640) / 2;
+ if (splashOriginH < 0)
+ splashOriginH = 0;
+ splashOriginV = ((thisMac.screen.bottom - thisMac.screen.top) - 480) / 2;
+ if (splashOriginV < 0)
+ splashOriginV = 0;
+
+ SetPort((GrafPtr)workSrcMap);
+ PaintRect(&workSrcRect);
+ LoadGraphic(kSplash8BitPICT);
+
+// if ((fadeGraysOut) && (isDoColorFade))
+// {
+// wasSeed = ExtractCTSeed((CGrafPtr)mainWindow);
+// SetPortWindowPort(mainWindow);
+// SetPaletteToGrays();
+// HardDrawMainWindow();
+// fadeGraysOut = false;
+// ForceCTSeed((CGrafPtr)mainWindow, wasSeed);
+// }
+
+ SetPortWindowPort(mainWindow);
+ }
+}
+
+//-------------------------------------------------------------- CloseMainWindow
+
+// Closes the main window.
+
+void CloseMainWindow (void)
+{
+ if (mainWindow != nil)
+ DisposeWindow(mainWindow);
+ mainWindow = nil;
+}
+
+//-------------------------------------------------------------- ZoomBetweenWindows
+// Zooms from one window size to another. Just for effect.
+
+/*
+#ifndef COMPILEDEMO
+void ZoomBetweenWindows (void)
+{
+ Rect aRect;
+ short h, v;
+
+ if (theMode == kEditMode)
+ {
+ QSetRect(&aRect, 0, 0, 512, 342);
+ QOffsetRect(&aRect, isEditH, isEditV);
+ ZoomRectToRect(&(thisMac.screen), &aRect);
+ }
+ else
+ {
+ aRect = mainWindow->portRect;
+ GetWindowLeftTop(mainWindow, &h, &v);
+ QOffsetRect(&aRect, h, v);
+ ZoomRectToRect(&aRect, &(thisMac.screen));
+ }
+}
+#endif
+*/
+
+//-------------------------------------------------------------- UpdateEditWindowTitle
+// Handles changing the title across the top of the main window. OnlyÉ
+// relevant when editing a house (room title displayed in window title).
+
+#ifndef COMPILEDEMO
+void UpdateEditWindowTitle (void)
+{
+ Str255 newTitle, tempStr;
+
+ if (mainWindow == nil)
+ return;
+
+ PasStringCopy(thisHouseName, newTitle);
+ PasStringConcat(newTitle, PSTR(" - "));
+ if (noRoomAtAll)
+ PasStringConcat(newTitle, PSTR("No rooms"));
+ else if (houseUnlocked)
+ {
+ PasStringConcat(newTitle, thisRoom->name);
+ PasStringConcat(newTitle, PSTR(" ("));
+ NumToString((long)thisRoom->floor, tempStr);
+ PasStringConcat(newTitle, tempStr);
+ PasStringConcat(newTitle, PSTR(", "));
+ NumToString((long)thisRoom->suite, tempStr);
+ PasStringConcat(newTitle, tempStr);
+ PasStringConcat(newTitle, PSTR(")"));
+ }
+ else
+ PasStringConcat(newTitle, PSTR("House Locked"));
+ SetWTitle(mainWindow, newTitle);
+}
+#endif
+
+//-------------------------------------------------------------- HandleMainClick
+
+// Handle a mouse click in the main window (relevant only when editing).
+
+void HandleMainClick (Point wherePt, Boolean isDoubleClick)
+{
+ KeyMap theseKeys;
+
+ if ((theMode != kEditMode) || (mainWindow == nil) ||
+ (!houseUnlocked))
+ return;
+
+ SetPortWindowPort(mainWindow);
+ GlobalToLocal(&wherePt);
+
+ if (toolSelected == kSelectTool)
+ DoSelectionClick(wherePt, isDoubleClick);
+ else
+ DoNewObjectClick(wherePt);
+
+ GetKeys(theseKeys);
+ if (!BitTst(&theseKeys, kShiftKeyMap))
+ {
+ EraseSelectedTool();
+ SelectTool(kSelectTool);
+ }
+}
+
+//-------------------------------------------------------------- ShowMenuBarOld
+// Displays the menu bar (after having been hidden).
+/*
+void ShowMenuBarOld (void)
+{
+ Rect theRect;
+ GrafPtr wasPort, tempPort;
+ RgnHandle worldRgn, menuBarRgn;
+
+ if (LMGetMBarHeight() == 0)
+ {
+ GetPort(&wasPort);
+ tempPort = (GrafPtr)NewPtrClear(sizeof(GrafPort));
+ OpenPort(tempPort);
+ SetPort((GrafPtr)tempPort);
+
+ LMSetMBarHeight(thisMac.menuHigh);
+
+ theRect = (**GetGrayRgn()).rgnBBox;
+ UnionRect(&theRect, &qd.screenBits.bounds, &theRect);
+ worldRgn = NewRgn();
+ OpenRgn();
+ FrameRoundRect(&theRect, 16, 16);
+ CloseRgn(worldRgn);
+
+ theRect = qd.screenBits.bounds;
+ theRect.bottom = theRect.top + thisMac.menuHigh;
+ menuBarRgn = NewRgn();
+ RectRgn(menuBarRgn, &theRect);
+
+ SectRgn(worldRgn, menuBarRgn, menuBarRgn); // /------------------\
+ DisposeRgn(worldRgn); // |__________________|
+
+ UnionRgn(tempPort->visRgn, menuBarRgn, tempPort->visRgn);
+ DiffRgn(tempPort->visRgn, menuBarRgn, tempPort->visRgn);
+ DisposeRgn(menuBarRgn);
+
+ ClosePort(tempPort);
+ SetPort((GrafPtr)wasPort);
+
+ DrawMenuBar();
+ }
+}
+*/
+//-------------------------------------------------------------- HideMenuBarOld
+// Hides the menu bar - completely erasing it from the screen.
+/*
+void HideMenuBarOld (void)
+{
+ Rect theRect;
+ RgnHandle worldRgn, menuBarRgn;
+ GrafPtr wasPort, tempPort;
+
+ if (LMGetMBarHeight() != 0)
+ {
+ GetPort(&wasPort);
+ tempPort = (GrafPtr)NewPtrClear(sizeof(GrafPort));
+ OpenPort(tempPort);
+ SetPort((GrafPtr)tempPort);
+
+ LMSetMBarHeight(0);
+
+ theRect = (**GetGrayRgn()).rgnBBox;
+ UnionRect(&theRect, &qd.screenBits.bounds, &theRect);
+ worldRgn = NewRgn();
+ OpenRgn();
+ FrameRoundRect(&theRect, 16, 16);
+ CloseRgn(worldRgn);
+
+ theRect = qd.screenBits.bounds;
+ theRect.bottom = theRect.top + thisMac.menuHigh;
+ menuBarRgn = NewRgn();
+ RectRgn(menuBarRgn, &theRect);
+
+ SectRgn(worldRgn, menuBarRgn, menuBarRgn); // /------------------\
+ DisposeRgn(worldRgn); // |__________________|
+
+ UnionRgn(tempPort->visRgn, menuBarRgn, tempPort->visRgn);
+ DisposeRgn(menuBarRgn);
+
+ PaintRect(&theRect);
+
+ ClosePort(tempPort);
+ SetPort((GrafPtr)wasPort);
+ }
+}
+*/
+//-------------------------------------------------------------- SetPaletteToGrays
+
+// Sets up a gray palette corresponding in luminance to the standard colorÉ
+// palette. This is to facilitate the gray->color fade when the game comes up.
+/*
+void SetPaletteToGrays (void)
+{
+ GDHandle theDevice;
+ long longGray;
+ short i;
+ char wasState;
+
+ wasState = HGetState((Handle)thisGDevice);
+ HLock((Handle)thisGDevice);
+ thePMap = (*thisGDevice)->gdPMap;
+ HSetState((Handle)thisGDevice, wasState);
+
+ theCTab = (*thePMap)->pmTable;
+ wasColors = nil;
+ wasColors = (ColorSpec*)NewPtr(sizeof(ColorSpec) * 256);
+ if (wasColors == nil)
+ RedAlert(kErrNoMemory);
+
+ newColors = nil;
+ newColors = (ColorSpec*)NewPtr(sizeof(ColorSpec) * 256);
+ if (newColors == nil)
+ RedAlert(kErrNoMemory);
+
+ for (i = 0; i < 256; i++)
+ {
+ wasColors[i] = (*theCTab)->ctTable[i];
+ newColors[i] = (*theCTab)->ctTable[i];
+
+ if (i != 5)
+ {
+ longGray = ((long)newColors[i].rgb.red * 3L) / 10L +
+ ((long)newColors[i].rgb.green * 6L) / 10L +
+ ((long)newColors[i].rgb.blue * 1L) / 10L;
+
+ newColors[i].rgb.red = (unsigned short)longGray;
+ newColors[i].rgb.green = (unsigned short)longGray;
+ newColors[i].rgb.blue = (unsigned short)longGray;
+ }
+ }
+
+ theDevice = GetGDevice();
+ SetGDevice(thisGDevice);
+ SetEntries(0, 255, newColors);
+ SetGDevice(theDevice);
+}
+*/
+//-------------------------------------------------------------- HardDrawMainWindow
+// Ignores the ToolBox - this function draws direct to screen in order toÉ
+// circumvent the Toolbox's attempt to color-match to the current palette.
+/*
+void HardDrawMainWindow (void)
+{
+ PixMapHandle pixMapH;
+ Point offsetPt;
+ long srcRowBytes, destRowBytes;
+ long src;
+ long dest;
+ short i, w;
+ SInt8 mode;
+ char wasState;
+
+ wasState = HGetState((Handle)thisGDevice);
+ HLock((Handle)thisGDevice);
+ pixMapH = (**thisGDevice).gdPMap;
+ HSetState((Handle)thisGDevice, wasState);
+
+ srcRowBytes = (long)((*(workSrcMap->portPixMap))->rowBytes & 0x7FFF);
+ destRowBytes = (**pixMapH).rowBytes & 0x7FFF;
+ src = (long)((*(workSrcMap->portPixMap))->baseAddr);
+ dest = (long)((**pixMapH).baseAddr) + splashOriginH +
+ ((splashOriginV + thisMac.menuHigh) * destRowBytes);
+
+ offsetPt.h = 0;
+ offsetPt.v = 0;
+ ShieldCursor(&mainWindowRect, offsetPt);
+ mode = true32b;
+ SwapMMUMode(&mode);
+ for (i = 0; i < 460; i++)
+ {
+ for (w = 0; w < 160; w++)
+ {
+ *(long *)dest = *(long *)src;
+ dest += 4L;
+ src += 4L;
+ }
+ src -= 640;
+ dest -= 640;
+ src += srcRowBytes;
+ dest += destRowBytes;
+ }
+ SwapMMUMode(&mode);
+ ShowCursor();
+}
+*/
+//-------------------------------------------------------------- WashColorIn
+// Slowly walks the palette from its gray luminance state to the full colorÉ
+// palette. In this way, color appears to slowly wash in.
+/*
+void WashColorIn (void)
+{
+ #define kGray2ColorSteps 180
+ GDHandle theDevice;
+ long longDelta;
+ short i, c;
+
+ theDevice = GetGDevice();
+ SetGDevice(thisGDevice);
+
+ for (i = 0; i < kGray2ColorSteps; i++)
+ {
+ for (c = 0; c < 256; c++)
+ {
+ if (c != 5)
+ {
+ longDelta = (((long)wasColors[c].rgb.red -
+ (long)newColors[c].rgb.red) /
+ (long)(kGray2ColorSteps - i)) + (long)newColors[c].rgb.red;
+ newColors[c].rgb.red = (unsigned short)longDelta;
+
+ longDelta = (((long)wasColors[c].rgb.green -
+ (long)newColors[c].rgb.green) /
+ (long)(kGray2ColorSteps - i)) +
+ (long)newColors[c].rgb.green;
+ newColors[c].rgb.green = (unsigned short)longDelta;
+
+ longDelta = (((long)wasColors[c].rgb.blue -
+ (long)newColors[c].rgb.blue) /
+ (long)(kGray2ColorSteps - i)) +
+ (long)newColors[c].rgb.blue;
+ newColors[c].rgb.blue = (unsigned short)longDelta;
+ }
+ }
+ SetEntries(0, 255, newColors);
+ if (Button())
+ break;
+ }
+
+ SetEntries(0, 255, wasColors);
+ SetGDevice(theDevice);
+
+ RestoreColorsSlam();
+
+ if (wasColors != nil)
+ DisposePtr((Ptr)wasColors);
+ if (newColors != nil)
+ DisposePtr((Ptr)newColors);
+}
+*/
diff --git a/GpApp/MainWindow.h b/GpApp/MainWindow.h
new file mode 100644
index 0000000..46bfe37
--- /dev/null
+++ b/GpApp/MainWindow.h
@@ -0,0 +1,11 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// MainWindow.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+extern GWorldPtr workSrcMap;
diff --git a/GpApp/Map.cpp b/GpApp/Map.cpp
new file mode 100644
index 0000000..bace10e
--- /dev/null
+++ b/GpApp/Map.cpp
@@ -0,0 +1,797 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Map.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLControlDefinitions.h"
+#include "PLResources.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "House.h"
+#include "RectUtils.h"
+#include "Utilities.h"
+
+
+#define kMapRoomsHigh 9 // was 7
+#define kMapRoomsWide 9 // was 7
+#define kMapScrollBarWidth 16
+#define kHScrollRef 5L
+#define kVScrollRef 27L
+#define kMapGroundValue 56
+#define kNewRoomAlert 1004
+#define kYesDoNewRoom 1
+#define kThumbnailPictID 1010
+
+
+void LoadGraphicPlus (short, Rect *);
+void RedrawMapContents (void);
+void LiveHScrollAction (ControlHandle, short);
+void LiveVScrollAction (ControlHandle, short);
+Boolean QueryNewRoom (void);
+void CreateNailOffscreen (void);
+void KillNailOffscreen (void);
+
+Rect nailSrcRect, activeRoomRect, wasActiveRoomRect;
+Rect mapHScrollRect, mapVScrollRect, mapCenterRect;
+Rect mapWindowRect;
+GWorldPtr nailSrcMap;
+WindowPtr mapWindow;
+ControlHandle mapHScroll, mapVScroll;
+short isMapH, isMapV, mapRoomsHigh, mapRoomsWide;
+short mapLeftRoom, mapTopRoom;
+Boolean isMapOpen, doPrettyMap;
+
+extern Boolean doBitchDialogs;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- ThisRoomVisibleOnMap
+
+#ifndef COMPILEDEMO
+Boolean ThisRoomVisibleOnMap (void)
+{
+ short h, v;
+
+ h = thisRoom->suite;
+ v = kMapGroundValue - thisRoom->floor;
+
+ if ((h < mapLeftRoom) || (v < mapTopRoom) ||
+ (h >= (mapLeftRoom + mapRoomsWide)) ||
+ (v >= (mapTopRoom + mapRoomsHigh)))
+ return (false);
+ else
+ return (true);
+}
+#endif
+
+//-------------------------------------------------------------- CenterMapOnRoom
+
+#ifndef COMPILEDEMO
+void CenterMapOnRoom (short h, short v)
+{
+ if (mapWindow == nil)
+ return;
+
+ mapLeftRoom = h - (mapRoomsWide / 2);
+ mapTopRoom = (kMapGroundValue - v) - (mapRoomsHigh / 2);
+
+ if (mapLeftRoom < 0)
+ mapLeftRoom = 0;
+ else if (mapLeftRoom > (kMaxNumRoomsH - mapRoomsWide))
+ mapLeftRoom = kMaxNumRoomsH - mapRoomsWide;
+
+ if (mapTopRoom < 0)
+ mapTopRoom = 0;
+ else if (mapTopRoom > (kMaxNumRoomsV - mapRoomsHigh))
+ mapTopRoom = kMaxNumRoomsV - mapRoomsHigh;
+
+ if (mapWindow != nil)
+ {
+ SetControlValue(mapHScroll, mapLeftRoom);
+ SetControlValue(mapVScroll, mapTopRoom);
+ }
+}
+#endif
+
+//-------------------------------------------------------------- FlagMapRoomsForUpdate
+
+#ifndef COMPILEDEMO
+void FlagMapRoomsForUpdate (void)
+{
+ if (mapWindow == nil)
+ return;
+
+// SetPortWindowPort(mapWindow);
+ InvalWindowRect(mapWindow, &wasActiveRoomRect);
+ InvalWindowRect(mapWindow, &activeRoomRect);
+}
+#endif
+
+//-------------------------------------------------------------- FindNewActiveRoomRect
+
+#ifndef COMPILEDEMO
+void FindNewActiveRoomRect (void)
+{
+ Rect aRoom;
+ short h, i;
+ short floor, suite, whoCares;
+ char wasState;
+ Boolean activeRoomVisible;
+
+ if (mapWindow == nil)
+ return;
+
+ activeRoomVisible = false;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ for (i = 0; i < mapRoomsHigh; i++)
+ {
+ for (h = 0; h < mapRoomsWide; h++)
+ {
+ QSetRect(&aRoom, 0, 0, kMapRoomWidth, kMapRoomHeight);
+ QOffsetRect(&aRoom, kMapRoomWidth * h, kMapRoomHeight * i);
+
+ suite = h + mapLeftRoom;
+ floor = kMapGroundValue - (i + mapTopRoom);
+ if ((RoomExists(suite, floor, &whoCares)) && (houseUnlocked))
+ {
+ if (whoCares == thisRoomNumber)
+ {
+ wasActiveRoomRect = activeRoomRect;
+ activeRoomRect = aRoom;
+ activeRoomVisible = true;
+ }
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ if (activeRoomVisible)
+ {
+ activeRoomRect.right++;
+ activeRoomRect.bottom++;
+ InsetRect(&activeRoomRect, -1, -1);
+ }
+}
+#endif
+
+//-------------------------------------------------------------- LoadGraphicPlus
+
+void LoadGraphicPlus (short resID, Rect *theRect)
+{
+ PicHandle thePicture;
+
+ thePicture = GetPicture(resID);
+ if (thePicture == nil)
+ {
+ thePicture = (PicHandle)GetResource('Date', resID);
+ if (thePicture == nil)
+ {
+ return;
+ }
+ }
+ DrawPicture(thePicture, theRect);
+ ReleaseResource((Handle)thePicture);
+}
+
+//-------------------------------------------------------------- RedrawMapContents
+
+#ifndef COMPILEDEMO
+void RedrawMapContents (void)
+{
+ Rect newClip, aRoom, src;
+ RgnHandle wasClip;
+ short h, i, groundLevel;
+ short floor, suite, whoCares, type;
+ char wasState;
+ Boolean activeRoomVisible;
+
+ if (mapWindow == nil)
+ return;
+
+ activeRoomVisible = false;
+ groundLevel = kMapGroundValue - mapTopRoom;
+
+ newClip.left = mapWindowRect.left;
+ newClip.top = mapWindowRect.top;
+ newClip.right = mapWindowRect.right + 2 - kMapScrollBarWidth;
+ newClip.bottom = mapWindowRect.bottom + 2 - kMapScrollBarWidth;
+
+ SetPort((GrafPtr)mapWindow);
+ wasClip = NewRgn();
+ if (wasClip != nil)
+ {
+ GetClip(wasClip);
+ ClipRect(&newClip);
+ }
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ for (i = 0; i < mapRoomsHigh; i++)
+ {
+ for (h = 0; h < mapRoomsWide; h++)
+ {
+ QSetRect(&aRoom, 0, 0, kMapRoomWidth, kMapRoomHeight);
+ QOffsetRect(&aRoom, kMapRoomWidth * h, kMapRoomHeight * i);
+
+ suite = h + mapLeftRoom;
+ floor = kMapGroundValue - (i + mapTopRoom);
+ if ((RoomExists(suite, floor, &whoCares)) && (houseUnlocked))
+ {
+ PenNormal();
+ type = (*thisHouse)->rooms[whoCares].background - kBaseBackgroundID;
+ if (type > kNumBackgrounds)
+ {
+ if (!doPrettyMap)
+ type = kNumBackgrounds; // Draw "?" thumbnail.
+ }
+ ForeColor(blackColor);
+ if (type > kNumBackgrounds) // Do a "pretty" thumbnail.
+ {
+ LoadGraphicPlus(type + kBaseBackgroundID, &aRoom);
+ }
+ else
+ {
+ QSetRect(&src, 0, 0, kMapRoomWidth, kMapRoomHeight);
+ QOffsetRect(&src, 0, type * kMapRoomHeight);
+ CopyBits((BitMap *)*GetGWorldPixMap(nailSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mapWindow)),
+ &src, &aRoom, srcCopy, nil);
+ }
+
+ if (whoCares == thisRoomNumber)
+ {
+ activeRoomRect = aRoom;
+ activeRoomVisible = true;
+ }
+ }
+ else
+ {
+ Pattern dummyPat;
+
+ PenPat(GetQDGlobalsGray(&dummyPat));
+ if (i >= groundLevel)
+ ForeColor(greenColor);
+ else
+ ForeColor(blueColor);
+ PaintRect(&aRoom);
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ ForeColor(blackColor);
+ PenNormal();
+
+ for (i = 1; i < mapRoomsWide; i++)
+ {
+ MoveTo(i * kMapRoomWidth, 0);
+ Line(0, mapRoomsHigh * kMapRoomHeight);
+ }
+
+ for (i = 1; i < mapRoomsHigh; i++)
+ {
+ MoveTo(0, i * kMapRoomHeight);
+ Line(mapRoomsWide * kMapRoomWidth, 0);
+ }
+
+ if (activeRoomVisible)
+ {
+ ForeColor(redColor);
+ activeRoomRect.right++;
+ activeRoomRect.bottom++;
+ FrameRect(&activeRoomRect);
+ InsetRect(&activeRoomRect, 1, 1);
+ FrameRect(&activeRoomRect);
+ ForeColor(blackColor);
+ InsetRect(&activeRoomRect, -1, -1);
+ }
+
+ if (wasClip != nil)
+ {
+ SetClip(wasClip);
+ DisposeRgn(wasClip);
+ }
+}
+#endif
+
+//-------------------------------------------------------------- UpdateMapWindow
+
+void UpdateMapWindow (void)
+{
+ #ifndef COMPILEDEMO
+ if (mapWindow == nil)
+ return;
+
+ SetControlValue(mapHScroll, mapLeftRoom);
+ SetControlValue(mapVScroll, mapTopRoom);
+
+ SetPortWindowPort(mapWindow);
+ DrawControls(mapWindow);
+ DrawGrowIcon(mapWindow);
+ RedrawMapContents();
+ #endif
+}
+
+//-------------------------------------------------------------- ResizeMapWindow
+
+void ResizeMapWindow (short newH, short newV)
+{
+#ifndef COMPILEDEMO
+ if ((newH == 0) && (newV == 0))
+ return;
+
+ SetPortWindowPort(mapWindow);
+ mapRoomsWide = newH / kMapRoomWidth;
+ if (mapRoomsWide < 3)
+ mapRoomsWide = 3;
+ mapRoomsHigh = newV / kMapRoomHeight;
+ if (mapRoomsHigh < 3)
+ mapRoomsHigh = 3;
+ QSetRect(&mapWindowRect, 0, 0,
+ mapRoomsWide * kMapRoomWidth + kMapScrollBarWidth - 2,
+ mapRoomsHigh * kMapRoomHeight + kMapScrollBarWidth - 2);
+ EraseRect(&mapWindowRect);
+ SizeWindow(mapWindow, mapWindowRect.right, mapWindowRect.bottom, true);
+
+ SetControlMaximum(mapHScroll, kMaxNumRoomsH - mapRoomsWide);
+ MoveControl(mapHScroll, 0, mapWindowRect.bottom - kMapScrollBarWidth + 2);
+ SizeControl(mapHScroll, mapWindowRect.right - kMapScrollBarWidth + 3,
+ kMapScrollBarWidth);
+ mapLeftRoom = GetControlValue(mapHScroll);
+
+ SetControlMaximum(mapVScroll, kMaxNumRoomsV - mapRoomsHigh);
+ MoveControl(mapVScroll, mapWindowRect.right - kMapScrollBarWidth + 2, 0);
+ SizeControl(mapVScroll, kMapScrollBarWidth,
+ mapWindowRect.bottom - kMapScrollBarWidth + 3);
+ mapTopRoom = GetControlValue(mapVScroll);
+
+ InvalWindowRect(mapWindow, &mapWindowRect);
+#endif
+}
+
+//-------------------------------------------------------------- OpenMapWindow
+
+void OpenMapWindow (void)
+{
+#ifndef COMPILEDEMO
+ Rect src, dest;
+ Point globalMouse;
+
+ if (mapWindow == nil)
+ {
+ CreateNailOffscreen();
+ QSetRect(&mapWindowRect, 0, 0,
+ mapRoomsWide * kMapRoomWidth + kMapScrollBarWidth - 2,
+ mapRoomsHigh * kMapRoomHeight + kMapScrollBarWidth - 2);
+ mapWindow = NewCWindow(nil, &mapWindowRect,
+ PSTR("Map"), false, kWindoidGrowWDEF, kPutInFront, true, 0L);
+
+ if (mapWindow == nil)
+ RedAlert(kErrNoMemory);
+
+// if (OptionKeyDown())
+// {
+// isMapH = 3;
+// isMapV = qd.screenBits.bounds.bottom - 100;
+// }
+ MoveWindow(mapWindow, isMapH, isMapV, true);
+ globalMouse = MyGetGlobalMouse();
+ QSetRect(&wasActiveRoomRect, 0, 0, 1, 1);
+ QSetRect(&activeRoomRect, 0, 0, 1, 1);
+ QSetRect(&src, 0, 0, 1, 1);
+ QOffsetRect(&src, globalMouse.h, globalMouse.v);
+ GetWindowRect(mapWindow, &dest);
+ BringToFront(mapWindow);
+ ShowHide(mapWindow, true);
+// FlagWindowFloating(mapWindow); TEMP - use flaoting windows
+ HiliteAllWindows();
+
+ SetPort((GrafPtr)mapWindow);
+ SetOrigin(1, 1);
+ QSetRect(&mapHScrollRect, -1, mapRoomsHigh * kMapRoomHeight,
+ mapRoomsWide * kMapRoomWidth + 1,
+ mapRoomsHigh * kMapRoomHeight + kMapScrollBarWidth);
+ QSetRect(&mapVScrollRect, mapRoomsWide * kMapRoomWidth, -1,
+ mapRoomsWide * kMapRoomWidth + kMapScrollBarWidth,
+ mapRoomsHigh * kMapRoomHeight + 1);
+ mapHScroll = NewControl(mapWindow, &mapHScrollRect, PSTR(""), true, mapLeftRoom,
+ 0, kMaxNumRoomsH - mapRoomsWide, scrollBarProc, kHScrollRef);
+ if (mapHScroll == nil)
+ RedAlert(kErrNoMemory);
+
+ mapVScroll = NewControl(mapWindow, &mapVScrollRect, PSTR(""), true, mapTopRoom,
+ 0, kMaxNumRoomsV - mapRoomsHigh, scrollBarProc, kVScrollRef);
+ if (mapVScroll == nil)
+ RedAlert(kErrNoMemory);
+
+ QSetRect(&mapCenterRect, -16, -16, 0, 0);
+ QOffsetRect(&mapCenterRect, mapWindowRect.right + 2,
+ mapWindowRect.bottom + 2);
+
+ CenterMapOnRoom(thisRoom->suite, thisRoom->floor);
+ }
+
+ UpdateMapCheckmark(true);
+#endif
+}
+
+//-------------------------------------------------------------- CloseMapWindow
+
+void CloseMapWindow (void)
+{
+#ifndef COMPILEDEMO
+ CloseThisWindow(&mapWindow);
+ UpdateMapCheckmark(false);
+#endif
+}
+
+//-------------------------------------------------------------- ToggleMapWindow
+
+void ToggleMapWindow (void)
+{
+#ifndef COMPILEDEMO
+ if (mapWindow == nil)
+ {
+ OpenMapWindow();
+ isMapOpen = true;
+ }
+ else
+ {
+ CloseMapWindow();
+ isMapOpen = false;
+ }
+#endif
+}
+
+//-------------------------------------------------------------- LiveHScrollAction
+#ifndef COMPILEDEMO
+
+void LiveHScrollAction (ControlHandle theControl, short thePart)
+{
+ short wasValue, newValue;
+
+ switch (thePart)
+ {
+ case kControlUpButtonPart:
+ wasValue = GetControlValue(theControl);
+ SetControlValue(theControl, wasValue - 1);
+ if (GetControlValue(theControl) != wasValue)
+ {
+ mapLeftRoom = GetControlValue(theControl);
+ RedrawMapContents();
+ }
+ break;
+
+ case kControlDownButtonPart:
+ wasValue = GetControlValue(theControl);
+ SetControlValue(theControl, wasValue + 1);
+ if (GetControlValue(theControl) != wasValue)
+ {
+ mapLeftRoom = GetControlValue(theControl);
+ RedrawMapContents();
+ }
+ break;
+
+ case kControlPageUpPart:
+ wasValue = GetControlValue(theControl);
+ newValue = wasValue - (mapRoomsWide / 2);
+ SetControlValue(theControl, newValue);
+ if (GetControlValue(theControl) != wasValue)
+ {
+ mapLeftRoom = GetControlValue(theControl);
+ RedrawMapContents();
+ }
+ break;
+
+ case kControlPageDownPart:
+ wasValue = GetControlValue(theControl);
+ newValue = wasValue + (mapRoomsWide / 2);
+ SetControlValue(theControl, newValue);
+ if (GetControlValue(theControl) != wasValue)
+ {
+ mapLeftRoom = GetControlValue(theControl);
+ RedrawMapContents();
+ }
+ break;
+
+ case kControlIndicatorPart:
+ break;
+ }
+}
+#endif
+
+//-------------------------------------------------------------- LiveVScrollAction
+#ifndef COMPILEDEMO
+
+void LiveVScrollAction (ControlHandle theControl, short thePart)
+{
+ short wasValue, newValue;
+
+ switch (thePart)
+ {
+ case kControlUpButtonPart:
+ wasValue = GetControlValue(theControl);
+ SetControlValue(theControl, wasValue - 1);
+ if (GetControlValue(theControl) != wasValue)
+ {
+ mapTopRoom = GetControlValue(theControl);
+ RedrawMapContents();
+ }
+ break;
+
+ case kControlDownButtonPart:
+ wasValue = GetControlValue(theControl);
+ SetControlValue(theControl, wasValue + 1);
+ if (GetControlValue(theControl) != wasValue)
+ {
+ mapTopRoom = GetControlValue(theControl);
+ RedrawMapContents();
+ }
+ break;
+
+ case kControlPageUpPart:
+ wasValue = GetControlValue(theControl);
+ newValue = wasValue - (mapRoomsHigh / 2);
+ SetControlValue(theControl, newValue);
+ if (GetControlValue(theControl) != wasValue)
+ {
+ mapTopRoom = GetControlValue(theControl);
+ RedrawMapContents();
+ }
+ break;
+
+ case kControlPageDownPart:
+ wasValue = GetControlValue(theControl);
+ newValue = wasValue + (mapRoomsHigh / 2);
+ SetControlValue(theControl, newValue);
+ if (GetControlValue(theControl) != wasValue)
+ {
+ mapTopRoom = GetControlValue(theControl);
+ RedrawMapContents();
+ }
+ break;
+
+ case kControlIndicatorPart:
+ break;
+ }
+}
+#endif
+
+//-------------------------------------------------------------- HandleMapClick
+
+void HandleMapClick (EventRecord *theEvent)
+{
+#ifndef COMPILEDEMO
+ Rect aRoom;
+ ControlHandle whichControl;
+ Point wherePt, globalWhere;
+ long controlRef;
+ short whichPart, localH, localV;
+ short roomH, roomV, itsNumber;
+ ControlActionUPP scrollHActionUPP, scrollVActionUPP;
+
+ wherePt = theEvent->where;
+
+ scrollHActionUPP = NewControlActionUPP(LiveHScrollAction);
+ scrollVActionUPP = NewControlActionUPP(LiveVScrollAction);
+
+ if (mapWindow == nil)
+ return;
+
+ SetPortWindowPort(mapWindow);
+ globalWhere = wherePt;
+ GlobalToLocal(&wherePt);
+ wherePt.h -= 1;
+ wherePt.v -= 1;
+
+ whichPart = FindControl(wherePt, mapWindow, &whichControl);
+ if (whichPart == 0) // User clicked in map content area.
+ {
+ localH = wherePt.h / kMapRoomWidth;
+ localV = wherePt.v / kMapRoomHeight;
+
+ if ((localH >= mapRoomsWide) || (localV >= mapRoomsHigh))
+ return;
+
+ roomH = localH + mapLeftRoom;
+ roomV = kMapGroundValue - (localV + mapTopRoom);
+
+ if (RoomExists(roomH, roomV, &itsNumber))
+ {
+ CopyRoomToThisRoom(itsNumber);
+ DeselectObject();
+ ReflectCurrentRoom(false);
+
+ if (thisMac.hasDrag)
+ {
+ SetPortWindowPort(mainWindow);
+ QSetRect(&aRoom, 0, 0, kMapRoomWidth, kMapRoomHeight);
+ CenterRectOnPoint(&aRoom, globalWhere);
+// if (DragRoom(theEvent, &aRoom, itsNumber))
+// { // TEMP disabled.
+// }
+ }
+ }
+ else
+ {
+ if (doBitchDialogs)
+ {
+ if (QueryNewRoom())
+ {
+ if (!CreateNewRoom(roomH, roomV))
+ {
+ YellowAlert(kYellowUnaccounted, 11);
+ return;
+ }
+ else
+ {
+ DeselectObject();
+ ReflectCurrentRoom(false);
+ }
+ }
+ else
+ return;
+ }
+ else
+ {
+ if (!CreateNewRoom(roomH, roomV))
+ {
+ YellowAlert(kYellowUnaccounted, 11);
+ return;
+ }
+ else
+ {
+ DeselectObject();
+ ReflectCurrentRoom(false);
+ }
+ }
+ }
+ }
+ else
+ {
+ controlRef = GetControlReference(whichControl);
+ if (controlRef == kHScrollRef)
+ {
+ switch (whichPart)
+ {
+ case kControlUpButtonPart:
+ case kControlDownButtonPart:
+ case kControlPageUpPart:
+ case kControlPageDownPart:
+ if (TrackControl(whichControl, wherePt, scrollHActionUPP))
+ {
+
+ }
+ break;
+
+ case kControlIndicatorPart:
+ if (TrackControl(whichControl, wherePt, nil))
+ {
+ mapLeftRoom = GetControlValue(whichControl);
+ RedrawMapContents();
+ }
+ break;
+ }
+ }
+ else if (controlRef == kVScrollRef)
+ {
+ switch (whichPart)
+ {
+ case kControlUpButtonPart:
+ case kControlDownButtonPart:
+ case kControlPageUpPart:
+ case kControlPageDownPart:
+ if (TrackControl(whichControl, wherePt, scrollVActionUPP))
+ {
+
+ }
+ break;
+
+ case kControlIndicatorPart:
+ if (TrackControl(whichControl, wherePt, nil))
+ {
+ mapTopRoom = GetControlValue(whichControl);
+ RedrawMapContents();
+ }
+ break;
+ }
+ }
+ }
+
+ DisposeControlActionUPP(scrollHActionUPP);
+ DisposeControlActionUPP(scrollVActionUPP);
+#endif
+}
+
+//-------------------------------------------------------------- QueryNewRoom
+
+#ifndef COMPILEDEMO
+Boolean QueryNewRoom (void)
+{
+ short hitWhat;
+
+// CenterAlert(kNewRoomAlert);
+ hitWhat = Alert(kNewRoomAlert, nil);
+ if (hitWhat == kYesDoNewRoom)
+ return (true);
+ else
+ return (false);
+}
+#endif
+
+//-------------------------------------------------------------- CreateNailOffscreen
+
+#ifndef COMPILEDEMO
+void CreateNailOffscreen (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ if (nailSrcMap == nil)
+ {
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&nailSrcRect, 0, 0, kMapRoomWidth, kMapRoomHeight * (kNumBackgrounds + 1));
+ theErr = CreateOffScreenGWorld(&nailSrcMap, &nailSrcRect, kPreferredDepth);
+ SetGWorld(nailSrcMap, nil);
+ LoadGraphic(kThumbnailPictID);
+
+ SetGWorld(wasCPort, wasWorld);
+ }
+}
+#endif
+
+//-------------------------------------------------------------- KillNailOffscreen
+
+#ifndef COMPILEDEMO
+void KillNailOffscreen (void)
+{
+ if (nailSrcMap != nil)
+ {
+// KillOffScreenPixMap(nailSrcMap);
+ DisposeGWorld(nailSrcMap);
+ nailSrcMap = nil;
+ }
+}
+#endif
+
+//-------------------------------------------------------------- MoveRoom
+
+void MoveRoom (Point wherePt)
+{
+ short localH, localV;
+ short roomH, roomV, itsNumber;
+
+ localH = wherePt.h / kMapRoomWidth;
+ localV = wherePt.v / kMapRoomHeight;
+
+ if ((localH >= mapRoomsWide) || (localV >= mapRoomsHigh))
+ return;
+
+ roomH = localH + mapLeftRoom;
+ roomV = kMapGroundValue - (localV + mapTopRoom);
+
+ if (RoomExists(roomH, roomV, &itsNumber))
+ {
+
+ }
+ else
+ {
+ thisRoom->floor = roomV;
+ thisRoom->suite = roomH;
+ fileDirty = true;
+ UpdateMenus(false);
+ RedrawMapContents();
+ }
+}
+
diff --git a/GpApp/Map.h b/GpApp/Map.h
new file mode 100644
index 0000000..a9ed724
--- /dev/null
+++ b/GpApp/Map.h
@@ -0,0 +1,12 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Map.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+extern GWorldPtr nailSrcMap;
+extern WindowPtr mapWindow;
diff --git a/GpApp/Marquee.cpp b/GpApp/Marquee.cpp
new file mode 100644
index 0000000..7e9d70d
--- /dev/null
+++ b/GpApp/Marquee.cpp
@@ -0,0 +1,511 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Marquee.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Marquee.h"
+#include "Objects.h"
+#include "ObjectEdit.h"
+#include "RectUtils.h"
+
+
+#define kMarqueePatListID 128
+#define kHandleSideLong 9
+
+
+void DrawGliderMarquee (void);
+void DrawMarquee (void);
+
+
+marquee theMarquee;
+Rect marqueeGliderRect;
+Boolean gliderMarqueeUp;
+
+
+extern Cursor handCursor, vertCursor, horiCursor, diagCursor;
+extern Rect leftStartGliderSrc;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DoMarquee
+
+void DoMarquee (void)
+{
+ if ((!theMarquee.active) || (theMarquee.paused))
+ return;
+
+ SetPortWindowPort(mainWindow);
+ PenMode(patXor);
+ PenPat(&theMarquee.pats[theMarquee.index]);
+ DrawMarquee();
+ theMarquee.index++;
+ if (theMarquee.index >= kNumMarqueePats)
+ theMarquee.index = 0;
+ PenPat(&theMarquee.pats[theMarquee.index]);
+ DrawMarquee();
+ PenNormal();
+}
+
+//-------------------------------------------------------------- StartMarquee
+
+void StartMarquee (Rect *theRect)
+{
+ if (theMarquee.active)
+ StopMarquee();
+
+ if (objActive == kNoObjectSelected)
+ return;
+
+ SetPortWindowPort(mainWindow);
+ theMarquee.bounds = *theRect;
+ theMarquee.active = true;
+ theMarquee.paused = false;
+ theMarquee.handled = false;
+ PenMode(patXor);
+ PenPat(&theMarquee.pats[theMarquee.index]);
+ DrawMarquee();
+ PenNormal();
+ SetCoordinateHVD(theMarquee.bounds.left, theMarquee.bounds.top, -1);
+}
+
+//-------------------------------------------------------------- StartMarqueeHandled
+
+void StartMarqueeHandled (Rect *theRect, short direction, short dist)
+{
+ if (theMarquee.active)
+ StopMarquee();
+
+ if (objActive == kNoObjectSelected)
+ return;
+
+ SetPortWindowPort(mainWindow);
+ theMarquee.bounds = *theRect;
+ theMarquee.active = true;
+ theMarquee.paused = false;
+ theMarquee.handled = true;
+ QSetRect(&theMarquee.handle, 0, 0, kHandleSideLong, kHandleSideLong);
+ QOffsetRect(&theMarquee.handle, kHandleSideLong / -2, kHandleSideLong / -2);
+ switch (direction)
+ {
+ case kAbove:
+ QOffsetRect(&theMarquee.handle, theMarquee.bounds.left,
+ theMarquee.bounds.top);
+ QOffsetRect(&theMarquee.handle, HalfRectWide(&theMarquee.bounds), -dist);
+ break;
+
+ case kToRight:
+ QOffsetRect(&theMarquee.handle, theMarquee.bounds.right,
+ theMarquee.bounds.top);
+ QOffsetRect(&theMarquee.handle, dist, HalfRectTall(&theMarquee.bounds));
+ break;
+
+ case kBelow:
+ QOffsetRect(&theMarquee.handle, theMarquee.bounds.left,
+ theMarquee.bounds.bottom);
+ QOffsetRect(&theMarquee.handle, HalfRectWide(&theMarquee.bounds), dist);
+ break;
+
+ case kToLeft:
+ QOffsetRect(&theMarquee.handle, theMarquee.bounds.left,
+ theMarquee.bounds.top);
+ QOffsetRect(&theMarquee.handle, -dist, HalfRectTall(&theMarquee.bounds));
+ break;
+
+ case kBottomCorner:
+ QOffsetRect(&theMarquee.handle, theMarquee.bounds.right,
+ theMarquee.bounds.bottom);
+ break;
+
+ case kTopCorner:
+ QOffsetRect(&theMarquee.handle, theMarquee.bounds.right,
+ theMarquee.bounds.top);
+ break;
+ }
+ theMarquee.direction = direction;
+ theMarquee.dist = dist;
+
+ PenMode(patXor);
+ PenPat(&theMarquee.pats[theMarquee.index]);
+ DrawMarquee();
+ PenNormal();
+ SetCoordinateHVD(theMarquee.bounds.left, theMarquee.bounds.top, dist);
+}
+
+//-------------------------------------------------------------- StopMarquee
+
+void StopMarquee (void)
+{
+ if (gliderMarqueeUp)
+ {
+ DrawGliderMarquee();
+ gliderMarqueeUp = false;
+ }
+
+ if (!theMarquee.active)
+ return;
+
+ SetPortWindowPort(mainWindow);
+ PenMode(patXor);
+ PenPat(&theMarquee.pats[theMarquee.index]);
+ DrawMarquee();
+ PenNormal();
+ theMarquee.active = false;
+ SetCoordinateHVD(-1, -1, -1);
+}
+
+//-------------------------------------------------------------- PauseMarquee
+
+void PauseMarquee (void)
+{
+ if (!theMarquee.active)
+ return;
+
+ theMarquee.paused = true;
+ StopMarquee();
+}
+
+//-------------------------------------------------------------- ResumeMarquee
+
+void ResumeMarquee (void)
+{
+ if (!theMarquee.paused)
+ return;
+
+ if (theMarquee.handled)
+ {
+ StartMarqueeHandled(&theMarquee.bounds, theMarquee.direction, theMarquee.dist);
+ HandleBlowerGlider();
+ }
+ else
+ StartMarquee(&theMarquee.bounds);
+}
+
+//-------------------------------------------------------------- DragOutMarqueeRect
+
+void DragOutMarqueeRect (Point start, Rect *theRect)
+{
+ Point wasPt, newPt;
+
+ SetPortWindowPort(mainWindow);
+ InitCursor();
+ QSetRect(theRect, start.h, start.v, start.h, start.v);
+ PenMode(patXor);
+ PenPat(&theMarquee.pats[theMarquee.index]);
+ FrameRect(theRect);
+ wasPt = start;
+
+ while (WaitMouseUp())
+ {
+ GetMouse(&newPt);
+ if (DeltaPoint(wasPt, newPt))
+ {
+ FrameRect(theRect);
+ QSetRect(theRect, start.h, start.v, newPt.h, newPt.v);
+ NormalizeRect(theRect);
+ FrameRect(theRect);
+ wasPt = newPt;
+ }
+ }
+ FrameRect(theRect);
+ PenNormal();
+}
+
+//-------------------------------------------------------------- DragMarqueeRect
+
+void DragMarqueeRect (Point start, Rect *theRect, Boolean lockH, Boolean lockV)
+{
+ Point wasPt, newPt;
+ short deltaH, deltaV;
+
+ SetCursor(&handCursor);
+ StopMarquee();
+ PenMode(patXor);
+ PenPat(&theMarquee.pats[theMarquee.index]);
+ theMarquee.bounds = *theRect;
+ FrameRect(&theMarquee.bounds);
+
+ wasPt = start;
+ while (WaitMouseUp())
+ {
+ GetMouse(&newPt);
+ if (DeltaPoint(wasPt, newPt))
+ {
+ if (lockV)
+ deltaH = 0;
+ else
+ deltaH = newPt.h - wasPt.h;
+ if (lockH)
+ deltaV = 0;
+ else
+ deltaV = newPt.v - wasPt.v;
+ FrameRect(&theMarquee.bounds);
+ QOffsetRect(&theMarquee.bounds, deltaH, deltaV);
+ FrameRect(&theMarquee.bounds);
+ wasPt = newPt;
+ SetCoordinateHVD(theMarquee.bounds.left, theMarquee.bounds.top, -2);
+ }
+ }
+ FrameRect(&theMarquee.bounds);
+ *theRect = theMarquee.bounds;
+ PenNormal();
+ InitCursor();
+}
+
+//-------------------------------------------------------------- DragMarqueeHandle
+
+void DragMarqueeHandle (Point start, short *dragged)
+{
+ Point wasPt, newPt;
+ short deltaH, deltaV;
+
+ if ((theMarquee.direction == kAbove) || (theMarquee.direction == kBelow))
+ SetCursor(&vertCursor);
+ else
+ SetCursor(&horiCursor);
+ StopMarquee();
+ PenMode(patXor);
+ PenPat(&theMarquee.pats[theMarquee.index]);
+ FrameRect(&theMarquee.bounds);
+ PaintRect(&theMarquee.handle);
+
+ wasPt = start;
+ while (WaitMouseUp())
+ {
+ GetMouse(&newPt);
+ if (DeltaPoint(wasPt, newPt))
+ {
+ switch (theMarquee.direction)
+ {
+ case kAbove:
+ deltaH = 0;
+ deltaV = newPt.v - wasPt.v;
+ *dragged -= deltaV;
+ if (*dragged <= 0)
+ {
+ deltaV += *dragged;
+ *dragged = 0;
+ }
+ DeltaCoordinateD(*dragged);
+ break;
+
+ case kToRight:
+ deltaH = newPt.h - wasPt.h;
+ deltaV = 0;
+ *dragged += deltaH;
+ if (*dragged <= 0)
+ {
+ deltaH -= *dragged;
+ *dragged = 0;
+ }
+ DeltaCoordinateD(*dragged);
+ break;
+
+ case kBelow:
+ deltaH = 0;
+ deltaV = newPt.v - wasPt.v;
+ *dragged += deltaV;
+ if (*dragged <= 0)
+ {
+ deltaV -= *dragged;
+ *dragged = 0;
+ }
+ DeltaCoordinateD(*dragged);
+ break;
+
+ case kToLeft:
+ deltaH = newPt.h - wasPt.h;
+ deltaV = 0;
+ *dragged -= deltaH;
+ if (*dragged <= 0)
+ {
+ deltaH += *dragged;
+ *dragged = 0;
+ }
+ DeltaCoordinateD(*dragged);
+ break;
+ }
+
+ PaintRect(&theMarquee.handle);
+ QOffsetRect(&theMarquee.handle, deltaH, deltaV);
+ PaintRect(&theMarquee.handle);
+ wasPt = newPt;
+ }
+ }
+ FrameRect(&theMarquee.bounds);
+ PaintRect(&theMarquee.handle);
+ PenNormal();
+ InitCursor();
+}
+
+//-------------------------------------------------------------- DragMarqueeCorner
+
+void DragMarqueeCorner (Point start, short *hDragged, short *vDragged, Boolean isTop)
+{
+ Point wasPt, newPt;
+ short deltaH, deltaV;
+
+ SetCursor(&diagCursor);
+ StopMarquee();
+ PenMode(patXor);
+ PenPat(&theMarquee.pats[theMarquee.index]);
+ FrameRect(&theMarquee.bounds);
+ PaintRect(&theMarquee.handle);
+
+ wasPt = start;
+ while (WaitMouseUp())
+ {
+ GetMouse(&newPt);
+ if (DeltaPoint(wasPt, newPt))
+ {
+ deltaH = newPt.h - wasPt.h;
+ if (isTop)
+ deltaV = wasPt.v - newPt.v;
+ else
+ deltaV = newPt.v - wasPt.v;
+ *hDragged += deltaH;
+ if (*hDragged <= 0)
+ {
+ deltaH -= *hDragged;
+ *hDragged = 0;
+ }
+ *vDragged += deltaV;
+ if (*vDragged <= 0)
+ {
+ deltaV -= *vDragged;
+ *vDragged = 0;
+ }
+ FrameRect(&theMarquee.bounds);
+ PaintRect(&theMarquee.handle);
+ if (isTop)
+ {
+ QOffsetRect(&theMarquee.handle, deltaH, -deltaV);
+ theMarquee.bounds.right += deltaH;
+ theMarquee.bounds.top -= deltaV;
+ }
+ else
+ {
+ QOffsetRect(&theMarquee.handle, deltaH, deltaV);
+ theMarquee.bounds.right += deltaH;
+ theMarquee.bounds.bottom += deltaV;
+ }
+ FrameRect(&theMarquee.bounds);
+ PaintRect(&theMarquee.handle);
+ wasPt = newPt;
+ }
+ }
+ FrameRect(&theMarquee.bounds);
+ PaintRect(&theMarquee.handle);
+ PenNormal();
+ InitCursor();
+}
+
+//-------------------------------------------------------------- MarqueeHasHandles
+
+Boolean MarqueeHasHandles (short *direction, short *dist)
+{
+ if (theMarquee.handled)
+ {
+ *direction = theMarquee.direction;
+ *dist = theMarquee.dist;
+ return (true);
+ }
+ else
+ {
+ *direction = 0;
+ *dist = 0;
+ return (false);
+ }
+}
+
+//-------------------------------------------------------------- PtInMarqueeHandle
+
+Boolean PtInMarqueeHandle (Point where)
+{
+ return (PtInRect(where, &theMarquee.handle));
+}
+
+//-------------------------------------------------------------- DrawGliderMarquee
+
+void DrawGliderMarquee (void)
+{
+ CopyBits((BitMap *)*GetGWorldPixMap(blowerMaskMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &leftStartGliderSrc,
+ &marqueeGliderRect,
+ srcXor, nil);
+}
+
+//-------------------------------------------------------------- SetMarqueeGliderCenter
+
+void SetMarqueeGliderRect (short h, short v)
+{
+ marqueeGliderRect = leftStartGliderSrc;
+ ZeroRectCorner(&marqueeGliderRect);
+ QOffsetRect(&marqueeGliderRect, h - kHalfGliderWide, v - kGliderHigh);
+
+ DrawGliderMarquee();
+ gliderMarqueeUp = true;
+}
+
+//-------------------------------------------------------------- DrawMarquee
+
+void DrawMarquee (void)
+{
+ FrameRect(&theMarquee.bounds);
+ if (theMarquee.handled)
+ {
+ PaintRect(&theMarquee.handle);
+ switch (theMarquee.direction)
+ {
+ case kAbove:
+ MoveTo(theMarquee.handle.left + (kHandleSideLong / 2),
+ theMarquee.handle.bottom);
+ LineTo(theMarquee.handle.left + (kHandleSideLong / 2),
+ theMarquee.bounds.top - 1);
+ break;
+
+ case kToRight:
+ MoveTo(theMarquee.handle.left,
+ theMarquee.handle.top + (kHandleSideLong / 2));
+ LineTo(theMarquee.bounds.right,
+ theMarquee.handle.top + (kHandleSideLong / 2));
+ break;
+
+ case kBelow:
+ MoveTo(theMarquee.handle.left + (kHandleSideLong / 2),
+ theMarquee.handle.top - 1);
+ LineTo(theMarquee.handle.left + (kHandleSideLong / 2),
+ theMarquee.bounds.bottom);
+ break;
+
+ case kToLeft:
+ MoveTo(theMarquee.handle.right,
+ theMarquee.handle.top + (kHandleSideLong / 2));
+ LineTo(theMarquee.bounds.left,
+ theMarquee.handle.top + (kHandleSideLong / 2));
+ break;
+ }
+ }
+
+ if (gliderMarqueeUp)
+ DrawGliderMarquee();
+}
+
+//-------------------------------------------------------------- InitMarquee
+
+void InitMarquee (void)
+{
+ short i;
+
+ for (i = 0; i < kNumMarqueePats; i++)
+ GetIndPattern(&theMarquee.pats[i], kMarqueePatListID, i + 1);
+ theMarquee.index = 0;
+ theMarquee.active = false;
+ theMarquee.paused = false;
+ theMarquee.handled = false;
+ gliderMarqueeUp = false;
+}
+
diff --git a/GpApp/Marquee.h b/GpApp/Marquee.h
new file mode 100644
index 0000000..09d324c
--- /dev/null
+++ b/GpApp/Marquee.h
@@ -0,0 +1,24 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Marquee.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#pragma once
+
+
+#include "PLQuickdraw.h"
+
+
+typedef struct
+{
+ Pattern pats[kNumMarqueePats];
+ Rect bounds, handle;
+ short index, direction, dist;
+ Boolean active, paused, handled;
+} marquee;
+
+
+extern marquee theMarquee;
+
diff --git a/GpApp/Menu.cpp b/GpApp/Menu.cpp
new file mode 100644
index 0000000..da07779
--- /dev/null
+++ b/GpApp/Menu.cpp
@@ -0,0 +1,814 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Menu.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+//#include
+#include "PLNumberFormatting.h"
+#include "PLPasStr.h"
+#include "PLToolUtils.h"
+#include "DialogUtils.h"
+#include "Externs.h"
+#include "House.h"
+#include "ObjectEdit.h"
+
+
+#define kSheWantsNewGame 1
+#define kSheWantsResumeGame 2
+
+
+void UpdateMenusEditMode (void);
+void UpdateMenusNonEditMode (void);
+void UpdateMenusHouseOpen (void);
+void UpdateMenusHouseClosed (void);
+void UpdateResumeDialog (DialogPtr);
+Boolean ResumeFilter (DialogPtr, EventRecord *, short *);
+short QueryResumeGame (void);
+void HeyYourPissingAHighScore (void);
+
+
+MenuHandle appleMenu, gameMenu, optionsMenu, houseMenu;
+Boolean menusUp, resumedSavedGame;
+
+
+extern long incrementModeTime;
+extern short demoHouseIndex, wasHouseVersion;
+extern short splashOriginH, splashOriginV, numberRooms;
+extern Boolean quitting, noRoomAtAll, twoPlayerGame;
+extern Boolean isMapOpen, isToolsOpen, isPlayMusicIdle;
+extern Boolean isCoordOpen, failedMusic, splashDrawn;
+extern Boolean houseOpen;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- UpdateMenusEditMode
+// Sets the menus to reflect that user is in edit mode.
+
+void UpdateMenusEditMode (void)
+{
+ DisableMenuItem(gameMenu, iNewGame);
+ DisableMenuItem(gameMenu, iTwoPlayer);
+ DisableMenuItem(gameMenu, iOpenSavedGame);
+ DisableMenuItem(optionsMenu, iHighScores);
+ DisableMenuItem(optionsMenu, iHelp);
+ CheckMenuItem(optionsMenu, iEditor, true);
+}
+
+//-------------------------------------------------------------- UpdateMenusNonEditMode
+// Sets the menus to reflect that user is NOT in edit mode.
+
+void UpdateMenusNonEditMode (void)
+{
+ if ((noRoomAtAll) || (!houseOpen) || (numberRooms <= 0))
+ {
+ DisableMenuItem(gameMenu, iNewGame);
+ DisableMenuItem(gameMenu, iTwoPlayer);
+ DisableMenuItem(gameMenu, iOpenSavedGame);
+ if (houseOpen)
+ {
+ EnableMenuItem(gameMenu, iLoadHouse);
+ EnableMenuItem(optionsMenu, iHighScores);
+ }
+ else
+ {
+ DisableMenuItem(gameMenu, iLoadHouse);
+ DisableMenuItem(optionsMenu, iHighScores);
+ }
+ }
+ else
+ {
+ EnableMenuItem(gameMenu, iNewGame);
+ EnableMenuItem(gameMenu, iTwoPlayer);
+ EnableMenuItem(gameMenu, iOpenSavedGame);
+ EnableMenuItem(gameMenu, iLoadHouse);
+ EnableMenuItem(optionsMenu, iHighScores);
+ }
+ if (demoHouseIndex == -1)
+ DisableMenuItem(optionsMenu, iHelp);
+ else
+ EnableMenuItem(optionsMenu, iHelp);
+ CheckMenuItem(optionsMenu, iEditor, false);
+}
+
+//-------------------------------------------------------------- UpdateMenusHouseOpen
+// Sets the menus to reflect that a house is currently open.
+
+void UpdateMenusHouseOpen (void)
+{
+ EnableMenuItem(gameMenu, iLoadHouse);
+ if ((fileDirty) && (houseUnlocked))
+ EnableMenuItem(houseMenu, iSave);
+ else
+ DisableMenuItem(houseMenu, iSave);
+ if (houseUnlocked)
+ {
+ // EnableMenuItem(houseMenu, iSaveAs);
+ EnableMenuItem(houseMenu, iHouse);
+ }
+ else
+ {
+ // DisableMenuItem(houseMenu, iSaveAs);
+ DisableMenuItem(houseMenu, iHouse);
+ }
+ if ((noRoomAtAll) || (!houseUnlocked))
+ DisableMenuItem(houseMenu, iRoom);
+ else
+ EnableMenuItem(houseMenu, iRoom);
+ if ((objActive == kNoObjectSelected) || (!houseUnlocked))
+ {
+ DisableMenuItem(houseMenu, iObject);
+ DisableMenuItem(houseMenu, iBringForward);
+ DisableMenuItem(houseMenu, iSendBack);
+ }
+ else
+ {
+ EnableMenuItem(houseMenu, iObject);
+ if ((objActive == kInitialGliderSelected) ||
+ (objActive == kLeftGliderSelected) ||
+ (objActive == kRightGliderSelected))
+ {
+ DisableMenuItem(houseMenu, iBringForward);
+ DisableMenuItem(houseMenu, iSendBack);
+ }
+ else
+ {
+ EnableMenuItem(houseMenu, iBringForward);
+ EnableMenuItem(houseMenu, iSendBack);
+ }
+ }
+}
+
+//-------------------------------------------------------------- UpdateMenusHouseClosed
+// Sets the menus to reflect that a house is NOT currently open.
+
+void UpdateMenusHouseClosed (void)
+{
+ DisableMenuItem(gameMenu, iLoadHouse);
+ DisableMenuItem(houseMenu, iSave);
+ // DisableMenuItem(houseMenu, iSaveAs);
+ DisableMenuItem(houseMenu, iHouse);
+ DisableMenuItem(houseMenu, iRoom);
+ DisableMenuItem(houseMenu, iObject);
+ DisableMenuItem(houseMenu, iCut);
+ DisableMenuItem(houseMenu, iCopy);
+ DisableMenuItem(houseMenu, iPaste);
+ DisableMenuItem(houseMenu, iClear);
+ DisableMenuItem(houseMenu, iDuplicate);
+}
+
+//-------------------------------------------------------------- UpdateClipboardMenus
+// Set the Cut/Copy/Paste menus to reflect if we have data in theÉ
+// Mac's "clipboard" or not.
+
+void UpdateClipboardMenus (void)
+{
+ Str255 title;
+
+ if (!houseOpen)
+ return;
+
+ if (houseUnlocked)
+ {
+ if (objActive > kNoObjectSelected)
+ {
+ GetLocalizedString(36, title);
+ SetMenuItemText(houseMenu, iCut, title);
+ GetLocalizedString(37, title);
+ SetMenuItemText(houseMenu, iCopy, title);
+ GetLocalizedString(38, title);
+ SetMenuItemText(houseMenu, iClear, title);
+ EnableMenuItem(houseMenu, iDuplicate);
+ }
+ else
+ {
+ GetLocalizedString(39, title);
+ SetMenuItemText(houseMenu, iCut, title);
+ GetLocalizedString(40, title);
+ SetMenuItemText(houseMenu, iCopy, title);
+ GetLocalizedString(41, title);
+ SetMenuItemText(houseMenu, iClear, title);
+ DisableMenuItem(houseMenu, iDuplicate);
+ }
+
+ EnableMenuItem(houseMenu, iCut);
+ EnableMenuItem(houseMenu, iCopy);
+// if (hasScrap)
+// {
+// EnableMenuItem(houseMenu, iPaste);
+// if (scrapIsARoom)
+// {
+// GetLocalizedString(42, title);
+// SetMenuItemText(houseMenu, iPaste, title);
+// }
+// else
+// {
+// GetLocalizedString(43, title);
+// SetMenuItemText(houseMenu, iPaste, title);
+// }
+// }
+// else
+ {
+ DisableMenuItem(houseMenu, iPaste);
+ GetLocalizedString(44, title);
+ SetMenuItemText(houseMenu, iPaste, title);
+ }
+ EnableMenuItem(houseMenu, iClear);
+ EnableMenuItem(houseMenu, iGoToRoom);
+ EnableMenuItem(houseMenu, iMapWindow);
+ EnableMenuItem(houseMenu, iObjectWindow);
+ EnableMenuItem(houseMenu, iCoordinateWindow);
+ }
+ else
+ {
+ DisableMenuItem(houseMenu, iCut);
+ DisableMenuItem(houseMenu, iCopy);
+ DisableMenuItem(houseMenu, iPaste);
+ DisableMenuItem(houseMenu, iClear);
+ DisableMenuItem(houseMenu, iDuplicate);
+ DisableMenuItem(houseMenu, iGoToRoom);
+ DisableMenuItem(houseMenu, iMapWindow);
+ DisableMenuItem(houseMenu, iObjectWindow);
+ DisableMenuItem(houseMenu, iCoordinateWindow);
+ }
+}
+
+//-------------------------------------------------------------- UpdateMenus
+// Called whenever a significant change to the environment has takenÉ
+// place and some of the menu states may have changes (for example,É
+// a menui was grayed out before becuase it wasn't an option - nowÉ
+// perhaps the situation has changed and we want the menu to be "usable").
+
+void UpdateMenus (Boolean newMode)
+{
+ if (!menusUp)
+ return;
+
+ if (newMode)
+ {
+ if (theMode == kEditMode)
+ InsertMenu(houseMenu, 0);
+ else
+ DeleteMenu(kHouseMenuID);
+ }
+
+ if (theMode == kEditMode)
+ {
+ UpdateMenusEditMode();
+ if (houseOpen)
+ {
+ UpdateMenusHouseOpen();
+ UpdateClipboardMenus();
+ }
+ else
+ UpdateMenusHouseClosed();
+ UpdateLinkControl();
+ }
+ else
+ UpdateMenusNonEditMode();
+
+ DrawMenuBar();
+}
+
+//-------------------------------------------------------------- DoAppleMenu
+// Handle the Apple menu (About box and desk accessories).
+
+void DoAppleMenu (short theItem)
+{
+// Str255 daName;
+// GrafPtr wasPort;
+// short daNumber;
+
+ switch (theItem)
+ {
+ case iAbout:
+ DoAbout();
+ break;
+
+ default:
+// GetMenuItemText(appleMenu, theItem, daName);
+// GetPort(&wasPort);
+// daNumber = OpenDeskAccesory(daName);
+// SetPort((GrafPtr)wasPort);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoGameMenu
+// Handle the user selecting an item from the Game menu.
+
+void DoGameMenu (short theItem)
+{
+ switch (theItem)
+ {
+ case iNewGame:
+ twoPlayerGame = false;
+ resumedSavedGame = false;
+ NewGame(kNewGameMode);
+ break;
+
+ case iTwoPlayer:
+ twoPlayerGame = true;
+ resumedSavedGame = false;
+ NewGame(kNewGameMode);
+ break;
+
+ case iOpenSavedGame:
+ resumedSavedGame = true;
+ HeyYourPissingAHighScore();
+ if (OpenSavedGame())
+ {
+ twoPlayerGame = false;
+ NewGame(kResumeGameMode);
+ }
+ break;
+
+ case iLoadHouse:
+#ifdef COMPILEDEMO
+ DoNotInDemo();
+#else
+ if (splashDrawn)
+ {
+ DoLoadHouse();
+ OpenCloseEditWindows();
+ UpdateMenus(false);
+ incrementModeTime = TickCount() + kIdleSplashTicks;
+ if ((theMode == kSplashMode) || (theMode == kPlayMode))
+ {
+ Rect updateRect;
+
+ SetRect(&updateRect, splashOriginH + 474, splashOriginV + 304, splashOriginH + 474 + 166, splashOriginV + 304 + 12);
+ InvalWindowRect(mainWindow, &updateRect);
+ }
+ }
+#endif
+ break;
+
+ case iQuit:
+#ifndef COMPILEDEMO
+ quitting = true;
+ if (!QuerySaveChanges())
+ quitting = false;
+#else
+ quitting = true;
+#endif
+ break;
+
+ default:
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoOptionsMenu
+// Handle the user selecting an item from the Options menu.
+
+void DoOptionsMenu (short theItem)
+{
+#ifndef COMPILEDEMO
+ OSErr theErr;
+#endif
+
+ switch (theItem)
+ {
+ case iEditor:
+#ifdef COMPILEDEMO
+ DoNotInDemo();
+#else
+ if (theMode == kEditMode) // switching to splash mode
+ {
+ if (fileDirty)
+ SortHouseObjects();
+ if (!QuerySaveChanges())
+ break;
+ theMode = kSplashMode;
+ CloseMapWindow();
+ CloseToolsWindow();
+ CloseCoordWindow();
+ CloseLinkWindow();
+ DeselectObject();
+ StopMarquee();
+ if (isPlayMusicIdle)
+ {
+ theErr = StartMusic();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowNoMusic, theErr);
+ failedMusic = true;
+ }
+ }
+ CloseMainWindow();
+ OpenMainWindow();
+ incrementModeTime = TickCount() + kIdleSplashTicks;
+ }
+ else if (theMode == kSplashMode) // switching to edit mode
+ {
+ theMode = kEditMode;
+ StopTheMusic();
+ CloseMainWindow();
+ OpenMainWindow();
+ OpenCloseEditWindows();
+ }
+ InitCursor();
+ UpdateMenus(true);
+#endif
+ break;
+
+ case iHighScores:
+ DoHighScores();
+ incrementModeTime = TickCount() + kIdleSplashTicks;
+ break;
+
+ case iPrefs:
+ DoSettingsMain();
+ incrementModeTime = TickCount() + kIdleSplashTicks;
+ break;
+
+ case iHelp:
+ DoDemoGame();
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoHouseMenu
+// Handle the user selecting an item from the House menu (only in Edit mode).
+
+void DoHouseMenu (short theItem)
+{
+#ifndef COMPILEDEMO
+ short direction, dist;
+ Boolean whoCares;
+
+ switch (theItem)
+ {
+ case iNewHouse:
+ if (CreateNewHouse())
+ {
+ whoCares = InitializeEmptyHouse();
+ OpenCloseEditWindows();
+ }
+ break;
+
+ case iSave:
+ DeselectObject();
+ if (fileDirty)
+ SortHouseObjects();
+ if ((fileDirty) && (houseUnlocked))
+ {
+// SaveGame(false);
+ if (wasHouseVersion < kHouseVersion)
+ ConvertHouseVer1To2();
+ wasHouseVersion = kHouseVersion;
+ whoCares = WriteHouse(true);
+ ForceThisRoom(thisRoomNumber);
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ GetThisRoomsObjRects();
+ DrawThisRoomsObjects();
+ }
+ break;
+
+// case iSaveAs:
+// whoCares = SaveHouseAs();
+// break;
+
+ case iHouse:
+ if (houseUnlocked)
+ DoHouseInfo();
+ break;
+
+ case iRoom:
+ if (houseUnlocked)
+ DoRoomInfo();
+ break;
+
+ case iObject:
+ if (houseUnlocked)
+ {
+ DoObjectInfo();
+ if (ObjectHasHandle(&direction, &dist))
+ {
+ StartMarqueeHandled(&roomObjectRects[objActive], direction, dist);
+ HandleBlowerGlider();
+ }
+ else
+ StartMarquee(&roomObjectRects[objActive]);
+ }
+ break;
+
+ case iCut:
+ if (houseUnlocked)
+ {
+ if (objActive > kNoObjectSelected)
+ {
+// PutObjectScrap();
+ DeleteObject();
+ }
+ else
+ {
+// PutRoomScrap();
+ DeleteRoom(false);
+ }
+ UpdateClipboardMenus();
+ }
+ break;
+
+ case iCopy:
+ if (houseUnlocked)
+ {
+// if (objActive > kNoObjectSelected)
+// PutObjectScrap();
+// else
+// PutRoomScrap();
+ UpdateClipboardMenus();
+ }
+ break;
+
+ case iPaste:
+ if (houseUnlocked)
+ {
+/* if (scrapIsARoom)
+ GetRoomScrap();
+ else
+ GetObjectScrap();
+ UpdateClipboardMenus();
+*/
+ }
+ break;
+
+ case iClear:
+ if (houseUnlocked)
+ {
+ if (objActive > kNoObjectSelected)
+ DeleteObject();
+ else
+ DeleteRoom(false);
+ UpdateClipboardMenus();
+ }
+ break;
+
+ case iDuplicate:
+ if (houseUnlocked)
+ DuplicateObject();
+ break;
+
+ case iBringForward:
+ if (houseUnlocked)
+ BringSendFrontBack(true);
+ break;
+
+ case iSendBack:
+ if (houseUnlocked)
+ BringSendFrontBack(false);
+ break;
+
+ case iGoToRoom:
+ if (houseUnlocked)
+ DoGoToDialog();
+ break;
+
+ case iMapWindow:
+ if (houseUnlocked)
+ ToggleMapWindow();
+ break;
+
+ case iObjectWindow:
+ if (houseUnlocked)
+ ToggleToolsWindow();
+ break;
+
+ case iCoordinateWindow:
+ if (houseUnlocked)
+ ToggleCoordinateWindow();
+ break;
+ }
+#endif
+}
+
+//-------------------------------------------------------------- DoMenuChoice
+// Users has selected a menu item - determin which menu was selectedÉ
+// and call the appropriate function above.
+
+void DoMenuChoice (long menuChoice)
+{
+ short theMenu, theItem;
+
+ if (menuChoice == 0)
+ return;
+
+ theMenu = HiWord(menuChoice);
+ theItem = LoWord(menuChoice);
+
+ switch (theMenu)
+ {
+ case kAppleMenuID:
+ DoAppleMenu(theItem);
+ break;
+
+ case kGameMenuID:
+ DoGameMenu(theItem);
+ break;
+
+ case kOptionsMenuID:
+ DoOptionsMenu(theItem);
+ break;
+
+ case kHouseMenuID:
+ DoHouseMenu(theItem);
+ break;
+ }
+
+ HiliteMenu(0);
+}
+
+//-------------------------------------------------------------- UpdateMapCheckmark
+// Checks or unchecks the Map Window item (to indicate if open or not).
+
+void UpdateMapCheckmark (Boolean checkIt)
+{
+ if (!menusUp)
+ return;
+
+ CheckMenuItem(houseMenu, iMapWindow, checkIt);
+}
+
+//-------------------------------------------------------------- UpdateToolsCheckmark
+// Checks or unchecks the Tools Window item (to indicate if open or not).
+
+void UpdateToolsCheckmark (Boolean checkIt)
+{
+ if (!menusUp)
+ return;
+
+ CheckMenuItem(houseMenu, iObjectWindow, checkIt);
+}
+
+//-------------------------------------------------------------- UpdateCoordinateCheckmark
+// Checks or unchecks the Coordinates Window item (to indicate if open or not).
+
+void UpdateCoordinateCheckmark (Boolean checkIt)
+{
+ if (!menusUp)
+ return;
+
+ CheckMenuItem(houseMenu, iCoordinateWindow, checkIt);
+}
+
+//-------------------------------------------------------------- UpdateResumeDialog
+// Update function for Resume dialog (below).
+
+void UpdateResumeDialog (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+}
+
+//-------------------------------------------------------------- ResumeFilter
+// Dialog filter for the Resume dialog (below).
+
+Boolean ResumeFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ if ((WindowPtr)event->message == GetDialogWindow(dial))
+ {
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateResumeDialog(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ }
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- QueryResumeGame
+// Dialog that asks user whether they want to resume a saved game orÉ
+// begin a new one. It displays a little info on the state of theirÉ
+// saved game (number of glider left, points, etc.).
+
+short QueryResumeGame (void)
+{
+ #define kResumeGameDial 1025
+ DialogPtr theDial;
+ houseType *thisHousePtr;
+ Str255 scoreStr, glidStr;
+ long hadPoints;
+ short hitWhat, hadGliders;
+ char wasState;
+ Boolean leaving;
+ ModalFilterUPP resumeFilterUPP;
+
+ resumeFilterUPP = NewModalFilterUPP(ResumeFilter);
+
+ wasState = HGetState((Handle)thisHouse); // get score & num. gliders
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+ hadPoints = thisHousePtr->savedGame.score;
+ hadGliders = thisHousePtr->savedGame.numGliders;
+ HSetState((Handle)thisHouse, wasState);
+ NumToString(hadPoints, scoreStr); // param text strings
+ NumToString((long)hadGliders, glidStr);
+ if (hadGliders == 1)
+ ParamText(glidStr, PSTR(""), scoreStr, PSTR(""));
+ else
+ ParamText(glidStr, PSTR("s"), scoreStr, PSTR(""));
+
+// CenterDialog(kResumeGameDial);
+ theDial = GetNewDialog(kResumeGameDial, nil, kPutInFront);
+ if (theDial == nil)
+ RedAlert(kErrDialogDidntLoad);
+ SetPort((GrafPtr)theDial);
+
+ ShowWindow(GetDialogWindow(theDial));
+ DrawDefaultButton(theDial);
+ leaving = false;
+
+ while (!leaving)
+ {
+ ModalDialog(resumeFilterUPP, &hitWhat);
+ if ((hitWhat == kSheWantsNewGame) || (hitWhat == kSheWantsResumeGame))
+ {
+ leaving = true;
+ }
+ }
+ DisposeDialog(theDial);
+ DisposeModalFilterUPP(resumeFilterUPP);
+
+ return (hitWhat);
+}
+
+//-------------------------------------------------------------- DoNotInDemo
+// Only compiled for "demo version" of Glider PRO. It brings up aÉ
+// dialog that says, essentially, "x" feature is not implemented inÉ
+// the demo version.
+
+#ifdef COMPILEDEMO
+void DoNotInDemo (void)
+{
+ #define kNotInDemoAlert 1037
+ short whoCares;
+
+// CenterAlert(kNotInDemoAlert);
+ whoCares = Alert(kNotInDemoAlert, nil);
+}
+#endif
+
+//-------------------------------------------------------------- HeyYourPissingAHighScore
+
+void HeyYourPissingAHighScore (void)
+{
+ #define kNoHighScoreAlert 1046
+ short whoCares;
+
+// CenterAlert(kNoHighScoreAlert);
+ whoCares = Alert(kNoHighScoreAlert, nil);
+}
+
+//-------------------------------------------------------------- OpenCloseEditWindows
+// Function goes through and either closes or opens all the variousÉ
+// editing windows (in response to switching in or out of editor).
+
+void OpenCloseEditWindows (void)
+{
+ if (theMode == kEditMode)
+ {
+ if (houseUnlocked)
+ {
+ if (isMapOpen)
+ OpenMapWindow();
+ if (isToolsOpen)
+ OpenToolsWindow();
+ if (isCoordOpen)
+ OpenCoordWindow();
+ }
+ else
+ {
+ CloseMapWindow();
+ CloseToolsWindow();
+ CloseCoordWindow();
+ }
+ }
+}
+
diff --git a/GpApp/Modes.cpp b/GpApp/Modes.cpp
new file mode 100644
index 0000000..03f7a3b
--- /dev/null
+++ b/GpApp/Modes.cpp
@@ -0,0 +1,640 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Modes.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "RectUtils.h"
+
+
+short saidFollow;
+
+extern Rect gliderSrc[];
+extern Rect transRect;
+extern short fadeInSequence[], linkedToWhat;
+extern short rightClip, leftClip, transRoom;
+extern Boolean hasMirror, shadowVisible, firstPlayer, twoPlayerGame;
+extern Boolean onePlayerLeft, playerDead;
+
+//============================================================== Functions
+//-------------------------------------------------------------- StartGliderFadingIn
+
+void StartGliderFadingIn (gliderPtr thisGlider)
+{
+ if (foilTotal <= 0)
+ showFoil = false;
+
+ thisGlider->mode = kGliderFadingIn;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->frame = 0;
+ thisGlider->dontDraw = false;
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src =
+ gliderSrc[fadeInSequence[thisGlider->frame] + kLeftFadeOffset];
+ thisGlider->mask =
+ gliderSrc[fadeInSequence[thisGlider->frame] + kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame]];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame]];
+ }
+}
+
+//-------------------------------------------------------------- StartGliderTransportingIn
+
+void StartGliderTransportingIn (gliderPtr thisGlider)
+{
+ if (foilTotal <= 0)
+ showFoil = false;
+
+ thisGlider->mode = kGliderTransportingIn;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->frame = 0;
+ thisGlider->dontDraw = false;
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src =
+ gliderSrc[fadeInSequence[thisGlider->frame] + kLeftFadeOffset];
+ thisGlider->mask =
+ gliderSrc[fadeInSequence[thisGlider->frame] + kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame]];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame]];
+ }
+}
+
+//-------------------------------------------------------------- StartGliderFadingOut
+
+void StartGliderFadingOut (gliderPtr thisGlider)
+{
+ Rect tempBounds;
+
+ if (thisGlider->mode == kGliderFadingOut)
+ return;
+
+ if (thisGlider->mode == kGliderGoingFoil)
+ DeckGliderInFoil(thisGlider);
+ else if (thisGlider->mode == kGliderLosingFoil)
+ RemoveFoilFromGlider(thisGlider);
+
+ if (RectTall(&thisGlider->dest) > kGliderHigh)
+ {
+ tempBounds = thisGlider->dest;
+ QOffsetRect(&tempBounds, playOriginH, playOriginV);
+ AddRectToWorkRects(&tempBounds);
+ if (hasMirror)
+ {
+ tempBounds = thisGlider->dest;
+ QOffsetRect(&tempBounds, playOriginH - 20, playOriginV - 16);
+ AddRectToWorkRects(&tempBounds);
+ }
+ thisGlider->dest.right = thisGlider->dest.left + kGliderWide;
+ thisGlider->dest.top = thisGlider->dest.bottom - kGliderHigh;
+ }
+ thisGlider->mode = kGliderFadingOut;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->frame = kLastFadeSequence - 1;
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src =
+ gliderSrc[fadeInSequence[thisGlider->frame] + kLeftFadeOffset];
+ thisGlider->mask =
+ gliderSrc[fadeInSequence[thisGlider->frame] + kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame]];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame]];
+ }
+}
+
+//-------------------------------------------------------------- StartGliderGoingUpStairs
+
+void StartGliderGoingUpStairs (gliderPtr thisGlider)
+{
+ if (thisGlider->mode == kGliderGoingFoil)
+ DeckGliderInFoil(thisGlider);
+ else if (thisGlider->mode == kGliderLosingFoil)
+ RemoveFoilFromGlider(thisGlider);
+
+ if (thisGlider->mode == kGliderBurning)
+ thisGlider->frame = kWasBurning;
+ else
+ thisGlider->frame = 0;
+
+ thisGlider->mode = kGliderGoingUp;
+}
+
+//-------------------------------------------------------------- StartGliderGoingDownStairs
+
+void StartGliderGoingDownStairs (gliderPtr thisGlider)
+{
+ if (thisGlider->mode == kGliderGoingFoil)
+ DeckGliderInFoil(thisGlider);
+ else if (thisGlider->mode == kGliderLosingFoil)
+ RemoveFoilFromGlider(thisGlider);
+
+ if (thisGlider->mode == kGliderBurning)
+ thisGlider->frame = kWasBurning;
+ else
+ thisGlider->frame = 0;
+
+ thisGlider->mode = kGliderGoingDown;
+ rightClip = GetUpStairsRightEdge();
+}
+
+//-------------------------------------------------------------- StartGliderMailingIn
+
+void StartGliderMailingIn (gliderPtr thisGlider, Rect *bounds, hotPtr who)
+{
+ short topSought, whoLinked;
+ Byte objLinked;
+ char wasState;
+
+ PlayPrioritySound(kTransOutSound, kTransOutPriority);
+
+ whoLinked = who->who;
+ transRoom = masterObjects[whoLinked].roomLink;
+ objLinked = masterObjects[whoLinked].objectLink;
+ linkedToWhat = WhatAreWeLinkedTo(transRoom, objLinked);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ GetObjectRect(&(*thisHouse)->rooms[transRoom].objects[objLinked], &transRect);
+ HSetState((Handle)thisHouse, wasState);
+
+ thisGlider->frame = 0;
+ thisGlider->clip = *bounds;
+ topSought = bounds->bottom - RectTall(&thisGlider->dest);
+ thisGlider->clip.top = topSought;
+}
+
+//-------------------------------------------------------------- StartGliderMailingOut
+
+void StartGliderMailingOut (gliderPtr thisGlider)
+{
+ if (thisGlider->mode == kGliderGoingFoil)
+ DeckGliderInFoil(thisGlider);
+ else if (thisGlider->mode == kGliderLosingFoil)
+ RemoveFoilFromGlider(thisGlider);
+
+ if (linkedToWhat == kLinkedToLeftMailbox)
+ {
+ thisGlider->facing = kFaceLeft;
+ thisGlider->mode = kGliderMailOutLeft;
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ else
+ {
+ thisGlider->facing = kFaceRight;
+ thisGlider->mode = kGliderMailOutRight;
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ }
+
+ thisGlider->hVel = 0;
+ thisGlider->vVel = 0;
+ thisGlider->hDesiredVel = 0;
+ thisGlider->vDesiredVel = 0;
+ thisGlider->tipped = false;
+ thisGlider->dontDraw = false;
+}
+
+//-------------------------------------------------------------- StartGliderDuctingDown
+
+void StartGliderDuctingDown (gliderPtr thisGlider, Rect *bounds, hotPtr who)
+{
+ short leftSought, whoLinked;
+ Byte objLinked;
+ char wasState;
+
+ PlayPrioritySound(kTransOutSound, kTransOutPriority);
+
+ if (thisGlider->mode == kGliderGoingFoil)
+ DeckGliderInFoil(thisGlider);
+ else if (thisGlider->mode == kGliderLosingFoil)
+ RemoveFoilFromGlider(thisGlider);
+
+ whoLinked = who->who;
+ transRoom = masterObjects[whoLinked].roomLink;
+ objLinked = masterObjects[whoLinked].objectLink;
+ linkedToWhat = WhatAreWeLinkedTo(transRoom, objLinked);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ GetObjectRect(&(*thisHouse)->rooms[transRoom].objects[objLinked], &transRect);
+ HSetState((Handle)thisHouse, wasState);
+
+ thisGlider->frame = 0;
+ thisGlider->clip = *bounds;
+ leftSought = bounds->left + ((RectWide(bounds) - kGliderWide) / 2);
+ thisGlider->clip.left = leftSought;
+
+ thisGlider->mode = kGliderDuctingDown;
+}
+
+//-------------------------------------------------------------- StartGliderDuctingUp
+
+void StartGliderDuctingUp (gliderPtr thisGlider, Rect *bounds, hotPtr who)
+{
+ short leftSought, whoLinked;
+ Byte objLinked;
+ char wasState;
+
+ PlayPrioritySound(kTransOutSound, kTransOutPriority);
+
+ if (thisGlider->mode == kGliderGoingFoil)
+ DeckGliderInFoil(thisGlider);
+ else if (thisGlider->mode == kGliderLosingFoil)
+ RemoveFoilFromGlider(thisGlider);
+
+ whoLinked = who->who;
+ transRoom = masterObjects[whoLinked].roomLink;
+ objLinked = masterObjects[whoLinked].objectLink;
+ linkedToWhat = WhatAreWeLinkedTo(transRoom, objLinked);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ GetObjectRect(&(*thisHouse)->rooms[transRoom].objects[objLinked], &transRect);
+ HSetState((Handle)thisHouse, wasState);
+
+ thisGlider->frame = 0;
+ thisGlider->clip = *bounds;
+ leftSought = bounds->left + ((RectWide(bounds) - kGliderWide) / 2);
+ thisGlider->clip.left = leftSought;
+
+ thisGlider->mode = kGliderDuctingUp;
+}
+
+//-------------------------------------------------------------- StartGliderDuctingIn
+
+void StartGliderDuctingIn (gliderPtr thisGlider)
+{
+ thisGlider->mode = kGliderDuctingIn;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->dontDraw = false;
+}
+
+//-------------------------------------------------------------- StartGliderTransporting
+
+void StartGliderTransporting (gliderPtr thisGlider, hotPtr who)
+{
+ short whoLinked;
+ Byte objLinked;
+ char wasState;
+
+ PlayPrioritySound(kTransOutSound, kTransOutPriority);
+
+ if (thisGlider->mode == kGliderGoingFoil)
+ DeckGliderInFoil(thisGlider);
+ else if (thisGlider->mode == kGliderLosingFoil)
+ RemoveFoilFromGlider(thisGlider);
+
+ whoLinked = who->who;
+ transRoom = masterObjects[whoLinked].roomLink;
+ objLinked = masterObjects[whoLinked].objectLink;
+ linkedToWhat = WhatAreWeLinkedTo(transRoom, objLinked);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ GetObjectRect(&(*thisHouse)->rooms[transRoom].objects[objLinked], &transRect);
+ HSetState((Handle)thisHouse, wasState);
+
+ thisGlider->dest.right = thisGlider->dest.left + kGliderWide;
+ thisGlider->dest.bottom = thisGlider->dest.top + kGliderHigh;
+ thisGlider->destShadow.right = thisGlider->destShadow.left + kGliderWide;
+ thisGlider->destShadow.bottom = thisGlider->destShadow.top + kShadowHigh;
+ thisGlider->mode = kGliderTransporting;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->frame = kLastFadeSequence - 1;
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src =
+ gliderSrc[fadeInSequence[thisGlider->frame] + kLeftFadeOffset];
+ thisGlider->mask =
+ gliderSrc[fadeInSequence[thisGlider->frame] + kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame]];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame]];
+ }
+}
+
+//-------------------------------------------------------------- FlagGliderNormal
+
+void FlagGliderNormal (gliderPtr thisGlider)
+{
+ thisGlider->dest.right = thisGlider->dest.left + kGliderWide;
+ thisGlider->dest.bottom = thisGlider->dest.top + kGliderHigh;
+ thisGlider->destShadow.right = thisGlider->destShadow.left + kGliderWide;
+ thisGlider->destShadow.bottom = thisGlider->destShadow.top + kShadowHigh;
+ thisGlider->mode = kGliderNormal;
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ }
+ thisGlider->hVel = 0;
+ thisGlider->vVel = 0;
+ thisGlider->hDesiredVel = 0;
+ thisGlider->vDesiredVel = 0;
+ thisGlider->tipped = false;
+ thisGlider->ignoreLeft = false;
+ thisGlider->ignoreRight = false;
+ thisGlider->ignoreGround = false;
+ thisGlider->dontDraw = false;
+ thisGlider->frame = 0;
+ shadowVisible = IsShadowVisible();
+}
+
+//-------------------------------------------------------------- FlagGliderShredding
+
+void FlagGliderShredding (gliderPtr thisGlider, Rect *bounds)
+{
+ PlayPrioritySound(kCaughtFireSound, kCaughtFirePriority);
+ thisGlider->dest.left = bounds->left + 36;
+ thisGlider->dest.right = thisGlider->dest.left + kGliderWide;
+ thisGlider->dest.bottom = thisGlider->dest.top + kGliderHigh;
+ if (thisGlider->dest.left > thisGlider->whole.left)
+ {
+ thisGlider->whole.right = thisGlider->dest.right;
+ thisGlider->wholeShadow.right = thisGlider->dest.right;
+ }
+ else
+ {
+ thisGlider->whole.left = thisGlider->dest.left;
+ thisGlider->wholeShadow.left = thisGlider->dest.left;
+ }
+ thisGlider->destShadow.left = thisGlider->dest.left;
+ thisGlider->destShadow.right = thisGlider->destShadow.left + kGliderWide;
+ thisGlider->destShadow.bottom = thisGlider->destShadow.top + kShadowHigh;
+ thisGlider->mode = kGliderShredding;
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ }
+ thisGlider->hVel = 0;
+ thisGlider->vVel = 0;
+ thisGlider->hDesiredVel = 0;
+ thisGlider->vDesiredVel = 0;
+ thisGlider->frame = bounds->bottom - 3;
+ thisGlider->tipped = false;
+}
+
+//-------------------------------------------------------------- FlagGliderBurning
+
+void FlagGliderBurning (gliderPtr thisGlider)
+{
+ #define kFramesToBurn 60
+
+ PlayPrioritySound(kCaughtFireSound, kCaughtFirePriority);
+
+ thisGlider->dest.right = thisGlider->dest.left + kGliderWide;
+ thisGlider->dest.top = thisGlider->dest.bottom - kGliderBurningHigh;
+ thisGlider->destShadow.right = thisGlider->destShadow.left + kGliderWide;
+ thisGlider->destShadow.bottom = thisGlider->destShadow.top + kShadowHigh;
+ thisGlider->mode = kGliderBurning;
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[25];
+ thisGlider->mask = gliderSrc[25];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[21];
+ thisGlider->mask = gliderSrc[21];
+ }
+ thisGlider->hVel = 0;
+ thisGlider->vVel = 0;
+ thisGlider->hDesiredVel = 0;
+ thisGlider->vDesiredVel = 0;
+ thisGlider->frame = 0;
+ thisGlider->wasMode = kFramesToBurn; // used to count down burning
+ thisGlider->tipped = false;
+}
+
+//-------------------------------------------------------------- FlagGliderFaceLeft
+
+void FlagGliderFaceLeft (gliderPtr thisGlider)
+{
+ thisGlider->mode = kGliderFaceLeft;
+ thisGlider->frame = kLastAboutFaceFrame;
+ thisGlider->src = gliderSrc[kLastAboutFaceFrame];
+ thisGlider->mask = gliderSrc[kLastAboutFaceFrame];
+}
+
+//-------------------------------------------------------------- FlagGliderFaceRight
+
+void FlagGliderFaceRight (gliderPtr thisGlider)
+{
+ thisGlider->mode = kGliderFaceRight;
+ thisGlider->frame = kFirstAboutFaceFrame;
+ thisGlider->src = gliderSrc[kFirstAboutFaceFrame];
+ thisGlider->mask = gliderSrc[kFirstAboutFaceFrame];
+}
+
+//-------------------------------------------------------------- FlagGliderInLimbo
+
+void FlagGliderInLimbo (gliderPtr thisGlider, Boolean sayIt)
+{
+ thisGlider->wasMode = thisGlider->mode;
+ thisGlider->mode = kGliderInLimbo;
+ if ((sayIt) && (saidFollow < 3))
+ {
+ PlayPrioritySound(kFollowSound, kFollowPriority);
+ saidFollow++;
+ }
+ firstPlayer = thisGlider->which;
+}
+
+//-------------------------------------------------------------- UndoGliderLimbo
+
+void UndoGliderLimbo (gliderPtr thisGlider)
+{
+ if ((twoPlayerGame) && (onePlayerLeft) && (thisGlider->which == playerDead))
+ return;
+
+ if (thisGlider->mode == kGliderInLimbo)
+ thisGlider->mode = thisGlider->wasMode;
+ thisGlider->dontDraw = false;
+}
+
+//-------------------------------------------------------------- ToggleGliderFacing
+
+void ToggleGliderFacing (gliderPtr thisGlider)
+{
+ if (thisGlider->mode != kGliderNormal)
+ return;
+
+ if (thisGlider->facing == kFaceLeft)
+ FlagGliderFaceRight(thisGlider);
+ else
+ FlagGliderFaceLeft(thisGlider);
+}
+
+//-------------------------------------------------------------- InsureGliderFacingRight
+
+void InsureGliderFacingRight (gliderPtr thisGlider)
+{
+ if ((twoPlayerGame) && (onePlayerLeft) && (thisGlider->which == playerDead))
+ return;
+
+ if ((thisGlider->facing == kFaceLeft) && (thisGlider->mode != kGliderBurning))
+ FlagGliderFaceRight(thisGlider);
+}
+
+//-------------------------------------------------------------- InsureGliderFacingLeft
+
+void InsureGliderFacingLeft (gliderPtr thisGlider)
+{
+ if ((twoPlayerGame) && (onePlayerLeft) && (thisGlider->which == playerDead))
+ return;
+
+ if ((thisGlider->facing == kFaceRight) && (thisGlider->mode != kGliderBurning))
+ FlagGliderFaceLeft(thisGlider);
+}
+
+//-------------------------------------------------------------- ReadyGliderForTripUpStairs
+
+void ReadyGliderForTripUpStairs (gliderPtr thisGlider)
+{
+ #define kVGliderAppearsComingUp 100
+
+ if ((twoPlayerGame) && (thisGlider->which == playerDead) && (onePlayerLeft))
+ return;
+
+ thisGlider->facing = kFaceLeft;
+ thisGlider->mode = kGliderComingUp;
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ thisGlider->hVel = 0;
+ thisGlider->vVel = 0;
+ thisGlider->hDesiredVel = 0;
+ thisGlider->vDesiredVel = 0;
+ thisGlider->tipped = false;
+
+ rightClip = GetUpStairsRightEdge();
+ thisGlider->dest = thisGlider->src;
+ ZeroRectCorner(&thisGlider->dest);
+ QOffsetRect(&thisGlider->dest, rightClip, kVGliderAppearsComingUp);
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->destShadow.left = thisGlider->dest.left;
+ thisGlider->destShadow.right = thisGlider->dest.right;
+ thisGlider->wholeShadow = thisGlider->destShadow;
+
+ FinishGliderUpStairs(thisGlider);
+}
+
+//-------------------------------------------------------------- ReadyGliderForTripDownStairs
+
+void ReadyGliderForTripDownStairs (gliderPtr thisGlider)
+{
+ #define kVGliderAppearsComingDown 100
+
+ if ((twoPlayerGame) && (thisGlider->which == playerDead) && (onePlayerLeft))
+ return;
+
+ thisGlider->facing = kFaceRight;
+ thisGlider->mode = kGliderComingDown;
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ thisGlider->hVel = 0;
+ thisGlider->vVel = 0;
+ thisGlider->hDesiredVel = 0;
+ thisGlider->vDesiredVel = 0;
+ thisGlider->tipped = false;
+
+ leftClip = GetDownStairsLeftEdge();
+ thisGlider->dest = thisGlider->src;
+ ZeroRectCorner(&thisGlider->dest);
+ QOffsetRect(&thisGlider->dest, leftClip - kGliderWide, kVGliderAppearsComingDown);
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->destShadow.left = thisGlider->dest.left;
+ thisGlider->destShadow.right = thisGlider->dest.right;
+ thisGlider->wholeShadow = thisGlider->destShadow;
+
+ FinishGliderDownStairs(thisGlider);
+}
+
+//-------------------------------------------------------------- StartGliderFoilGoing
+
+void StartGliderFoilGoing (gliderPtr thisGlider)
+{
+ if ((thisGlider->mode == kGliderGoingFoil) || (thisGlider->mode == kGliderInLimbo))
+ return;
+
+ QuickFoilRefresh(false);
+
+ thisGlider->mode = kGliderGoingFoil;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->frame = 0;
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[(10 - thisGlider->frame) + kLeftFadeOffset];
+ thisGlider->mask = gliderSrc[(10 - thisGlider->frame) + kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[10 - thisGlider->frame];
+ thisGlider->mask = gliderSrc[10 - thisGlider->frame];
+ }
+}
+
+//-------------------------------------------------------------- StartGliderFoilLosing
+
+void StartGliderFoilLosing (gliderPtr thisGlider)
+{
+ if ((thisGlider->mode == kGliderLosingFoil) ||
+ (thisGlider->mode == kGliderInLimbo))
+ return;
+
+ QuickFoilRefresh(false);
+ PlayPrioritySound(kFizzleSound, kFizzlePriority);
+
+ thisGlider->mode = kGliderLosingFoil;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->frame = 0;
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[(10 - thisGlider->frame) + kLeftFadeOffset];
+ thisGlider->mask = gliderSrc[(10 - thisGlider->frame) + kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[10 - thisGlider->frame];
+ thisGlider->mask = gliderSrc[10 - thisGlider->frame];
+ }
+}
+
+//-------------------------------------------------------------- TagGliderIdle
+
+void TagGliderIdle (gliderPtr thisGlider)
+{
+ if ((twoPlayerGame) && (onePlayerLeft) && (thisGlider->which == playerDead))
+ return;
+
+ thisGlider->wasMode = thisGlider->mode;
+ thisGlider->mode = kGliderIdle;
+ thisGlider->hVel = 30; // used for 30 frame delay
+}
+
diff --git a/GpApp/Music.cpp b/GpApp/Music.cpp
new file mode 100644
index 0000000..f6d9962
--- /dev/null
+++ b/GpApp/Music.cpp
@@ -0,0 +1,416 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Music.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLResources.h"
+#include "PLSound.h"
+#include "Environ.h"
+#include "Externs.h"
+
+
+#define kBaseBufferMusicID 2000
+#define kMaxMusic 7
+#define kLastMusicPiece 16
+#define kLastGamePiece 6
+
+
+void MusicCallBack (SndChannelPtr, SndCommand *);
+OSErr LoadMusicSounds (void);
+OSErr DumpMusicSounds (void);
+OSErr OpenMusicChannel (void);
+OSErr CloseMusicChannel (void);
+
+
+SndCallBackUPP musicCallBackUPP;
+SndChannelPtr musicChannel;
+Ptr theMusicData[kMaxMusic];
+short musicSoundID, musicCursor;
+short musicScore[kLastMusicPiece];
+short gameScore[kLastGamePiece];
+short musicMode;
+Boolean isMusicOn, isPlayMusicIdle, isPlayMusicGame;
+Boolean failedMusic, dontLoadMusic;
+
+extern Boolean isSoundOn;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- StartMusic
+
+OSErr StartMusic (void)
+{
+ SndCommand theCommand;
+ OSErr theErr;
+ short soundVolume;
+
+ theErr = noErr;
+
+ if (dontLoadMusic)
+ return(theErr);
+
+ UnivGetSoundVolume(&soundVolume, thisMac.hasSM3);
+
+ if ((soundVolume != 0) && (!failedMusic))
+ {
+ theCommand.cmd = bufferCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = (intptr_t)(theMusicData[musicSoundID]);
+ theErr = SndDoCommand(musicChannel, &theCommand, false);
+ if (theErr != noErr)
+ return (theErr);
+
+ // GP: No idea what "1964" means
+ theCommand.cmd = nullCmd;
+ theCommand.param1 = 1964;
+ theCommand.param2 = 0;
+ theErr = SndDoCommand(musicChannel, &theCommand, false);
+ if (theErr != noErr)
+ return (theErr);
+
+ musicCursor++;
+ if (musicCursor >= kLastMusicPiece)
+ musicCursor = 0;
+ musicSoundID = musicScore[musicCursor];
+
+ theCommand.cmd = bufferCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = (intptr_t)(theMusicData[musicSoundID]);
+ theErr = SndDoCommand(musicChannel, &theCommand, false);
+ if (theErr != noErr)
+ return (theErr);
+
+ theCommand.cmd = callBackCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0;
+ theErr = SndDoCommand(musicChannel, &theCommand, false);
+
+ isMusicOn = true;
+ }
+
+ return (theErr);
+}
+
+//-------------------------------------------------------------- StopTheMusic
+
+void StopTheMusic (void)
+{
+ SndCommand theCommand;
+ OSErr theErr;
+
+ if (dontLoadMusic)
+ return;
+
+ theErr = noErr;
+ if ((isMusicOn) && (!failedMusic))
+ {
+ theCommand.cmd = flushCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0L;
+ theErr = SndDoImmediate(musicChannel, &theCommand);
+
+ theCommand.cmd = quietCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0L;
+ theErr = SndDoImmediate(musicChannel, &theCommand);
+
+ isMusicOn = false;
+ }
+}
+
+//-------------------------------------------------------------- ToggleMusicWhilePlaying
+
+void ToggleMusicWhilePlaying (void)
+{
+ OSErr theErr;
+
+ if (dontLoadMusic)
+ return;
+
+ if (isPlayMusicGame)
+ {
+ if (!isMusicOn)
+ theErr = StartMusic();
+ }
+ else
+ {
+ if (isMusicOn)
+ StopTheMusic();
+ }
+}
+
+//-------------------------------------------------------------- SetMusicalPiece
+
+void SetMusicalMode (short newMode)
+{
+ if (dontLoadMusic)
+ return;
+
+ switch (newMode)
+ {
+ case kKickGameScoreMode:
+ musicCursor = 2;
+ break;
+
+ case kProdGameScoreMode:
+ musicCursor = -1;
+ break;
+
+ default:
+ musicMode = newMode;
+ musicCursor = 0;
+ break;
+ }
+}
+
+//-------------------------------------------------------------- MusicCallBack
+
+void MusicCallBack (SndChannelPtr theChannel, SndCommand *theCommand)
+{
+ OSErr theErr;
+
+// gameA5 = theCommand.param2;
+// thisA5 = SetA5(gameA5);
+
+ switch (musicMode)
+ {
+ case kPlayGameScoreMode:
+ musicCursor++;
+ if (musicCursor >= kLastGamePiece)
+ musicCursor = 1;
+ musicSoundID = gameScore[musicCursor];
+ if (musicSoundID < 0)
+ {
+ musicCursor += musicSoundID;
+ musicSoundID = gameScore[musicCursor];
+ }
+ break;
+
+ case kPlayWholeScoreMode:
+ musicCursor++;
+ if (musicCursor >= kLastMusicPiece - 1)
+ musicCursor = 0;
+ musicSoundID = musicScore[musicCursor];
+ break;
+
+ default:
+ musicSoundID = musicMode;
+ break;
+ }
+
+ theCommand->cmd = bufferCmd;
+ theCommand->param1 = 0;
+ theCommand->param2 = (intptr_t)(theMusicData[musicSoundID]);
+ theErr = SndDoCommand(musicChannel, theCommand, false);
+
+ theCommand->cmd = callBackCmd;
+ theCommand->param1 = 0;
+ theCommand->param2 = 0;
+ theErr = SndDoCommand(musicChannel, theCommand, false);
+}
+
+//-------------------------------------------------------------- LoadMusicSounds
+
+OSErr LoadMusicSounds (void)
+{
+ Handle theSound;
+ long soundDataSize;
+ OSErr theErr;
+ short i;
+
+ theErr = noErr;
+
+ for (i = 0; i < kMaxMusic; i++)
+ theMusicData[i] = nil;
+
+ for (i = 0; i < kMaxMusic; i++)
+ {
+ theSound = GetResource('snd ', i + kBaseBufferMusicID);
+ if (theSound == nil)
+ return (MemError());
+
+ HLock(theSound);
+ soundDataSize = GetHandleSize(theSound) - 20L;
+ HUnlock(theSound);
+
+ theMusicData[i] = NewPtr(soundDataSize);
+ if (theMusicData[i] == nil)
+ return (MemError());
+
+ HLock(theSound);
+ BlockMove((Ptr)(static_cast(*theSound) + 20L), theMusicData[i], soundDataSize);
+ ReleaseResource(theSound);
+ }
+ return (theErr);
+}
+
+//-------------------------------------------------------------- DumpMusicSounds
+
+OSErr DumpMusicSounds (void)
+{
+ OSErr theErr;
+ short i;
+
+ theErr = noErr;
+
+ for (i = 0; i < kMaxMusic; i++)
+ {
+ if (theMusicData[i] != nil)
+ DisposePtr(theMusicData[i]);
+ theMusicData[i] = nil;
+ }
+
+ return (theErr);
+}
+
+//-------------------------------------------------------------- OpenMusicChannel
+
+OSErr OpenMusicChannel (void)
+{
+ OSErr theErr;
+
+ musicCallBackUPP = NewSndCallBackProc(MusicCallBack);
+
+ theErr = noErr;
+
+ if (musicChannel != nil)
+ return (theErr);
+
+ musicChannel = nil;
+ theErr = SndNewChannel(&musicChannel,
+ sampledSynth, initNoInterp + initMono,
+ (SndCallBackUPP)musicCallBackUPP);
+
+ return (theErr);
+}
+
+//-------------------------------------------------------------- CloseMusicChannel
+
+OSErr CloseMusicChannel (void)
+{
+ OSErr theErr;
+
+ theErr = noErr;
+
+ if (musicChannel != nil)
+ theErr = SndDisposeChannel(musicChannel, true);
+ musicChannel = nil;
+
+ DisposeSndCallBackUPP(musicCallBackUPP);
+
+ return (theErr);
+}
+
+//-------------------------------------------------------------- InitMusic
+
+void InitMusic (void)
+{
+ OSErr theErr;
+
+ if (dontLoadMusic)
+ return;
+
+ musicChannel = nil;
+
+ failedMusic = false;
+ isMusicOn = false;
+ theErr = LoadMusicSounds();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowNoMusic, theErr);
+ failedMusic = true;
+ return;
+ }
+ theErr = OpenMusicChannel();
+
+ musicScore[0] = 0;
+ musicScore[1] = 1;
+ musicScore[2] = 2;
+ musicScore[3] = 3;
+ musicScore[4] = 4;
+ musicScore[5] = 4;
+ musicScore[6] = 0;
+ musicScore[7] = 1;
+ musicScore[8] = 2;
+ musicScore[9] = 3;
+ musicScore[10] = kPlayChorus;
+ musicScore[11] = kPlayChorus;
+ musicScore[12] = kPlayRefrainSparse1;
+ musicScore[13] = kPlayRefrainSparse2;
+ musicScore[14] = kPlayChorus;
+ musicScore[15] = kPlayChorus;
+
+ gameScore[0] = kPlayRefrainSparse2;
+ gameScore[1] = kPlayRefrainSparse1;
+ gameScore[2] = -1;
+ gameScore[3] = kPlayRefrainSparse2;
+ gameScore[4] = kPlayChorus;
+ gameScore[5] = kPlayChorus;
+
+ musicCursor = 0;
+ musicSoundID = musicScore[musicCursor];
+ musicMode = kPlayWholeScoreMode;
+
+ if (isPlayMusicIdle)
+ {
+ theErr = StartMusic();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowNoMusic, theErr);
+ failedMusic = true;
+ }
+ }
+}
+
+//-------------------------------------------------------------- KillMusic
+
+void KillMusic (void)
+{
+ OSErr theErr;
+
+ if (dontLoadMusic)
+ return;
+
+ theErr = DumpMusicSounds();
+ theErr = CloseMusicChannel();
+}
+
+//-------------------------------------------------------------- MusicBytesNeeded
+
+long MusicBytesNeeded (void)
+{
+ Handle theSound;
+ long totalBytes;
+ short i;
+
+ totalBytes = 0L;
+ SetResLoad(false);
+ for (i = 0; i < kMaxMusic; i++)
+ {
+ theSound = GetResource('snd ', i + kBaseBufferMusicID);
+ if (theSound == nil)
+ {
+ SetResLoad(true);
+ return ((long)ResError());
+ }
+ totalBytes += GetMaxResourceSize(theSound);
+// ReleaseResource(theSound);
+ }
+ SetResLoad(true);
+ return totalBytes;
+}
+
+//-------------------------------------------------------------- TellHerNoMusic
+
+void TellHerNoMusic (void)
+{
+ #define kNoMemForMusicAlert 1038
+ short hitWhat;
+
+// CenterAlert(kNoMemForMusicAlert);
+ hitWhat = Alert(kNoMemForMusicAlert, nil);
+}
+
diff --git a/GpApp/ObjectAdd.cpp b/GpApp/ObjectAdd.cpp
new file mode 100644
index 0000000..4008c61
--- /dev/null
+++ b/GpApp/ObjectAdd.cpp
@@ -0,0 +1,1084 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// ObjectAdd.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLToolUtils.h"
+#include "Externs.h"
+#include "ObjectEdit.h"
+#include "RectUtils.h"
+
+
+#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);
+short HowManyCandleObjects (void);
+short HowManyTikiObjects (void);
+short HowManyBBQObjects (void);
+short HowManyCuckooObjects (void);
+short HowManyBandsObjects (void);
+short HowManyGreaseObjects (void);
+short HowManyStarsObjects (void);
+short HowManySoundObjects (void);
+short HowManyUpStairsObjects (void);
+short HowManyDownStairsObjects (void);
+short HowManyShredderObjects (void);
+short HowManyDynamicObjects (void);
+void ShoutNoMoreSpecialObjects (void);
+
+
+short wasFlower;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- AddNewObject
+
+Boolean AddNewObject (Point where, short what, Boolean showItNow)
+{
+ KeyMap theseKeys;
+ Rect srcRect, newRect;
+ short direction, dist;
+ Boolean handled, drawWholeRoom;
+
+#ifndef COMPILEDEMO
+
+ objActive = FindEmptyObjectSlot();
+ if (objActive == -1)
+ {
+ ShoutNoMoreObjects();
+ return (false);
+ }
+
+ drawWholeRoom = false;
+
+ switch (what)
+ {
+ case kFloorVent:
+ case kFloorBlower:
+ case kSewerGrate:
+ case kTaper:
+ case kCandle:
+ case kStubby:
+ case kTiki:
+ case kBBQ:
+ case kInvisBlower:
+ case kGrecoVent:
+ case kSewerBlower:
+ case kLiftArea:
+ if (((what == kTaper) || (what == kCandle) || (what == kStubby)) &&
+ (HowManyCandleObjects() >= kMaxCandles))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ else if ((what == kTiki) && (HowManyTikiObjects() >= kMaxTikis))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ else if ((what == kBBQ) && (HowManyBBQObjects() >= kMaxCoals))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ srcRect = srcRects[what];
+ thisRoom->objects[objActive].data.a.topLeft.h = where.h - HalfRectWide(&srcRect);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRect), RectTall(&srcRect));
+ if (what == kFloorVent)
+ thisRoom->objects[objActive].data.a.topLeft.v = kFloorVentTop;
+ else if (what == kFloorBlower)
+ thisRoom->objects[objActive].data.a.topLeft.v = kFloorBlowerTop;
+ else if ((what == kTaper) || (what == kCandle) || (what == kStubby) ||
+ (what == kTiki) || (what == kBBQ) || (what == kInvisBlower) ||
+ (what == kLiftArea))
+ thisRoom->objects[objActive].data.a.topLeft.v = where.v - HalfRectTall(&srcRect);
+ else if (what == kGrecoVent)
+ thisRoom->objects[objActive].data.a.topLeft.v = kGrecoVentTop;
+ else if (what == kSewerBlower)
+ thisRoom->objects[objActive].data.a.topLeft.v = kSewerBlowerTop;
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.a.topLeft.h,
+ thisRoom->objects[objActive].data.a.topLeft.v);
+ thisRoom->objects[objActive].data.a.distance = 64;
+ thisRoom->objects[objActive].data.a.initial = true;
+ thisRoom->objects[objActive].data.a.state = true;
+ thisRoom->objects[objActive].data.a.vector = 0x01;
+ if (what == kLiftArea)
+ thisRoom->objects[objActive].data.a.tall = 0x10;
+ else
+ thisRoom->objects[objActive].data.a.tall = 0x00;
+ break;
+
+ case kCeilingVent:
+ case kCeilingBlower:
+ srcRect = srcRects[what];
+ thisRoom->objects[objActive].data.a.topLeft.h = where.h - HalfRectWide(&srcRect);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRect), RectTall(&srcRect));
+ if (what == kCeilingVent)
+ thisRoom->objects[objActive].data.a.topLeft.v = kCeilingVentTop;
+ else if (what == kCeilingBlower)
+ thisRoom->objects[objActive].data.a.topLeft.v = kCeilingBlowerTop;
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.a.topLeft.h,
+ thisRoom->objects[objActive].data.a.topLeft.v);
+ thisRoom->objects[objActive].data.a.distance = 32;
+ thisRoom->objects[objActive].data.a.initial = true;
+ thisRoom->objects[objActive].data.a.state = true;
+ thisRoom->objects[objActive].data.a.vector = 0x04;
+ break;
+
+ case kLeftFan:
+ thisRoom->objects[objActive].data.a.topLeft.h =
+ where.h - HalfRectWide(&srcRects[kLeftFan]);
+ thisRoom->objects[objActive].data.a.topLeft.v =
+ where.v - HalfRectTall(&srcRects[kLeftFan]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[kLeftFan]),
+ RectTall(&srcRects[kLeftFan]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.a.topLeft.h,
+ thisRoom->objects[objActive].data.a.topLeft.v);
+ thisRoom->objects[objActive].data.a.distance = 32;
+ thisRoom->objects[objActive].data.a.initial = true;
+ thisRoom->objects[objActive].data.a.state = true;
+ thisRoom->objects[objActive].data.a.vector = 0x08;
+ break;
+
+ case kRightFan:
+ thisRoom->objects[objActive].data.a.topLeft.h =
+ where.h - HalfRectWide(&srcRects[kRightFan]);
+ thisRoom->objects[objActive].data.a.topLeft.v =
+ where.v - HalfRectTall(&srcRects[kRightFan]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[kRightFan]), RectTall(&srcRects[kRightFan]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.a.topLeft.h,
+ thisRoom->objects[objActive].data.a.topLeft.v);
+ thisRoom->objects[objActive].data.a.distance = 32;
+ thisRoom->objects[objActive].data.a.initial = true;
+ thisRoom->objects[objActive].data.a.state = true;
+ thisRoom->objects[objActive].data.a.vector = 0x02;
+ 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 kBooks:
+ case kInvisBounce:
+ newRect = srcRects[what];
+ CenterRectOnPoint(&newRect, where);
+ if (what == kCounter)
+ newRect.bottom = kCounterBottom;
+ else if (what == kDresser)
+ newRect.bottom = kDresserBottom;
+ thisRoom->objects[objActive].data.b.bounds = newRect;
+ thisRoom->objects[objActive].data.b.pict = 0;
+ break;
+
+ case kManhole:
+ newRect = srcRects[kManhole];
+ CenterRectOnPoint(&newRect, where);
+ newRect.left = (((newRect.left - 3) / 64) * 64) + 3;
+ newRect.right = newRect.left + RectWide(&srcRects[kManhole]);
+ newRect.bottom = kManholeSits;
+ newRect.top = newRect.bottom - RectTall(&srcRects[kManhole]);
+ thisRoom->objects[objActive].data.b.bounds = newRect;
+ thisRoom->objects[objActive].data.b.pict = 0;
+ break;
+
+ case kRedClock:
+ case kBlueClock:
+ case kYellowClock:
+ case kCuckoo:
+ case kPaper:
+ case kBattery:
+ case kBands:
+ case kFoil:
+ case kStar:
+ case kSparkle:
+ case kHelium:
+ if ((what == kCuckoo) && (HowManyCuckooObjects() >= kMaxPendulums))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ else if ((what == kBands) && (HowManyBandsObjects() >= kMaxRubberBands))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ else if ((what == kStar) && (HowManyStarsObjects() >= kMaxStars))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ else if ((what == kSparkle) && (HowManyDynamicObjects() >= kMaxDynamicObs))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ thisRoom->objects[objActive].data.c.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.c.topLeft.v =
+ where.v - HalfRectTall(&srcRects[what]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.c.topLeft.h,
+ thisRoom->objects[objActive].data.c.topLeft.v);
+ thisRoom->objects[objActive].data.c.length = 0;
+ thisRoom->objects[objActive].data.c.points = 0;
+ thisRoom->objects[objActive].data.c.state = true;
+ thisRoom->objects[objActive].data.c.initial = true;
+ break;
+
+ case kGreaseRt:
+ case kGreaseLf:
+ if (HowManyGreaseObjects() >= kMaxGrease)
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ thisRoom->objects[objActive].data.c.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.c.topLeft.v =
+ where.v - HalfRectTall(&srcRects[what]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]), RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.c.topLeft.h,
+ thisRoom->objects[objActive].data.c.topLeft.v);
+ thisRoom->objects[objActive].data.c.length = 64;
+ thisRoom->objects[objActive].data.c.points = 0;
+ thisRoom->objects[objActive].data.c.state = true;
+ thisRoom->objects[objActive].data.c.initial = true;
+ break;
+
+ case kInvisBonus:
+ thisRoom->objects[objActive].data.c.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.c.topLeft.v =
+ where.v - HalfRectTall(&srcRects[what]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]), RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.c.topLeft.h,
+ thisRoom->objects[objActive].data.c.topLeft.v);
+ thisRoom->objects[objActive].data.c.length = 0;
+ thisRoom->objects[objActive].data.c.points = 100;
+ thisRoom->objects[objActive].data.c.state = true;
+ thisRoom->objects[objActive].data.c.initial = true;
+ break;
+
+ case kSlider:
+ thisRoom->objects[objActive].data.c.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.c.topLeft.v =
+ where.v - HalfRectTall(&srcRects[what]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]), RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.c.topLeft.h,
+ thisRoom->objects[objActive].data.c.topLeft.v);
+ thisRoom->objects[objActive].data.c.length = 64;
+ thisRoom->objects[objActive].data.c.points = 0;
+ thisRoom->objects[objActive].data.c.state = true;
+ thisRoom->objects[objActive].data.c.initial = true;
+ break;
+
+ case kUpStairs:
+ case kDownStairs:
+ if ((what == kUpStairs) && (HowManyUpStairsObjects() >= kMaxStairs))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ else if ((what == kDownStairs) && (HowManyDownStairsObjects() >= kMaxStairs))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ thisRoom->objects[objActive].data.d.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.d.topLeft.v = kStairsTop;
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.d.topLeft.h,
+ thisRoom->objects[objActive].data.d.topLeft.v);
+ thisRoom->objects[objActive].data.d.tall = 0;
+ thisRoom->objects[objActive].data.d.where = -1;
+ thisRoom->objects[objActive].data.d.who = 255;
+ thisRoom->objects[objActive].data.d.wide = 0;
+ break;
+
+ case kMailboxLf:
+ case kMailboxRt:
+ thisRoom->objects[objActive].data.d.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.d.topLeft.v =
+ where.v - HalfRectTall(&srcRects[what]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.d.topLeft.h,
+ thisRoom->objects[objActive].data.d.topLeft.v);
+ thisRoom->objects[objActive].data.d.tall = 0;
+ thisRoom->objects[objActive].data.d.where = -1;
+ thisRoom->objects[objActive].data.d.who = 255;
+ thisRoom->objects[objActive].data.d.wide = 0;
+ break;
+
+ case kFloorTrans:
+ thisRoom->objects[objActive].data.d.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.d.topLeft.v = kFloorTransTop;
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.d.topLeft.h,
+ thisRoom->objects[objActive].data.d.topLeft.v);
+ thisRoom->objects[objActive].data.d.tall = 0;
+ thisRoom->objects[objActive].data.d.where = -1;
+ thisRoom->objects[objActive].data.d.who = 255;
+ thisRoom->objects[objActive].data.d.wide = 0;
+ break;
+
+ case kCeilingTrans:
+ thisRoom->objects[objActive].data.d.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.d.topLeft.v = kCeilingTransTop;
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.d.topLeft.h,
+ thisRoom->objects[objActive].data.d.topLeft.v);
+ thisRoom->objects[objActive].data.d.tall = 0;
+ thisRoom->objects[objActive].data.d.where = -1;
+ thisRoom->objects[objActive].data.d.who = 255;
+ thisRoom->objects[objActive].data.d.wide = 0;
+ break;
+
+ case kDoorInLf:
+ case kDoorInRt:
+ case kDoorExRt:
+ case kDoorExLf:
+ case kWindowInLf:
+ case kWindowInRt:
+ case kWindowExRt:
+ case kWindowExLf:
+ if ((what == kDoorInLf) || (what == kDoorInRt))
+ {
+ if (where.h > (kRoomWide / 2))
+ {
+ what = kDoorInRt;
+ thisRoom->objects[objActive].what = kDoorInRt;
+ thisRoom->objects[objActive].data.d.topLeft.h = kDoorInRtLeft;
+ thisRoom->objects[objActive].data.d.topLeft.v = kDoorInTop;
+ }
+ else
+ {
+ what = kDoorInLf;
+ thisRoom->objects[objActive].what = kDoorInLf;
+ thisRoom->objects[objActive].data.d.topLeft.h = kDoorInLfLeft;
+ thisRoom->objects[objActive].data.d.topLeft.v = kDoorInTop;
+ }
+ }
+ else if ((what == kDoorExRt) || (what == kDoorExLf))
+ {
+ if (where.h > (kRoomWide / 2))
+ {
+ what = kDoorExRt;
+ thisRoom->objects[objActive].what = kDoorExRt;
+ thisRoom->objects[objActive].data.d.topLeft.h = kDoorExRtLeft;
+ thisRoom->objects[objActive].data.d.topLeft.v = kDoorExTop;
+ }
+ else
+ {
+ what = kDoorExLf;
+ thisRoom->objects[objActive].what = kDoorExLf;
+ thisRoom->objects[objActive].data.d.topLeft.h = kDoorExLfLeft;
+ thisRoom->objects[objActive].data.d.topLeft.v = kDoorExTop;
+ }
+ }
+ else if ((what == kWindowInLf) || (what == kWindowInRt))
+ {
+ if (where.h > (kRoomWide / 2))
+ {
+ what = kWindowInRt;
+ thisRoom->objects[objActive].what = kWindowInRt;
+ thisRoom->objects[objActive].data.d.topLeft.h = kWindowInRtLeft;
+ thisRoom->objects[objActive].data.d.topLeft.v = kWindowInTop;
+ }
+ else
+ {
+ what = kWindowInLf;
+ thisRoom->objects[objActive].what = kWindowInLf;
+ thisRoom->objects[objActive].data.d.topLeft.h = kWindowInLfLeft;
+ thisRoom->objects[objActive].data.d.topLeft.v = kWindowInTop;
+ }
+ }
+ else if ((what == kWindowExRt) || (what == kWindowExLf))
+ {
+ if (where.h > (kRoomWide / 2))
+ {
+ what = kWindowExRt;
+ thisRoom->objects[objActive].what = kWindowExRt;
+ thisRoom->objects[objActive].data.d.topLeft.h = kWindowExRtLeft;
+ thisRoom->objects[objActive].data.d.topLeft.v = kWindowExTop;
+ }
+ else
+ {
+ what = kWindowExLf;
+ thisRoom->objects[objActive].what = kWindowExLf;
+ thisRoom->objects[objActive].data.d.topLeft.h = kWindowExLfLeft;
+ thisRoom->objects[objActive].data.d.topLeft.v = kWindowExTop;
+ }
+ }
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.d.topLeft.h,
+ thisRoom->objects[objActive].data.d.topLeft.v);
+ thisRoom->objects[objActive].data.d.tall = 0;
+ thisRoom->objects[objActive].data.d.where = -1;
+ thisRoom->objects[objActive].data.d.who = 255;
+ thisRoom->objects[objActive].data.d.wide = 0;
+ drawWholeRoom = true;
+ break;
+
+ case kInvisTrans:
+ newRect = srcRects[what];
+ CenterRectOnPoint(&newRect, where);
+ thisRoom->objects[objActive].data.d.topLeft.h = newRect.left;
+ thisRoom->objects[objActive].data.d.topLeft.v = newRect.top;
+ thisRoom->objects[objActive].data.d.tall = newRect.bottom - newRect.top;
+ thisRoom->objects[objActive].data.d.where = -1;
+ thisRoom->objects[objActive].data.d.who = 255;
+ thisRoom->objects[objActive].data.d.wide = 0;
+ break;
+
+ case kDeluxeTrans:
+ newRect = srcRects[what];
+ CenterRectOnPoint(&newRect, where);
+ thisRoom->objects[objActive].data.d.topLeft.h = newRect.left;
+ thisRoom->objects[objActive].data.d.topLeft.v = newRect.top;
+ thisRoom->objects[objActive].data.d.tall = 0x1010; // 64 x 64
+ thisRoom->objects[objActive].data.d.where = -1;
+ thisRoom->objects[objActive].data.d.who = 255;
+ thisRoom->objects[objActive].data.d.wide = 0x10; // Initially on
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ case kSoundTrigger:
+ if ((what == kSoundTrigger) && (HowManySoundObjects() >= kMaxSoundTriggers))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ thisRoom->objects[objActive].data.e.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.e.topLeft.v =
+ where.v - HalfRectTall(&srcRects[what]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.e.topLeft.h,
+ thisRoom->objects[objActive].data.e.topLeft.v);
+ thisRoom->objects[objActive].data.e.delay = 0;
+ if (what == kSoundTrigger)
+ thisRoom->objects[objActive].data.e.where = 3000;
+ else
+ thisRoom->objects[objActive].data.e.where = -1;
+ thisRoom->objects[objActive].data.e.who = 255;
+ if ((what == kTrigger) || (what == kLgTrigger))
+ thisRoom->objects[objActive].data.e.type = kOneShot;
+ else
+ thisRoom->objects[objActive].data.e.type = kToggle;
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kTrackLight:
+ case kInvisLight:
+ if (what == kCeilingLight)
+ {
+ thisRoom->objects[objActive].data.f.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.f.topLeft.v = kCeilingLightTop;
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.f.topLeft.h,
+ thisRoom->objects[objActive].data.f.topLeft.v);
+ thisRoom->objects[objActive].data.f.length = 64;
+ }
+ else if (what == kHipLamp)
+ {
+ thisRoom->objects[objActive].data.f.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.f.topLeft.v = kHipLampTop;
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.f.topLeft.h,
+ thisRoom->objects[objActive].data.f.topLeft.v);
+ thisRoom->objects[objActive].data.f.length = 0;
+ }
+ else if (what == kDecoLamp)
+ {
+ thisRoom->objects[objActive].data.f.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.f.topLeft.v = kDecoLampTop;
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.f.topLeft.h,
+ thisRoom->objects[objActive].data.f.topLeft.v);
+ thisRoom->objects[objActive].data.f.length = 0;
+ }
+ else if (what == kFlourescent)
+ {
+ thisRoom->objects[objActive].data.f.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.f.topLeft.v = kFlourescentTop;
+ newRect = srcRects[what];
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.f.topLeft.h,
+ thisRoom->objects[objActive].data.f.topLeft.v);
+ thisRoom->objects[objActive].data.f.length = 64;
+ }
+ else if (what == kTrackLight)
+ {
+ thisRoom->objects[objActive].data.f.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.f.topLeft.v = kTrackLightTop;
+ newRect = srcRects[what];
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.f.topLeft.h,
+ thisRoom->objects[objActive].data.f.topLeft.v);
+ thisRoom->objects[objActive].data.f.length = 64;
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.f.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.f.topLeft.v =
+ where.v - HalfRectTall(&srcRects[what]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.f.topLeft.h,
+ thisRoom->objects[objActive].data.f.topLeft.v);
+ thisRoom->objects[objActive].data.f.length = 0;
+ }
+ thisRoom->objects[objActive].data.f.initial = true;
+ thisRoom->objects[objActive].data.f.state = true;
+ thisRoom->objects[objActive].data.f.byte0 = 0;
+ thisRoom->objects[objActive].data.f.byte1 = 0;
+ drawWholeRoom = true;
+ 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:
+ if ((what != kGuitar) && (what != kCinderBlock) && (what != kFlowerBox) &&
+ (what != kCDs) && (what != kCustomPict) &&
+ (HowManyShredderObjects() >= kMaxShredded))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ thisRoom->objects[objActive].data.g.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.g.topLeft.v =
+ where.v - HalfRectTall(&srcRects[what]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.g.topLeft.h,
+ thisRoom->objects[objActive].data.g.topLeft.v);
+ if (what == kToaster)
+ {
+ thisRoom->objects[objActive].data.g.height = 64;
+ thisRoom->objects[objActive].data.g.delay = 10 + RandomInt(10);
+ }
+ else if (what == kOutlet)
+ {
+ thisRoom->objects[objActive].data.g.height = 0;
+ thisRoom->objects[objActive].data.g.delay = 10 + RandomInt(10);
+ }
+ else if (what == kCustomPict)
+ {
+ thisRoom->objects[objActive].data.g.height = 10000;
+ thisRoom->objects[objActive].data.g.delay = 0;
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.g.height = 0;
+ thisRoom->objects[objActive].data.g.delay = 0;
+ }
+ if (what == kMicrowave)
+ thisRoom->objects[objActive].data.g.byte0 = 7;
+ else
+ thisRoom->objects[objActive].data.g.byte0 = 0;
+ thisRoom->objects[objActive].data.g.initial = true;
+ thisRoom->objects[objActive].data.g.state = true;
+ break;
+
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kDartLf:
+ case kDartRt:
+ case kCobweb:
+ if ((what != kCobweb) && (HowManyDynamicObjects() >= kMaxDynamicObs))
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ if (what == kDartLf)
+ {
+ thisRoom->objects[objActive].data.h.topLeft.h =
+ kRoomWide - RectWide(&srcRects[what]);
+ }
+ else if (what == kDartRt)
+ {
+ thisRoom->objects[objActive].data.h.topLeft.h = 0;
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.h.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ }
+ if ((what == kDartLf) || (what == kDartRt) || (what == kCobweb))
+ {
+ thisRoom->objects[objActive].data.h.topLeft.v =
+ where.v - HalfRectTall(&srcRects[what]);
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.h.topLeft.v =
+ (kTileHigh / 2) - HalfRectTall(&srcRects[what]);
+ }
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.h.topLeft.h,
+ thisRoom->objects[objActive].data.h.topLeft.v);
+ thisRoom->objects[objActive].data.h.length = 0;
+ if (what == kCobweb)
+ thisRoom->objects[objActive].data.h.delay = 0;
+ else
+ thisRoom->objects[objActive].data.h.delay = 10 + RandomInt(10);
+ thisRoom->objects[objActive].data.h.byte0 = 0;
+ thisRoom->objects[objActive].data.h.initial = true;
+ thisRoom->objects[objActive].data.h.state = true;
+ break;
+
+ case kBall:
+ case kDrip:
+ case kFish:
+ if (HowManyDynamicObjects() >= kMaxDynamicObs)
+ {
+ ShoutNoMoreSpecialObjects();
+ return (false);
+ }
+ thisRoom->objects[objActive].data.h.topLeft.h =
+ where.h - HalfRectWide(&srcRects[what]);
+ thisRoom->objects[objActive].data.h.topLeft.v =
+ where.v - HalfRectTall(&srcRects[what]);
+ QSetRect(&newRect, 0, 0, RectWide(&srcRects[what]),
+ RectTall(&srcRects[what]));
+ QOffsetRect(&newRect, thisRoom->objects[objActive].data.h.topLeft.h,
+ thisRoom->objects[objActive].data.h.topLeft.v);
+ thisRoom->objects[objActive].data.h.length = 64;
+ if (what == kBall)
+ thisRoom->objects[objActive].data.h.delay = 0;
+ else
+ thisRoom->objects[objActive].data.h.delay = 10 + RandomInt(10);
+ thisRoom->objects[objActive].data.h.byte0 = 0;
+ thisRoom->objects[objActive].data.h.initial = true;
+ thisRoom->objects[objActive].data.h.state = true;
+ break;
+
+ case kMousehole:
+ newRect = srcRects[what];
+ CenterRectOnPoint(&newRect, where);
+ newRect.bottom = kMouseholeBottom;
+ newRect.top = newRect.bottom - RectTall(&srcRects[what]);
+ thisRoom->objects[objActive].data.i.bounds = newRect;
+ thisRoom->objects[objActive].data.i.pict = 0;
+ break;
+
+ case kFireplace:
+ newRect = srcRects[what];
+ CenterRectOnPoint(&newRect, where);
+ newRect.bottom = kFireplaceBottom;
+ newRect.top = newRect.bottom - RectTall(&srcRects[what]);
+ thisRoom->objects[objActive].data.i.bounds = newRect;
+ thisRoom->objects[objActive].data.i.pict = 0;
+ break;
+
+ case kFlower:
+ GetKeys(theseKeys);
+ if (!BitTst(&theseKeys, kShiftKeyMap))
+ wasFlower = RandomInt(kNumFlowers);
+ newRect = flowerSrc[wasFlower];
+ CenterRectOnPoint(&newRect, where);
+ thisRoom->objects[objActive].data.i.bounds = newRect;
+ thisRoom->objects[objActive].data.i.pict = wasFlower;
+ break;
+
+ case kOzma:
+ case kMirror:
+ case kWallWindow:
+ case kBear:
+ case kCalendar:
+ case kVase1:
+ case kVase2:
+ case kBulletin:
+ case kCloud:
+ case kFaucet:
+ case kRug:
+ case kChimes:
+ newRect = srcRects[what];
+ CenterRectOnPoint(&newRect, where);
+ thisRoom->objects[objActive].data.i.bounds = newRect;
+ thisRoom->objects[objActive].data.i.pict = 0;
+ break;
+
+ default:
+ return (false);
+ break;
+ }
+
+ thisRoom->objects[objActive].what = what;
+ thisRoom->numObjects++;
+ if (KeepObjectLegal())
+ {
+ }
+ fileDirty = true;
+ UpdateMenus(false);
+ handled = ObjectHasHandle(&direction, &dist);
+
+ if (showItNow)
+ {
+ if (drawWholeRoom)
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ GetThisRoomsObjRects();
+ DrawThisRoomsObjects();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+
+ if (handled)
+ {
+ StartMarqueeHandled(&roomObjectRects[objActive], direction, dist);
+ HandleBlowerGlider();
+ }
+ else
+ StartMarquee(&roomObjectRects[objActive]);
+ }
+
+#endif
+
+ return (true);
+}
+
+//-------------------------------------------------------------- FindEmptyObjectSlot
+
+#ifndef COMPILEDEMO
+short FindEmptyObjectSlot (void)
+{
+ short i, emptySlot;
+
+ emptySlot = -1;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (thisRoom->objects[i].what == kObjectIsEmpty)
+ {
+ emptySlot = i;
+ break;
+ }
+
+ return (emptySlot);
+}
+
+//-------------------------------------------------------------- FindObjectSlotInRoom
+
+short FindObjectSlotInRoom (short roomNumber)
+{
+ roomType *testRoomPtr;
+ short i, emptySlot;
+ char wasState;
+
+ emptySlot = -1;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNumber]);
+
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (testRoomPtr->objects[i].what == kObjectIsEmpty)
+ {
+ emptySlot = i;
+ break;
+ }
+
+
+ HSetState((Handle)thisHouse, wasState);
+
+ return (emptySlot);
+}
+
+//-------------------------------------------------------------- DoesRoomNumHaveObject
+
+Boolean DoesRoomNumHaveObject (short room, short what)
+{
+ roomType *testRoomPtr;
+ short i;
+ char wasState;
+ Boolean hasIt;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[room]);
+
+ hasIt = false;
+
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (testRoomPtr->objects[i].what == what)
+ {
+ hasIt = true;
+ break;
+ }
+
+
+ HSetState((Handle)thisHouse, wasState);
+
+ return (hasIt);
+}
+
+//-------------------------------------------------------------- ShoutNoMoreObjects
+
+void ShoutNoMoreObjects (void)
+{
+ short hitWhat;
+
+// CenterAlert(kNoMoreObjectsAlert);
+ hitWhat = Alert(kNoMoreObjectsAlert, nil);
+}
+
+//-------------------------------------------------------------- HowManyCandleObjects
+
+short HowManyCandleObjects (void)
+{
+ short i, aCandle;
+
+ aCandle = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if ((thisRoom->objects[i].what == kTaper) ||
+ (thisRoom->objects[i].what == kCandle) ||
+ (thisRoom->objects[i].what == kStubby))
+ aCandle++;
+
+ return (aCandle);
+}
+
+//-------------------------------------------------------------- HowManyTikiObjects
+
+short HowManyTikiObjects (void)
+{
+ short i, aTiki;
+
+ aTiki = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (thisRoom->objects[i].what == kTiki)
+ aTiki++;
+
+ return (aTiki);
+}
+
+//-------------------------------------------------------------- HowManyBBQObjects
+
+short HowManyBBQObjects (void)
+{
+ short i, aBBQ;
+
+ aBBQ = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (thisRoom->objects[i].what == kBBQ)
+ aBBQ++;
+
+ return (aBBQ);
+}
+
+//-------------------------------------------------------------- HowManyCuckooObjects
+
+short HowManyCuckooObjects (void)
+{
+ short i, aCuckoo;
+
+ aCuckoo = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (thisRoom->objects[i].what == kCuckoo)
+ aCuckoo++;
+
+ return (aCuckoo);
+}
+
+//-------------------------------------------------------------- HowManyBandsObjects
+
+short HowManyBandsObjects (void)
+{
+ short i, aBands;
+
+ aBands = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (thisRoom->objects[i].what == kBands)
+ aBands++;
+
+ return (aBands);
+}
+
+//-------------------------------------------------------------- HowManyGreaseObjects
+
+short HowManyGreaseObjects (void)
+{
+ short i, aGrease;
+
+ aGrease = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if ((thisRoom->objects[i].what == kGreaseRt) ||
+ (thisRoom->objects[i].what == kGreaseLf))
+ aGrease++;
+
+ return (aGrease);
+}
+
+//-------------------------------------------------------------- HowManyStarsObjects
+
+short HowManyStarsObjects (void)
+{
+ short i, aStar;
+
+ aStar = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (thisRoom->objects[i].what == kStar)
+ aStar++;
+
+ return (aStar);
+}
+
+//-------------------------------------------------------------- HowManySoundObjects
+
+short HowManySoundObjects (void)
+{
+ short i, aSound;
+
+ aSound = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (thisRoom->objects[i].what == kSoundTrigger)
+ aSound++;
+
+ return (aSound);
+}
+
+//-------------------------------------------------------------- HowManyUpStairsObjects
+
+short HowManyUpStairsObjects (void)
+{
+ short i, aStair;
+
+ aStair = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (thisRoom->objects[i].what == kUpStairs)
+ aStair++;
+
+ return (aStair);
+}
+
+//-------------------------------------------------------------- HowManyDownStairsObjects
+
+short HowManyDownStairsObjects (void)
+{
+ short i, aStair;
+
+ aStair = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (thisRoom->objects[i].what == kDownStairs)
+ aStair++;
+
+ return (aStair);
+}
+
+//-------------------------------------------------------------- HowManyShredderObjects
+
+short HowManyShredderObjects (void)
+{
+ short i, aShredder;
+
+ aShredder = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if (thisRoom->objects[i].what == kShredder)
+ aShredder++;
+
+ return (aShredder);
+}
+
+//-------------------------------------------------------------- HowManyDynamicObjects
+
+short HowManyDynamicObjects (void)
+{
+ short i, aDinah;
+
+ aDinah = 0;
+ for (i = 0; i < kMaxRoomObs; i++)
+ if ((thisRoom->objects[i].what == kSparkle) ||
+ (thisRoom->objects[i].what == kToaster) ||
+ (thisRoom->objects[i].what == kMacPlus) ||
+ (thisRoom->objects[i].what == kTV) ||
+ (thisRoom->objects[i].what == kCoffee) ||
+ (thisRoom->objects[i].what == kOutlet) ||
+ (thisRoom->objects[i].what == kVCR) ||
+ (thisRoom->objects[i].what == kStereo) ||
+ (thisRoom->objects[i].what == kMicrowave) ||
+ (thisRoom->objects[i].what == kBalloon) ||
+ (thisRoom->objects[i].what == kCopterLf) ||
+ (thisRoom->objects[i].what == kCopterRt) ||
+ (thisRoom->objects[i].what == kDartLf) ||
+ (thisRoom->objects[i].what == kDartRt) ||
+ (thisRoom->objects[i].what == kBall) ||
+ (thisRoom->objects[i].what == kDrip) ||
+ (thisRoom->objects[i].what == kFish))
+ aDinah++;
+
+ return (aDinah);
+}
+
+//-------------------------------------------------------------- ShoutNoMoreSpecialObjects
+
+void ShoutNoMoreSpecialObjects (void)
+{
+ short hitWhat;
+
+// CenterAlert(kNoMoreSpecialAlert);
+ hitWhat = Alert(kNoMoreSpecialAlert, nil);
+}
+
+#endif
+
diff --git a/GpApp/ObjectDraw.cpp b/GpApp/ObjectDraw.cpp
new file mode 100644
index 0000000..4d8d765
--- /dev/null
+++ b/GpApp/ObjectDraw.cpp
@@ -0,0 +1,1406 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// ObjectDraw.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Environ.h"
+#include "Objects.h"
+#include "RectUtils.h"
+#include "Room.h"
+
+
+#define k8WhiteColor 0
+#define kYellowColor 5
+#define kGoldColor 11
+#define k8RedColor 35
+#define kPaleVioletColor 42
+#define k8LtTanColor 52
+#define k8BambooColor 53
+#define kDarkFleshColor 58
+#define k8TanColor 94
+#define k8PissYellowColor 95
+#define k8OrangeColor 59
+#define k8BrownColor 137
+#define k8Red4Color 143
+#define k8SkyColor 150
+#define k8EarthBlueColor 170
+#define k8DkRedColor 222
+#define k8DkRed2Color 223
+#define kIntenseGreenColor 225
+#define kIntenseBlueColor 235
+#define k8PumpkinColor 101
+#define k8LtstGrayColor 245
+#define k8LtstGray2Color 246
+#define k8LtstGray3Color 43
+#define k8LtstGray4Color 247
+#define k8LtstGray5Color 248
+#define k8LtGrayColor 249
+#define k8GrayColor 250
+#define k8Gray2Color 251
+#define k8DkGrayColor 252
+#define k8DkGray2Color 253
+#define k8DkGray3Color 172
+#define k8DkstGrayColor 254
+#define k8BlackColor 255
+
+
+void DrawClockDigit (short, Rect *);
+void DrawClockHands (Point, short, short);
+void DrawLargeClockHands (Point, short, short);
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DrawSimpleBlowers
+
+void DrawSimpleBlowers (short what, Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(blowerSrcMap),
+ (BitMap *)*GetGWorldPixMap(blowerMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], &srcRects[what], theRect);
+}
+
+//-------------------------------------------------------------- DrawTiki
+
+void DrawTiki (Rect *theRect, short down)
+{
+#define kTikiPoleBase 300
+ long darkGrayC, lightWoodC, darkWoodC;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ if (thisMac.isDepth == 4)
+ {
+ darkGrayC = 14;
+ lightWoodC = 6;
+ darkWoodC = 9;
+ }
+ else
+ {
+ darkGrayC = k8DkstGrayColor;
+ lightWoodC = k8BambooColor;
+ darkWoodC = k8PissYellowColor;
+ }
+
+ if (theRect->bottom < kTikiPoleBase + down)
+ {
+ ColorLine(theRect->left + 11, theRect->bottom - 1,
+ theRect->left + 11, kTikiPoleBase + down - 1, darkGrayC);
+ ColorLine(theRect->left + 12, theRect->bottom - 1,
+ theRect->left + 12, kTikiPoleBase + down, lightWoodC);
+ ColorLine(theRect->left + 13, theRect->bottom - 1,
+ theRect->left + 13, kTikiPoleBase + down, darkWoodC);
+ ColorLine(theRect->left + 14, theRect->bottom - 1,
+ theRect->left + 14, kTikiPoleBase + down, darkWoodC);
+ ColorLine(theRect->left + 15, theRect->bottom - 1,
+ theRect->left + 15, kTikiPoleBase + down - 1, darkGrayC);
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(blowerSrcMap),
+ (BitMap *)*GetGWorldPixMap(blowerMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kTiki], &srcRects[kTiki], theRect);
+}
+
+//-------------------------------------------------------------- DrawInvisibleBlower
+
+void DrawInvisibleBlower (Rect *theRect)
+{
+ Rect tempRect;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ QSetRect(&tempRect, 0, 0, 24, 24);
+ QOffsetRect(&tempRect, theRect->left, theRect->top);
+
+ ColorFrameRect(&tempRect, 192);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawLiftArea
+
+void DrawLiftArea (Rect *theRect)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ ColorFrameRect(theRect, 192);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawTable
+
+void DrawTable (Rect *tableTop, short down)
+{
+ #define kTableBaseTop 296
+ #define kTableShadowTop 312
+ #define kTableShadowOffset 12
+ Rect tempRect;
+ long brownC, tanC, dkRedC, blackC;
+ short hCenter, vShadow;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ Pattern dummyPattern;
+
+ if (thisMac.isDepth == 4)
+ {
+ brownC = 11;
+ tanC = 9;
+ dkRedC = 14;
+ blackC = 15;
+ }
+ else
+ {
+ brownC = k8BrownColor;
+ tanC = k8TanColor;
+ dkRedC = k8DkRed2Color;
+ blackC = k8BlackColor;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ QSetRect(&tempRect, tableTop->left, 0, tableTop->right,
+ RectWide(tableTop) / 10);
+ QOffsetRect(&tempRect, 0,
+ -HalfRectTall(&tempRect) + kTableShadowTop + down);
+ QOffsetRect(&tempRect, kTableShadowOffset, -kTableShadowOffset);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ PenMode(patOr);
+ if (thisMac.isDepth == 4)
+ ColorOval(&tempRect, 15);
+ else
+ ColorOval(&tempRect, k8DkstGrayColor);
+ PenNormal();
+
+ InsetRect(tableTop, 0, 1);
+ ColorRect(tableTop, brownC);
+ InsetRect(tableTop, 0, -1);
+
+ ColorLine(tableTop->left, tableTop->top + 1,
+ tableTop->left, tableTop->top + 1, k8WhiteColor);
+ ColorLine(tableTop->left + 1, tableTop->top,
+ tableTop->right - 2, tableTop->top, k8WhiteColor);
+ ColorLine(tableTop->right - 1, tableTop->top + 1,
+ tableTop->right - 1, tableTop->top + 1, k8WhiteColor);
+
+ ColorLine(tableTop->left + 1, tableTop->top + 1,
+ tableTop->right - 2, tableTop->top + 1, tanC);
+ ColorLine(tableTop->left, tableTop->top + 2,
+ tableTop->left, tableTop->bottom - 2, tanC);
+
+ ColorLine(tableTop->left + 1, tableTop->bottom - 1,
+ tableTop->right - 2, tableTop->bottom - 1, blackC);
+ ColorLine(tableTop->right - 1, tableTop->top + 2,
+ tableTop->right - 1, tableTop->bottom - 2, blackC);
+
+ ColorLine(tableTop->left + 1, tableTop->bottom - 2,
+ tableTop->right - 2, tableTop->bottom - 2, dkRedC);
+
+ if (tableTop->bottom < kTableBaseTop + down)
+ {
+ hCenter = (tableTop->left + tableTop->right) / 2;
+
+ ColorLine(hCenter - 3, tableTop->bottom,
+ hCenter - 3, kTableBaseTop + down, blackC);
+ ColorLine(hCenter - 2, tableTop->bottom,
+ hCenter - 2, kTableBaseTop + down, k8LtGrayColor);
+ ColorLine(hCenter - 1, tableTop->bottom,
+ hCenter - 1, kTableBaseTop + down, k8GrayColor);
+ ColorLine(hCenter, tableTop->bottom,
+ hCenter, kTableBaseTop + down, k8DkGrayColor);
+ ColorLine(hCenter + 1, tableTop->bottom,
+ hCenter + 1, kTableBaseTop + down, blackC);
+
+ vShadow = tableTop->bottom + RectWide(tableTop) / 4 - 2;
+ if (vShadow > kTableBaseTop + down)
+ {
+ ColorLine(hCenter - 2, tableTop->bottom,
+ hCenter - 2, kTableBaseTop + down, k8DkGrayColor);
+ ColorLine(hCenter - 1, tableTop->bottom,
+ hCenter - 1, kTableBaseTop + down, k8DkGrayColor);
+ ColorLine(hCenter, tableTop->bottom,
+ hCenter, kTableBaseTop + down, blackC);
+ }
+ else
+ {
+ ColorLine(hCenter - 2, tableTop->bottom,
+ hCenter - 2, vShadow, k8DkGrayColor);
+ ColorLine(hCenter - 1, tableTop->bottom,
+ hCenter - 1, vShadow + 1, k8DkGrayColor);
+ ColorLine(hCenter, tableTop->bottom,
+ hCenter, vShadow + 2, blackC);
+ }
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+
+ tempRect = tableSrc;
+ QOffsetRect(&tempRect, -HalfRectWide(&tableSrc) + tableTop->left +
+ HalfRectWide(tableTop), kTableBaseTop + down);
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &tableSrc, &tableSrc, &tempRect);
+}
+
+//-------------------------------------------------------------- DrawShelf
+
+void DrawShelf (Rect *shelfTop)
+{
+ #define kBracketInset 18
+ #define kShelfDeep 4
+ #define kBracketThick 5
+ #define kShelfShadowOff 12
+ Rect tempRect;
+ long brownC, ltTanC, tanC, dkRedC, blackC;
+ RgnHandle shadowRgn;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ Pattern dummyPattern;
+
+ if (thisMac.isDepth == 4)
+ {
+ brownC = 11;
+ ltTanC = 7;
+ tanC = 9;
+ dkRedC = 14;
+ blackC = 15;
+ }
+ else
+ {
+ brownC = k8BrownColor;
+ ltTanC = k8LtTanColor;
+ tanC = k8TanColor;
+ dkRedC = k8DkRed2Color;
+ blackC = k8BlackColor;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ MoveTo(shelfTop->left, shelfTop->bottom);
+ shadowRgn = NewRgn();
+ if (shadowRgn == nil)
+ RedAlert(kErrUnnaccounted);
+ OpenRgn();
+ Line(kShelfShadowOff, kShelfShadowOff);
+ Line(RectWide(shelfTop) - kShelfDeep, 0);
+ Line(0, -kShelfThick + 1);
+ Line(-kShelfShadowOff, -kShelfShadowOff);
+ LineTo(shelfTop->left, shelfTop->bottom);
+ CloseRgn(shadowRgn);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ PenMode(patOr);
+ if (thisMac.isDepth == 4)
+ ColorRegion(shadowRgn, 15);
+ else
+ ColorRegion(shadowRgn, k8DkstGrayColor);
+ PenNormal();
+ DisposeRgn(shadowRgn);
+
+ InsetRect(shelfTop, 0, 1);
+ ColorRect(shelfTop, brownC);
+ InsetRect(shelfTop, 0, -1);
+
+ ColorLine(shelfTop->left + 1, shelfTop->top,
+ shelfTop->left + 1 + kShelfDeep, shelfTop->top, ltTanC);
+ ColorLine(shelfTop->left, shelfTop->top + 1,
+ shelfTop->left + kShelfDeep, shelfTop->top + 1, tanC);
+ ColorLine(shelfTop->left, shelfTop->top + 2,
+ shelfTop->left + kShelfDeep, shelfTop->top + 2, tanC);
+ ColorLine(shelfTop->left, shelfTop->top + 3,
+ shelfTop->left + kShelfDeep, shelfTop->top + 3, tanC);
+ ColorLine(shelfTop->left + 1, shelfTop->bottom - 1,
+ shelfTop->left + 1 + kShelfDeep, shelfTop->bottom - 1, dkRedC);
+ ColorLine(shelfTop->left + 2 + kShelfDeep, shelfTop->bottom - 1,
+ shelfTop->right - 2, shelfTop->bottom - 1, blackC);
+ ColorLine(shelfTop->left + 2 + kShelfDeep, shelfTop->top,
+ shelfTop->right - 2, shelfTop->top, tanC);
+ ColorLine(shelfTop->right - 1, shelfTop->top + 1,
+ shelfTop->right - 1, shelfTop->bottom - 2, blackC);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ tempRect = shelfSrc;
+ ZeroRectCorner(&tempRect);
+ QOffsetRect(&tempRect, shelfTop->left + kBracketInset, shelfTop->bottom);
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &shelfSrc, &shelfSrc, &tempRect);
+
+ ZeroRectCorner(&tempRect);
+ QOffsetRect(&tempRect, shelfTop->right - kBracketInset - kShelfDeep -
+ kBracketThick, shelfTop->bottom);
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &shelfSrc, &shelfSrc, &tempRect);
+}
+
+//-------------------------------------------------------------- DrawCabinet
+
+void DrawCabinet (Rect *cabinet)
+{
+ #define kCabinetDeep 4
+ #define kCabinetShadowOff 6
+ Rect tempRect;
+ long brownC, dkGrayC, ltTanC, tanC, dkRedC, blackC;
+ RgnHandle shadowRgn;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ Pattern dummyPattern;
+
+ if (thisMac.isDepth == 4)
+ {
+ brownC = 11;
+ dkGrayC = 14;
+ ltTanC = 7;
+ tanC = 9;
+ dkRedC = 14;
+ blackC = 15;
+ }
+ else
+ {
+ brownC = k8BrownColor;
+ dkGrayC = k8DkstGrayColor;
+ ltTanC = k8LtTanColor;
+ tanC = k8TanColor;
+ dkRedC = k8DkRed2Color;
+ blackC = k8BlackColor;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ MoveTo(cabinet->left, cabinet->bottom);
+ shadowRgn = NewRgn();
+ if (shadowRgn == nil)
+ RedAlert(kErrUnnaccounted);
+ OpenRgn();
+ Line(kCabinetShadowOff, kCabinetShadowOff);
+ Line(RectWide(cabinet), 0);
+ Line(0, -RectTall(cabinet) + kCabinetDeep);
+ Line(-kCabinetShadowOff, -kCabinetShadowOff);
+ LineTo(cabinet->left, cabinet->bottom);
+ CloseRgn(shadowRgn);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ PenMode(patOr);
+ if (thisMac.isDepth == 4)
+ ColorRegion(shadowRgn, 15);
+ else
+ ColorRegion(shadowRgn, dkGrayC);
+ PenNormal();
+ DisposeRgn(shadowRgn);
+
+ InsetRect(cabinet, 1, 1); // fill bulk of cabinet brown
+ ColorRect(cabinet, brownC);
+ InsetRect(cabinet, -1, -1);
+
+ tempRect = *cabinet; // add lighter left side
+ tempRect.right = tempRect.left + kCabinetDeep;
+ ColorRect(&tempRect, tanC);
+ // hilight top edge
+ ColorLine(cabinet->left + 1, cabinet->top + 1,
+ cabinet->left + kCabinetDeep, cabinet->top + 1, ltTanC);
+ ColorLine(cabinet->left + kCabinetDeep, cabinet->top + 1,
+ cabinet->right - 3, cabinet->top + 1, tanC);
+ // shadow bottom edge
+
+ ColorLine(cabinet->left + kCabinetDeep + 3, cabinet->top + 5,
+ cabinet->left + kCabinetDeep + 3, cabinet->bottom - 6, tanC);
+ ColorLine(cabinet->left + kCabinetDeep + 4, cabinet->top + 5,
+ cabinet->left + kCabinetDeep + 4, cabinet->bottom - 6, tanC);
+ ColorLine(cabinet->left + kCabinetDeep + 9, cabinet->top + 10,
+ cabinet->left + kCabinetDeep + 9, cabinet->bottom - 11, dkGrayC);
+
+ ColorLine(cabinet->right - 4, cabinet->top + 6,
+ cabinet->right - 4, cabinet->bottom - 5, dkRedC);
+ ColorLine(cabinet->right - 5, cabinet->top + 5,
+ cabinet->right - 5, cabinet->bottom - 6, dkGrayC);
+ ColorLine(cabinet->right - 10, cabinet->top + 10,
+ cabinet->right - 10, cabinet->bottom - 11, tanC);
+
+ ColorLine(cabinet->left + kCabinetDeep + 4, cabinet->top + 4,
+ cabinet->left + kCabinetDeep + 4, cabinet->top + 4, ltTanC);
+ ColorLine(cabinet->left + kCabinetDeep + 5, cabinet->top + 4,
+ cabinet->right - 6, cabinet->top + 4, tanC);
+ ColorLine(cabinet->left + kCabinetDeep + 10, cabinet->top + 9,
+ cabinet->right - 11, cabinet->top + 9, dkGrayC);
+
+ ColorLine(cabinet->right - 5, cabinet->bottom - 5,
+ cabinet->right - 5, cabinet->bottom - 5, dkRedC);
+ ColorLine(cabinet->left + kCabinetDeep + 6, cabinet->bottom - 4,
+ cabinet->right - 5, cabinet->bottom - 4, dkRedC);
+ ColorLine(cabinet->left + kCabinetDeep + 5, cabinet->bottom - 5,
+ cabinet->right - 6, cabinet->bottom - 5, dkGrayC);
+
+ ColorLine(cabinet->left + kCabinetDeep + 10, cabinet->bottom - 10,
+ cabinet->right - 11, cabinet->bottom - 10, tanC);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ tempRect = hingeSrc;
+ ZeroRectCorner(&tempRect);
+ QOffsetRect(&tempRect, cabinet->left + kCabinetDeep + 2, cabinet->top + 10);
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &hingeSrc, &hingeSrc, &tempRect);
+
+ tempRect = hingeSrc;
+ ZeroRectCorner(&tempRect);
+ QOffsetRect(&tempRect, cabinet->left + kCabinetDeep + 2, cabinet->bottom - 26);
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &hingeSrc, &hingeSrc, &tempRect);
+
+ tempRect = handleSrc;
+ ZeroRectCorner(&tempRect);
+ QOffsetRect(&tempRect, cabinet->right - 8, cabinet->top +
+ HalfRectTall(cabinet) - HalfRectTall(&handleSrc));
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &handleSrc, &handleSrc, &tempRect);
+
+ FrameRect(cabinet);
+}
+
+//-------------------------------------------------------------- DrawSimpleFurniture
+
+void DrawSimpleFurniture (short what, Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], &srcRects[what], theRect);
+}
+
+//-------------------------------------------------------------- DrawCounter
+
+void DrawCounter (Rect *counter)
+{
+ #define kCounterFooterHigh 12
+ #define kCounterStripWide 6
+ #define kCounterStripTall 29
+ #define kCounterPanelDrop 12
+ Rect tempRect;
+ RgnHandle shadowRgn;
+ long brownC, dkGrayC, tanC, blackC, dkstRedC;
+ short nRects, width, i;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ Pattern dummyPattern;
+
+ if (thisMac.isDepth == 4)
+ {
+ brownC = 11;
+ dkGrayC = 14;
+ tanC = 9;
+ blackC = 15;
+ dkstRedC = 15;
+ }
+ else
+ {
+ brownC = k8BrownColor;
+ dkGrayC = k8DkstGrayColor;
+ tanC = k8TanColor;
+ blackC = k8BlackColor;
+ dkstRedC = k8DkRed2Color;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ MoveTo(counter->right - 2, counter->bottom);
+ shadowRgn = NewRgn();
+ if (shadowRgn == nil)
+ RedAlert(kErrUnnaccounted);
+ OpenRgn();
+ Line(10, -10);
+ Line(0, -RectTall(counter) + 29);
+ Line(2, 0);
+ Line(0, -7);
+ Line(-12, -12);
+ LineTo(counter->right - 2, counter->bottom);
+ CloseRgn(shadowRgn);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ PenMode(patOr);
+ if (thisMac.isDepth == 4)
+ ColorRegion(shadowRgn, 15);
+ else
+ ColorRegion(shadowRgn, dkGrayC);
+ PenNormal();
+ DisposeRgn(shadowRgn);
+
+ InsetRect(counter, 2, 2);
+ ColorRect(counter, brownC);
+ InsetRect(counter, -2, -2);
+
+ tempRect = *counter;
+ tempRect.top = tempRect.bottom - kCounterFooterHigh;
+ tempRect.left += 2;
+ tempRect.right -= 2;
+ ColorRect(&tempRect, dkGrayC);
+ ColorLine(counter->left + 2, counter->bottom - kCounterFooterHigh,
+ counter->right - 3, counter->bottom - kCounterFooterHigh, blackC);
+ ColorLine(counter->left + 2, counter->bottom - kCounterFooterHigh + 1,
+ counter->right - 3, counter->bottom - kCounterFooterHigh + 1, blackC);
+ ColorLine(counter->right - 3, counter->bottom - kCounterFooterHigh,
+ counter->right - 3, counter->bottom - 1, blackC);
+ ColorLine(counter->left + 2, counter->bottom - kCounterFooterHigh,
+ counter->left + 2, counter->bottom - 1, k8DkGrayColor);
+
+ ColorLine(counter->right - 2, counter->top,
+ counter->right - 2, counter->bottom - kCounterFooterHigh - 1, dkstRedC);
+ ColorLine(counter->left + 1, counter->top + 8,
+ counter->left + 1, counter->bottom - kCounterFooterHigh - 1, tanC);
+
+ if (thisMac.isDepth == 4)
+ {
+ ColorLine(counter->left - 1, counter->top,
+ counter->right, counter->top, 1);
+ ColorLine(counter->left - 1, counter->top + 1,
+ counter->right, counter->top + 1, 2);
+ ColorLine(counter->left - 1, counter->top + 2,
+ counter->right, counter->top + 2, 3);
+ ColorLine(counter->left - 1, counter->top + 3,
+ counter->right, counter->top + 3, 4);
+ ColorLine(counter->left - 1, counter->top + 4,
+ counter->right, counter->top + 4, 5);
+ ColorLine(counter->left - 1, counter->top + 5,
+ counter->right, counter->top + 5, 5);
+ ColorLine(counter->left - 1, counter->top + 6,
+ counter->right, counter->top + 6, 5);
+ ColorLine(counter->left - 1, counter->top,
+ counter->left - 1, counter->top + 6, 1);
+ }
+ else
+ {
+ ColorLine(counter->left - 1, counter->top,
+ counter->right, counter->top, k8LtstGrayColor);
+ ColorLine(counter->left - 1, counter->top + 1,
+ counter->right, counter->top + 1, k8LtstGray2Color);
+ ColorLine(counter->left - 1, counter->top + 2,
+ counter->right, counter->top + 2, k8LtstGray3Color);
+ ColorLine(counter->left - 1, counter->top + 3,
+ counter->right, counter->top + 3, k8LtstGray4Color);
+ ColorLine(counter->left - 1, counter->top + 4,
+ counter->right, counter->top + 4, k8LtstGray5Color);
+ ColorLine(counter->left - 1, counter->top + 5,
+ counter->right, counter->top + 5, k8LtstGray5Color);
+ ColorLine(counter->left - 1, counter->top + 6,
+ counter->right, counter->top + 6, k8LtstGray5Color);
+ ColorLine(counter->left - 1, counter->top,
+ counter->left - 1, counter->top + 6, k8LtstGrayColor);
+ }
+
+ ColorLine(counter->right, counter->top,
+ counter->right, counter->top + 6, k8LtGrayColor);
+ ColorLine(counter->left + 1, counter->top + 7,
+ counter->right - 2, counter->top + 7, dkstRedC);
+ ColorLine(counter->left + 1, counter->top + 8,
+ counter->right - 2, counter->top + 8, dkstRedC);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ nRects = RectWide(counter) / 40;
+ if (nRects == 0)
+ nRects = 1;
+ width = ((RectWide(counter) - kCounterStripWide) / nRects) - kCounterStripWide;
+ QSetRect(&tempRect, 0, 0, width, RectTall(counter) - kCounterStripTall);
+ QOffsetRect(&tempRect, counter->left + kCounterStripWide,
+ counter->top + kCounterPanelDrop);
+ for (i = 0; i < nRects; i++)
+ {
+ HiliteRect(&tempRect, tanC, dkstRedC);
+ InsetRect(&tempRect, 4, 4);
+ HiliteRect(&tempRect, dkstRedC, tanC);
+ InsetRect(&tempRect, -4, -4);
+ QOffsetRect(&tempRect, kCounterStripWide + width, 0);
+ }
+}
+
+//-------------------------------------------------------------- DrawDresser
+
+void DrawDresser (Rect *dresser)
+{
+ #define kDresserTopThick 4
+ #define kDresserCrease 9
+ #define kDresserDrawerDrop 12
+ #define kDresserSideSpare 14
+ Rect tempRect, dest;
+ long yellowC, brownC, dkGrayC, ltTanC, dkstRedC;
+ RgnHandle shadowRgn;
+ short nRects, height, i;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ Pattern dummyPattern;
+
+ if (thisMac.isDepth == 4)
+ {
+ yellowC = 9;
+ brownC = 11;
+ dkGrayC = 14;
+ ltTanC = 7;
+ dkstRedC = 15;
+ }
+ else
+ {
+ yellowC = k8PissYellowColor;
+ brownC = k8BrownColor;
+ dkGrayC = k8DkstGrayColor;
+ ltTanC = k8LtTanColor;
+ dkstRedC = k8DkRed2Color;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ MoveTo(dresser->left + 10, dresser->bottom + 9);
+ shadowRgn = NewRgn();
+ if (shadowRgn == nil)
+ RedAlert(kErrUnnaccounted);
+ OpenRgn();
+ Line(RectWide(dresser) - 11, 0);
+ Line(9, -9);
+ Line(0, -RectTall(dresser) + 12);
+ Line(-9, -9);
+ Line(-RectWide(dresser) + 11, 0);
+ LineTo(dresser->left + 10, dresser->bottom + 9);
+ CloseRgn(shadowRgn);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ PenMode(patOr);
+ if (thisMac.isDepth == 4)
+ ColorRegion(shadowRgn, 15);
+ else
+ ColorRegion(shadowRgn, k8DkstGrayColor);
+ PenNormal();
+ DisposeRgn(shadowRgn);
+
+ InsetRect(dresser, 2, 2);
+ ColorRect(dresser, k8PumpkinColor);
+ HiliteRect(dresser, k8OrangeColor, dkstRedC);
+ InsetRect(dresser, -2, -2);
+
+ tempRect = *dresser;
+ tempRect.bottom = tempRect.top + kDresserTopThick;
+ ColorRect(&tempRect, k8PissYellowColor);
+ HiliteRect(&tempRect, ltTanC, dkstRedC);
+ ColorLine(dresser->left + 2, dresser->top + kDresserTopThick,
+ dresser->right - 3, dresser->top + kDresserTopThick, k8Red4Color);
+
+ ColorLine(dresser->left + kDresserCrease, dresser->top + kDresserTopThick + 1,
+ dresser->left + kDresserCrease, dresser->bottom - 4, k8Red4Color);
+ ColorLine(dresser->right - kDresserCrease, dresser->top + kDresserTopThick + 1,
+ dresser->right - kDresserCrease, dresser->bottom - 4, k8OrangeColor);
+
+ nRects = RectTall(dresser) / 30;
+ if (nRects == 0)
+ nRects = 1;
+ height = (RectTall(dresser) - 14) / nRects - 4;
+ QSetRect(&tempRect, 0, 0, RectWide(dresser) - kDresserSideSpare, height);
+ QOffsetRect(&tempRect, dresser->left + 7, dresser->top + 10);
+ for (i = 0; i < nRects; i++)
+ {
+ ColorLine(tempRect.left + 1, tempRect.bottom,
+ tempRect.right, tempRect.bottom, dkstRedC);
+ ColorLine(tempRect.right, tempRect.top + 1,
+ tempRect.right, tempRect.bottom, dkstRedC);
+ ColorRect(&tempRect, yellowC);
+ HiliteRect(&tempRect, ltTanC, brownC);
+ InsetRect(&tempRect, 1, 1);
+ HiliteRect(&tempRect, ltTanC, brownC);
+ InsetRect(&tempRect, -1, -1);
+
+ QSetRect(&dest, -4, -4, 4, 4);
+ QOffsetRect(&dest, HalfRectTall(&tempRect), HalfRectTall(&tempRect));
+ QOffsetRect(&dest, tempRect.left, tempRect.top);
+ CopyBits((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &knobSrc, &dest, srcCopy, nil);
+
+ QSetRect(&dest, -4, -4, 4, 4);
+ QOffsetRect(&dest, -HalfRectTall(&tempRect), HalfRectTall(&tempRect));
+ QOffsetRect(&dest, tempRect.right, tempRect.top);
+ CopyBits((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &knobSrc, &dest, srcCopy, nil);
+
+ QOffsetRect(&tempRect, 0, kDresserTopThick + height);
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+
+ dest = leftFootSrc;
+ ZeroRectCorner(&dest);
+ QOffsetRect(&dest, dresser->left + 6, dresser->bottom - 2);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &leftFootSrc, &leftFootSrc, &dest);
+
+ dest = rightFootSrc;
+ ZeroRectCorner(&dest);
+ QOffsetRect(&dest, dresser->right - 19, dresser->bottom - 2);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &rightFootSrc, &rightFootSrc, &dest);
+}
+
+//-------------------------------------------------------------- DrawDeckTable
+
+void DrawDeckTable (Rect *tableTop, short down)
+{
+ #define kTableBaseTop 296
+ #define kTableShadowTop 312
+ #define kTableShadowOffset 12
+
+ Rect tempRect;
+ long bambooC, brownC, dkGrayC;
+ short hCenter, vShadow;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ Pattern dummyPattern;
+
+ if (thisMac.isDepth == 4)
+ {
+ bambooC = 6;
+ brownC = 11;
+ dkGrayC = 14;
+ }
+ else
+ {
+ bambooC = k8BambooColor;
+ brownC = k8BrownColor;
+ dkGrayC = k8DkstGrayColor;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ QSetRect(&tempRect, tableTop->left, 0, tableTop->right,
+ RectWide(tableTop) / 10);
+ QOffsetRect(&tempRect, 0,
+ -HalfRectTall(&tempRect) + kTableShadowTop + down);
+ QOffsetRect(&tempRect, kTableShadowOffset, -kTableShadowOffset);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ PenMode(patOr);
+ ColorOval(&tempRect, dkGrayC);
+ PenNormal();
+
+ InsetRect(tableTop, 0, 1);
+ ColorRect(tableTop, kGoldColor);
+ InsetRect(tableTop, 0, -1);
+
+ ColorLine(tableTop->left, tableTop->top + 1,
+ tableTop->left, tableTop->top + 1, k8WhiteColor);
+ ColorLine(tableTop->left + 1, tableTop->top,
+ tableTop->right - 2, tableTop->top, k8WhiteColor);
+ ColorLine(tableTop->right - 1, tableTop->top + 1,
+ tableTop->right - 1, tableTop->top + 1, k8WhiteColor);
+
+ ColorLine(tableTop->left + 1, tableTop->top + 1,
+ tableTop->right - 2, tableTop->top + 1, kYellowColor);
+ ColorLine(tableTop->left, tableTop->top + 2,
+ tableTop->left, tableTop->bottom - 2, kYellowColor);
+
+ ColorLine(tableTop->left + 1, tableTop->bottom - 1,
+ tableTop->right - 2, tableTop->bottom - 1, brownC);
+ ColorLine(tableTop->right - 1, tableTop->top + 2,
+ tableTop->right - 1, tableTop->bottom - 2, brownC);
+
+ ColorLine(tableTop->left + 1, tableTop->bottom - 2,
+ tableTop->right - 2, tableTop->bottom - 2, bambooC);
+
+ if (tableTop->bottom < kTableBaseTop + down)
+ {
+ hCenter = (tableTop->left + tableTop->right) / 2;
+
+ ColorLine(hCenter - 3, tableTop->bottom,
+ hCenter - 3, kTableBaseTop + down, dkGrayC);
+ ColorLine(hCenter - 2, tableTop->bottom,
+ hCenter - 2, kTableBaseTop + down, k8WhiteColor);
+ ColorLine(hCenter - 1, tableTop->bottom,
+ hCenter - 1, kTableBaseTop + down, k8WhiteColor);
+ ColorLine(hCenter, tableTop->bottom,
+ hCenter, kTableBaseTop + down, k8LtGrayColor);
+ ColorLine(hCenter + 1, tableTop->bottom,
+ hCenter + 1, kTableBaseTop + down, dkGrayC);
+
+ vShadow = tableTop->bottom + RectWide(tableTop) / 4 - 2;
+ if (vShadow > kTableBaseTop + down)
+ {
+ ColorLine(hCenter - 2, tableTop->bottom,
+ hCenter - 2, kTableBaseTop + down, k8LtGrayColor);
+ ColorLine(hCenter - 1, tableTop->bottom,
+ hCenter - 1, kTableBaseTop + down, k8LtGrayColor);
+ ColorLine(hCenter, tableTop->bottom,
+ hCenter, kTableBaseTop + down, dkGrayC);
+ }
+ else
+ {
+ ColorLine(hCenter - 2, tableTop->bottom,
+ hCenter - 2, vShadow, k8LtGrayColor);
+ ColorLine(hCenter - 1, tableTop->bottom,
+ hCenter - 1, vShadow + 1, k8LtGrayColor);
+ ColorLine(hCenter, tableTop->bottom,
+ hCenter, vShadow + 2, dkGrayC);
+ }
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+
+ tempRect = deckSrc;
+ ZeroRectCorner(&tempRect);
+ QOffsetRect(&tempRect, -HalfRectWide(&deckSrc) + tableTop->left +
+ HalfRectWide(tableTop), kTableBaseTop + down);
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &deckSrc, &deckSrc, &tempRect);
+}
+
+//-------------------------------------------------------------- DrawStool
+
+void DrawStool (Rect *theRect, short down)
+{
+ #define kStoolBase 304
+ long grayC, dkGrayC;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ if (thisMac.isDepth == 4)
+ {
+ grayC = 13;
+ dkGrayC = 14;
+ }
+ else
+ {
+ grayC = k8DkGray2Color;
+ dkGrayC = k8DkstGrayColor;
+ }
+
+ if (theRect->bottom < kStoolBase + down)
+ {
+ ColorLine(theRect->left + 21, theRect->bottom - 1,
+ theRect->left + 21, kStoolBase + down - 1, k8DkGrayColor);
+ ColorLine(theRect->left + 22, theRect->bottom - 1,
+ theRect->left + 22, kStoolBase + down, k8Gray2Color);
+ ColorLine(theRect->left + 23, theRect->bottom - 1,
+ theRect->left + 23, kStoolBase + down, k8DkGrayColor);
+ ColorLine(theRect->left + 24, theRect->bottom - 1,
+ theRect->left + 24, kStoolBase + down, k8DkGray3Color);
+ ColorLine(theRect->left + 25, theRect->bottom - 1,
+ theRect->left + 25, kStoolBase + down, grayC);
+ ColorLine(theRect->left + 26, theRect->bottom - 1,
+ theRect->left + 26, kStoolBase + down - 1, dkGrayC);
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(furnitureSrcMap),
+ (BitMap *)*GetGWorldPixMap(furnitureMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kStool], &srcRects[kStool], theRect);
+}
+
+//-------------------------------------------------------------- DrawInvisObstacle
+
+void DrawInvisObstacle (Rect *theRect)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ ColorFrameRect(theRect, k8BrownColor);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawInvisBounce
+
+void DrawInvisBounce (Rect *theRect)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ ColorFrameRect(theRect, k8RedColor);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawRedClock
+
+void DrawRedClock (Rect *theRect)
+{
+ DateTimeRec timeRec;
+ Rect dest;
+ short hour, minutes;
+
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kRedClock], &srcRects[kRedClock], theRect);
+
+ GetTime(&timeRec);
+ hour = timeRec.hour % 12;
+ if (hour == 0)
+ hour = 12;
+ minutes = timeRec.minute;
+
+ QSetRect(&dest, 0, 0, 4, 6);
+ QOffsetRect(&dest, theRect->left + 5, theRect->top + 7);
+ if (hour > 9)
+ DrawClockDigit(hour / 10, &dest);
+ QOffsetRect(&dest, 4, 0);
+ DrawClockDigit(hour % 10, &dest);
+ QOffsetRect(&dest, 6, 0);
+ DrawClockDigit(minutes / 10, &dest);
+ QOffsetRect(&dest, 4, 0);
+ DrawClockDigit(minutes % 10, &dest);
+}
+
+//-------------------------------------------------------------- DrawClockDigit
+
+void DrawClockDigit (short number, Rect *dest)
+{
+ CopyBits((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &digits[number], dest, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- DrawBlueClock
+
+void DrawBlueClock (Rect *theRect)
+{
+ DateTimeRec timeRec;
+ Point dest;
+ short hour, minutes;
+
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kBlueClock], &srcRects[kBlueClock], theRect);
+
+ dest.h = theRect->left + 13;
+ dest.v = theRect->top + 13;
+ GetTime(&timeRec);
+ hour = timeRec.hour % 12;
+ minutes = ((timeRec.minute + 2) / 5) % 12;
+ DrawClockHands(dest, minutes, hour);
+}
+
+//-------------------------------------------------------------- DrawYellowClock
+
+void DrawYellowClock (Rect *theRect)
+{
+ DateTimeRec timeRec;
+ Point dest;
+ short hour, minutes;
+
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kYellowClock], &srcRects[kYellowClock], theRect);
+
+ dest.h = theRect->left + 13;
+ dest.v = theRect->top + 15;
+ GetTime(&timeRec);
+ hour = timeRec.hour % 12;
+ minutes = ((timeRec.minute + 2) / 5) % 12;
+ DrawClockHands(dest, minutes, hour);
+}
+
+//-------------------------------------------------------------- DrawCuckoo
+
+void DrawCuckoo (Rect *theRect)
+{
+ DateTimeRec timeRec;
+ Point dest;
+ short hour, minutes;
+
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kCuckoo], &srcRects[kCuckoo], theRect);
+
+ dest.h = theRect->left + 19;
+ dest.v = theRect->top + 31;
+ GetTime(&timeRec);
+ hour = timeRec.hour % 12;
+ minutes = ((timeRec.minute + 2) / 5) % 12;
+ DrawLargeClockHands(dest, minutes, hour);
+}
+
+//-------------------------------------------------------------- DrawClockHands
+
+void DrawClockHands (Point where, short bigHand, short littleHand)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ MoveTo(where.h, where.v);
+ switch (bigHand)
+ {
+ case 0:
+ Line(0, -6);
+ break;
+
+ case 1:
+ Line(3, -5);
+ break;
+
+ case 2:
+ Line(5, -3);
+ break;
+
+ case 3:
+ Line(6, 0);
+ break;
+
+ case 4:
+ Line(5, 3);
+ break;
+
+ case 5:
+ Line(3, 5);
+ break;
+
+ case 6:
+ Line(0, 6);
+ break;
+
+ case 7:
+ Line(-3, 5);
+ break;
+
+ case 8:
+ Line(-5, 3);
+ break;
+
+ case 9:
+ Line(-6, 0);
+ break;
+
+ case 10:
+ Line(-5, -3);
+ break;
+
+ case 11:
+ Line(-3, -5);
+ break;
+ }
+
+ MoveTo(where.h, where.v);
+ switch (littleHand)
+ {
+ case 0:
+ Line(0, -4);
+ break;
+
+ case 1:
+ Line(2, -3);
+ break;
+
+ case 2:
+ Line(3, -2);
+ break;
+
+ case 3:
+ Line(4, 0);
+ break;
+
+ case 4:
+ Line(3, 2);
+ break;
+
+ case 5:
+ Line(2, 3);
+ break;
+
+ case 6:
+ Line(0, 4);
+ break;
+
+ case 7:
+ Line(-2, 3);
+ break;
+
+ case 8:
+ Line(-3, 2);
+ break;
+
+ case 9:
+ Line(-4, 0);
+ break;
+
+ case 10:
+ Line(-3, -2);
+ break;
+
+ case 11:
+ Line(-2, -3);
+ break;
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawClockHands
+
+void DrawLargeClockHands (Point where, short bigHand, short littleHand)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ ForeColor(whiteColor);
+
+ MoveTo(where.h, where.v);
+ switch (bigHand)
+ {
+ case 0:
+ Line(0, -10);
+ break;
+
+ case 1:
+ Line(5, -9);
+ break;
+
+ case 2:
+ Line(9, -5);
+ break;
+
+ case 3:
+ Line(10, 0);
+ break;
+
+ case 4:
+ Line(9, 5);
+ break;
+
+ case 5:
+ Line(5, 9);
+ break;
+
+ case 6:
+ Line(0, 10);
+ break;
+
+ case 7:
+ Line(-5, 9);
+ break;
+
+ case 8:
+ Line(-9, 5);
+ break;
+
+ case 9:
+ Line(-10, 0);
+ break;
+
+ case 10:
+ Line(-9, -5);
+ break;
+
+ case 11:
+ Line(-5, -9);
+ break;
+ }
+
+ MoveTo(where.h, where.v);
+ switch (littleHand)
+ {
+ case 0:
+ Line(0, -6);
+ break;
+
+ case 1:
+ Line(3, -5);
+ break;
+
+ case 2:
+ Line(5, -3);
+ break;
+
+ case 3:
+ Line(6, 0);
+ break;
+
+ case 4:
+ Line(5, 3);
+ break;
+
+ case 5:
+ Line(3, 5);
+ break;
+
+ case 6:
+ Line(0, 6);
+ break;
+
+ case 7:
+ Line(-3, 5);
+ break;
+
+ case 8:
+ Line(-5, 3);
+ break;
+
+ case 9:
+ Line(-6, 0);
+ break;
+
+ case 10:
+ Line(-5, -3);
+ break;
+
+ case 11:
+ Line(-3, -5);
+ break;
+ }
+
+ ForeColor(blackColor);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawSimplePrizes
+
+void DrawSimplePrizes (short what, Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], &srcRects[what], theRect);
+}
+
+//-------------------------------------------------------------- DrawGreaseRt
+
+void DrawGreaseRt (Rect *theRect, short distance, Boolean state)
+{
+ Rect spill, dest;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ dest = *theRect;
+ if (state) // grease upright
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &greaseSrcRt[0], &greaseSrcRt[0], &dest);
+ }
+ else // grease spilled
+ {
+ QOffsetRect(&dest, 6, 0);
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &greaseSrcRt[3], &greaseSrcRt[3], &dest);
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ QSetRect(&spill, 0, -2, distance - 5, 0);
+ QOffsetRect(&spill, dest.right - 1, dest.bottom);
+ PaintRect(&spill);
+ SetGWorld(wasCPort, wasWorld);
+ }
+}
+
+//-------------------------------------------------------------- DrawGreaseLf
+
+void DrawGreaseLf (Rect *theRect, short distance, Boolean state)
+{
+ Rect spill, dest;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ dest = *theRect;
+ if (state) // grease upright
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &greaseSrcLf[0], &greaseSrcLf[0], &dest);
+ }
+ else // grease spilled
+ {
+ QOffsetRect(&dest, -6, 0);
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &greaseSrcLf[3], &greaseSrcLf[3], &dest);
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ QSetRect(&spill, -distance + 5, -2, 0, 0);
+ QOffsetRect(&spill, dest.left + 1, dest.bottom);
+ PaintRect(&spill);
+ SetGWorld(wasCPort, wasWorld);
+ }
+}
+
+//-------------------------------------------------------------- DrawBands
+
+void DrawFoil (Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kFoil], &srcRects[kFoil], theRect);
+}
+
+//-------------------------------------------------------------- DrawInvisBonus
+
+void DrawInvisBonus (Rect *theRect)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ ColorFrameOval(theRect, 227);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawSlider
+
+void DrawSlider (Rect *theRect)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ FrameRect(theRect);
+ SetGWorld(wasCPort, wasWorld);
+}
+
diff --git a/GpApp/ObjectDraw2.cpp b/GpApp/ObjectDraw2.cpp
new file mode 100644
index 0000000..f03ebd8
--- /dev/null
+++ b/GpApp/ObjectDraw2.cpp
@@ -0,0 +1,1438 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// ObjectDraw2.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLResources.h"
+#include "PLTextUtils.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "Objects.h"
+#include "RectUtils.h"
+#include "Room.h"
+#include "Utilities.h"
+
+
+#define k8WhiteColor 0
+#define kIntenseYellowColor 5
+#define kPaleVioletColor 42
+#define kDarkFleshColor 58
+#define k8TanColor 94
+#define k8PissYellowColor 95
+#define k8BrownColor 137
+#define k8SkyColor 150
+#define k8EarthBlueColor 170
+#define k8DkRed2Color 223
+#define kIntenseGreenColor 225
+#define kIntenseBlueColor 235
+#define k8LtstGrayColor 245
+#define k8LtstGray4Color 247
+#define k8LtstGray5Color 248
+#define k8LtGrayColor 249
+#define k8Gray2Color 251
+#define k8DkGrayColor 252
+#define k8DkGray2Color 253
+
+#define kBBQMaskID 3900
+#define kUpStairsMaskID 3901
+#define kTrunkMaskID 3902
+#define kMailboxRightMaskID 3903
+#define kMailboxLeftMaskID 3904
+#define kDoorInLeftMaskID 3905
+#define kDoorInRightMaskID 3906
+#define kWindowInLeftMaskID 3907
+#define kWindowInRightMaskID 3908
+#define kHipLampMaskID 3909
+#define kDecoLampMaskID 3910
+#define kGuitarMaskID 3911
+#define kTVMaskID 3912
+#define kVCRMaskID 3913
+#define kStereoMaskID 3914
+#define kMicrowaveMaskID 3915
+#define kFireplaceMaskID 3916
+#define kBearMaskID 3917
+#define kVase1MaskID 3918
+#define kVase2MaskID 3919
+#define kManholeMaskID 3920
+#define kBooksMaskID 3922
+#define kCloudMaskID 3921
+#define kRugMaskID 3923
+#define kChimesMaskID 3924
+#define kCinderMaskID 3925
+#define kFlowerBoxMaskID 3926
+#define kCobwebMaskID 3927
+#define kCobwebPictID 3958
+#define kFlowerBoxPictID 3959
+#define kCinderPictID 3960
+#define kChimesPictID 3961
+#define kRugPictID 3962
+#define kBooksPictID 3964
+#define kCloudPictID 3965
+#define kBulletinPictID 3966
+#define kManholePictID 3967
+#define kVase2PictID 3968
+#define kVase1PictID 3969
+#define kCalendarPictID 3970
+#define kMicrowavePictID 3971
+#define kBearPictID 3972
+#define kFireplacePictID 3973
+#define kOzmaPictID 3975
+#define kWindowExRightPictID 3977
+#define kWindowExLeftPictID 3978
+#define kWindowInRightPictID 3979
+#define kWindowInLeftPictID 3980
+#define kDoorExLeftPictID 3981
+#define kDoorExRightPictID 3982
+#define kDoorInRightPictID 3983
+#define kDoorInLeftPictID 3984
+#define kMailboxRightPictID 3985
+#define kMailboxLeftPictID 3986
+#define kTrunkPictID 3987
+#define kBBQPictID 3988
+#define kStereoPictID 3989
+#define kVCRPictID 3990
+#define kGuitarPictID 3991
+#define kTVPictID 3992
+#define kDecoLampPictID 3993
+#define kHipLampPictID 3994
+#define kFilingCabinetPictID 3995
+#define kDownStairsPictID 3996
+#define kUpStairsPictID 3997
+
+#define kMailboxBase 296
+#define kMonthStringID 1005
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DrawMailboxLeft
+
+void DrawMailboxLeft (Rect *theRect, short down)
+{
+ Rect bounds;
+ GWorldPtr tempMap;
+ GWorldPtr tempMask;
+ long darkGrayC, lightWoodC, darkWoodC;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ if (thisMac.isDepth == 4)
+ {
+ darkGrayC = 13;
+ lightWoodC = 9;
+ darkWoodC = 11;
+ }
+ else
+ {
+ darkGrayC = k8DkGray2Color;
+ lightWoodC = k8PissYellowColor;
+ darkWoodC = k8BrownColor;
+ }
+
+ if (theRect->bottom < down + kMailboxBase)
+ {
+ ColorLine(theRect->left + 49, theRect->bottom,
+ theRect->left + 49, down + kMailboxBase, darkGrayC);
+ ColorLine(theRect->left + 50, theRect->bottom,
+ theRect->left + 50, down + kMailboxBase + 1, lightWoodC);
+ ColorLine(theRect->left + 51, theRect->bottom,
+ theRect->left + 51, down + kMailboxBase + 2, lightWoodC);
+ ColorLine(theRect->left + 52, theRect->bottom,
+ theRect->left + 52, down + kMailboxBase + 3, lightWoodC);
+ ColorLine(theRect->left + 53, theRect->bottom,
+ theRect->left + 53, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 54, theRect->bottom,
+ theRect->left + 54, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 55, theRect->bottom,
+ theRect->left + 55, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 56, theRect->bottom,
+ theRect->left + 56, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 57, theRect->bottom,
+ theRect->left + 57, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 58, theRect->bottom,
+ theRect->left + 58, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 59, theRect->bottom,
+ theRect->left + 59, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 60, theRect->bottom,
+ theRect->left + 60, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 61, theRect->bottom,
+ theRect->left + 61, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 62, theRect->bottom,
+ theRect->left + 62, down + kMailboxBase + 3, darkGrayC);
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+
+ bounds = srcRects[kMailboxLf];
+ theErr = CreateOffScreenGWorld(&tempMap, &bounds, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(kMailboxLeftPictID);
+
+ theErr = CreateOffScreenGWorld(&tempMask, &bounds, 1);
+ SetGWorld(tempMask, nil);
+ LoadGraphic(kMailboxLeftMaskID);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(tempMask),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kMailboxLf], &srcRects[kMailboxLf], theRect);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ DisposeGWorld(tempMap);
+ DisposeGWorld(tempMask);
+// SetPort((GrafPtr)backSrcMap);
+}
+
+//-------------------------------------------------------------- DrawMailboxRight
+
+void DrawMailboxRight (Rect *theRect, short down)
+{
+ Rect bounds;
+ GWorldPtr tempMap;
+ GWorldPtr tempMask;
+ long darkGrayC, lightWoodC, darkWoodC;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ if (thisMac.isDepth == 4)
+ {
+ darkGrayC = 13;
+ lightWoodC = 9;
+ darkWoodC = 11;
+ }
+ else
+ {
+ darkGrayC = k8DkGray2Color;
+ lightWoodC = k8PissYellowColor;
+ darkWoodC = k8BrownColor;
+ }
+
+ if (theRect->bottom < down + kMailboxBase)
+ {
+ ColorLine(theRect->left + 34, theRect->bottom,
+ theRect->left + 34, down + kMailboxBase, darkGrayC);
+ ColorLine(theRect->left + 35, theRect->bottom,
+ theRect->left + 35, down + kMailboxBase + 1, lightWoodC);
+ ColorLine(theRect->left + 36, theRect->bottom,
+ theRect->left + 36, down + kMailboxBase + 2, lightWoodC);
+ ColorLine(theRect->left + 37, theRect->bottom,
+ theRect->left + 37, down + kMailboxBase + 3, lightWoodC);
+ ColorLine(theRect->left + 38, theRect->bottom,
+ theRect->left + 38, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 39, theRect->bottom,
+ theRect->left + 39, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 40, theRect->bottom,
+ theRect->left + 40, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 41, theRect->bottom,
+ theRect->left + 41, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 42, theRect->bottom,
+ theRect->left + 42, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 43, theRect->bottom,
+ theRect->left + 43, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 44, theRect->bottom,
+ theRect->left + 44, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 45, theRect->bottom,
+ theRect->left + 45, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 46, theRect->bottom,
+ theRect->left + 46, down + kMailboxBase + 3, darkWoodC);
+ ColorLine(theRect->left + 47, theRect->bottom,
+ theRect->left + 47, down + kMailboxBase + 3, darkGrayC);
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+
+ bounds = srcRects[kMailboxRt];
+ theErr = CreateOffScreenGWorld(&tempMap, &bounds, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(kMailboxRightPictID);
+
+ theErr = CreateOffScreenGWorld(&tempMask, &bounds, 1);
+ SetGWorld(tempMask, nil);
+ LoadGraphic(kMailboxRightMaskID);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(tempMask),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kMailboxRt], &srcRects[kMailboxRt], theRect);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ DisposeGWorld(tempMap);
+ DisposeGWorld(tempMask);
+// SetPort((GrafPtr)backSrcMap);
+}
+
+//-------------------------------------------------------------- DrawSimpleTransport
+
+void DrawSimpleTransport (short what, Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(transSrcMap),
+ (BitMap *)*GetGWorldPixMap(transMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], &srcRects[what], theRect);
+}
+
+//-------------------------------------------------------------- DrawInvisTransport
+
+void DrawInvisTransport (Rect *theRect)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ ColorFrameRect(theRect, 32);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawLightSwitch
+
+void DrawLightSwitch (Rect *theRect, Boolean state)
+{
+ if (state)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(switchSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &lightSwitchSrc[0], theRect, srcCopy, nil);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(switchSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &lightSwitchSrc[1], theRect, srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- DrawMachineSwitch
+
+void DrawMachineSwitch (Rect *theRect, Boolean state)
+{
+ if (state)
+ CopyBits((BitMap *)*GetGWorldPixMap(switchSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &machineSwitchSrc[0], theRect, srcCopy, nil);
+ else
+ CopyBits((BitMap *)*GetGWorldPixMap(switchSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &machineSwitchSrc[1], theRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- DrawThermostat
+
+void DrawThermostat (Rect *theRect, Boolean state)
+{
+ if (state)
+ CopyBits((BitMap *)*GetGWorldPixMap(switchSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &thermostatSrc[0], theRect, srcCopy, nil);
+ else
+ CopyBits((BitMap *)*GetGWorldPixMap(switchSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &thermostatSrc[1], theRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- DrawPowerSwitch
+
+void DrawPowerSwitch (Rect *theRect, Boolean state)
+{
+ if (state)
+ CopyBits((BitMap *)*GetGWorldPixMap(switchSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &powerSrc[0], theRect, srcCopy, nil);
+ else
+ CopyBits((BitMap *)*GetGWorldPixMap(switchSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &powerSrc[1], theRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- DrawKnifeSwitch
+
+void DrawKnifeSwitch (Rect *theRect, Boolean state)
+{
+ if (state)
+ CopyBits((BitMap *)*GetGWorldPixMap(switchSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &knifeSwitchSrc[0], theRect, srcCopy, nil);
+ else
+ CopyBits((BitMap *)*GetGWorldPixMap(switchSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &knifeSwitchSrc[1], theRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- DrawInvisibleSwitch
+
+void DrawInvisibleSwitch (Rect *theRect)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ ColorFrameRect(theRect, kIntenseGreenColor);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawTrigger
+
+void DrawTrigger (Rect *theRect)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ ColorFrameRect(theRect, kIntenseBlueColor);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawSoundTrigger
+
+void DrawSoundTrigger (Rect *theRect)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ ColorFrameRect(theRect, kIntenseYellowColor);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawSimpleLight
+
+void DrawSimpleLight (short what, Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(lightSrcMap),
+ (BitMap *)*GetGWorldPixMap(lightMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], &srcRects[what], theRect);
+}
+
+//-------------------------------------------------------------- DrawFlourescent
+
+void DrawFlourescent (Rect *theRect)
+{
+ Rect partRect;
+ long grayC, gray2C, gray3C, gray4C, violetC;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ if (thisMac.isDepth == 4)
+ {
+ grayC = 7L;
+ gray2C = 5L;
+ gray3C = 4L;
+ gray4C = 1L;
+ violetC = 3L;
+ }
+ else
+ {
+ grayC = k8LtGrayColor;
+ gray2C = k8LtstGray5Color;
+ gray3C = k8LtstGray4Color;
+ gray4C = k8LtstGrayColor;
+ violetC = kPaleVioletColor;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ ColorLine(theRect->left + 16, theRect->top,
+ theRect->right - 17, theRect->top, grayC);
+ ColorLine(theRect->left + 16, theRect->top + 1,
+ theRect->right - 17, theRect->top + 1, gray2C);
+ ColorLine(theRect->left + 16, theRect->top + 2,
+ theRect->right - 17, theRect->top + 2, gray2C);
+ ColorLine(theRect->left + 16, theRect->top + 3,
+ theRect->right - 17, theRect->top + 3, gray3C);
+ ColorLine(theRect->left + 16, theRect->top + 4,
+ theRect->right - 17, theRect->top + 4, gray4C);
+ ColorLine(theRect->left + 16, theRect->top + 5,
+ theRect->right - 17, theRect->top + 5, violetC);
+ ColorLine(theRect->left + 16, theRect->top + 6,
+ theRect->right - 17, theRect->top + 6, k8WhiteColor);
+ ColorLine(theRect->left + 16, theRect->top + 7,
+ theRect->right - 17, theRect->top + 7, k8WhiteColor);
+ ColorLine(theRect->left + 16, theRect->top + 8,
+ theRect->right - 17, theRect->top + 8, k8WhiteColor);
+ ColorLine(theRect->left + 16, theRect->top + 9,
+ theRect->right - 17, theRect->top + 9, k8WhiteColor);
+ ColorLine(theRect->left + 16, theRect->top + 10,
+ theRect->right - 17, theRect->top + 10, k8WhiteColor);
+ ColorLine(theRect->left + 16, theRect->top + 11,
+ theRect->right - 17, theRect->top + 11, violetC);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ partRect = flourescentSrc1;
+ ZeroRectCorner(&partRect);
+ QOffsetRect(&partRect, theRect->left, theRect->top);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(lightSrcMap),
+ (BitMap *)*GetGWorldPixMap(lightMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &flourescentSrc1, &flourescentSrc1, &partRect);
+
+ partRect = flourescentSrc2;
+ ZeroRectCorner(&partRect);
+ QOffsetRect(&partRect, -partRect.right, 0);
+ QOffsetRect(&partRect, theRect->right, theRect->top);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(lightSrcMap),
+ (BitMap *)*GetGWorldPixMap(lightMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &flourescentSrc2, &flourescentSrc2, &partRect);
+}
+
+//-------------------------------------------------------------- DrawTrackLight
+
+void DrawTrackLight (Rect *theRect)
+{
+ #define kTrackLightSpacing 64
+ Rect partRect;
+ long grayC, gray2C, gray3C, gray4C;
+ short which, howMany, i, spread;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ if (thisMac.isDepth == 4)
+ {
+ grayC = 7L;
+ gray2C = 8L;
+ gray3C = 4L;
+ gray4C = 11L;
+ }
+ else
+ {
+ grayC = k8LtGrayColor;
+ gray2C = k8Gray2Color;
+ gray3C = k8LtstGray4Color;
+ gray4C = k8DkGrayColor;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ ColorLine(theRect->left, theRect->top - 3,
+ theRect->right - 1, theRect->top - 3, gray2C);
+ ColorLine(theRect->left, theRect->top - 2,
+ theRect->right - 1, theRect->top - 2, grayC);
+ ColorLine(theRect->left, theRect->top - 1,
+ theRect->right - 1, theRect->top - 1, grayC);
+ ColorLine(theRect->left, theRect->top,
+ theRect->right - 1, theRect->top, gray3C);
+ ColorLine(theRect->left, theRect->top + 1,
+ theRect->right - 1, theRect->top + 1, gray4C);
+ ColorLine(theRect->left, theRect->top + 2,
+ theRect->right - 1, theRect->top + 2, gray3C);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ partRect = trackLightSrc[0]; // left most track light
+ ZeroRectCorner(&partRect);
+ QOffsetRect(&partRect, theRect->left, theRect->top);
+ which = 0;
+ CopyMask((BitMap *)*GetGWorldPixMap(lightSrcMap),
+ (BitMap *)*GetGWorldPixMap(lightMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &trackLightSrc[which], &trackLightSrc[which], &partRect);
+
+ partRect = trackLightSrc[0]; // right most track light
+ ZeroRectCorner(&partRect);
+ QOffsetRect(&partRect, -partRect.right, 0);
+ QOffsetRect(&partRect, theRect->right, theRect->top);
+ which = 2;
+ CopyMask((BitMap *)*GetGWorldPixMap(lightSrcMap),
+ (BitMap *)*GetGWorldPixMap(lightMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &trackLightSrc[which], &trackLightSrc[which], &partRect);
+
+ howMany = ((RectWide(theRect) - RectWide(&trackLightSrc[0])) /
+ kTrackLightSpacing) - 1;
+ if (howMany > 0)
+ {
+ which = 0;
+ spread = (RectWide(theRect) - RectWide(&trackLightSrc[0])) / (howMany + 1);
+ for (i = 0; i < howMany; i++)
+ {
+ partRect = trackLightSrc[0]; // filler track lights
+ ZeroRectCorner(&partRect);
+ QOffsetRect(&partRect, theRect->left, theRect->top);
+ QOffsetRect(&partRect, spread * (i + 1), 0);
+ which++;
+ if (which >= kNumTrackLights)
+ which = 0;
+ CopyMask((BitMap *)*GetGWorldPixMap(lightSrcMap),
+ (BitMap *)*GetGWorldPixMap(lightMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &trackLightSrc[which], &trackLightSrc[which], &partRect);
+ }
+ }
+}
+
+//-------------------------------------------------------------- DrawInvisLight
+
+void DrawInvisLight (Rect *theRect)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ ColorFrameOval(theRect, 17);
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawSimpleAppliance
+
+void DrawSimpleAppliance (short what, Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(applianceMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], &srcRects[what], theRect);
+}
+
+//-------------------------------------------------------------- DrawMacPlus
+
+void DrawMacPlus (Rect *theRect, Boolean isOn, Boolean isLit)
+{
+ Rect screen;
+
+ if (isLit)
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(applianceMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kMacPlus], &srcRects[kMacPlus], theRect);
+ }
+
+ screen = plusScreen1;
+ ZeroRectCorner(&screen);
+ QOffsetRect(&screen, theRect->left + 10, theRect->top + 7);
+ if (isOn)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &plusScreen2, &screen, srcCopy, nil);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &plusScreen1, &screen, srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- DrawTV
+
+void DrawTV (Rect *theRect, Boolean isOn, Boolean isLit)
+{
+ Rect bounds;
+ GWorldPtr tempMap;
+ GWorldPtr tempMask;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ if (isLit)
+ {
+ GetGWorld(&wasCPort, &wasWorld);
+
+ bounds = srcRects[kTV];
+ theErr = CreateOffScreenGWorld(&tempMap, &bounds, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(kTVPictID);
+
+ theErr = CreateOffScreenGWorld(&tempMask, &bounds, 1);
+ SetGWorld(tempMask, nil);
+ LoadGraphic(kTVMaskID);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(tempMask),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kTV], &srcRects[kTV], theRect);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ DisposeGWorld(tempMap);
+ DisposeGWorld(tempMask);
+// SetPort((GrafPtr)backSrcMap);
+ }
+
+ bounds = tvScreen1;
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds, theRect->left + 17, theRect->top + 10);
+ if (isOn)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &tvScreen2, &bounds, srcCopy, nil);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &tvScreen1, &bounds, srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- DrawCoffee
+
+void DrawCoffee (Rect *theRect, Boolean isOn, Boolean isLit)
+{
+ Rect light;
+
+ if (isLit)
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(applianceMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kCoffee], &srcRects[kCoffee], theRect);
+ }
+
+ light = coffeeLight1;
+ ZeroRectCorner(&light);
+ QOffsetRect(&light, theRect->left + 32, theRect->top + 57);
+ if (isOn)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &coffeeLight2, &light, srcCopy, nil);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &coffeeLight1, &light, srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- DrawOutlet
+
+void DrawOutlet (Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(applianceMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kOutlet], &srcRects[kOutlet], theRect);
+}
+
+//-------------------------------------------------------------- DrawVCR
+
+void DrawVCR (Rect *theRect, Boolean isOn, Boolean isLit)
+{
+ Rect bounds;
+ GWorldPtr tempMap;
+ GWorldPtr tempMask;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ if (isLit)
+ {
+ GetGWorld(&wasCPort, &wasWorld);
+
+ bounds = srcRects[kVCR];
+ theErr = CreateOffScreenGWorld(&tempMap, &bounds, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(kVCRPictID);
+
+ theErr = CreateOffScreenGWorld(&tempMask, &bounds, 1);
+ SetGWorld(tempMask, nil);
+ LoadGraphic(kVCRMaskID);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(tempMask),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kVCR], &srcRects[kVCR], theRect);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ DisposeGWorld(tempMap);
+ DisposeGWorld(tempMask);
+
+// SetPort((GrafPtr)backSrcMap);
+ }
+
+ bounds = vcrTime1;
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds, theRect->left + 64, theRect->top + 6);
+ if (isOn)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &vcrTime2, &bounds, srcCopy, nil);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &vcrTime1, &bounds, srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- DrawStereo
+
+void DrawStereo (Rect *theRect, Boolean isOn, Boolean isLit)
+{
+ Rect bounds;
+ GWorldPtr tempMap;
+ GWorldPtr tempMask;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+
+ if (isLit)
+ {
+ GetGWorld(&wasCPort, &wasWorld);
+
+ bounds = srcRects[kStereo];
+ theErr = CreateOffScreenGWorld(&tempMap, &bounds, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(kStereoPictID);
+
+ theErr = CreateOffScreenGWorld(&tempMask, &bounds, 1);
+ SetGWorld(tempMask, nil);
+ LoadGraphic(kStereoMaskID);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(tempMask),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kStereo], &srcRects[kStereo], theRect);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ DisposeGWorld(tempMap);
+ DisposeGWorld(tempMask);
+
+// SetPort((GrafPtr)backSrcMap);
+ }
+
+ bounds = stereoLight1;
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds, theRect->left + 56, theRect->top + 20);
+ if (isOn)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &stereoLight2, &bounds, srcCopy, nil);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &stereoLight1, &bounds, srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- DrawMicrowave
+
+void DrawMicrowave (Rect *theRect, Boolean isOn, Boolean isLit)
+{
+ Rect bounds;
+ GWorldPtr tempMap;
+ GWorldPtr tempMask;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+
+ if (isLit)
+ {
+ GetGWorld(&wasCPort, &wasWorld);
+
+ bounds = srcRects[kMicrowave];
+ theErr = CreateOffScreenGWorld(&tempMap, &bounds, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(kMicrowavePictID);
+
+ theErr = CreateOffScreenGWorld(&tempMask, &bounds, 1);
+ SetGWorld(tempMask, nil);
+ LoadGraphic(kMicrowaveMaskID);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(tempMask),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[kMicrowave], &srcRects[kMicrowave], theRect);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ DisposeGWorld(tempMap);
+ DisposeGWorld(tempMask);
+
+// SetPort((GrafPtr)backSrcMap);
+ }
+
+ bounds = microOn;
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds, theRect->left + 14, theRect->top + 13);
+ if (isOn)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOn, &bounds, srcCopy, nil);
+ QOffsetRect(&bounds, 16, 0);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOn, &bounds, srcCopy, nil);
+ QOffsetRect(&bounds, 16, 0);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOn, &bounds, srcCopy, nil);
+ }
+ else if (isLit)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOff, &bounds, srcCopy, nil);
+ QOffsetRect(&bounds, 16, 0);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOff, &bounds, srcCopy, nil);
+ QOffsetRect(&bounds, 16, 0);
+ CopyBits((BitMap *)*GetGWorldPixMap(applianceSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ µOff, &bounds, srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- DrawBalloon
+
+void DrawBalloon (Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(balloonSrcMap),
+ (BitMap *)*GetGWorldPixMap(balloonMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &balloonSrc[1], &balloonSrc[1], theRect);
+}
+
+//-------------------------------------------------------------- DrawCopter
+
+void DrawCopter (Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(copterSrcMap),
+ (BitMap *)*GetGWorldPixMap(copterMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &copterSrc[1], &copterSrc[1], theRect);
+}
+
+//-------------------------------------------------------------- DrawDart
+
+void DrawDart (Rect *theRect, short which)
+{
+ if (which == kDartLf)
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(dartSrcMap),
+ (BitMap *)*GetGWorldPixMap(dartMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &dartSrc[0], &dartSrc[0], theRect);
+ }
+ else
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(dartSrcMap),
+ (BitMap *)*GetGWorldPixMap(dartMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &dartSrc[2], &dartSrc[2], theRect);
+ }
+}
+
+//-------------------------------------------------------------- DrawBall
+
+void DrawBall (short what, Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(ballSrcMap),
+ (BitMap *)*GetGWorldPixMap(ballMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], &srcRects[what], theRect);
+}
+
+//-------------------------------------------------------------- DrawFish
+
+void DrawFish (short what, Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(enemySrcMap),
+ (BitMap *)*GetGWorldPixMap(enemyMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], &srcRects[what], theRect);
+}
+
+//-------------------------------------------------------------- DrawDrip
+
+void DrawDrip (Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(dripSrcMap),
+ (BitMap *)*GetGWorldPixMap(dripMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &dripSrc[3], &dripSrc[3], theRect);
+}
+
+//-------------------------------------------------------------- DrawMirror
+
+void DrawMirror (Rect *mirror)
+{
+ Rect tempRect;
+ long grayC;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ if (thisMac.isDepth == 4)
+ {
+ grayC = 13;
+ }
+ else
+ {
+ grayC = k8DkGray2Color;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ tempRect = *mirror;
+ ColorRect(&tempRect, k8WhiteColor);
+ ColorFrameRect(&tempRect, grayC);
+ InsetRect(&tempRect, 1, 1);
+ ColorFrameRect(&tempRect, k8EarthBlueColor);
+ InsetRect(&tempRect, 1, 1);
+ ColorFrameRect(&tempRect, k8EarthBlueColor);
+ InsetRect(&tempRect, 1, 1);
+ ColorFrameRect(&tempRect, grayC);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawSimpleClutter
+
+void DrawSimpleClutter (short what, Rect *theRect)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(clutterSrcMap),
+ (BitMap *)*GetGWorldPixMap(clutterMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], &srcRects[what], theRect);
+}
+
+//-------------------------------------------------------------- DrawFlower
+
+void DrawFlower (Rect *theRect, short which)
+{
+ CopyMask((BitMap *)*GetGWorldPixMap(clutterSrcMap),
+ (BitMap *)*GetGWorldPixMap(clutterMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &flowerSrc[which], &flowerSrc[which], theRect);
+}
+
+//-------------------------------------------------------------- DrawWallWindow
+
+void DrawWallWindow (Rect *window)
+{
+ #define kWindowSillThick 7
+ Rect tempRect, tempRect2;
+ long brownC, tanC, dkstRedC;
+ short halfWay;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ if (thisMac.isDepth == 4)
+ {
+ brownC = 11;
+ tanC = 9;
+ dkstRedC = 15;
+ }
+ else
+ {
+ brownC = k8BrownColor;
+ tanC = k8TanColor;
+ dkstRedC = k8DkRed2Color;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ tempRect = *window;
+ InsetRect(&tempRect, 3, 0);
+ ColorRect(&tempRect, brownC);
+ HiliteRect(&tempRect, tanC, dkstRedC);
+
+ tempRect = *window; // top sill
+ tempRect.bottom = tempRect.top + kWindowSillThick;
+ tempRect.left++;
+ tempRect.right--;
+ ColorRect(&tempRect, brownC);
+ HiliteRect(&tempRect, tanC, dkstRedC);
+ tempRect.left--;
+ tempRect.right++;
+ tempRect.top += 2;
+ tempRect.bottom -= 2;
+ ColorRect(&tempRect, brownC);
+ HiliteRect(&tempRect, tanC, dkstRedC);
+
+ tempRect = *window; // bottom sill
+ tempRect.top = tempRect.bottom - kWindowSillThick;
+ QOffsetRect(&tempRect, 0, -4);
+ tempRect.left++;
+ tempRect.right--;
+ ColorRect(&tempRect, brownC);
+ HiliteRect(&tempRect, tanC, dkstRedC);
+ tempRect.left--;
+ tempRect.right++;
+ tempRect.top += 2;
+ tempRect.bottom -= 2;
+ ColorRect(&tempRect, brownC);
+ HiliteRect(&tempRect, tanC, dkstRedC);
+
+ tempRect = *window; // inside frame
+ tempRect.left += 8;
+ tempRect.right -= 8;
+ tempRect.top += 11;
+ tempRect.bottom -= 15;
+ HiliteRect(&tempRect, dkstRedC, tanC);
+
+ halfWay = (tempRect.top + tempRect.bottom) / 2;
+
+ tempRect2 = tempRect; // top pane
+ tempRect2.bottom = halfWay + 2;
+ InsetRect(&tempRect2, 5, 5);
+ HiliteRect(&tempRect2, dkstRedC, tanC);
+ InsetRect(&tempRect2, 1, 1);
+ if (thisMac.isDepth == 4)
+ ColorRect(&tempRect2, 5);
+ else
+ ColorRect(&tempRect2, k8SkyColor);
+
+ tempRect2 = tempRect; // bottom pane
+ tempRect2.top = halfWay - 3;
+ InsetRect(&tempRect2, 5, 5);
+ HiliteRect(&tempRect2, dkstRedC, tanC);
+ InsetRect(&tempRect2, 1, 1);
+ if (thisMac.isDepth == 4)
+ ColorRect(&tempRect2, 5);
+ else
+ ColorRect(&tempRect2, k8SkyColor);
+
+ ColorLine(tempRect2.left - 5, tempRect2.top - 7,
+ tempRect2.right + 5, tempRect2.top - 7, tanC);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawCalendar
+
+void DrawCalendar (Rect *theRect)
+{
+ DateTimeRec timeRec;
+ Rect bounds;
+ PicHandle thePicture;
+ Str255 monthStr;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ thePicture = GetPicture(kCalendarPictID);
+ if (thePicture == nil)
+ RedAlert(kErrFailedGraphicLoad);
+
+ HLock((Handle)thePicture);
+ bounds = (*thePicture)->picFrame;
+ HUnlock((Handle)thePicture);
+ QOffsetRect(&bounds, -bounds.left, -bounds.top);
+ QOffsetRect(&bounds, theRect->left, theRect->top);
+ DrawPicture(thePicture, &bounds);
+ ReleaseResource((Handle)thePicture);
+
+ SetPort((GrafPtr)backSrcMap);
+ TextFace(bold);
+ TextFont(applFont);
+ TextSize(9);
+ GetTime(&timeRec);
+ GetIndString(monthStr, kMonthStringID, timeRec.month);
+ MoveTo(theRect->left + ((64 - StringWidth(monthStr)) / 2), theRect->top + 55);
+ ColorText(monthStr, kDarkFleshColor);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawBulletin
+
+void DrawBulletin (Rect *theRect)
+{
+ Rect bounds;
+ PicHandle thePicture;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ thePicture = GetPicture(kBulletinPictID);
+ if (thePicture == nil)
+ RedAlert(kErrFailedGraphicLoad);
+
+ HLock((Handle)thePicture);
+ bounds = (*thePicture)->picFrame;
+ HUnlock((Handle)thePicture);
+ QOffsetRect(&bounds, -bounds.left, -bounds.top);
+ QOffsetRect(&bounds, theRect->left, theRect->top);
+ DrawPicture(thePicture, &bounds);
+ ReleaseResource((Handle)thePicture);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawPictObject
+
+void DrawPictObject (short what, Rect *theRect)
+{
+ Rect bounds;
+ PicHandle thePicture;
+ short pictID;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ switch (what)
+ {
+ case kFilingCabinet:
+ pictID = kFilingCabinetPictID;
+ break;
+
+ case kDownStairs:
+ pictID = kDownStairsPictID;
+ break;
+
+ case kDoorExRt:
+ pictID = kDoorExRightPictID;
+ break;
+
+ case kDoorExLf:
+ pictID = kDoorExLeftPictID;
+ break;
+
+ case kWindowExRt:
+ pictID = kWindowExRightPictID;
+ break;
+
+ case kWindowExLf:
+ pictID = kWindowExLeftPictID;
+ break;
+
+ case kOzma:
+ pictID = kOzmaPictID;
+ break;
+ }
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ thePicture = GetPicture(pictID);
+ if (thePicture == nil)
+ RedAlert(kErrFailedGraphicLoad);
+
+ bounds = srcRects[what];
+ QOffsetRect(&bounds, theRect->left, theRect->top);
+ DrawPicture(thePicture, &bounds);
+ ReleaseResource((Handle)thePicture);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- DrawPictWithMaskObject
+
+void DrawPictWithMaskObject (short what, Rect *theRect)
+{
+ Rect bounds;
+ GWorldPtr tempMap;
+ GWorldPtr tempMask;
+ short pictID, maskID;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ switch (what)
+ {
+ case kCobweb:
+ pictID = kCobwebPictID;
+ maskID = kCobwebMaskID;
+ break;
+
+ case kCloud:
+ pictID = kCloudPictID;
+ maskID = kCloudMaskID;
+ break;
+ }
+
+ bounds = srcRects[what];
+ theErr = CreateOffScreenGWorld(&tempMap, &bounds, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(pictID);
+
+ theErr = CreateOffScreenGWorld(&tempMask, &bounds, 1);
+ SetGWorld(tempMask, nil);
+ LoadGraphic(maskID);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(tempMask),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], &srcRects[what], theRect);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ DisposeGWorld(tempMap);
+ DisposeGWorld(tempMask);
+
+// SetPort((GrafPtr)backSrcMap);
+}
+
+//-------------------------------------------------------------- DrawPictSansWhiteObject
+
+void DrawPictSansWhiteObject (short what, Rect *theRect)
+{
+ Rect bounds;
+ CGrafPtr tempMap;
+ short pictID;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ switch (what)
+ {
+ case kBBQ:
+ pictID = kBBQPictID;
+ break;
+
+ case kTrunk:
+ pictID = kTrunkPictID;
+ break;
+
+ case kManhole:
+ pictID = kManholePictID;
+ break;
+
+ case kBooks:
+ pictID = kBooksPictID;
+ break;
+
+ case kUpStairs:
+ pictID = kUpStairsPictID;
+ break;
+
+ case kDoorInLf:
+ pictID = kDoorInLeftPictID;
+ break;
+
+ case kDoorInRt:
+ pictID = kDoorInRightPictID;
+ break;
+
+ case kWindowInLf:
+ pictID = kWindowInLeftPictID;
+ break;
+
+ case kWindowInRt:
+ pictID = kWindowInRightPictID;
+ break;
+
+ case kHipLamp:
+ pictID = kHipLampPictID;
+ break;
+
+ case kDecoLamp:
+ pictID = kDecoLampPictID;
+ break;
+
+ case kGuitar:
+ pictID = kGuitarPictID;
+ break;
+
+ case kCinderBlock:
+ pictID = kCinderPictID;
+ break;
+
+ case kFlowerBox:
+ pictID = kFlowerBoxPictID;
+ break;
+
+ case kFireplace:
+ pictID = kFireplacePictID;
+ break;
+
+ case kBear:
+ pictID = kBearPictID;
+ break;
+
+ case kVase1:
+ pictID = kVase1PictID;
+ break;
+
+ case kVase2:
+ pictID = kVase2PictID;
+ break;
+
+ case kRug:
+ pictID = kRugPictID;
+ break;
+
+ case kChimes:
+ pictID = kChimesPictID;
+ break;
+ }
+
+ bounds = srcRects[what];
+ theErr = CreateOffScreenGWorld(&tempMap, &bounds, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(pictID);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &srcRects[what], theRect, transparent, nil);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ DisposeGWorld(tempMap);
+// SetPort((GrafPtr)backSrcMap);
+}
+//-------------------------------------------------------------- DrawCustPictSansWhite
+
+void DrawCustPictSansWhite (short pictID, Rect *theRect)
+{
+ Rect bounds;
+ GWorldPtr tempMap;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ bounds = *theRect;
+ ZeroRectCorner(&bounds);
+ theErr = CreateOffScreenGWorld(&tempMap, &bounds, kPreferredDepth);
+ SetGWorld(tempMap, nil);
+ LoadGraphic(pictID);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(tempMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &bounds, theRect, transparent, nil);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ DisposeGWorld(tempMap);
+// SetPort((GrafPtr)backSrcMap);
+}
+
diff --git a/GpApp/ObjectDrawAll.cpp b/GpApp/ObjectDrawAll.cpp
new file mode 100644
index 0000000..cacae68
--- /dev/null
+++ b/GpApp/ObjectDrawAll.cpp
@@ -0,0 +1,966 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// ObjectDrawAll.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Environ.h"
+#include "RectUtils.h"
+
+
+extern Rect localRoomsDest[], movieRect;
+extern short localNumbers[];
+extern short numLights, tvWithMovieNumber;
+extern Boolean tvOn;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DrawARoomsObjects
+
+void DrawARoomsObjects (short neighbor, Boolean redraw)
+{
+ objectType thisObject;
+ Rect whoCares, itsRect, rectA, rectB, testRect;
+ RgnHandle theRgn;
+ short i, legit, dynamicNum, n;
+ short floor, suite, room, obj;
+ char wasState;
+ Boolean isLit;
+
+ if (localNumbers[neighbor] == kRoomIsEmpty)
+ return;
+
+ testRect = houseRect;
+ ZeroRectCorner(&testRect);
+ isLit = (numLights > 0);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ for (i = 0; i < kMaxRoomObs; i++)
+ {
+ dynamicNum = -1;
+ legit = -1;
+
+ if (IsThisValid(localNumbers[neighbor], i))
+ {
+ thisObject = (*thisHouse)->rooms[localNumbers[neighbor]].objects[i];
+ switch (thisObject.what)
+ {
+ case kObjectIsEmpty:
+ break;
+
+ case kFloorVent:
+ case kCeilingVent:
+ case kFloorBlower:
+ case kCeilingBlower:
+ case kSewerGrate:
+ case kLeftFan:
+ case kRightFan:
+ case kGrecoVent:
+ case kSewerBlower:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawSimpleBlowers(thisObject.what, &itsRect);
+ break;
+
+ case kTaper:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (isLit)
+ DrawSimpleBlowers(thisObject.what, &itsRect);
+ if (neighbor == kCentralRoom)
+ {
+ if (redraw)
+ ReBackUpFlames(localNumbers[neighbor], i);
+ else
+ AddCandleFlame(localNumbers[neighbor], i,
+ itsRect.left + 10, itsRect.top + 7);
+ }
+ else
+ {
+ QSetRect(&rectA, 0, 0, 16, 15);
+ QOffsetRect(&rectA, itsRect.left + 10 - 8, itsRect.top + 7 - 15);
+ rectB = localRoomsDest[kCentralRoom];
+ rectB.top -= kFloorSupportTall;
+ rectB.bottom += kFloorSupportTall;
+ if (!SectRect(&rectA, &rectB, &whoCares))
+ {
+ if (redraw)
+ ReBackUpFlames(localNumbers[neighbor], i);
+ else
+ AddCandleFlame(localNumbers[neighbor], i,
+ itsRect.left + 10, itsRect.top + 7);
+ }
+ }
+ }
+ break;
+
+ case kCandle:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (isLit)
+ DrawSimpleBlowers(thisObject.what, &itsRect);
+ if (neighbor == kCentralRoom)
+ {
+ if (redraw)
+ ReBackUpFlames(localNumbers[neighbor], i);
+ else
+ AddCandleFlame(localNumbers[neighbor], i,
+ itsRect.left + 14, itsRect.top + 7);
+ }
+ else
+ {
+ QSetRect(&rectA, 0, 0, 16, 15);
+ QOffsetRect(&rectA, itsRect.left + 14 - 8, itsRect.top + 7 - 15);
+ rectB = localRoomsDest[kCentralRoom];
+ rectB.top -= kFloorSupportTall;
+ rectB.bottom += kFloorSupportTall;
+ if (!SectRect(&rectA, &rectB, &whoCares))
+ {
+ if (redraw)
+ ReBackUpFlames(localNumbers[neighbor], i);
+ else
+ AddCandleFlame(localNumbers[neighbor], i,
+ itsRect.left + 14, itsRect.top + 7);
+ }
+ }
+ }
+ break;
+
+ case kStubby:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (isLit)
+ DrawSimpleBlowers(thisObject.what, &itsRect);
+ if (neighbor == kCentralRoom)
+ {
+ if (redraw)
+ ReBackUpFlames(localNumbers[neighbor], i);
+ else
+ AddCandleFlame(localNumbers[neighbor], i,
+ itsRect.left + 9, itsRect.top + 7);
+ }
+ else
+ {
+ QSetRect(&rectA, 0, 0, 16, 15);
+ QOffsetRect(&rectA, itsRect.left + 9 - 8, itsRect.top + 7 - 15);
+ rectB = localRoomsDest[kCentralRoom];
+ rectB.top -= kFloorSupportTall;
+ rectB.bottom += kFloorSupportTall;
+ if (!SectRect(&rectA, &rectB, &whoCares))
+ {
+ if (redraw)
+ ReBackUpFlames(localNumbers[neighbor], i);
+ else
+ AddCandleFlame(localNumbers[neighbor], i,
+ itsRect.left + 9, itsRect.top + 7);
+ }
+ }
+ }
+ break;
+
+ case kTiki:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (isLit)
+ DrawTiki(&itsRect, playOriginV + VerticalRoomOffset(neighbor));
+ if (redraw)
+ ReBackUpTikiFlames(localNumbers[neighbor], i);
+ else
+ AddTikiFlame(localNumbers[neighbor], i,
+ itsRect.left + 10, itsRect.top - 9);
+ break;
+
+ case kBBQ:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (isLit)
+ DrawPictSansWhiteObject(thisObject.what, &itsRect);
+ if (redraw)
+ ReBackUpBBQCoals(localNumbers[neighbor], i);
+ else
+ AddBBQCoals(localNumbers[neighbor], i,
+ itsRect.left + 16, itsRect.top + 9);
+ }
+ break;
+
+ case kInvisBlower:
+ case kLiftArea:
+ break;
+
+ case kTable:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (isLit)
+ DrawTable(&itsRect, playOriginV);
+ break;
+
+ case kShelf:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (isLit)
+ DrawShelf(&itsRect);
+ break;
+
+ case kCabinet:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawCabinet(&itsRect);
+ break;
+
+ case kFilingCabinet:
+ case kOzma:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawPictObject(thisObject.what, &itsRect);
+ break;
+
+ case kWasteBasket:
+ case kMilkCrate:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawSimpleFurniture(thisObject.what, &itsRect);
+ break;
+
+ case kCounter:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawCounter(&itsRect);
+ break;
+
+ case kDresser:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (isLit)
+ DrawDresser(&itsRect);
+ break;
+
+ case kDeckTable:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (isLit)
+ DrawDeckTable(&itsRect, playOriginV);
+ break;
+
+ case kStool:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (isLit)
+ DrawStool(&itsRect, playOriginV + VerticalRoomOffset(neighbor));
+ break;
+
+ case kInvisObstacle:
+ break;
+
+ case kManhole:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ AddTempManholeRect(&itsRect);
+ if (isLit)
+ DrawPictSansWhiteObject(thisObject.what, &itsRect);
+ }
+ break;
+
+ case kInvisBounce:
+ break;
+
+ case kRedClock:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (redraw)
+ legit = ReBackUpSavedMap(&itsRect, localNumbers[neighbor], i);
+ else
+ legit = BackUpToSavedMap(&itsRect, localNumbers[neighbor], i);
+ if (legit != -1)
+ DrawRedClock(&itsRect);
+ }
+ break;
+
+ case kBlueClock:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (redraw)
+ legit = ReBackUpSavedMap(&itsRect, localNumbers[neighbor], i);
+ else
+ legit = BackUpToSavedMap(&itsRect, localNumbers[neighbor], i);
+ if (legit != -1)
+ DrawBlueClock(&itsRect);
+ }
+ break;
+
+ case kYellowClock:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (redraw)
+ legit = ReBackUpSavedMap(&itsRect, localNumbers[neighbor], i);
+ else
+ legit = BackUpToSavedMap(&itsRect, localNumbers[neighbor], i);
+ if (legit != -1)
+ DrawYellowClock(&itsRect);
+ }
+ break;
+
+ case kCuckoo:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (redraw)
+ legit = ReBackUpSavedMap(&itsRect, localNumbers[neighbor], i);
+ else
+ legit = BackUpToSavedMap(&itsRect, localNumbers[neighbor], i);
+ if (legit != -1)
+ {
+ DrawCuckoo(&itsRect);
+ if (redraw)
+ ReBackUpPendulum(localNumbers[neighbor], i);
+ else
+ AddPendulum(localNumbers[neighbor], i,
+ itsRect.left + 4, itsRect.top + 46);
+ }
+ }
+ break;
+
+ case kPaper:
+ case kBattery:
+ case kBands:
+ case kHelium:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (redraw)
+ legit = ReBackUpSavedMap(&itsRect, localNumbers[neighbor], i);
+ else
+ legit = BackUpToSavedMap(&itsRect, localNumbers[neighbor], i);
+ if (legit != -1)
+ DrawSimplePrizes(thisObject.what, &itsRect);
+ }
+ break;
+
+ case kGreaseRt:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (thisObject.data.c.state) // standing
+ {
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (redraw)
+ dynamicNum = ReBackUpGrease(localNumbers[neighbor], i);
+ else
+ dynamicNum = AddGrease(localNumbers[neighbor], i,
+ itsRect.left, itsRect.top,
+ thisObject.data.c.length, true);
+ if (dynamicNum != -1)
+ DrawGreaseRt(&itsRect, thisObject.data.c.length, true);
+ }
+ }
+ else // fallen
+ DrawGreaseRt(&itsRect, thisObject.data.c.length, false);
+ break;
+
+ case kGreaseLf:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (thisObject.data.c.state)
+ {
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (redraw)
+ dynamicNum = ReBackUpGrease(localNumbers[neighbor], i);
+ else
+ dynamicNum = AddGrease(localNumbers[neighbor], i,
+ itsRect.left, itsRect.top,
+ thisObject.data.c.length, false);
+ if (dynamicNum != -1)
+ DrawGreaseLf(&itsRect, thisObject.data.c.length, true);
+ }
+ }
+ else
+ DrawGreaseLf(&itsRect, thisObject.data.c.length, false);
+ break;
+
+ case kFoil:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (redraw)
+ legit = ReBackUpSavedMap(&itsRect, localNumbers[neighbor], i);
+ else
+ legit = BackUpToSavedMap(&itsRect, localNumbers[neighbor], i);
+ if (legit != -1)
+ DrawFoil(&itsRect);
+ }
+ break;
+
+ case kInvisBonus:
+ case kSlider:
+ break;
+
+ case kStar:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (redraw)
+ legit = ReBackUpSavedMap(&itsRect, localNumbers[neighbor], i);
+ else
+ legit = BackUpToSavedMap(&itsRect, localNumbers[neighbor], i);
+ if (legit != -1)
+ {
+ if (redraw)
+ ReBackUpStar(localNumbers[neighbor], i);
+ else
+ AddStar(localNumbers[neighbor], i, itsRect.left,
+ itsRect.top);
+ DrawSimplePrizes(thisObject.what, &itsRect);
+ }
+ }
+ break;
+
+ case kSparkle:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if ((!redraw) && (neighbor == kCentralRoom))
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kSparkle, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.c.state);
+ }
+ }
+ break;
+
+ case kUpStairs:
+ case kDoorInLf:
+ case kDoorInRt:
+ case kWindowInLf:
+ case kWindowInRt:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ DrawPictSansWhiteObject(thisObject.what, &itsRect);
+ break;
+
+ case kDownStairs:
+ case kDoorExRt:
+ case kDoorExLf:
+ case kWindowExRt:
+ case kWindowExLf:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ DrawPictObject(thisObject.what, &itsRect);
+ break;
+
+ case kMailboxLf:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ DrawMailboxLeft(&itsRect, playOriginV + VerticalRoomOffset(neighbor));
+ break;
+
+ case kMailboxRt:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ DrawMailboxRight(&itsRect, playOriginV + VerticalRoomOffset(neighbor));
+ break;
+
+ case kFloorTrans:
+ case kCeilingTrans:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ DrawSimpleTransport(thisObject.what, &itsRect);
+ break;
+
+ case kInvisTrans:
+ case kDeluxeTrans:
+ break;
+
+ case kLightSwitch:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ ExtractFloorSuite(thisObject.data.e.where, &floor, &suite);
+ room = GetRoomNumber(floor, suite);
+ obj = (short)thisObject.data.e.who;
+ DrawLightSwitch(&itsRect, GetObjectState(room, obj));
+ }
+ dynamicNum = masterObjects[i].hotNum;
+ break;
+
+ case kMachineSwitch:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ ExtractFloorSuite(thisObject.data.e.where, &floor, &suite);
+ room = GetRoomNumber(floor, suite);
+ obj = (short)thisObject.data.e.who;
+ DrawMachineSwitch(&itsRect, GetObjectState(room, obj));
+ }
+ dynamicNum = masterObjects[i].hotNum;
+ break;
+
+ case kThermostat:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ ExtractFloorSuite(thisObject.data.e.where, &floor, &suite);
+ room = GetRoomNumber(floor, suite);
+ obj = (short)thisObject.data.e.who;
+ DrawThermostat(&itsRect, GetObjectState(room, obj));
+ }
+ dynamicNum = masterObjects[i].hotNum;
+ break;
+
+ case kPowerSwitch:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ ExtractFloorSuite(thisObject.data.e.where, &floor, &suite);
+ room = GetRoomNumber(floor, suite);
+ obj = (short)thisObject.data.e.who;
+ DrawPowerSwitch(&itsRect, GetObjectState(room, obj));
+ }
+ dynamicNum = masterObjects[i].hotNum;
+ break;
+
+ case kKnifeSwitch:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ ExtractFloorSuite(thisObject.data.e.where, &floor, &suite);
+ room = GetRoomNumber(floor, suite);
+ obj = (short)thisObject.data.e.who;
+ DrawKnifeSwitch(&itsRect, GetObjectState(room, obj));
+ }
+ dynamicNum = masterObjects[i].hotNum;
+ break;
+
+ case kInvisSwitch:
+ dynamicNum = masterObjects[i].hotNum;
+ break;
+
+ case kTrigger:
+ case kLgTrigger:
+ case kSoundTrigger:
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawSimpleLight(thisObject.what, &itsRect);
+ break;
+
+ case kTrunk:
+ case kBooks:
+ case kHipLamp:
+ case kDecoLamp:
+ case kGuitar:
+ case kCinderBlock:
+ case kFlowerBox:
+ case kFireplace:
+ case kBear:
+ case kVase1:
+ case kVase2:
+ case kRug:
+ case kChimes:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawPictSansWhiteObject(thisObject.what, &itsRect);
+ break;
+
+ case kCustomPict:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawCustPictSansWhite(thisObject.data.g.height, &itsRect);
+ break;
+
+ case kFlourescent:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawFlourescent(&itsRect);
+ break;
+
+ case kTrackLight:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawTrackLight(&itsRect);
+ break;
+
+ case kInvisLight:
+ break;
+
+ case kShredder:
+ case kCDs:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawSimpleAppliance(thisObject.what, &itsRect);
+ break;
+
+ case kToaster:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ DrawSimpleAppliance(thisObject.what, &itsRect);
+ if ((!redraw) && (neighbor == kCentralRoom))
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kToaster, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.g.state);
+ }
+ }
+ break;
+
+ case kMacPlus:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ DrawMacPlus(&itsRect, thisObject.data.g.state, isLit);
+ if (!redraw)
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kMacPlus, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.g.state);
+ }
+ }
+ break;
+
+ case kTV:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+#ifdef COMPILEQT
+ if ((thisMac.hasQT) && (hasMovie) && (neighbor == kCentralRoom) &&
+ (!tvInRoom))
+ {
+ whoCares = tvScreen1;
+ ZeroRectCorner(&whoCares);
+ OffsetRect(&whoCares, itsRect.left + 17, itsRect.top + 10);
+ GetMovieBox(theMovie, &movieRect);
+ CenterRectInRect(&movieRect, &whoCares);
+ SetMovieBox(theMovie, &movieRect);
+ theRgn = NewRgn();
+ RectRgn(theRgn, &whoCares);
+ SetMovieDisplayClipRgn(theMovie, theRgn);
+ DisposeRgn(theRgn);
+ tvOn = thisObject.data.g.state;
+ }
+#endif
+ DrawTV(&itsRect, thisObject.data.g.state, isLit);
+ if (!redraw)
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kTV, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.g.state);
+#ifdef COMPILEQT
+ if ((thisMac.hasQT) && (hasMovie) && (neighbor == kCentralRoom) &&
+ (!tvInRoom))
+ {
+ tvWithMovieNumber = dynamicNum;
+ tvInRoom = true;
+ }
+#endif
+ }
+ }
+ break;
+
+ case kCoffee:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ DrawCoffee(&itsRect, thisObject.data.g.state, isLit);
+ if (!redraw)
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kCoffee, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.g.state);
+ }
+ }
+ break;
+
+ case kOutlet:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ if (isLit)
+ DrawOutlet(&itsRect);
+ if (!redraw)
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kOutlet, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.g.state);
+ }
+ }
+ break;
+
+ case kVCR:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ DrawVCR(&itsRect, thisObject.data.g.state, isLit);
+ if (!redraw)
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kVCR, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.g.state);
+ }
+ }
+ break;
+
+ case kStereo:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ DrawStereo(&itsRect, isPlayMusicGame, isLit);
+ if (!redraw)
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kStereo, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.g.state);
+ }
+ }
+ break;
+
+ case kMicrowave:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ DrawMicrowave(&itsRect, thisObject.data.g.state, isLit);
+ if (!redraw)
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kMicrowave, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.g.state);
+ }
+ }
+ break;
+
+ case kBalloon:
+ if ((neighbor == kCentralRoom) && (!redraw))
+ {
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ QOffsetRect(&itsRect, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kBalloon, &itsRect, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.h.state);
+ }
+ break;
+
+ case kCopterLf:
+ if ((neighbor == kCentralRoom) && (!redraw))
+ {
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ QOffsetRect(&itsRect, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kCopterLf, &itsRect, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.h.state);
+ }
+ break;
+
+ case kCopterRt:
+ if ((neighbor == kCentralRoom) && (!redraw))
+ {
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ QOffsetRect(&itsRect, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kCopterRt, &itsRect, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.h.state);
+ }
+ break;
+
+ case kDartLf:
+ if ((neighbor == kCentralRoom) && (!redraw))
+ {
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ QOffsetRect(&itsRect, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kDartLf, &itsRect, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.h.state);
+ }
+ break;
+
+ case kDartRt:
+ if ((neighbor == kCentralRoom) && (!redraw))
+ {
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ QOffsetRect(&itsRect, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kDartRt, &itsRect, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.h.state);
+ }
+ break;
+
+ case kBall:
+ if ((neighbor == kCentralRoom) && (!redraw))
+ {
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ QOffsetRect(&itsRect, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kBall, &itsRect, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.h.state);
+ }
+ break;
+
+ case kDrip:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ DrawDrip(&itsRect);
+ if ((!redraw) && (neighbor == kCentralRoom))
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kDrip, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.h.state);
+ }
+ }
+ break;
+
+ case kFish:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ {
+ DrawFish(thisObject.what, &itsRect);
+ if ((!redraw) && (neighbor == kCentralRoom))
+ {
+ rectA = itsRect;
+ QOffsetRect(&rectA, -playOriginH, -playOriginV);
+ dynamicNum = AddDynamicObject(kFish, &rectA, &thisObject,
+ localNumbers[neighbor], i, thisObject.data.h.state);
+ }
+ }
+ break;
+
+ case kCobweb:
+ case kCloud:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawPictWithMaskObject(thisObject.what, &itsRect);
+ break;
+
+ case kMirror:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawMirror(&itsRect);
+ if ((neighbor == kCentralRoom) && (!redraw))
+ {
+ InsetRect(&itsRect, 4, 4);
+ AddToMirrorRegion(&itsRect);
+ }
+ break;
+
+ case kMousehole:
+ case kFaucet:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawSimpleClutter(thisObject.what, &itsRect);
+ break;
+
+ case kFlower:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawFlower(&itsRect, thisObject.data.i.pict);
+ break;
+
+ case kWallWindow:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if (SectRect(&itsRect, &testRect, &whoCares))
+ DrawWallWindow(&itsRect);
+ break;
+
+ case kCalendar:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawCalendar(&itsRect);
+ break;
+
+ case kBulletin:
+ GetObjectRect(&thisObject, &itsRect);
+ OffsetRectRoomRelative(&itsRect, neighbor);
+ if ((SectRect(&itsRect, &testRect, &whoCares)) && isLit)
+ DrawBulletin(&itsRect);
+ break;
+
+ }
+ }
+
+ if (!redraw) // set up links
+ {
+ for (n = 0; n < numMasterObjects; n++)
+ {
+ if ((masterObjects[n].objectNum == i) &&
+ (masterObjects[n].roomNum == localNumbers[neighbor]))
+ masterObjects[n].dynaNum = dynamicNum;
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
diff --git a/GpApp/ObjectEdit.cpp b/GpApp/ObjectEdit.cpp
new file mode 100644
index 0000000..f9da849
--- /dev/null
+++ b/GpApp/ObjectEdit.cpp
@@ -0,0 +1,2811 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// ObjectEdit.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLSound.h"
+#include "PLToolUtils.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "House.h"
+#include "MainWindow.h"
+#include "Marquee.h"
+#include "ObjectEdit.h"
+#include "Objects.h"
+#include "Play.h"
+#include "RectUtils.h"
+#include "Room.h"
+
+
+short FindObjectSelected (Point);
+void DragHandle (Point);
+void DragObject (Point);
+void AddObjectPairing (void);
+Boolean ObjectIsUpBlower (objectType *);
+
+
+Rect roomObjectRects[kMaxRoomObs];
+Rect initialGliderRect;
+Rect leftStartGliderSrc, rightStartGliderSrc;
+Rect leftStartGliderDest, rightStartGliderDest;
+short objActive;
+Boolean isFirstRoom;
+
+
+extern retroLink retroLinkList[];
+extern Rect gliderSrc[kNumGliderSrcRects];
+extern short toolSelected, toolMode;
+extern Boolean noRoomAtAll;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- FindObjectSelected
+
+#ifndef COMPILEDEMO
+short FindObjectSelected (Point where)
+{
+ short found, i;
+
+ found = kNoObjectSelected;
+
+ if (PtInRect(where, &initialGliderRect))
+ return (kInitialGliderSelected);
+ else if (PtInRect(where, &leftStartGliderDest))
+ return (kLeftGliderSelected);
+ else if (PtInRect(where, &rightStartGliderDest))
+ return (kRightGliderSelected);
+
+ for (i = kMaxRoomObs - 1; i >= 0; i--)
+ {
+ if (PtInRect(where, &roomObjectRects[i]))
+ {
+ found = i;
+ break;
+ }
+ }
+ return (found);
+}
+#endif
+
+//-------------------------------------------------------------- DoSelectionClick
+
+void DoSelectionClick (Point where, Boolean isDoubleClick)
+{
+#ifndef COMPILEDEMO
+ short direction, dist;
+
+ StopMarquee();
+
+ if ((PtInMarqueeHandle(where)) && (objActive != kNoObjectSelected))
+ {
+ if (StillDown())
+ DragHandle(where);
+ if (ObjectHasHandle(&direction, &dist))
+ {
+ StartMarqueeHandled(&roomObjectRects[objActive], direction, dist);
+ HandleBlowerGlider();
+ }
+ else
+ StartMarquee(&roomObjectRects[objActive]);
+ }
+ else
+ {
+ objActive = FindObjectSelected(where);
+ if (objActive == kNoObjectSelected)
+ {
+ if (isDoubleClick)
+ DoRoomInfo();
+ }
+ else
+ {
+ if (isDoubleClick)
+ {
+ DoObjectInfo();
+ if (ObjectHasHandle(&direction, &dist))
+ {
+ StartMarqueeHandled(&roomObjectRects[objActive], direction, dist);
+ HandleBlowerGlider();
+ }
+ else
+ StartMarquee(&roomObjectRects[objActive]);
+ }
+ else
+ {
+ if (StillDown())
+ DragObject(where);
+ if (ObjectHasHandle(&direction, &dist))
+ {
+ StartMarqueeHandled(&roomObjectRects[objActive], direction, dist);
+ HandleBlowerGlider();
+ }
+ else
+ {
+ if (objActive == kInitialGliderSelected)
+ StartMarquee(&initialGliderRect);
+ else if (objActive == kLeftGliderSelected)
+ StartMarquee(&leftStartGliderDest);
+ else if (objActive == kRightGliderSelected)
+ StartMarquee(&rightStartGliderDest);
+ else
+ StartMarquee(&roomObjectRects[objActive]);
+ }
+ }
+ }
+ }
+ UpdateMenus(false);
+#endif
+}
+
+//-------------------------------------------------------------- DragHandle
+
+#ifndef COMPILEDEMO
+void DragHandle (Point where)
+{
+ short hDelta, vDelta;
+ Boolean whoCares;
+
+ switch (thisRoom->objects[objActive].what)
+ {
+ case kFloorVent:
+ case kCeilingVent:
+ case kFloorBlower:
+ case kCeilingBlower:
+ case kSewerGrate:
+ case kTaper:
+ case kCandle:
+ case kStubby:
+ case kTiki:
+ case kBBQ:
+ case kGrecoVent:
+ case kSewerBlower:
+ vDelta = thisRoom->objects[objActive].data.a.distance;
+ DragMarqueeHandle(where, &vDelta);
+ thisRoom->objects[objActive].data.a.distance = vDelta;
+ whoCares = KeepObjectLegal();
+ break;
+
+ case kLiftArea:
+ hDelta = thisRoom->objects[objActive].data.a.distance;
+ vDelta = thisRoom->objects[objActive].data.a.tall * 2;
+ DragMarqueeCorner(where, &hDelta, &vDelta, false);
+ thisRoom->objects[objActive].data.a.distance = hDelta;
+ thisRoom->objects[objActive].data.a.tall = vDelta / 2;
+ whoCares = KeepObjectLegal();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ break;
+
+ case kLeftFan:
+ case kRightFan:
+ hDelta = thisRoom->objects[objActive].data.a.distance;
+ DragMarqueeHandle(where, &hDelta);
+ thisRoom->objects[objActive].data.a.distance = hDelta;
+ whoCares = KeepObjectLegal();
+ break;
+
+ case kInvisBlower:
+ if (((thisRoom->objects[objActive].data.a.vector & 0x0F) == 1) ||
+ ((thisRoom->objects[objActive].data.a.vector & 0x0F) == 4))
+ {
+ vDelta = thisRoom->objects[objActive].data.a.distance;
+ DragMarqueeHandle(where, &vDelta);
+ thisRoom->objects[objActive].data.a.distance = vDelta;
+ }
+ else
+ {
+ hDelta = thisRoom->objects[objActive].data.a.distance;
+ DragMarqueeHandle(where, &hDelta);
+ thisRoom->objects[objActive].data.a.distance = hDelta;
+ }
+ whoCares = KeepObjectLegal();
+ break;
+
+ case kTable:
+ case kShelf:
+ case kDeckTable:
+ hDelta = RectWide(&thisRoom->objects[objActive].data.b.bounds);
+ DragMarqueeHandle(where, &hDelta);
+ thisRoom->objects[objActive].data.b.bounds.right =
+ thisRoom->objects[objActive].data.b.bounds.left + hDelta;
+ whoCares = KeepObjectLegal();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ break;
+
+ case kCabinet:
+ case kInvisObstacle:
+ case kInvisBounce:
+ hDelta = RectWide(&thisRoom->objects[objActive].data.b.bounds);
+ vDelta = RectTall(&thisRoom->objects[objActive].data.b.bounds);
+ DragMarqueeCorner(where, &hDelta, &vDelta, false);
+ thisRoom->objects[objActive].data.b.bounds.right =
+ thisRoom->objects[objActive].data.b.bounds.left + hDelta;
+ thisRoom->objects[objActive].data.b.bounds.bottom =
+ thisRoom->objects[objActive].data.b.bounds.top + vDelta;
+ whoCares = KeepObjectLegal();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ break;
+
+ case kCounter:
+ case kDresser:
+ hDelta = RectWide(&thisRoom->objects[objActive].data.b.bounds);
+ vDelta = RectTall(&thisRoom->objects[objActive].data.b.bounds);
+ DragMarqueeCorner(where, &hDelta, &vDelta, true);
+ thisRoom->objects[objActive].data.b.bounds.right =
+ thisRoom->objects[objActive].data.b.bounds.left + hDelta;
+ thisRoom->objects[objActive].data.b.bounds.top =
+ thisRoom->objects[objActive].data.b.bounds.bottom - vDelta;
+ whoCares = KeepObjectLegal();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ break;
+
+ case kGreaseRt:
+ case kGreaseLf:
+ case kSlider:
+ hDelta = thisRoom->objects[objActive].data.c.length;
+ DragMarqueeHandle(where, &hDelta);
+ thisRoom->objects[objActive].data.c.length = hDelta;
+ whoCares = KeepObjectLegal();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ break;
+
+ case kInvisTrans:
+ hDelta = thisRoom->objects[objActive].data.d.wide;
+ vDelta = thisRoom->objects[objActive].data.d.tall;
+ DragMarqueeCorner(where, &hDelta, &vDelta, false);
+ if (hDelta > 127)
+ hDelta = 127;
+ thisRoom->objects[objActive].data.d.wide = (Byte)hDelta;
+ thisRoom->objects[objActive].data.d.tall = vDelta;
+ whoCares = KeepObjectLegal();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ break;
+
+ case kDeluxeTrans:
+ hDelta = ((thisRoom->objects[objActive].data.d.tall & 0xFF00) >> 8) * 4;
+ vDelta = (thisRoom->objects[objActive].data.d.tall & 0x00FF) * 4;
+ DragMarqueeCorner(where, &hDelta, &vDelta, false);
+ if (hDelta < 64)
+ hDelta = 64;
+ if (vDelta < 32)
+ vDelta = 32;
+ thisRoom->objects[objActive].data.d.tall = ((hDelta / 4) << 8) + (vDelta / 4);
+ whoCares = KeepObjectLegal();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ break;
+
+ case kFlourescent:
+ case kTrackLight:
+ hDelta = thisRoom->objects[objActive].data.f.length;
+ DragMarqueeHandle(where, &hDelta);
+ thisRoom->objects[objActive].data.f.length = hDelta;
+ whoCares = KeepObjectLegal();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ break;
+
+ case kToaster:
+ vDelta = thisRoom->objects[objActive].data.g.height;
+ DragMarqueeHandle(where, &vDelta);
+ thisRoom->objects[objActive].data.g.height = vDelta;
+ whoCares = KeepObjectLegal();
+ break;
+
+ case kBall:
+ case kDrip:
+ case kFish:
+ vDelta = thisRoom->objects[objActive].data.h.length;
+ DragMarqueeHandle(where, &vDelta);
+ thisRoom->objects[objActive].data.h.length = vDelta;
+ whoCares = KeepObjectLegal();
+ break;
+
+ case kMirror:
+ case kWallWindow:
+ hDelta = RectWide(&thisRoom->objects[objActive].data.i.bounds);
+ vDelta = RectTall(&thisRoom->objects[objActive].data.i.bounds);
+ DragMarqueeCorner(where, &hDelta, &vDelta, false);
+ thisRoom->objects[objActive].data.i.bounds.right =
+ thisRoom->objects[objActive].data.i.bounds.left + hDelta;
+ thisRoom->objects[objActive].data.i.bounds.bottom =
+ thisRoom->objects[objActive].data.i.bounds.top + vDelta;
+ whoCares = KeepObjectLegal();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ break;
+
+ }
+
+ fileDirty = true;
+ UpdateMenus(false);
+}
+#endif
+
+//-------------------------------------------------------------- DragObject
+
+#ifndef COMPILEDEMO
+void DragObject (Point where)
+{
+ Rect newRect, wasRect;
+ short deltaH, deltaV, increment;
+ char wasState;
+ Boolean invalAll;
+
+ if (objActive == kInitialGliderSelected)
+ {
+ wasRect = initialGliderRect;
+ newRect = initialGliderRect;
+ DragMarqueeRect(where, &newRect, false, false);
+ }
+ else if (objActive == kLeftGliderSelected)
+ {
+ wasRect = leftStartGliderDest;
+ newRect = leftStartGliderDest;
+ DragMarqueeRect(where, &newRect, false, true);
+ }
+ else if (objActive == kRightGliderSelected)
+ {
+ wasRect = rightStartGliderDest;
+ newRect = rightStartGliderDest;
+ DragMarqueeRect(where, &newRect, false, true);
+ }
+ else
+ {
+ wasRect = roomObjectRects[objActive];
+ newRect = roomObjectRects[objActive];
+ switch (thisRoom->objects[objActive].what)
+ {
+ case kFloorVent:
+ case kCeilingVent:
+ case kFloorBlower:
+ case kCeilingBlower:
+ case kSewerGrate:
+ case kGrecoVent:
+ case kSewerBlower:
+ case kManhole:
+ case kUpStairs:
+ case kDownStairs:
+ case kCeilingLight:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kFloorTrans:
+ case kCeilingTrans:
+ case kDoorInLf:
+ case kDoorInRt:
+ case kDoorExRt:
+ case kDoorExLf:
+ case kWindowInLf:
+ case kWindowInRt:
+ case kWindowExRt:
+ case kWindowExLf:
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kMousehole:
+ case kFireplace:
+ DragMarqueeRect(where, &newRect, true, false);
+ invalAll = false;
+ break;
+
+ case kDartLf:
+ case kDartRt:
+ DragMarqueeRect(where, &newRect, false, true);
+ invalAll = false;
+ break;
+
+ case kTiki:
+ case kTable:
+ case kShelf:
+ case kCabinet:
+ case kDeckTable:
+ case kStool:
+ case kInvisObstacle:
+ case kInvisBounce:
+ case kGreaseRt:
+ case kGreaseLf:
+ case kSlider:
+ case kMailboxLf:
+ case kMailboxRt:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ case kMirror:
+ case kWallWindow:
+ DragMarqueeRect(where, &newRect, false, false);
+ invalAll = true;
+ break;
+
+ case kCounter:
+ case kDresser:
+ case kTrackLight:
+ DragMarqueeRect(where, &newRect, true, false);
+ invalAll = true;
+ break;
+
+ case kRedClock:
+ case kBlueClock:
+ case kYellowClock:
+ case kCuckoo:
+ case kPaper:
+ case kBattery:
+ case kBands:
+ case kFoil:
+ case kInvisBonus:
+ case kStar:
+ case kSparkle:
+ case kHelium:
+ case kLeftFan:
+ case kRightFan:
+ case kTaper:
+ case kCandle:
+ case kStubby:
+ case kBBQ:
+ case kInvisBlower:
+ case kLiftArea:
+ case kFilingCabinet:
+ case kWasteBasket:
+ case kMilkCrate:
+ case kTrunk:
+ case kBooks:
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ case kSoundTrigger:
+ case kLightBulb:
+ case kTableLamp:
+ case kInvisLight:
+ 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:
+ case kBall:
+ case kDrip:
+ case kFish:
+ case kCobweb:
+ case kOzma:
+ case kFlower:
+ case kBear:
+ case kCalendar:
+ case kVase1:
+ case kVase2:
+ case kBulletin:
+ case kCloud:
+ case kFaucet:
+ case kRug:
+ case kChimes:
+ DragMarqueeRect(where, &newRect, false, false);
+ invalAll = false;
+ break;
+ }
+ }
+
+ deltaH = newRect.left - wasRect.left;
+ deltaV = newRect.top - wasRect.top;
+ if ((deltaH != 0) || (deltaV != 0))
+ {
+ fileDirty = true;
+ UpdateMenus(false);
+ }
+
+ if (objActive == kInitialGliderSelected)
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ (*thisHouse)->initial.h += deltaH;
+ (*thisHouse)->initial.v += deltaV;
+ HSetState((Handle)thisHouse, wasState);
+ }
+ else if (objActive == kLeftGliderSelected)
+ {
+ increment = thisRoom->leftStart + deltaV;
+ if (increment > 255)
+ increment = 255;
+ else if (increment < 0)
+ increment = 0;
+ thisRoom->leftStart = (Byte)increment;
+ QSetRect(&leftStartGliderDest, 0, 0, 48, 16);
+ QOffsetRect(&leftStartGliderDest, 0,
+ kGliderStartsDown + (short)thisRoom->leftStart);
+ }
+ else if (objActive == kRightGliderSelected)
+ {
+ increment = thisRoom->rightStart + deltaV;
+ if (increment > 255)
+ increment = 255;
+ else if (increment < 0)
+ increment = 0;
+ thisRoom->rightStart = (Byte)increment;
+ QSetRect(&rightStartGliderDest, 0, 0, 48, 16);
+ QOffsetRect(&rightStartGliderDest, 0,
+ kGliderStartsDown + (short)thisRoom->rightStart);
+ }
+ else
+ {
+ switch (thisRoom->objects[objActive].what)
+ {
+ case kFloorVent:
+ case kCeilingVent:
+ case kFloorBlower:
+ case kCeilingBlower:
+ case kSewerGrate:
+ case kGrecoVent:
+ case kSewerBlower:
+ thisRoom->objects[objActive].data.a.topLeft.h += deltaH;
+ break;
+
+ case kLeftFan:
+ case kRightFan:
+ case kTaper:
+ case kCandle:
+ case kStubby:
+ case kTiki:
+ case kBBQ:
+ case kInvisBlower:
+ case kLiftArea:
+ thisRoom->objects[objActive].data.a.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.a.topLeft.v += deltaV;
+ break;
+
+ case kTable:
+ case kShelf:
+ case kCabinet:
+ case kFilingCabinet:
+ case kWasteBasket:
+ case kMilkCrate:
+ case kDeckTable:
+ case kStool:
+ case kTrunk:
+ case kInvisObstacle:
+ case kBooks:
+ case kInvisBounce:
+ thisRoom->objects[objActive].data.b.bounds.left += deltaH;
+ thisRoom->objects[objActive].data.b.bounds.right += deltaH;
+ thisRoom->objects[objActive].data.b.bounds.top += deltaV;
+ thisRoom->objects[objActive].data.b.bounds.bottom += deltaV;
+ break;
+
+ case kCounter:
+ case kDresser:
+ case kManhole:
+ thisRoom->objects[objActive].data.b.bounds.left += deltaH;
+ thisRoom->objects[objActive].data.b.bounds.right += deltaH;
+ 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:
+ thisRoom->objects[objActive].data.c.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.c.topLeft.v += deltaV;
+ break;
+
+ case kUpStairs:
+ case kDownStairs:
+ case kFloorTrans:
+ case kCeilingTrans:
+ case kDoorInLf:
+ case kDoorInRt:
+ case kDoorExRt:
+ case kDoorExLf:
+ case kWindowInLf:
+ case kWindowInRt:
+ case kWindowExRt:
+ case kWindowExLf:
+ thisRoom->objects[objActive].data.d.topLeft.h += deltaH;
+ break;
+
+ case kMailboxLf:
+ case kMailboxRt:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ thisRoom->objects[objActive].data.d.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.d.topLeft.v += deltaV;
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ case kSoundTrigger:
+ thisRoom->objects[objActive].data.e.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.e.topLeft.v += deltaV;
+ break;
+
+ case kCeilingLight:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kTrackLight:
+ thisRoom->objects[objActive].data.f.topLeft.h += deltaH;
+ break;
+
+ case kLightBulb:
+ case kTableLamp:
+ case kInvisLight:
+ thisRoom->objects[objActive].data.f.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.f.topLeft.v += deltaV;
+ 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:
+ thisRoom->objects[objActive].data.g.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.g.topLeft.v += deltaV;
+ break;
+
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ thisRoom->objects[objActive].data.h.topLeft.h += deltaH;
+ break;
+
+ case kDartLf:
+ case kDartRt:
+ thisRoom->objects[objActive].data.h.topLeft.v += deltaV;
+ break;
+
+ case kBall:
+ case kDrip:
+ case kFish:
+ case kCobweb:
+ thisRoom->objects[objActive].data.h.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.h.topLeft.v += deltaV;
+ break;
+
+ case kOzma:
+ case kMirror:
+ case kFlower:
+ case kWallWindow:
+ case kBear:
+ case kCalendar:
+ case kVase1:
+ case kVase2:
+ case kBulletin:
+ case kCloud:
+ case kFaucet:
+ case kRug:
+ case kChimes:
+ thisRoom->objects[objActive].data.i.bounds.left += deltaH;
+ thisRoom->objects[objActive].data.i.bounds.right += deltaH;
+ thisRoom->objects[objActive].data.i.bounds.top += deltaV;
+ thisRoom->objects[objActive].data.i.bounds.bottom += deltaV;
+ break;
+
+ case kMousehole:
+ case kFireplace:
+ thisRoom->objects[objActive].data.i.bounds.left += deltaH;
+ thisRoom->objects[objActive].data.i.bounds.right += deltaH;
+ break;
+ }
+ }
+
+ if (KeepObjectLegal())
+ {
+ }
+ GetThisRoomsObjRects();
+ if (invalAll)
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ else
+ {
+ InvalWindowRect(mainWindow, &wasRect);
+ if (objActive == kInitialGliderSelected)
+ InvalWindowRect(mainWindow, &initialGliderRect);
+ else if (objActive == kLeftGliderSelected)
+ InvalWindowRect(mainWindow, &leftStartGliderDest);
+ else if (objActive == kRightGliderSelected)
+ InvalWindowRect(mainWindow, &rightStartGliderDest);
+ else
+ InvalWindowRect(mainWindow, &roomObjectRects[objActive]);
+ }
+
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+}
+#endif
+
+//-------------------------------------------------------------- DoNewObjectClick
+
+void DoNewObjectClick (Point where)
+{
+#ifndef COMPILEDEMO
+ short whatObject;
+
+ StopMarquee();
+ objActive = kNoObjectSelected;
+
+ whatObject = toolSelected + ((toolMode - 1) * 0x0010);
+ if (AddNewObject(where, whatObject, true))
+ IgnoreThisClick();
+ UpdateMenus(false);
+
+ AddObjectPairing();
+#endif
+}
+
+//-------------------------------------------------------------- AddObjectPairing
+
+void AddObjectPairing (void)
+{
+ roomType *testRoomPtr;
+ short roomNum, emptySlot;
+ char wasState;
+ Str255 message;
+
+ if (thisRoom->objects[objActive].what == kDoorInRt)
+ {
+ roomNum = DoesNeighborRoomExist(kRoomToRight);
+ if (roomNum != -1)
+ {
+ emptySlot = FindObjectSlotInRoom(roomNum);
+ if ((emptySlot != -1) && (!DoesRoomNumHaveObject(roomNum, kDoorExLf)))
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNum]);
+
+ testRoomPtr->objects[emptySlot].what = kDoorExLf;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.h = kDoorExLfLeft;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.v = kDoorExTop;
+ testRoomPtr->objects[emptySlot].data.d.tall = 0;
+ testRoomPtr->objects[emptySlot].data.d.where = -1;
+ testRoomPtr->objects[emptySlot].data.d.who = 255;
+ testRoomPtr->objects[emptySlot].data.d.wide = 0;
+
+ testRoomPtr->numObjects++;
+ HSetState((Handle)thisHouse, wasState);
+
+ GetLocalizedString(45, message);
+ OpenMessageWindow(message);
+ ForeColor(blueColor);
+ GetLocalizedString(46, message);
+ SetMessageWindowMessage(message);
+ ForeColor(blackColor);
+ DelayTicks(60);
+ CloseMessageWindow();
+ }
+ }
+ }
+ else if (thisRoom->objects[objActive].what == kDoorInLf)
+ {
+ roomNum = DoesNeighborRoomExist(kRoomToLeft);
+ if (roomNum != -1)
+ {
+ emptySlot = FindObjectSlotInRoom(roomNum);
+ if ((emptySlot != -1) && (!DoesRoomNumHaveObject(roomNum, kDoorExRt)))
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNum]);
+
+ testRoomPtr->objects[emptySlot].what = kDoorExRt;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.h = kDoorExRtLeft;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.v = kDoorExTop;
+ testRoomPtr->objects[emptySlot].data.d.tall = 0;
+ testRoomPtr->objects[emptySlot].data.d.where = -1;
+ testRoomPtr->objects[emptySlot].data.d.who = 255;
+ testRoomPtr->objects[emptySlot].data.d.wide = 0;
+
+ testRoomPtr->numObjects++;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ GetLocalizedString(45, message);
+ OpenMessageWindow(message);
+ ForeColor(blueColor);
+ GetLocalizedString(46, message);
+ SetMessageWindowMessage(message);
+ ForeColor(blackColor);
+ DelayTicks(60);
+ CloseMessageWindow();
+ }
+ }
+ }
+ else if (thisRoom->objects[objActive].what == kDoorExRt)
+ {
+ roomNum = DoesNeighborRoomExist(kRoomToRight);
+ if (roomNum != -1)
+ {
+ emptySlot = FindObjectSlotInRoom(roomNum);
+ if ((emptySlot != -1) && (!DoesRoomNumHaveObject(roomNum, kDoorInLfLeft)))
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNum]);
+
+ testRoomPtr->objects[emptySlot].what = kDoorInLf;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.h = kDoorInLfLeft;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.v = kDoorInTop;
+ testRoomPtr->objects[emptySlot].data.d.tall = 0;
+ testRoomPtr->objects[emptySlot].data.d.where = -1;
+ testRoomPtr->objects[emptySlot].data.d.who = 255;
+ testRoomPtr->objects[emptySlot].data.d.wide = 0;
+
+ testRoomPtr->numObjects++;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ GetLocalizedString(45, message);
+ OpenMessageWindow(message);
+ ForeColor(blueColor);
+ GetLocalizedString(47, message);
+ SetMessageWindowMessage(message);
+ ForeColor(blackColor);
+ DelayTicks(60);
+ CloseMessageWindow();
+ }
+ }
+ }
+ else if (thisRoom->objects[objActive].what == kDoorExLf)
+ {
+ roomNum = DoesNeighborRoomExist(kRoomToLeft);
+ if (roomNum != -1)
+ {
+ emptySlot = FindObjectSlotInRoom(roomNum);
+ if ((emptySlot != -1) && (!DoesRoomNumHaveObject(roomNum, kDoorInRtLeft)))
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNum]);
+
+ testRoomPtr->objects[emptySlot].what = kDoorInRt;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.h = kDoorInRtLeft;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.v = kDoorInTop;
+ testRoomPtr->objects[emptySlot].data.d.tall = 0;
+ testRoomPtr->objects[emptySlot].data.d.where = -1;
+ testRoomPtr->objects[emptySlot].data.d.who = 255;
+ testRoomPtr->objects[emptySlot].data.d.wide = 0;
+
+ testRoomPtr->numObjects++;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ GetLocalizedString(45, message);
+ OpenMessageWindow(message);
+ ForeColor(blueColor);
+ GetLocalizedString(47, message);
+ SetMessageWindowMessage(message);
+ ForeColor(blackColor);
+ DelayTicks(60);
+ CloseMessageWindow();
+ }
+ }
+ }
+ else if (thisRoom->objects[objActive].what == kWindowInLf)
+ {
+ roomNum = DoesNeighborRoomExist(kRoomToLeft);
+ if (roomNum != -1)
+ {
+ emptySlot = FindObjectSlotInRoom(roomNum);
+ if ((emptySlot != -1) && (!DoesRoomNumHaveObject(roomNum, kWindowExRt)))
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNum]);
+
+ testRoomPtr->objects[emptySlot].what = kWindowExRt;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.h = kWindowExRtLeft;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.v = kWindowExTop;
+ testRoomPtr->objects[emptySlot].data.d.tall = 0;
+ testRoomPtr->objects[emptySlot].data.d.where = -1;
+ testRoomPtr->objects[emptySlot].data.d.who = 255;
+ testRoomPtr->objects[emptySlot].data.d.wide = 0;
+
+ testRoomPtr->numObjects++;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ GetLocalizedString(45, message);
+ OpenMessageWindow(message);
+ ForeColor(blueColor);
+ GetLocalizedString(48, message);
+ SetMessageWindowMessage(message);
+ ForeColor(blackColor);
+ DelayTicks(60);
+ CloseMessageWindow();
+ }
+ }
+ }
+ else if (thisRoom->objects[objActive].what == kWindowInRt)
+ {
+ roomNum = DoesNeighborRoomExist(kRoomToRight);
+ if (roomNum != -1)
+ {
+ emptySlot = FindObjectSlotInRoom(roomNum);
+ if ((emptySlot != -1) && (!DoesRoomNumHaveObject(roomNum, kWindowExLf)))
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNum]);
+
+ testRoomPtr->objects[emptySlot].what = kWindowExLf;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.h = kWindowExLfLeft;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.v = kWindowExTop;
+ testRoomPtr->objects[emptySlot].data.d.tall = 0;
+ testRoomPtr->objects[emptySlot].data.d.where = -1;
+ testRoomPtr->objects[emptySlot].data.d.who = 255;
+ testRoomPtr->objects[emptySlot].data.d.wide = 0;
+
+ testRoomPtr->numObjects++;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ GetLocalizedString(45, message);
+ OpenMessageWindow(message);
+ ForeColor(blueColor);
+ GetLocalizedString(48, message);
+ SetMessageWindowMessage(message);
+ ForeColor(blackColor);
+ DelayTicks(60);
+ CloseMessageWindow();
+ }
+ }
+ }
+ else if (thisRoom->objects[objActive].what == kWindowExRt)
+ {
+ roomNum = DoesNeighborRoomExist(kRoomToRight);
+ if (roomNum != -1)
+ {
+ emptySlot = FindObjectSlotInRoom(roomNum);
+ if ((emptySlot != -1) && (!DoesRoomNumHaveObject(roomNum, kWindowInLf)))
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNum]);
+
+ testRoomPtr->objects[emptySlot].what = kWindowInLf;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.h = kWindowInLfLeft;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.v = kWindowInTop;
+ testRoomPtr->objects[emptySlot].data.d.tall = 0;
+ testRoomPtr->objects[emptySlot].data.d.where = -1;
+ testRoomPtr->objects[emptySlot].data.d.who = 255;
+ testRoomPtr->objects[emptySlot].data.d.wide = 0;
+
+ testRoomPtr->numObjects++;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ GetLocalizedString(45, message);
+ OpenMessageWindow(message);
+ ForeColor(blueColor);
+ GetLocalizedString(49, message);
+ SetMessageWindowMessage(message);
+ ForeColor(blackColor);
+ DelayTicks(60);
+ CloseMessageWindow();
+ }
+ }
+ }
+ else if (thisRoom->objects[objActive].what == kWindowExLf)
+ {
+ roomNum = DoesNeighborRoomExist(kRoomToLeft);
+ if (roomNum != -1)
+ {
+ emptySlot = FindObjectSlotInRoom(roomNum);
+ if ((emptySlot != -1) && (!DoesRoomNumHaveObject(roomNum, kWindowInRt)))
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNum]);
+
+ testRoomPtr->objects[emptySlot].what = kWindowInRt;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.h = kWindowInRtLeft;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.v = kWindowInTop;
+ testRoomPtr->objects[emptySlot].data.d.tall = 0;
+ testRoomPtr->objects[emptySlot].data.d.where = -1;
+ testRoomPtr->objects[emptySlot].data.d.who = 255;
+ testRoomPtr->objects[emptySlot].data.d.wide = 0;
+
+ testRoomPtr->numObjects++;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ GetLocalizedString(45, message);
+ OpenMessageWindow(message);
+ ForeColor(blueColor);
+ GetLocalizedString(49, message);
+ SetMessageWindowMessage(message);
+ ForeColor(blackColor);
+ DelayTicks(60);
+ CloseMessageWindow();
+ }
+ }
+ }
+ else if (thisRoom->objects[objActive].what == kUpStairs)
+ {
+ roomNum = DoesNeighborRoomExist(kRoomAbove);
+ if (roomNum != -1)
+ {
+ emptySlot = FindObjectSlotInRoom(roomNum);
+ if ((emptySlot != -1) && (!DoesRoomNumHaveObject(roomNum, kDownStairs)))
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNum]);
+
+ testRoomPtr->objects[emptySlot].what = kDownStairs;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.h =
+ thisRoom->objects[objActive].data.d.topLeft.h;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.v = kStairsTop;
+ testRoomPtr->objects[emptySlot].data.d.tall = 0;
+ testRoomPtr->objects[emptySlot].data.d.where = -1;
+ testRoomPtr->objects[emptySlot].data.d.who = 255;
+ testRoomPtr->objects[emptySlot].data.d.wide = 0;
+
+ testRoomPtr->numObjects++;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ GetLocalizedString(45, message);
+ OpenMessageWindow(message);
+ ForeColor(blueColor);
+ GetLocalizedString(50, message);
+ SetMessageWindowMessage(message);
+ ForeColor(blackColor);
+ DelayTicks(60);
+ CloseMessageWindow();
+ }
+ }
+ }
+ else if (thisRoom->objects[objActive].what == kDownStairs)
+ {
+ roomNum = DoesNeighborRoomExist(kRoomBelow);
+ if (roomNum != -1)
+ {
+ emptySlot = FindObjectSlotInRoom(roomNum);
+ if ((emptySlot != -1) && (!DoesRoomNumHaveObject(roomNum, kUpStairs)))
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ testRoomPtr = &((*thisHouse)->rooms[roomNum]);
+
+ testRoomPtr->objects[emptySlot].what = kUpStairs;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.h =
+ thisRoom->objects[objActive].data.d.topLeft.h;
+ testRoomPtr->objects[emptySlot].data.d.topLeft.v = kStairsTop;
+ testRoomPtr->objects[emptySlot].data.d.tall = 0;
+ testRoomPtr->objects[emptySlot].data.d.where = -1;
+ testRoomPtr->objects[emptySlot].data.d.who = 255;
+ testRoomPtr->objects[emptySlot].data.d.wide = 0;
+
+ testRoomPtr->numObjects++;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ GetLocalizedString(45, message);
+ OpenMessageWindow(message);
+ ForeColor(blueColor);
+ GetLocalizedString(51, message);
+ SetMessageWindowMessage(message);
+ ForeColor(blackColor);
+ DelayTicks(60);
+ CloseMessageWindow();
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- DeleteObject
+
+void DeleteObject (void)
+{
+#ifndef COMPILEDEMO
+ short i;
+
+ if ((theMode != kEditMode) || (objActive == kNoObjectSelected))
+ return;
+
+ if ((objActive == kInitialGliderSelected) ||
+ (objActive == kLeftGliderSelected) ||
+ (objActive == kRightGliderSelected))
+ {
+ SysBeep(1);
+ return;
+ }
+
+ for (i = 0; i < kMaxRoomObs; i++)
+ {
+ if ((retroLinkList[i].room == thisRoomNumber) &&
+ (retroLinkList[i].object == objActive))
+ retroLinkList[i].room = -1;
+ }
+
+ thisRoom->objects[objActive].what = kObjectIsEmpty;
+ thisRoom->numObjects--;
+ fileDirty = true;
+ UpdateMenus(false);
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ QSetRect(&roomObjectRects[objActive], -1, -1, 0, 0);
+ DeselectObject();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+#endif
+}
+
+//-------------------------------------------------------------- DuplicateObject
+
+void DuplicateObject (void)
+{
+ objectType tempObject;
+ Point placePt;
+ short direction, dist;
+ Boolean handled;
+
+ tempObject = thisRoom->objects[objActive];
+
+ placePt.h = roomObjectRects[objActive].left +
+ HalfRectWide(&roomObjectRects[objActive]) + 64;
+ placePt.v = roomObjectRects[objActive].top +
+ HalfRectTall(&roomObjectRects[objActive]);
+
+ StopMarquee();
+
+ if (AddNewObject(placePt, tempObject.what, false))
+ {
+ switch (tempObject.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:
+ thisRoom->objects[objActive].data.a.distance = tempObject.data.a.distance;
+ thisRoom->objects[objActive].data.a.initial = tempObject.data.a.initial;
+ thisRoom->objects[objActive].data.a.state = tempObject.data.a.state;
+ thisRoom->objects[objActive].data.a.vector = tempObject.data.a.vector;
+ thisRoom->objects[objActive].data.a.tall = tempObject.data.a.tall;
+ break;
+
+ case kLiftArea:
+ thisRoom->objects[objActive].data.a.topLeft.h = tempObject.data.a.topLeft.h + 64;
+ thisRoom->objects[objActive].data.a.topLeft.v = tempObject.data.a.topLeft.v;
+ thisRoom->objects[objActive].data.a.distance = tempObject.data.a.distance;
+ thisRoom->objects[objActive].data.a.initial = tempObject.data.a.initial;
+ thisRoom->objects[objActive].data.a.state = tempObject.data.a.state;
+ thisRoom->objects[objActive].data.a.vector = tempObject.data.a.vector;
+ thisRoom->objects[objActive].data.a.tall = tempObject.data.a.tall;
+ break;
+
+ case kFilingCabinet: case kWasteBasket: case kMilkCrate:
+ case kStool: case kTrunk: case kManhole:
+ case kBooks:
+ thisRoom->objects[objActive].data.b.pict = tempObject.data.b.pict;
+ break;
+
+ case kTable: case kShelf: case kCabinet:
+ case kCounter: case kDresser: case kDeckTable:
+ case kInvisObstacle: case kInvisBounce:
+ thisRoom->objects[objActive].data.b.bounds = tempObject.data.b.bounds;
+ QOffsetRect(&thisRoom->objects[objActive].data.b.bounds, 64, 0);
+ thisRoom->objects[objActive].data.b.pict = tempObject.data.b.pict;
+ 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:
+ thisRoom->objects[objActive].data.c.length = tempObject.data.c.length;
+ thisRoom->objects[objActive].data.c.points = tempObject.data.c.points;
+ thisRoom->objects[objActive].data.c.state = tempObject.data.c.state;
+ thisRoom->objects[objActive].data.c.initial = tempObject.data.c.initial;
+ break;
+
+ case kSlider:
+ thisRoom->objects[objActive].data.c.topLeft.h = tempObject.data.c.topLeft.h + 64;
+ thisRoom->objects[objActive].data.c.length = tempObject.data.c.length;
+ thisRoom->objects[objActive].data.c.points = tempObject.data.c.points;
+ thisRoom->objects[objActive].data.c.state = tempObject.data.c.state;
+ thisRoom->objects[objActive].data.c.initial = tempObject.data.c.initial;
+ 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:
+ thisRoom->objects[objActive].data.d.tall = tempObject.data.d.tall;
+ thisRoom->objects[objActive].data.d.where = tempObject.data.d.where;
+ thisRoom->objects[objActive].data.d.who = tempObject.data.d.who;
+ thisRoom->objects[objActive].data.d.wide = tempObject.data.d.wide;
+ break;
+
+ case kInvisTrans: case kDeluxeTrans:
+ thisRoom->objects[objActive].data.d.topLeft.h = tempObject.data.d.topLeft.h + 64;
+ thisRoom->objects[objActive].data.d.topLeft.v = tempObject.data.d.topLeft.v;
+ thisRoom->objects[objActive].data.d.tall = tempObject.data.d.tall;
+ thisRoom->objects[objActive].data.d.where = tempObject.data.d.where;
+ thisRoom->objects[objActive].data.d.who = tempObject.data.d.who;
+ thisRoom->objects[objActive].data.d.wide = tempObject.data.d.wide;
+ break;
+
+ case kLightSwitch: case kMachineSwitch: case kThermostat:
+ case kPowerSwitch: case kKnifeSwitch: case kInvisSwitch:
+ case kTrigger: case kLgTrigger: case kSoundTrigger:
+ thisRoom->objects[objActive].data.e.delay = tempObject.data.e.delay;
+ thisRoom->objects[objActive].data.e.where = tempObject.data.e.where;
+ thisRoom->objects[objActive].data.e.who = tempObject.data.e.who;
+ thisRoom->objects[objActive].data.e.type = tempObject.data.e.type;
+ break;
+
+ case kCeilingLight: case kLightBulb: case kTableLamp:
+ case kHipLamp: case kDecoLamp: case kFlourescent:
+ case kTrackLight: case kInvisLight:
+ thisRoom->objects[objActive].data.f.length = tempObject.data.f.length;
+ thisRoom->objects[objActive].data.f.byte0 = tempObject.data.f.byte0;
+ thisRoom->objects[objActive].data.f.byte1 = tempObject.data.f.byte1;
+ thisRoom->objects[objActive].data.f.initial = tempObject.data.f.initial;
+ thisRoom->objects[objActive].data.f.state = tempObject.data.f.state;
+ 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:
+ thisRoom->objects[objActive].data.g.height = tempObject.data.g.height;
+ thisRoom->objects[objActive].data.g.byte0 = tempObject.data.g.byte0;
+ thisRoom->objects[objActive].data.g.delay = tempObject.data.g.delay;
+ thisRoom->objects[objActive].data.g.initial = tempObject.data.g.initial;
+ thisRoom->objects[objActive].data.g.state = tempObject.data.g.state;
+ break;
+
+ case kCustomPict:
+ thisRoom->objects[objActive].data.g.topLeft.h =
+ tempObject.data.g.topLeft.h + 64;
+ thisRoom->objects[objActive].data.g.topLeft.v = tempObject.data.g.topLeft.v;
+ thisRoom->objects[objActive].data.g.height = tempObject.data.g.height;
+ thisRoom->objects[objActive].data.g.byte0 = tempObject.data.g.byte0;
+ thisRoom->objects[objActive].data.g.delay = tempObject.data.g.delay;
+ thisRoom->objects[objActive].data.g.initial = tempObject.data.g.initial;
+ thisRoom->objects[objActive].data.g.state = tempObject.data.g.state;
+ break;
+
+ case kBalloon: case kCopterLf: case kCopterRt:
+ case kDartLf: case kDartRt: case kBall:
+ case kDrip: case kFish: case kCobweb:
+ thisRoom->objects[objActive].data.h.length = tempObject.data.h.length;
+ thisRoom->objects[objActive].data.h.delay = tempObject.data.h.delay;
+ thisRoom->objects[objActive].data.h.byte0 = tempObject.data.h.byte0;
+ thisRoom->objects[objActive].data.h.initial = tempObject.data.h.initial;
+ thisRoom->objects[objActive].data.h.state = tempObject.data.h.state;
+ break;
+
+ case kOzma: case kMousehole: case kFireplace:
+ case kBear: case kCalendar: case kVase1:
+ case kVase2: case kBulletin: case kCloud:
+ case kFaucet: case kRug: case kChimes:
+ thisRoom->objects[objActive].data.i.pict = tempObject.data.i.pict;
+ break;
+
+ case kMirror: case kFlower: case kWallWindow:
+ thisRoom->objects[objActive].data.i.bounds = tempObject.data.i.bounds;
+ QOffsetRect(&thisRoom->objects[objActive].data.i.bounds, 64, 0);
+ thisRoom->objects[objActive].data.i.pict = tempObject.data.i.pict;
+ break;
+ }
+
+ if (KeepObjectLegal())
+ {
+ }
+ handled = ObjectHasHandle(&direction, &dist);
+
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ GetThisRoomsObjRects();
+ DrawThisRoomsObjects();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+
+ if (handled)
+ {
+ StartMarqueeHandled(&roomObjectRects[objActive], direction, dist);
+ HandleBlowerGlider();
+ }
+ else
+ StartMarquee(&roomObjectRects[objActive]);
+ }
+}
+
+//-------------------------------------------------------------- MoveObject
+
+void MoveObject (short whichWay, Boolean shiftDown)
+{
+#ifndef COMPILEDEMO
+ Rect wasRect;
+ short deltaH, deltaV, increment;
+ short dist, direction;
+ char wasState;
+
+ if (theMode != kEditMode)
+ return;
+
+ StopMarquee();
+
+ if (shiftDown)
+ increment = 10;
+ else
+ {
+ if (objActive == kInitialGliderSelected)
+ {
+ increment = 1;
+ }
+ else
+ {
+ if ((whichWay == kBumpRight) || (whichWay == kBumpLeft))
+ {
+ switch (thisRoom->objects[objActive].what)
+ {
+ case kTaper:
+ case kCandle:
+ case kStubby:
+ case kTiki:
+ case kBBQ:
+ 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:
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ case kSoundTrigger:
+ case kToaster:
+ case kMacPlus:
+ case kTV:
+ case kCoffee:
+ case kOutlet:
+ case kVCR:
+ case kStereo:
+ case kMicrowave:
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kBall:
+ case kDrip:
+ case kFish:
+ case kMirror:
+ increment = 2;
+ break;
+
+ case kManhole:
+ increment = 64;
+ break;
+
+ default:
+ increment = 1;
+ break;
+ }
+ }
+ else
+ increment = 1;
+ }
+ }
+
+ switch (whichWay)
+ {
+ case kBumpUp:
+ deltaH = 0;
+ deltaV = -increment;
+ break;
+
+ case kBumpDown:
+ deltaH = 0;
+ deltaV = increment;
+ break;
+
+ case kBumpRight:
+ deltaH = increment;
+ deltaV = 0;
+ break;
+
+ case kBumpLeft:
+ deltaH = -increment;
+ deltaV = 0;
+ break;
+ }
+
+ if (objActive == kInitialGliderSelected)
+ {
+ wasRect = initialGliderRect;
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ (*thisHouse)->initial.h += deltaH;
+ (*thisHouse)->initial.v += deltaV;
+ HSetState((Handle)thisHouse, wasState);
+ }
+ else if (objActive == kLeftGliderSelected)
+ {
+ wasRect = leftStartGliderDest;
+ increment = thisRoom->leftStart + deltaV;
+ if (increment > 255)
+ increment = 255;
+ else if (increment < 0)
+ increment = 0;
+ thisRoom->leftStart = (Byte)increment;
+ QSetRect(&leftStartGliderDest, 0, 0, 48, 16);
+ QOffsetRect(&leftStartGliderDest, 0,
+ kGliderStartsDown + (short)thisRoom->leftStart);
+ }
+ else if (objActive == kRightGliderSelected)
+ {
+ wasRect = rightStartGliderDest;
+ increment = thisRoom->rightStart + deltaV;
+ if (increment > 255)
+ increment = 255;
+ else if (increment < 0)
+ increment = 0;
+ thisRoom->rightStart = (Byte)increment;
+ QSetRect(&rightStartGliderDest, 0, 0, 48, 16);
+ QOffsetRect(&rightStartGliderDest, kRoomWide - 48,
+ kGliderStartsDown + (short)thisRoom->rightStart);
+ }
+ else
+ {
+ wasRect = roomObjectRects[objActive];
+ switch (thisRoom->objects[objActive].what)
+ {
+ case kFloorVent:
+ case kCeilingVent:
+ case kFloorBlower:
+ case kCeilingBlower:
+ case kSewerGrate:
+ case kGrecoVent:
+ case kSewerBlower:
+ thisRoom->objects[objActive].data.a.topLeft.h += deltaH;
+ break;
+
+ case kLeftFan:
+ case kRightFan:
+ case kTaper:
+ case kCandle:
+ case kStubby:
+ case kTiki:
+ case kBBQ:
+ case kInvisBlower:
+ case kLiftArea:
+ thisRoom->objects[objActive].data.a.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.a.topLeft.v += deltaV;
+ break;
+
+ case kTable:
+ case kShelf:
+ case kCabinet:
+ case kFilingCabinet:
+ case kWasteBasket:
+ case kMilkCrate:
+ case kDeckTable:
+ case kStool:
+ case kTrunk:
+ case kInvisObstacle:
+ case kBooks:
+ case kInvisBounce:
+ thisRoom->objects[objActive].data.b.bounds.left += deltaH;
+ thisRoom->objects[objActive].data.b.bounds.right += deltaH;
+ thisRoom->objects[objActive].data.b.bounds.top += deltaV;
+ thisRoom->objects[objActive].data.b.bounds.bottom += deltaV;
+ break;
+
+ case kCounter:
+ case kDresser:
+ case kManhole:
+ thisRoom->objects[objActive].data.b.bounds.left += deltaH;
+ thisRoom->objects[objActive].data.b.bounds.right += deltaH;
+ 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:
+ thisRoom->objects[objActive].data.c.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.c.topLeft.v += deltaV;
+ break;
+
+ case kUpStairs:
+ case kDownStairs:
+ case kFloorTrans:
+ case kCeilingTrans:
+ thisRoom->objects[objActive].data.d.topLeft.h += deltaH;
+ break;
+
+ case kMailboxLf:
+ case kMailboxRt:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ thisRoom->objects[objActive].data.d.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.d.topLeft.v += deltaV;
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ case kSoundTrigger:
+ thisRoom->objects[objActive].data.e.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.e.topLeft.v += deltaV;
+ break;
+
+ case kCeilingLight:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kTrackLight:
+ thisRoom->objects[objActive].data.f.topLeft.h += deltaH;
+ break;
+
+ case kLightBulb:
+ case kTableLamp:
+ case kInvisLight:
+ thisRoom->objects[objActive].data.f.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.f.topLeft.v += deltaV;
+ 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:
+ thisRoom->objects[objActive].data.g.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.g.topLeft.v += deltaV;
+ break;
+
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ thisRoom->objects[objActive].data.h.topLeft.h += deltaH;
+ break;
+
+ case kDartLf:
+ case kDartRt:
+ thisRoom->objects[objActive].data.h.topLeft.v += deltaV;
+ break;
+
+ case kBall:
+ case kDrip:
+ case kFish:
+ case kCobweb:
+ thisRoom->objects[objActive].data.h.topLeft.h += deltaH;
+ thisRoom->objects[objActive].data.h.topLeft.v += deltaV;
+ break;
+
+ case kOzma:
+ case kMirror:
+ case kFlower:
+ case kWallWindow:
+ case kBear:
+ case kCalendar:
+ case kVase1:
+ case kVase2:
+ case kBulletin:
+ case kCloud:
+ case kFaucet:
+ case kRug:
+ case kChimes:
+ thisRoom->objects[objActive].data.i.bounds.left += deltaH;
+ thisRoom->objects[objActive].data.i.bounds.right += deltaH;
+ thisRoom->objects[objActive].data.i.bounds.top += deltaV;
+ thisRoom->objects[objActive].data.i.bounds.bottom += deltaV;
+ break;
+
+ case kMousehole:
+ case kFireplace:
+ thisRoom->objects[objActive].data.i.bounds.left += deltaH;
+ thisRoom->objects[objActive].data.i.bounds.right += deltaH;
+ break;
+
+ }
+ }
+
+ if (KeepObjectLegal())
+ {
+ }
+ fileDirty = true;
+ UpdateMenus(false);
+ GetThisRoomsObjRects();
+
+ if (objActive == kInitialGliderSelected)
+ {
+ InvalWindowRect(mainWindow, &wasRect);
+ InvalWindowRect(mainWindow, &initialGliderRect);
+ }
+ else if (objActive == kLeftGliderSelected)
+ {
+ InvalWindowRect(mainWindow, &wasRect);
+ InvalWindowRect(mainWindow, &leftStartGliderDest);
+ }
+ else if (objActive == kRightGliderSelected)
+ {
+ InvalWindowRect(mainWindow, &wasRect);
+ InvalWindowRect(mainWindow, &rightStartGliderDest);
+ }
+ else
+ {
+ switch (thisRoom->objects[objActive].what)
+ {
+ case kTiki:
+ case kTable:
+ case kShelf:
+ case kCabinet:
+ case kDeckTable:
+ case kStool:
+ case kCounter:
+ case kDresser:
+ case kGreaseRt:
+ case kGreaseLf:
+ case kSlider:
+ case kMailboxLf:
+ case kMailboxRt:
+ case kTrackLight:
+ case kMirror:
+ case kWallWindow:
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ break;
+
+ default:
+ InvalWindowRect(mainWindow, &wasRect);
+ InvalWindowRect(mainWindow, &roomObjectRects[objActive]);
+ break;
+ }
+ }
+
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+
+ if (ObjectHasHandle(&direction, &dist))
+ {
+ StartMarqueeHandled(&roomObjectRects[objActive], direction, dist);
+ HandleBlowerGlider();
+ }
+ else
+ {
+ if (objActive == kInitialGliderSelected)
+ StartMarquee(&initialGliderRect);
+ else if (objActive == kLeftGliderSelected)
+ StartMarquee(&leftStartGliderDest);
+ else if (objActive == kRightGliderSelected)
+ StartMarquee(&rightStartGliderDest);
+ else
+ StartMarquee(&roomObjectRects[objActive]);
+ }
+#endif
+}
+
+//-------------------------------------------------------------- DeselectObject
+
+void DeselectObject (void)
+{
+#ifndef COMPILEDEMO
+ if ((theMode != kEditMode) || (objActive == kNoObjectSelected))
+ return;
+
+ objActive = kNoObjectSelected;
+ StopMarquee();
+ UpdateMenus(false);
+#endif
+}
+
+//-------------------------------------------------------------- ObjectHasHandle
+
+#ifndef COMPILEDEMO
+Boolean ObjectHasHandle (short *direction, short *dist)
+{
+ if ((objActive == kInitialGliderSelected) ||
+ (objActive == kNoObjectSelected))
+ return (false);
+
+ switch (thisRoom->objects[objActive].what)
+ {
+ case kFloorVent:
+ case kFloorBlower:
+ case kSewerGrate:
+ case kTaper:
+ case kCandle:
+ case kStubby:
+ case kTiki:
+ case kBBQ:
+ case kGrecoVent:
+ case kSewerBlower:
+ *direction = kAbove;
+ *dist = thisRoom->objects[objActive].data.a.distance;
+ return (true);
+ break;
+
+ case kCeilingVent:
+ case kCeilingBlower:
+ *direction = kBelow;
+ *dist = thisRoom->objects[objActive].data.a.distance;
+ return (true);
+ break;
+
+ case kLeftFan:
+ *direction = kToLeft;
+ *dist = thisRoom->objects[objActive].data.a.distance;
+ return (true);
+ break;
+
+ case kRightFan:
+ *direction = kToRight;
+ *dist = thisRoom->objects[objActive].data.a.distance;
+ return (true);
+ break;
+
+ case kInvisBlower:
+ switch (thisRoom->objects[objActive].data.a.vector & 0x0F)
+ {
+ case 1: // up
+ *direction = kAbove;
+ break;
+
+ case 2: // right
+ *direction = kToRight;
+ break;
+
+ case 4: // down
+ *direction = kBelow;
+ break;
+
+ case 8: // left
+ *direction = kToLeft;
+ break;
+ }
+ *dist = thisRoom->objects[objActive].data.a.distance;
+ return (true);
+ break;
+
+ case kTable:
+ case kShelf:
+ case kDeckTable:
+ *direction = kToRight;
+ *dist = 0;
+ return (true);
+ break;
+
+ case kLiftArea:
+ case kCabinet:
+ case kInvisObstacle:
+ case kInvisBounce:
+ case kMirror:
+ case kWallWindow:
+ *direction = kBottomCorner;
+ *dist = 0;
+ return (true);
+ break;
+
+ case kCounter:
+ case kDresser:
+ *direction = kTopCorner;
+ *dist = 0;
+ return (true);
+ break;
+
+ case kGreaseRt:
+ *direction = kToRight;
+ *dist = thisRoom->objects[objActive].data.c.length;
+ return (true);
+ break;
+
+ case kGreaseLf:
+ *direction = kToLeft;
+ *dist = thisRoom->objects[objActive].data.c.length;
+ return (true);
+ break;
+
+ case kSlider:
+ *direction = kToRight;
+ *dist = 0;
+ return (true);
+ break;
+
+ case kInvisTrans:
+ case kDeluxeTrans:
+ *direction = kBottomCorner;
+ *dist = 0;
+ return (true);
+ break;
+
+ case kFlourescent:
+ case kTrackLight:
+ *direction = kToRight;
+ *dist = 0;
+ return (true);
+ break;
+
+ case kToaster:
+ *direction = kAbove;
+ *dist = thisRoom->objects[objActive].data.g.height;
+ return (true);
+ break;
+
+ case kBall:
+ case kFish:
+ *direction = kAbove;
+ *dist = thisRoom->objects[objActive].data.h.length;
+ return (true);
+ break;
+
+ case kDrip:
+ *direction = kBelow;
+ *dist = thisRoom->objects[objActive].data.h.length;
+ return (true);
+ break;
+
+ default:
+ return (false);
+ break;
+ }
+}
+#endif
+
+//-------------------------------------------------------------- ObjectIsUpBlower
+
+Boolean ObjectIsUpBlower (objectType *who)
+{
+ if ((who->what == kFloorVent) || (who->what == kFloorBlower) ||
+ (who->what == kSewerGrate) || (who->what == kTaper) ||
+ (who->what == kCandle) || (who->what == kStubby) ||
+ (who->what == kTiki) || (who->what == kBBQ) ||
+ (who->what == kGrecoVent) || (who->what == kSewerBlower))
+ return (true);
+ else if ((who->what == kInvisBlower) || (who->what == kLiftArea))
+ {
+ if ((who->data.a.vector & 0x01) == 0x01)
+ return (true);
+ else
+ return (false);
+ }
+ else
+ return (false);
+}
+
+//-------------------------------------------------------------- HandleBlowerGlider
+
+void HandleBlowerGlider (void)
+{
+#ifndef COMPILEDEMO
+ short direction, dist;
+
+ if (ObjectIsUpBlower(&thisRoom->objects[objActive]))
+ {
+ if (ObjectHasHandle(&direction, &dist))
+ {
+ SetMarqueeGliderRect(((roomObjectRects[objActive].right +
+ roomObjectRects[objActive].left) / 2),
+ roomObjectRects[objActive].top - dist);
+ }
+ }
+#endif
+}
+
+//-------------------------------------------------------------- SelectNextObject
+
+void SelectNextObject (void)
+{
+#ifndef COMPILEDEMO
+ short direction, dist;
+ Boolean noneFound;
+
+ if ((theMode != kEditMode) || (thisRoom->numObjects <= 0))
+ return;
+
+ noneFound = true;
+
+ while (noneFound)
+ {
+ objActive++;
+ if (objActive >= kMaxRoomObs)
+ objActive = 0;
+ if (thisRoom->objects[objActive].what != kObjectIsEmpty)
+ noneFound = false;
+ }
+
+ UpdateMenus(false);
+ if (ObjectHasHandle(&direction, &dist))
+ {
+ StartMarqueeHandled(&roomObjectRects[objActive], direction, dist);
+ HandleBlowerGlider();
+ }
+ else
+ StartMarquee(&roomObjectRects[objActive]);
+#endif
+}
+
+//-------------------------------------------------------------- SelectPrevObject
+
+void SelectPrevObject (void)
+{
+#ifndef COMPILEDEMO
+ short direction, dist;
+ Boolean noneFound;
+
+ if ((theMode != kEditMode) || (thisRoom->numObjects <= 0))
+ return;
+
+ noneFound = true;
+
+ while (noneFound)
+ {
+ objActive--;
+ if (objActive < 0)
+ objActive = kMaxRoomObs - 1;
+ if (thisRoom->objects[objActive].what != kObjectIsEmpty)
+ noneFound = false;
+ }
+
+ UpdateMenus(false);
+ if (ObjectHasHandle(&direction, &dist))
+ {
+ StartMarqueeHandled(&roomObjectRects[objActive], direction, dist);
+ HandleBlowerGlider();
+ }
+ else
+ StartMarquee(&roomObjectRects[objActive]);
+#endif
+}
+
+//-------------------------------------------------------------- GetThisRoomsObjRects
+
+#ifndef COMPILEDEMO
+void GetThisRoomsObjRects (void)
+{
+ PicHandle thePict;
+ short i, wide, tall;
+
+ isFirstRoom = (GetFirstRoomNumber() == thisRoomNumber);
+
+ if ((isFirstRoom) && (!noRoomAtAll) && (houseUnlocked))
+ WhereDoesGliderBegin(&initialGliderRect, kNewGameMode);
+ else
+ QSetRect(&initialGliderRect, 0, 0, 0, 0);
+
+ QSetRect(&leftStartGliderDest, 0, 0, 48, 16);
+ QOffsetRect(&leftStartGliderDest, 0,
+ kGliderStartsDown + (short)thisRoom->leftStart);
+
+ QSetRect(&rightStartGliderDest, 0, 0, 48, 16);
+ QOffsetRect(&rightStartGliderDest, kRoomWide - 48,
+ kGliderStartsDown + (short)thisRoom->rightStart);
+
+ if ((noRoomAtAll) || (!houseUnlocked))
+ {
+ return;
+ }
+ else
+ {
+ for (i = 0; i < kMaxRoomObs; i++)
+ {
+ switch (thisRoom->objects[i].what)
+ {
+ case kObjectIsEmpty:
+ QSetRect(&roomObjectRects[i], -2, -2, -1, -1);
+ 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:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.a.topLeft.h,
+ thisRoom->objects[i].data.a.topLeft.v);
+ break;
+
+ case kLiftArea:
+ QSetRect(&roomObjectRects[i], 0, 0,
+ thisRoom->objects[i].data.a.distance,
+ thisRoom->objects[i].data.a.tall * 2);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.a.topLeft.h,
+ thisRoom->objects[i].data.a.topLeft.v);
+ 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:
+ roomObjectRects[i] = thisRoom->objects[i].data.b.bounds;
+ break;
+
+ case kRedClock:
+ case kBlueClock:
+ case kYellowClock:
+ case kCuckoo:
+ case kPaper:
+ case kBattery:
+ case kBands:
+ case kFoil:
+ case kInvisBonus:
+ case kStar:
+ case kSparkle:
+ case kHelium:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.c.topLeft.h,
+ thisRoom->objects[i].data.c.topLeft.v);
+ break;
+
+ case kGreaseRt:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.c.topLeft.h,
+ thisRoom->objects[i].data.c.topLeft.v);
+ if (!thisRoom->objects[i].data.c.initial)
+ QOffsetRect(&roomObjectRects[i], 8, 0);
+ break;
+
+ case kGreaseLf:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.c.topLeft.h,
+ thisRoom->objects[i].data.c.topLeft.v);
+ if (!thisRoom->objects[i].data.c.initial)
+ QOffsetRect(&roomObjectRects[i], -8, 0);
+ break;
+
+ case kSlider:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.c.topLeft.h,
+ thisRoom->objects[i].data.c.topLeft.v);
+ roomObjectRects[i].right = roomObjectRects[i].left +
+ thisRoom->objects[i].data.c.length;
+ 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:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.d.topLeft.h,
+ thisRoom->objects[i].data.d.topLeft.v);
+ break;
+
+ case kInvisTrans:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.d.topLeft.h,
+ thisRoom->objects[i].data.d.topLeft.v);
+ roomObjectRects[i].bottom = roomObjectRects[i].top +
+ thisRoom->objects[i].data.d.tall;
+ roomObjectRects[i].right += (short)thisRoom->objects[i].data.d.wide;
+ break;
+
+ case kDeluxeTrans: // Uses a kludge to get width & height (x4)
+ wide = (thisRoom->objects[i].data.d.tall & 0xFF00) >> 8;
+ tall = thisRoom->objects[i].data.d.tall & 0x00FF;
+ QSetRect(&roomObjectRects[i], 0, 0, wide * 4, tall * 4);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.d.topLeft.h,
+ thisRoom->objects[i].data.d.topLeft.v);
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ case kSoundTrigger:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.e.topLeft.h,
+ thisRoom->objects[i].data.e.topLeft.v);
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ case kHipLamp:
+ case kDecoLamp:
+ case kInvisLight:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.f.topLeft.h,
+ thisRoom->objects[i].data.f.topLeft.v);
+ break;
+
+ case kFlourescent:
+ case kTrackLight:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ roomObjectRects[i].right = thisRoom->objects[i].data.f.length;
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.f.topLeft.h,
+ thisRoom->objects[i].data.f.topLeft.v);
+ 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:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.g.topLeft.h,
+ thisRoom->objects[i].data.g.topLeft.v);
+ break;
+
+ case kCustomPict:
+ thePict = GetPicture(thisRoom->objects[i].data.g.height);
+ if (thePict == nil)
+ {
+ thisRoom->objects[i].data.g.height = 10000;
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ }
+ else
+ {
+ HLock((Handle)thePict);
+ roomObjectRects[i] = (*thePict)->picFrame;
+ HUnlock((Handle)thePict);
+ }
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.g.topLeft.h,
+ thisRoom->objects[i].data.g.topLeft.v);
+ break;
+
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kDartLf:
+ case kDartRt:
+ case kBall:
+ case kDrip:
+ case kFish:
+ case kCobweb:
+ roomObjectRects[i] = srcRects[thisRoom->objects[i].what];
+ ZeroRectCorner(&roomObjectRects[i]);
+ QOffsetRect(&roomObjectRects[i],
+ thisRoom->objects[i].data.h.topLeft.h,
+ thisRoom->objects[i].data.h.topLeft.v);
+ 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:
+ roomObjectRects[i] = thisRoom->objects[i].data.i.bounds;
+ break;
+
+ default:
+ QSetRect(&roomObjectRects[i], -2, -2, -1, -1);
+ break;
+
+ }
+ }
+ }
+}
+#endif
+
+//-------------------------------------------------------------- DrawThisRoomsObjects
+
+#ifndef COMPILEDEMO
+void DrawThisRoomsObjects (void)
+{
+ Rect tempRect;
+ short i;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ Pattern dummyPattern;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ if ((noRoomAtAll) || (!houseUnlocked))
+ return;
+ else
+ {
+ if (GetNumberOfLights(thisRoomNumber) <= 0)
+ {
+ PenMode(srcOr);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ PaintRect(&backSrcRect);
+ PenNormal();
+ }
+
+ for (i = 0; i < kMaxRoomObs; i++)
+ {
+ switch (thisRoom->objects[i].what)
+ {
+ case kObjectIsEmpty:
+ break;
+
+ case kFloorVent:
+ case kCeilingVent:
+ case kFloorBlower:
+ case kCeilingBlower:
+ case kSewerGrate:
+ case kLeftFan:
+ case kRightFan:
+ case kTaper:
+ case kCandle:
+ case kStubby:
+ case kGrecoVent:
+ case kSewerBlower:
+ DrawSimpleBlowers(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kTiki:
+ DrawTiki(&roomObjectRects[i], 0);
+ break;
+
+ case kInvisBlower:
+ DrawInvisibleBlower(&roomObjectRects[i]);
+ break;
+
+ case kLiftArea:
+ DrawLiftArea(&roomObjectRects[i]);
+ break;
+
+ case kTable:
+ DrawTable(&roomObjectRects[i], 0);
+ break;
+
+ case kShelf:
+ DrawShelf(&roomObjectRects[i]);
+ break;
+
+ case kCabinet:
+ DrawCabinet(&roomObjectRects[i]);
+ break;
+
+ case kFilingCabinet:
+ case kDownStairs:
+ case kDoorExRt:
+ case kDoorExLf:
+ case kWindowExRt:
+ case kWindowExLf:
+ case kOzma:
+ DrawPictObject(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kWasteBasket:
+ case kMilkCrate:
+ DrawSimpleFurniture(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kCounter:
+ DrawCounter(&roomObjectRects[i]);
+ break;
+
+ case kDresser:
+ DrawDresser(&roomObjectRects[i]);
+ break;
+
+ case kDeckTable:
+ DrawDeckTable(&roomObjectRects[i], 0);
+ break;
+
+ case kStool:
+ DrawStool(&roomObjectRects[i], 0);
+ break;
+
+ case kInvisObstacle:
+ DrawInvisObstacle(&roomObjectRects[i]);
+ break;
+
+ case kInvisBounce:
+ DrawInvisBounce(&roomObjectRects[i]);
+ break;
+
+ case kRedClock:
+ DrawRedClock(&roomObjectRects[i]);
+ break;
+
+ case kBlueClock:
+ DrawBlueClock(&roomObjectRects[i]);
+ break;
+
+ case kYellowClock:
+ DrawYellowClock(&roomObjectRects[i]);
+ break;
+
+ case kCuckoo:
+ DrawCuckoo(&roomObjectRects[i]);
+ break;
+
+ case kPaper:
+ case kBattery:
+ case kBands:
+ case kStar:
+ case kSparkle:
+ case kHelium:
+ DrawSimplePrizes(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kGreaseRt:
+ tempRect = roomObjectRects[i];
+ if (!thisRoom->objects[i].data.c.initial)
+ QOffsetRect(&tempRect, -8, 0);
+ DrawGreaseRt(&tempRect, thisRoom->objects[i].data.c.length,
+ thisRoom->objects[i].data.c.initial);
+ break;
+
+ case kGreaseLf:
+ tempRect = roomObjectRects[i];
+ if (!thisRoom->objects[i].data.c.initial)
+ QOffsetRect(&tempRect, 8, 0);
+ DrawGreaseLf(&tempRect, thisRoom->objects[i].data.c.length,
+ thisRoom->objects[i].data.c.initial);
+ break;
+
+ case kFoil:
+ DrawFoil(&roomObjectRects[i]);
+ break;
+
+ case kInvisBonus:
+ DrawInvisBonus(&roomObjectRects[i]);
+ break;
+
+ case kSlider:
+ DrawSlider(&roomObjectRects[i]);
+ break;
+
+ case kBBQ:
+ case kTrunk:
+ case kManhole:
+ case kBooks:
+ case kUpStairs:
+ case kDoorInLf:
+ case kDoorInRt:
+ case kWindowInLf:
+ case kWindowInRt:
+ case kHipLamp:
+ case kDecoLamp:
+ case kGuitar:
+ case kCinderBlock:
+ case kFlowerBox:
+ case kFireplace:
+ case kBear:
+ case kVase1:
+ case kVase2:
+ case kRug:
+ case kChimes:
+ DrawPictSansWhiteObject(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kCustomPict:
+ DrawCustPictSansWhite(thisRoom->objects[i].data.g.height,
+ &roomObjectRects[i]);
+ break;
+
+ case kMailboxLf:
+ DrawMailboxLeft(&roomObjectRects[i], 0);
+ break;
+
+ case kMailboxRt:
+ DrawMailboxRight(&roomObjectRects[i], 0);
+ break;
+
+ case kFloorTrans:
+ case kCeilingTrans:
+ DrawSimpleTransport(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kInvisTrans:
+ case kDeluxeTrans:
+ DrawInvisTransport(&roomObjectRects[i]);
+ break;
+
+ case kLightSwitch:
+ DrawLightSwitch(&roomObjectRects[i], true);
+ break;
+
+ case kMachineSwitch:
+ DrawMachineSwitch(&roomObjectRects[i], true);
+ break;
+
+ case kThermostat:
+ DrawThermostat(&roomObjectRects[i], true);
+ break;
+
+ case kPowerSwitch:
+ DrawPowerSwitch(&roomObjectRects[i], true);
+ break;
+
+ case kKnifeSwitch:
+ DrawKnifeSwitch(&roomObjectRects[i], true);
+ break;
+
+ case kInvisSwitch:
+ DrawInvisibleSwitch(&roomObjectRects[i]);
+ break;
+
+ case kTrigger:
+ case kLgTrigger:
+ DrawTrigger(&roomObjectRects[i]);
+ break;
+
+ case kSoundTrigger:
+ DrawSoundTrigger(&roomObjectRects[i]);
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ DrawSimpleLight(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kFlourescent:
+ DrawFlourescent(&roomObjectRects[i]);
+ break;
+
+ case kTrackLight:
+ DrawTrackLight(&roomObjectRects[i]);
+ break;
+
+ case kInvisLight:
+ DrawInvisLight(&roomObjectRects[i]);
+ break;
+
+ case kShredder:
+ case kToaster:
+ case kCDs:
+ DrawSimpleAppliance(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kMacPlus:
+ DrawMacPlus(&roomObjectRects[i],
+ thisRoom->objects[i].data.g.initial, true);
+ break;
+
+ case kTV:
+ DrawTV(&roomObjectRects[i],
+ thisRoom->objects[i].data.g.initial, true);
+ break;
+
+ case kCoffee:
+ DrawCoffee(&roomObjectRects[i],
+ thisRoom->objects[i].data.g.initial, true);
+ break;
+
+ case kOutlet:
+ DrawOutlet(&roomObjectRects[i]);
+ break;
+
+ case kVCR:
+ DrawVCR(&roomObjectRects[i],
+ thisRoom->objects[i].data.g.initial, true);
+ break;
+
+ case kStereo:
+ DrawStereo(&roomObjectRects[i], isPlayMusicGame, true);
+ break;
+
+ case kMicrowave:
+ DrawMicrowave(&roomObjectRects[i],
+ thisRoom->objects[i].data.g.initial, true);
+ break;
+
+ case kBalloon:
+ DrawBalloon(&roomObjectRects[i]);
+ break;
+
+ case kCopterLf:
+ case kCopterRt:
+ DrawCopter(&roomObjectRects[i]);
+ break;
+
+ case kDartLf:
+ case kDartRt:
+ DrawDart(&roomObjectRects[i], thisRoom->objects[i].what);
+ break;
+
+ case kBall:
+ DrawBall(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kDrip:
+ DrawDrip(&roomObjectRects[i]);
+ break;
+
+ case kFish:
+ DrawFish(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kCobweb:
+ case kCloud:
+ DrawPictWithMaskObject(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kMirror:
+ DrawMirror(&roomObjectRects[i]);
+ break;
+
+ case kMousehole:
+ case kFaucet:
+ DrawSimpleClutter(thisRoom->objects[i].what, &roomObjectRects[i]);
+ break;
+
+ case kFlower:
+ DrawFlower(&roomObjectRects[i], thisRoom->objects[i].data.i.pict);
+ break;
+
+ case kWallWindow:
+ DrawWallWindow(&roomObjectRects[i]);
+ break;
+
+ case kCalendar:
+ DrawCalendar(&roomObjectRects[i]);
+ break;
+
+ case kBulletin:
+ DrawBulletin(&roomObjectRects[i]);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+
+ if (isFirstRoom)
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(glidSrcMap),
+ (BitMap *)*GetGWorldPixMap(glidMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &gliderSrc[0], &gliderSrc[0], &initialGliderRect);
+ }
+
+ CopyMask((BitMap *)*GetGWorldPixMap(blowerSrcMap),
+ (BitMap *)*GetGWorldPixMap(blowerMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &leftStartGliderSrc, &leftStartGliderSrc, &leftStartGliderDest);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(blowerSrcMap),
+ (BitMap *)*GetGWorldPixMap(blowerMaskMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &rightStartGliderSrc, &rightStartGliderSrc, &rightStartGliderDest);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &backSrcRect, &backSrcRect, srcCopy, nil);
+}
+#endif
+
+//-------------------------------------------------------------- HiliteAllObjects
+
+void HiliteAllObjects (void)
+{
+#ifndef COMPILEDEMO
+ KeyMap theseKeys;
+ short i;
+ Pattern dummyPattern;
+
+ if (theMode != kEditMode)
+ return;
+
+ PauseMarquee();
+ SetPort((GrafPtr)mainWindow);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ PenMode(patXor);
+
+ for (i = 0; i < kMaxRoomObs; i++)
+ FrameRect(&roomObjectRects[i]);
+
+ do
+ {
+ GetKeys(theseKeys);
+ }
+ while ((BitTst(&theseKeys, kCommandKeyMap)) &&
+ (BitTst(&theseKeys, kOptionKeyMap)));
+
+ for (i = 0; i < kMaxRoomObs; i++)
+ FrameRect(&roomObjectRects[i]);
+
+ PenNormal();
+ ResumeMarquee();
+#endif
+}
+
+//-------------------------------------------------------------- GoToObjectInRoom
+
+void GoToObjectInRoom (short object, short floor, short suite)
+{
+ #ifndef COMPILEDEMO
+ short itsNumber, direction, dist;
+
+ if (RoomExists(suite, floor, &itsNumber))
+ {
+ if (itsNumber != thisRoomNumber)
+ {
+ CopyRoomToThisRoom(itsNumber);
+ DeselectObject();
+ ReflectCurrentRoom(false);
+ }
+ else
+ DeselectObject();
+
+ if (thisRoom->objects[object].what != kObjectIsEmpty)
+ {
+ objActive = object;
+ if (ObjectHasHandle(&direction, &dist))
+ {
+ StartMarqueeHandled(&roomObjectRects[objActive], direction, dist);
+ HandleBlowerGlider();
+ }
+ else
+ StartMarquee(&roomObjectRects[objActive]);
+ UpdateMenus(false);
+ }
+ }
+ #endif
+}
+
+//-------------------------------------------------------------- GoToObjectInRoomNum
+
+void GoToObjectInRoomNum (short object, short roomNum)
+{
+ short floor, suite;
+
+ if (GetRoomFloorSuite(roomNum, &floor, &suite))
+ GoToObjectInRoom(object, floor, suite);
+}
+
diff --git a/GpApp/ObjectEdit.h b/GpApp/ObjectEdit.h
new file mode 100644
index 0000000..5d29758
--- /dev/null
+++ b/GpApp/ObjectEdit.h
@@ -0,0 +1,15 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// ObjectEdit.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#pragma once
+
+
+#include "PLQuickdraw.h"
+
+
+extern Rect roomObjectRects[];
+extern short objActive;
diff --git a/GpApp/ObjectInfo.cpp b/GpApp/ObjectInfo.cpp
new file mode 100644
index 0000000..cfe09b4
--- /dev/null
+++ b/GpApp/ObjectInfo.cpp
@@ -0,0 +1,2568 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// ObjectInfo.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLNumberFormatting.h"
+#include "PLSound.h"
+#include "PLTextUtils.h"
+#include "PLPasStr.h"
+#include "DialogUtils.h"
+#include "Externs.h"
+#include "ObjectEdit.h"
+#include "RectUtils.h"
+
+
+#define kBlowerInfoDialogID 1007
+#define kFurnitureInfoDialogID 1010
+#define kSwitchInfoDialogID 1011
+#define kLightInfoDialogID 1013
+#define kApplianceInfoDialogID 1014
+#define kInvisBonusInfoDialogID 1015
+#define kGreaseInfoDialogID 1019
+#define kTransInfoDialogID 1022
+#define kEnemyInfoDialogID 1027
+#define kFlowerInfoDialogID 1033
+#define kTriggerInfoDialogID 1034
+#define kMicrowaveInfoDialogID 1035
+#define kCustPictInfoDialogID 1045
+#define kCustPictIDItem 7
+#define kInitialStateCheckbox 6
+#define kForceCheckbox 7
+#define kDirectionText 9
+#define kLeftFacingRadio 16
+#define kRightFacingRadio 17
+#define kToggleRadio 6
+#define kForceOnRadio 7
+#define kForceOffRadio 8
+#define kDelay3Item 6
+#define kDelayItem 8
+#define kDelayLabelItem 9
+#define k100PtRadio 6
+#define k300PtRadio 7
+#define k500PtRadio 8
+#define kGreaseItem 6
+#define kLinkTransButton 6
+#define kInitialStateCheckbox3 13
+#define kTransRoomText 8
+#define kTransObjectText 9
+#define kKillBandsCheckbox 8
+#define kKillBatteryCheckbox 9
+#define kKillFoilCheckbox 10
+#define kDelay2Item 7
+#define kDelay2LabelItem 8
+#define kDelay2LabelItem2 9
+#define kInitialStateCheckbox2 10
+#define kRadioFlower1 6
+#define kRadioFlower6 11
+#define kFlowerCancel 12
+#define kGotoButton1 11
+#define kGotoButton2 14
+
+
+void UpdateBlowerInfo (DialogPtr);
+void UpdateFurnitureInfo (DialogPtr);
+void UpdateCustPictInfo (DialogPtr);
+void UpdateSwitchInfo (DialogPtr);
+void UpdateTriggerInfo (DialogPtr);
+void UpdateLightInfo (DialogPtr);
+void UpdateApplianceInfo (DialogPtr);
+void UpdateMicrowaveInfo (DialogPtr);
+void UpdateGreaseInfo (DialogPtr);
+void UpdateInvisBonusInfo (DialogPtr);
+void UpdateTransInfo (DialogPtr);
+void UpdateEnemyInfo (DialogPtr);
+void UpdateFlowerInfo (DialogPtr);
+Boolean BlowerFilter (DialogPtr, EventRecord *, short *);
+Boolean FurnitureFilter (DialogPtr, EventRecord *, short *);
+Boolean CustPictFilter (DialogPtr, EventRecord *, short *);
+Boolean SwitchFilter (DialogPtr, EventRecord *, short *);
+Boolean TriggerFilter (DialogPtr, EventRecord *, short *);
+Boolean LightFilter (DialogPtr, EventRecord *, short *);
+Boolean ApplianceFilter (DialogPtr, EventRecord *, short *);
+Boolean MicrowaveFilter (DialogPtr, EventRecord *, short *);
+Boolean GreaseFilter (DialogPtr, EventRecord *, short *);
+Boolean InvisBonusFilter (DialogPtr, EventRecord *, short *);
+Boolean TransFilter (DialogPtr, EventRecord *, short *);
+Boolean EnemyFilter (DialogPtr, EventRecord *, short *);
+Boolean FlowerFilter (DialogPtr, EventRecord *, short *);
+void DoBlowerObjectInfo (short);
+void DoFurnitureObjectInfo (void);
+void DoCustPictObjectInfo (void);
+void DoSwitchObjectInfo (void);
+void DoTriggerObjectInfo (void);
+void DoLightObjectInfo (void);
+void DoApplianceObjectInfo (short);
+void DoMicrowaveObjectInfo (void);
+void DoGreaseObjectInfo (void);
+void DoInvisBonusObjectInfo (void);
+void DoTransObjectInfo (short);
+void DoEnemyObjectInfo (short);
+void DoFlowerObjectInfo (void);
+
+
+short newDirection, newPoint;
+Byte newType;
+
+extern retroLink retroLinkList[];
+extern short linkRoom, linkType, wasFlower;
+extern Byte linkObject;
+extern Boolean linkerIsSwitch;
+
+
+#ifndef COMPILEDEMO
+
+//============================================================== Functions
+//-------------------------------------------------------------- UpdateBlowerInfo
+
+void UpdateBlowerInfo (DialogPtr theDialog)
+{
+ #define kArrowheadLength 4
+ Rect bounds;
+
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 5, kRedOrangeColor8);
+
+ if ((thisRoom->objects[objActive].what != kLeftFan) &&
+ (thisRoom->objects[objActive].what != kRightFan))
+ {
+ GetDialogItemRect(theDialog, 8, &bounds);
+ bounds.right += 2;
+ bounds.bottom += 2;
+ EraseRect(&bounds);
+ bounds.right -= 2;
+ bounds.bottom -= 2;
+ PenSize(2, 2);
+
+ switch (newDirection)
+ {
+ case 1: // up
+ MoveTo(bounds.left + HalfRectWide(&bounds), bounds.top);
+ Line(0, RectTall(&bounds));
+ MoveTo(bounds.left + HalfRectWide(&bounds), bounds.top);
+ Line(kArrowheadLength, kArrowheadLength);
+ MoveTo(bounds.left + HalfRectWide(&bounds), bounds.top);
+ Line(-kArrowheadLength, kArrowheadLength);
+ break;
+
+ case 2: // right
+ MoveTo(bounds.right, bounds.top + HalfRectTall(&bounds));
+ Line(-RectWide(&bounds), 0);
+ MoveTo(bounds.right, bounds.top + HalfRectTall(&bounds));
+ Line(-kArrowheadLength, kArrowheadLength);
+ MoveTo(bounds.right, bounds.top + HalfRectTall(&bounds));
+ Line(-kArrowheadLength, -kArrowheadLength);
+ break;
+
+ case 4: // down
+ MoveTo(bounds.left + HalfRectWide(&bounds), bounds.top);
+ Line(0, RectTall(&bounds));
+ MoveTo(bounds.left + HalfRectWide(&bounds), bounds.bottom);
+ Line(kArrowheadLength, -kArrowheadLength);
+ MoveTo(bounds.left + HalfRectWide(&bounds), bounds.bottom);
+ Line(-kArrowheadLength, -kArrowheadLength);
+ break;
+
+ case 8: // left
+ MoveTo(bounds.left, bounds.top + HalfRectTall(&bounds));
+ Line(RectWide(&bounds), 0);
+ MoveTo(bounds.left, bounds.top + HalfRectTall(&bounds));
+ Line(kArrowheadLength, -kArrowheadLength);
+ MoveTo(bounds.left, bounds.top + HalfRectTall(&bounds));
+ Line(kArrowheadLength, kArrowheadLength);
+ break;
+
+ default:
+ break;
+ }
+
+ PenNormal();
+
+ if ((thisRoom->objects[objActive].what == kInvisBlower) ||
+ (thisRoom->objects[objActive].what == kLiftArea))
+ {
+ switch (newDirection)
+ {
+ case 1: // up
+ EraseDialogItem(theDialog, 11);
+ FrameOvalDialogItem(theDialog, 12);
+ FrameOvalDialogItem(theDialog, 13);
+ FrameOvalDialogItem(theDialog, 14);
+ break;
+
+ case 2: // right
+ FrameOvalDialogItem(theDialog, 11);
+ EraseDialogItem(theDialog, 12);
+ FrameOvalDialogItem(theDialog, 13);
+ FrameOvalDialogItem(theDialog, 14);
+ break;
+
+ case 4: // down
+ FrameOvalDialogItem(theDialog, 11);
+ FrameOvalDialogItem(theDialog, 12);
+ EraseDialogItem(theDialog, 13);
+ FrameOvalDialogItem(theDialog, 14);
+ break;
+
+ case 8: // left
+ FrameOvalDialogItem(theDialog, 11);
+ FrameOvalDialogItem(theDialog, 12);
+ FrameOvalDialogItem(theDialog, 13);
+ EraseDialogItem(theDialog, 14);
+ break;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- UpdateFurnitureInfo
+
+void UpdateFurnitureInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 4, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateCustPictInfo
+
+void UpdateCustPictInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 5, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateSwitchInfo
+
+void UpdateSwitchInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ SelectFromRadioGroup(theDialog, newType + kToggleRadio,
+ kToggleRadio, kForceOffRadio);
+ FrameDialogItemC(theDialog, 4, kRedOrangeColor8);
+ FrameDialogItemC(theDialog, 13, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateTriggerInfo
+
+void UpdateTriggerInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 4, kRedOrangeColor8);
+ FrameDialogItemC(theDialog, 13, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateLightInfo
+
+void UpdateLightInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 5, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateApplianceInfo
+
+void UpdateApplianceInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 5, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateMicrowaveInfo
+
+void UpdateMicrowaveInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 5, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateGreaseInfo
+
+void UpdateGreaseInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 5, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateInvisBonusInfo
+
+void UpdateInvisBonusInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ SelectFromRadioGroup(theDialog, newPoint + k100PtRadio,
+ k100PtRadio, k500PtRadio);
+ FrameDialogItemC(theDialog, 4, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateTransInfo
+
+void UpdateTransInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 4, kRedOrangeColor8);
+ FrameDialogItemC(theDialog, 10, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateEnemyInfo
+
+void UpdateEnemyInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 4, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- UpdateFlowerInfo
+
+void UpdateFlowerInfo (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+ FrameDialogItemC(theDialog, 4, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- BlowerFilter
+
+Boolean BlowerFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ case kTabKeyASCII:
+// SelectDialogItemText(dial, kRoomNameItem, 0, 1024);
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case mouseUp:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateBlowerInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- FurnitureFilter
+
+Boolean FurnitureFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateFurnitureInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- CustPictFilter
+
+Boolean CustPictFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateCustPictInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- SwitchFilter
+
+Boolean SwitchFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateSwitchInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- TriggerFilter
+
+Boolean TriggerFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ case kTabKeyASCII:
+ SelectDialogItemText(dial, kDelay3Item, 0, 1024);
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateTriggerInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- LightFilter
+
+Boolean LightFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case mouseUp:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateLightInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- ApplianceFilter
+
+Boolean ApplianceFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ case kTabKeyASCII:
+ SelectDialogItemText(dial, kDelayItem, 0, 1024);
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case mouseUp:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateApplianceInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- MicrowaveFilter
+
+Boolean MicrowaveFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case mouseUp:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateMicrowaveInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- GreaseFilter
+
+Boolean GreaseFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateGreaseInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- InvisBonusFilter
+
+Boolean InvisBonusFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateInvisBonusInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- TransFilter
+
+Boolean TransFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateTransInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- EnemyFilter
+
+Boolean EnemyFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ case kTabKeyASCII:
+ SelectDialogItemText(dial, kDelay2Item, 0, 1024);
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case mouseUp:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateEnemyInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- EnemyFilter
+
+Boolean FlowerFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case mouseUp:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateFlowerInfo(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoBlowerObjectInfo
+
+void DoBlowerObjectInfo (short what)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr, distStr;
+ short item, initial;
+ Boolean leaving, doReturn, leftFacing;
+ ModalFilterUPP blowerFilterUPP;
+
+ blowerFilterUPP = NewModalFilterUPP(BlowerFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ NumToString(thisRoom->objects[objActive].data.a.distance, distStr);
+ ParamText(numberStr, kindStr, distStr, PSTR(""));
+
+// CenterDialog(kBlowerInfoDialogID);
+ infoDial = GetNewDialog(kBlowerInfoDialogID, nil, kPutInFront);
+ if (infoDial == nil)
+ RedAlert(kErrDialogDidntLoad);
+ SetPort((GrafPtr)infoDial);
+
+ newDirection = thisRoom->objects[objActive].data.a.vector & 0x0F;
+ if (thisRoom->objects[objActive].data.a.initial)
+ SetDialogItemValue(infoDial, kInitialStateCheckbox, 1);
+ else
+ SetDialogItemValue(infoDial, kInitialStateCheckbox, 0);
+
+ if ((what == kTaper) || (what == kCandle) || (what == kStubby) ||
+ (what == kTiki) || (what == kBBQ))
+ {
+ HideDialogItem(infoDial, kInitialStateCheckbox);
+ }
+
+ if ((what == kLeftFan) || (what == kRightFan))
+ {
+ if (what == kLeftFan)
+ {
+ SelectFromRadioGroup(infoDial, kLeftFacingRadio,
+ kLeftFacingRadio, kRightFacingRadio);
+ leftFacing = true;
+ }
+ else
+ {
+ SelectFromRadioGroup(infoDial, kRightFacingRadio,
+ kLeftFacingRadio, kRightFacingRadio);
+ leftFacing = false;
+ }
+ HideDialogItem(infoDial, kDirectionText);
+ }
+ else
+ {
+ HideDialogItem(infoDial, kLeftFacingRadio);
+ HideDialogItem(infoDial, kRightFacingRadio);
+ }
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 15);
+
+ ShowWindow(GetDialogWindow(infoDial));
+
+ leaving = false;
+ doReturn = false;
+
+ while (!leaving)
+ {
+ ModalDialog(blowerFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogItemValue(infoDial, kInitialStateCheckbox, &initial);
+ if (initial == 1)
+ thisRoom->objects[objActive].data.a.initial = true;
+ else
+ thisRoom->objects[objActive].data.a.initial = false;
+ thisRoom->objects[objActive].data.a.vector = (Byte)newDirection;
+ if ((what == kLeftFan) || (what == kRightFan))
+ {
+ if (leftFacing)
+ thisRoom->objects[objActive].what = kLeftFan;
+ else
+ thisRoom->objects[objActive].what = kRightFan;
+ if (KeepObjectLegal())
+ {
+ }
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ }
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ }
+ else if (item == kCancelButton)
+ leaving = true;
+ else if (item == kInitialStateCheckbox)
+ ToggleDialogItemValue(infoDial, kInitialStateCheckbox);
+ else if (item == 15) // Linked From? button.
+ {
+ GetDialogItemValue(infoDial, kInitialStateCheckbox, &initial);
+ if (initial == 1)
+ thisRoom->objects[objActive].data.a.initial = true;
+ else
+ thisRoom->objects[objActive].data.a.initial = false;
+ thisRoom->objects[objActive].data.a.vector = (Byte)newDirection;
+ if ((what == kLeftFan) || (what == kRightFan))
+ {
+ if (leftFacing)
+ thisRoom->objects[objActive].what = kLeftFan;
+ else
+ thisRoom->objects[objActive].what = kRightFan;
+ if (KeepObjectLegal())
+ {
+ }
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ }
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doReturn = true;
+ }
+ else if (item == kLeftFacingRadio)
+ {
+ leftFacing = true;
+ SelectFromRadioGroup(infoDial, kLeftFacingRadio, kLeftFacingRadio,
+ kRightFacingRadio);
+ }
+ else if (item == kRightFacingRadio)
+ {
+ leftFacing = false;
+ SelectFromRadioGroup(infoDial, kRightFacingRadio, kLeftFacingRadio,
+ kRightFacingRadio);
+ }
+ else if ((thisRoom->objects[objActive].what == kInvisBlower) ||
+ (thisRoom->objects[objActive].what == kLiftArea))
+ {
+ switch (item)
+ {
+ case 11:
+ newDirection = 0x01;
+ break;
+
+ case 12:
+ newDirection = 0x02;
+ break;
+
+ case 13:
+ newDirection = 0x04;
+ break;
+
+ case 14:
+ newDirection = 0x08;
+ break;
+ }
+ UpdateBlowerInfo(infoDial);
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(blowerFilterUPP);
+
+ if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoFurnitureObjectInfo
+
+void DoFurnitureObjectInfo (void)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr;
+ short item;
+ Boolean leaving, doReturn;
+ ModalFilterUPP furnitureFilterUPP;
+
+ furnitureFilterUPP = NewModalFilterUPP(FurnitureFilter);
+
+ if (objActive == kInitialGliderSelected)
+ {
+ PasStringCopy(PSTR("-"), numberStr);
+ PasStringCopy(PSTR("Glider Begins"), kindStr);
+ }
+ else if (objActive == kLeftGliderSelected)
+ {
+ PasStringCopy(PSTR("-"), numberStr);
+ PasStringCopy(PSTR("New Glider (left)"), kindStr);
+ }
+ else if (objActive == kRightGliderSelected)
+ {
+ PasStringCopy(PSTR("-"), numberStr);
+ PasStringCopy(PSTR("New Glider (right)"), kindStr);
+ }
+ else
+ {
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ }
+ ParamText(numberStr, kindStr, PSTR(""), PSTR(""));
+
+ BringUpDialog(&infoDial, kFurnitureInfoDialogID);
+
+ if ((objActive < 0) || (retroLinkList[objActive].room == -1))
+ HideDialogItem(infoDial, 6);
+
+ leaving = false;
+ doReturn = false;
+
+ while (!leaving)
+ {
+ ModalDialog(furnitureFilterUPP, &item);
+
+ if (item == kOkayButton)
+ leaving = true;
+ else if (item == 6) // Linked From? button.
+ {
+ leaving = true;
+ doReturn = true;
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(furnitureFilterUPP);
+
+ if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoCustPictObjectInfo
+
+void DoCustPictObjectInfo (void)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr;
+ long wasPict;
+ short item;
+ Boolean leaving;
+ ModalFilterUPP custPictFilterUPP;
+
+ custPictFilterUPP = NewModalFilterUPP(CustPictFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ if (thisRoom->objects[objActive].what == kCustomPict)
+ ParamText(numberStr, kindStr, PSTR("PICT"), PSTR("10000"));
+ else
+ ParamText(numberStr, kindStr, PSTR("Sound"), PSTR("3000"));
+
+ BringUpDialog(&infoDial, kCustPictInfoDialogID);
+ if (thisRoom->objects[objActive].what == kCustomPict)
+ {
+ wasPict = (long)(thisRoom->objects[objActive].data.g.height);
+ SetDialogNumToStr(infoDial, kCustPictIDItem, wasPict);
+ }
+ else
+ {
+ wasPict = (long)(thisRoom->objects[objActive].data.e.where);
+ SetDialogNumToStr(infoDial, kCustPictIDItem, wasPict);
+ }
+ SelectDialogItemText(infoDial, kCustPictIDItem, 0, 1024);
+ leaving = false;
+
+ while (!leaving)
+ {
+ ModalDialog(custPictFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogNumFromStr(infoDial, kCustPictIDItem, &wasPict);
+ if (thisRoom->objects[objActive].what == kCustomPict)
+ {
+ if ((wasPict < 10000L) || (wasPict > 32767L))
+ {
+ SysBeep(1);
+ wasPict = (long)(thisRoom->objects[objActive].data.g.height);
+ SetDialogNumToStr(infoDial, kCustPictIDItem, wasPict);
+ SelectDialogItemText(infoDial, kCustPictIDItem, 0, 1024);
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.g.height = (short)wasPict;
+ if (KeepObjectLegal())
+ {
+ }
+ fileDirty = true;
+ UpdateMenus(false);
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ leaving = true;
+ }
+ }
+ else
+ {
+ if ((wasPict < 3000L) || (wasPict > 32767L))
+ {
+ SysBeep(1);
+ wasPict = (long)(thisRoom->objects[objActive].data.e.where);
+ SetDialogNumToStr(infoDial, kCustPictIDItem, wasPict);
+ SelectDialogItemText(infoDial, kCustPictIDItem, 0, 1024);
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.e.where = (short)wasPict;
+ fileDirty = true;
+ UpdateMenus(false);
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ leaving = true;
+ }
+ }
+ }
+ else if (item == kCancelButton)
+ {
+ leaving = true;
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(custPictFilterUPP);
+}
+
+//-------------------------------------------------------------- DoSwitchObjectInfo
+
+void DoSwitchObjectInfo (void)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr, roomStr, tempStr, objStr;
+ short item, floor, suite;
+ Boolean leaving, doLink, doGoTo, doReturn;
+ ModalFilterUPP switchFilterUPP;
+
+ switchFilterUPP = NewModalFilterUPP(SwitchFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ if (thisRoom->objects[objActive].data.e.where == -1)
+ PasStringCopy(PSTR("none"), roomStr);
+ else
+ {
+ ExtractFloorSuite(thisRoom->objects[objActive].data.e.where, &floor, &suite);
+ NumToString((long)floor, roomStr);
+ PasStringConcat(roomStr, PSTR(" / "));
+ NumToString((long)suite, tempStr);
+ PasStringConcat(roomStr, tempStr);
+ }
+
+ if (thisRoom->objects[objActive].data.e.who == 255)
+ PasStringCopy(PSTR("none"), objStr);
+ else
+ NumToString((long)thisRoom->objects[objActive].data.e.who + 1, objStr);
+
+ ParamText(numberStr, kindStr, roomStr, objStr);
+ newType = thisRoom->objects[objActive].data.e.type;
+
+ BringUpDialog(&infoDial, kSwitchInfoDialogID);
+ leaving = false;
+ doLink = false;
+ doGoTo = false;
+ doReturn = false;
+
+ if (thisRoom->objects[objActive].data.e.who == 255)
+ MyDisableControl(infoDial, kGotoButton2);
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 15);
+
+ while (!leaving)
+ {
+ ModalDialog(switchFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ thisRoom->objects[objActive].data.e.type = newType;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ }
+ else if (item == kCancelButton)
+ leaving = true;
+ else if (item == kToggleRadio)
+ {
+ SelectFromRadioGroup(infoDial, item, kToggleRadio, kForceOffRadio);
+ newType = kToggle;
+ }
+ else if (item == kForceOnRadio)
+ {
+ SelectFromRadioGroup(infoDial, item, kToggleRadio, kForceOffRadio);
+ newType = kForceOn;
+ }
+ else if (item == kForceOffRadio)
+ {
+ SelectFromRadioGroup(infoDial, item, kToggleRadio, kForceOffRadio);
+ newType = kForceOff;
+ }
+ else if (item == 9)
+ {
+ thisRoom->objects[objActive].data.e.type = newType;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doLink = true;
+ }
+ else if (item == kGotoButton2)
+ {
+ thisRoom->objects[objActive].data.e.type = newType;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doGoTo = true;
+ }
+ else if (item == 15) // Linked From? button.
+ {
+ thisRoom->objects[objActive].data.e.type = newType;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doReturn = true;
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(switchFilterUPP);
+
+ if (doLink)
+ {
+ linkType = kSwitchLinkOnly;
+ linkerIsSwitch = true;
+ OpenLinkWindow();
+ linkRoom = thisRoomNumber;
+ linkObject = (Byte)objActive;
+ DeselectObject();
+ }
+ else if (doGoTo)
+ {
+ GoToObjectInRoom((short)thisRoom->objects[objActive].data.e.who, floor, suite);
+ }
+ else if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoTriggerObjectInfo
+
+void DoTriggerObjectInfo (void)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr, roomStr, tempStr, objStr;
+ long delayIs;
+ short item, floor, suite;
+ Boolean leaving, doLink, doGoTo, doReturn;
+ ModalFilterUPP triggerFilterUPP;
+
+ triggerFilterUPP = NewModalFilterUPP(TriggerFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ if (thisRoom->objects[objActive].data.e.where == -1)
+ PasStringCopy(PSTR("none"), roomStr);
+ else
+ {
+ ExtractFloorSuite(thisRoom->objects[objActive].data.e.where, &floor, &suite);
+ NumToString((long)floor, roomStr);
+ PasStringConcat(roomStr, PSTR(" / "));
+ NumToString((long)suite, tempStr);
+ PasStringConcat(roomStr, tempStr);
+ }
+
+ if (thisRoom->objects[objActive].data.e.who == 255)
+ PasStringCopy(PSTR("none"), objStr);
+ else
+ NumToString((long)thisRoom->objects[objActive].data.e.who + 1, objStr);
+
+ ParamText(numberStr, kindStr, roomStr, objStr);
+ newType = thisRoom->objects[objActive].data.e.type;
+
+ BringUpDialog(&infoDial, kTriggerInfoDialogID);
+ leaving = false;
+ doLink = false;
+ doGoTo = false;
+ doReturn = false;
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 15);
+
+ if (thisRoom->objects[objActive].data.e.who == 255)
+ MyDisableControl(infoDial, kGotoButton2);
+
+ SetDialogNumToStr(infoDial, kDelay3Item,
+ (long)thisRoom->objects[objActive].data.e.delay);
+ SelectDialogItemText(infoDial, kDelay3Item, 0, 1024);
+
+ while (!leaving)
+ {
+ ModalDialog(triggerFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogNumFromStr(infoDial, kDelay3Item, &delayIs);
+ if ((delayIs < 0L) || (delayIs > 32767L))
+ {
+ SysBeep(1);
+ SetDialogNumToStr(infoDial, kDelay3Item,
+ (long)thisRoom->objects[objActive].data.e.delay);
+ SelectDialogItemText(infoDial, kDelay3Item, 0, 1024);
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.e.delay = (short)delayIs;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ }
+ }
+ else if (item == kCancelButton)
+ leaving = true;
+ else if (item == 9)
+ {
+ GetDialogNumFromStr(infoDial, kDelay3Item, &delayIs);
+ if ((delayIs < 0L) || (delayIs > 32767L))
+ {
+ SysBeep(1);
+ SetDialogNumToStr(infoDial, kDelay3Item,
+ (long)thisRoom->objects[objActive].data.e.delay);
+ SelectDialogItemText(infoDial, kDelay3Item, 0, 1024);
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.e.delay = (short)delayIs;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doLink = true;
+ }
+ }
+ else if (item == kGotoButton2)
+ {
+ GetDialogNumFromStr(infoDial, kDelay3Item, &delayIs);
+ if ((delayIs < 0L) || (delayIs > 32767L))
+ {
+ SysBeep(1);
+ SetDialogNumToStr(infoDial, kDelay3Item,
+ (long)thisRoom->objects[objActive].data.e.delay);
+ SelectDialogItemText(infoDial, kDelay3Item, 0, 1024);
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.e.delay = (short)delayIs;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doGoTo = true;
+ }
+ }
+ else if (item == 15) // Linked From? button.
+ {
+ GetDialogNumFromStr(infoDial, kDelay3Item, &delayIs);
+ if ((delayIs < 0L) || (delayIs > 32767L))
+ {
+ SysBeep(1);
+ SetDialogNumToStr(infoDial, kDelay3Item,
+ (long)thisRoom->objects[objActive].data.e.delay);
+ SelectDialogItemText(infoDial, kDelay3Item, 0, 1024);
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.e.delay = (short)delayIs;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doReturn = true;
+ }
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(triggerFilterUPP);
+
+ if (doLink)
+ {
+ linkType = kTriggerLinkOnly;
+ linkerIsSwitch = true;
+ OpenLinkWindow();
+ linkRoom = thisRoomNumber;
+ linkObject = (Byte)objActive;
+ DeselectObject();
+ }
+ else if (doGoTo)
+ {
+ GoToObjectInRoom((short)thisRoom->objects[objActive].data.e.who, floor, suite);
+ }
+ else if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoLightObjectInfo
+
+void DoLightObjectInfo (void)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr;
+ short item, initial;
+ Boolean leaving, doReturn;
+ ModalFilterUPP lightFilterUPP;
+
+ lightFilterUPP = NewModalFilterUPP(LightFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ ParamText(numberStr, kindStr, PSTR(""), PSTR(""));
+
+// CenterDialog(kLightInfoDialogID);
+ infoDial = GetNewDialog(kLightInfoDialogID, nil, kPutInFront);
+ if (infoDial == nil)
+ RedAlert(kErrDialogDidntLoad);
+ SetPort((GrafPtr)infoDial);
+
+ if (thisRoom->objects[objActive].data.f.initial)
+ SetDialogItemValue(infoDial, kInitialStateCheckbox, 1);
+ else
+ SetDialogItemValue(infoDial, kInitialStateCheckbox, 0);
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 8);
+
+ ShowWindow(GetDialogWindow(infoDial));
+
+ leaving = false;
+ doReturn = false;
+
+ while (!leaving)
+ {
+ ModalDialog(lightFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogItemValue(infoDial, kInitialStateCheckbox, &initial);
+ if (initial == 1)
+ thisRoom->objects[objActive].data.f.initial = true;
+ else
+ thisRoom->objects[objActive].data.f.initial = false;
+
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ }
+ else if (item == kCancelButton)
+ leaving = true;
+ else if (item == kInitialStateCheckbox)
+ ToggleDialogItemValue(infoDial, kInitialStateCheckbox);
+ else if (item == 8) // Linked From? button.
+ {
+ GetDialogItemValue(infoDial, kInitialStateCheckbox, &initial);
+ if (initial == 1)
+ thisRoom->objects[objActive].data.f.initial = true;
+ else
+ thisRoom->objects[objActive].data.f.initial = false;
+
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doReturn = true;
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(lightFilterUPP);
+
+ if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoApplianceObjectInfo
+
+void DoApplianceObjectInfo (short what)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr;
+ long delay;
+ short item, initial;
+ Boolean leaving, doReturn;
+ ModalFilterUPP applianceFilterUPP;
+
+ applianceFilterUPP = NewModalFilterUPP(ApplianceFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ ParamText(numberStr, kindStr, PSTR(""), PSTR(""));
+
+ BringUpDialog(&infoDial, kApplianceInfoDialogID);
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 10);
+
+ if (thisRoom->objects[objActive].data.g.initial)
+ SetDialogItemValue(infoDial, kInitialStateCheckbox, 1);
+ else
+ SetDialogItemValue(infoDial, kInitialStateCheckbox, 0);
+
+ if ((what == kShredder) || (what == kMacPlus) || (what == kTV) ||
+ (what == kCoffee) || (what == kVCR) || (what == kMicrowave))
+ {
+ HideDialogItem(infoDial, kDelayItem);
+ HideDialogItem(infoDial, kDelayLabelItem);
+ }
+
+ delay = thisRoom->objects[objActive].data.g.delay;
+ SetDialogNumToStr(infoDial, kDelayItem, (long)delay);
+ SelectDialogItemText(infoDial, kDelayItem, 0, 1024);
+
+ leaving = false;
+ doReturn = false;
+
+ while (!leaving)
+ {
+ ModalDialog(applianceFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogNumFromStr(infoDial, kDelayItem, &delay);
+ if ((delay < 0L) || (delay > 255L))
+ {
+ SysBeep(0);
+ delay = thisRoom->objects[objActive].data.g.delay;
+ SetDialogNumToStr(infoDial, kDelayItem, (long)delay);
+ SelectDialogItemText(infoDial, kDelayItem, 0, 1024);
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.g.delay = (Byte)delay;
+ GetDialogItemValue(infoDial, kInitialStateCheckbox, &initial);
+ if (initial == 1)
+ thisRoom->objects[objActive].data.g.initial = true;
+ else
+ thisRoom->objects[objActive].data.g.initial = false;
+ fileDirty = true;
+ UpdateMenus(false);
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ leaving = true;
+ }
+ }
+ else if (item == kCancelButton)
+ leaving = true;
+ else if (item == kInitialStateCheckbox)
+ ToggleDialogItemValue(infoDial, kInitialStateCheckbox);
+ else if (item == 10) // Linked From? button.
+ {
+ GetDialogNumFromStr(infoDial, kDelayItem, &delay);
+ if ((delay < 0L) || (delay > 255L))
+ {
+ SysBeep(0);
+ delay = thisRoom->objects[objActive].data.g.delay;
+ SetDialogNumToStr(infoDial, kDelayItem, (long)delay);
+ SelectDialogItemText(infoDial, kDelayItem, 0, 1024);
+ }
+ else
+ {
+ thisRoom->objects[objActive].data.g.delay = (Byte)delay;
+ GetDialogItemValue(infoDial, kInitialStateCheckbox, &initial);
+ if (initial == 1)
+ thisRoom->objects[objActive].data.g.initial = true;
+ else
+ thisRoom->objects[objActive].data.g.initial = false;
+ fileDirty = true;
+ UpdateMenus(false);
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ leaving = true;
+ doReturn = true;
+ }
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(applianceFilterUPP);
+
+ if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoMicrowaveObjectInfo
+
+void DoMicrowaveObjectInfo (void)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr;
+ short item, initial, kills;
+ Boolean leaving, doReturn;
+ ModalFilterUPP microwaveFilterUPP;
+
+ microwaveFilterUPP = NewModalFilterUPP(MicrowaveFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ ParamText(numberStr, kindStr, PSTR(""), PSTR(""));
+
+ BringUpDialog(&infoDial, kMicrowaveInfoDialogID);
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 11);
+
+ if (thisRoom->objects[objActive].data.g.initial)
+ SetDialogItemValue(infoDial, kInitialStateCheckbox, 1);
+ else
+ SetDialogItemValue(infoDial, kInitialStateCheckbox, 0);
+
+ kills = (short)thisRoom->objects[objActive].data.g.byte0;
+ if ((kills & 0x0001) == 0x0001)
+ SetDialogItemValue(infoDial, kKillBandsCheckbox, 1);
+ else
+ SetDialogItemValue(infoDial, kKillBandsCheckbox, 0);
+ if ((kills & 0x0002) == 0x0002)
+ SetDialogItemValue(infoDial, kKillBatteryCheckbox, 1);
+ else
+ SetDialogItemValue(infoDial, kKillBatteryCheckbox, 0);
+ if ((kills & 0x0004) == 0x0004)
+ SetDialogItemValue(infoDial, kKillFoilCheckbox, 1);
+ else
+ SetDialogItemValue(infoDial, kKillFoilCheckbox, 0);
+
+ leaving = false;
+ doReturn = false;
+
+ while (!leaving)
+ {
+ ModalDialog(microwaveFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogItemValue(infoDial, kInitialStateCheckbox, &initial);
+ if (initial == 1)
+ thisRoom->objects[objActive].data.g.initial = true;
+ else
+ thisRoom->objects[objActive].data.g.initial = false;
+ kills = 0;
+ GetDialogItemValue(infoDial, kKillBandsCheckbox, &initial);
+ if (initial == 1)
+ kills += 1;
+ GetDialogItemValue(infoDial, kKillBatteryCheckbox, &initial);
+ if (initial == 1)
+ kills += 2;
+ GetDialogItemValue(infoDial, kKillFoilCheckbox, &initial);
+ if (initial == 1)
+ kills += 4;
+ thisRoom->objects[objActive].data.g.byte0 = (Byte)kills;
+
+ fileDirty = true;
+ UpdateMenus(false);
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ leaving = true;
+ }
+ else if (item == kCancelButton)
+ leaving = true;
+ else if (item == kInitialStateCheckbox)
+ ToggleDialogItemValue(infoDial, kInitialStateCheckbox);
+ else if (item == kKillBandsCheckbox)
+ ToggleDialogItemValue(infoDial, kKillBandsCheckbox);
+ else if (item == kKillBatteryCheckbox)
+ ToggleDialogItemValue(infoDial, kKillBatteryCheckbox);
+ else if (item == kKillFoilCheckbox)
+ ToggleDialogItemValue(infoDial, kKillFoilCheckbox);
+ else if (item == 11) // Linked From? button.
+ {
+ GetDialogItemValue(infoDial, kInitialStateCheckbox, &initial);
+ if (initial == 1)
+ thisRoom->objects[objActive].data.g.initial = true;
+ else
+ thisRoom->objects[objActive].data.g.initial = false;
+ kills = 0;
+ GetDialogItemValue(infoDial, kKillBandsCheckbox, &initial);
+ if (initial == 1)
+ kills += 1;
+ GetDialogItemValue(infoDial, kKillBatteryCheckbox, &initial);
+ if (initial == 1)
+ kills += 2;
+ GetDialogItemValue(infoDial, kKillFoilCheckbox, &initial);
+ if (initial == 1)
+ kills += 4;
+ thisRoom->objects[objActive].data.g.byte0 = (Byte)kills;
+
+ fileDirty = true;
+ UpdateMenus(false);
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ leaving = true;
+ doReturn = true;
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(microwaveFilterUPP);
+
+ if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoGreaseObjectInfo
+
+void DoGreaseObjectInfo (void)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr;
+ short item;
+ Boolean leaving, wasSpilled, doReturn;
+ ModalFilterUPP greaseFilterUPP;
+
+ greaseFilterUPP = NewModalFilterUPP(GreaseFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ ParamText(numberStr, kindStr, PSTR(""), PSTR(""));
+
+ BringUpDialog(&infoDial, kGreaseInfoDialogID);
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 8);
+
+ wasSpilled = !(thisRoom->objects[objActive].data.c.initial);
+ SetDialogItemValue(infoDial, kGreaseItem, (short)wasSpilled);
+ leaving = false;
+ doReturn = false;
+
+ while (!leaving)
+ {
+ ModalDialog(greaseFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ thisRoom->objects[objActive].data.c.initial = !wasSpilled;
+ fileDirty = true;
+ UpdateMenus(false);
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ leaving = true;
+ }
+ else if (item == kCancelButton)
+ {
+ leaving = true;
+ }
+ else if (item == kGreaseItem)
+ {
+ wasSpilled = !wasSpilled;
+ SetDialogItemValue(infoDial, kGreaseItem, (short)wasSpilled);
+ }
+ else if (item == 8) // Linked From? button.
+ {
+ thisRoom->objects[objActive].data.c.initial = !wasSpilled;
+ fileDirty = true;
+ UpdateMenus(false);
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ leaving = true;
+ doReturn = true;
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(greaseFilterUPP);
+
+ if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoInvisBonusObjectInfo
+
+void DoInvisBonusObjectInfo (void)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr;
+ short item;
+ Boolean leaving, doReturn;
+ ModalFilterUPP invisBonusFilterUPP;
+
+ invisBonusFilterUPP = NewModalFilterUPP(InvisBonusFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ ParamText(numberStr, kindStr, PSTR(""), PSTR(""));
+
+ switch (thisRoom->objects[objActive].data.c.points)
+ {
+ case 300:
+ newPoint = 1;
+ break;
+
+ case 500:
+ newPoint = 2;
+ break;
+
+ default:
+ newPoint = 0;
+ break;
+ }
+
+ BringUpDialog(&infoDial, kInvisBonusInfoDialogID);
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 9);
+
+ leaving = false;
+ doReturn = false;
+
+ while (!leaving)
+ {
+ ModalDialog(invisBonusFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ switch (newPoint)
+ {
+ case 0:
+ thisRoom->objects[objActive].data.c.points = 100;
+ break;
+
+ case 1:
+ thisRoom->objects[objActive].data.c.points = 300;
+ break;
+
+ case 2:
+ thisRoom->objects[objActive].data.c.points = 500;
+ break;
+ }
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ }
+ else if (item == kCancelButton)
+ leaving = true;
+ else if (item == k100PtRadio)
+ {
+ SelectFromRadioGroup(infoDial, item, k100PtRadio, k500PtRadio);
+ newPoint = 0;
+ }
+ else if (item == k300PtRadio)
+ {
+ SelectFromRadioGroup(infoDial, item, k100PtRadio, k500PtRadio);
+ newPoint = 1;
+ }
+ else if (item == k500PtRadio)
+ {
+ SelectFromRadioGroup(infoDial, item, k100PtRadio, k500PtRadio);
+ newPoint = 2;
+ }
+ else if (item == 9) // Linked From? button.
+ {
+ switch (newPoint)
+ {
+ case 0:
+ thisRoom->objects[objActive].data.c.points = 100;
+ break;
+
+ case 1:
+ thisRoom->objects[objActive].data.c.points = 300;
+ break;
+
+ case 2:
+ thisRoom->objects[objActive].data.c.points = 500;
+ break;
+ }
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doReturn = true;
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(invisBonusFilterUPP);
+
+ if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoTransObjectInfo
+
+void DoTransObjectInfo (short what)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr, roomStr, tempStr, objStr;
+ short item, floor, suite;
+ Boolean leaving, doLink, doGoTo, doReturn, wasState;
+ ModalFilterUPP transFilterUPP;
+
+ transFilterUPP = NewModalFilterUPP(TransFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ if (thisRoom->objects[objActive].data.d.where == -1)
+ PasStringCopy(PSTR("none"), roomStr);
+ else
+ {
+ ExtractFloorSuite(thisRoom->objects[objActive].data.d.where, &floor, &suite);
+ NumToString((long)floor, roomStr);
+ PasStringConcat(roomStr, PSTR(" / "));
+ NumToString((long)suite, tempStr);
+ PasStringConcat(roomStr, tempStr);
+ }
+
+ if (thisRoom->objects[objActive].data.d.who == 255)
+ PasStringCopy(PSTR("none"), objStr);
+ else
+ NumToString((long)thisRoom->objects[objActive].data.d.who + 1, objStr);
+
+ ParamText(numberStr, kindStr, roomStr, objStr);
+
+ BringUpDialog(&infoDial, kTransInfoDialogID);
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 12);
+ if (what != kDeluxeTrans)
+ HideDialogItem(infoDial, kInitialStateCheckbox3);
+ else
+ {
+ wasState = (thisRoom->objects[objActive].data.d.wide & 0xF0) >> 4;
+ SetDialogItemValue(infoDial, kInitialStateCheckbox3, (short)wasState);
+ }
+
+ leaving = false;
+ doLink = false;
+ doGoTo = false;
+ doReturn = false;
+
+ if (thisRoom->objects[objActive].data.d.who == 255)
+ MyDisableControl(infoDial, kGotoButton1);
+
+ while (!leaving)
+ {
+ ModalDialog(transFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ if (what == kDeluxeTrans)
+ thisRoom->objects[objActive].data.d.wide = wasState << 4;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ }
+ else if (item == kCancelButton)
+ leaving = true;
+ else if (item == kLinkTransButton)
+ {
+ if (what == kDeluxeTrans)
+ thisRoom->objects[objActive].data.d.wide = wasState << 4;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doLink = true;
+ }
+ else if (item == kGotoButton1)
+ {
+ if (what == kDeluxeTrans)
+ thisRoom->objects[objActive].data.d.wide = wasState << 4;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doGoTo = true;
+ }
+ else if (item == 12) // Linked From? button.
+ {
+ if (what == kDeluxeTrans)
+ thisRoom->objects[objActive].data.d.wide = wasState << 4;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doReturn = true;
+ }
+ else if (item == kInitialStateCheckbox3)
+ {
+ wasState = !wasState;
+ SetDialogItemValue(infoDial, kInitialStateCheckbox3, (short)wasState);
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(transFilterUPP);
+
+ if (doLink)
+ {
+ linkType = kTransportLinkOnly;
+ linkerIsSwitch = false;
+ OpenLinkWindow();
+ linkRoom = thisRoomNumber;
+ linkObject = (Byte)objActive;
+ DeselectObject();
+ }
+ else if (doGoTo)
+ {
+ GoToObjectInRoom((short)thisRoom->objects[objActive].data.d.who, floor, suite);
+ }
+ else if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoEnemyObjectInfo
+
+void DoEnemyObjectInfo (short what)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr;
+ long delay;
+ short item, initial;
+ Boolean leaving, doReturn;
+ ModalFilterUPP enemyFilterUPP;
+
+ enemyFilterUPP = NewModalFilterUPP(EnemyFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ ParamText(numberStr, kindStr, PSTR(""), PSTR(""));
+
+ BringUpDialog(&infoDial, kEnemyInfoDialogID);
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 11);
+
+ delay = thisRoom->objects[objActive].data.h.delay;
+ SetDialogNumToStr(infoDial, kDelay2Item, (long)delay);
+ SelectDialogItemText(infoDial, kDelay2Item, 0, 1024);
+
+ if (thisRoom->objects[objActive].data.h.initial)
+ SetDialogItemValue(infoDial, kInitialStateCheckbox2, 1);
+ else
+ SetDialogItemValue(infoDial, kInitialStateCheckbox2, 0);
+
+ if (what == kBall)
+ {
+ HideDialogItem(infoDial, kDelay2Item);
+ HideDialogItem(infoDial, 8);
+ HideDialogItem(infoDial, 9);
+ }
+
+ leaving = false;
+ doReturn = false;
+
+ while (!leaving)
+ {
+ ModalDialog(enemyFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogNumFromStr(infoDial, kDelay2Item, &delay);
+ if (((delay < 0L) || (delay > 255L)) && (what != kBall))
+ {
+ SysBeep(0);
+ delay = thisRoom->objects[objActive].data.h.delay;
+ SetDialogNumToStr(infoDial, kDelay2Item, (long)delay);
+ SelectDialogItemText(infoDial, kDelay2Item, 0, 1024);
+ }
+ else
+ {
+ GetDialogItemValue(infoDial, kInitialStateCheckbox2, &initial);
+ if (initial == 1)
+ thisRoom->objects[objActive].data.h.initial = true;
+ else
+ thisRoom->objects[objActive].data.h.initial = false;
+ if (what != kBall)
+ thisRoom->objects[objActive].data.h.delay = (Byte)delay;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ }
+ }
+ else if (item == kCancelButton)
+ leaving = true;
+ else if (item == kInitialStateCheckbox2)
+ ToggleDialogItemValue(infoDial, kInitialStateCheckbox2);
+ else if (item == 11) // Linked From? button.
+ {
+ GetDialogNumFromStr(infoDial, kDelay2Item, &delay);
+ if (((delay < 0L) || (delay > 255L)) && (what != kBall))
+ {
+ SysBeep(0);
+ delay = thisRoom->objects[objActive].data.h.delay;
+ SetDialogNumToStr(infoDial, kDelay2Item, (long)delay);
+ SelectDialogItemText(infoDial, kDelay2Item, 0, 1024);
+ }
+ else
+ {
+ GetDialogItemValue(infoDial, kInitialStateCheckbox2, &initial);
+ if (initial == 1)
+ thisRoom->objects[objActive].data.h.initial = true;
+ else
+ thisRoom->objects[objActive].data.h.initial = false;
+ if (what != kBall)
+ thisRoom->objects[objActive].data.h.delay = (Byte)delay;
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ doReturn = true;
+ }
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(enemyFilterUPP);
+
+ if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoFlowerObjectInfo
+
+void DoFlowerObjectInfo (void)
+{
+ DialogPtr infoDial;
+ Str255 numberStr, kindStr;
+ short item, flower;
+ Boolean leaving, doReturn;
+ ModalFilterUPP flowerFilterUPP;
+
+ flowerFilterUPP = NewModalFilterUPP(FlowerFilter);
+
+ NumToString(objActive + 1, numberStr);
+ GetIndString(kindStr, kObjectNameStrings, thisRoom->objects[objActive].what);
+ ParamText(numberStr, kindStr, PSTR(""), PSTR(""));
+
+ BringUpDialog(&infoDial, kFlowerInfoDialogID);
+
+ if (retroLinkList[objActive].room == -1)
+ HideDialogItem(infoDial, 13);
+
+ flower = thisRoom->objects[objActive].data.i.pict + kRadioFlower1;
+ SelectFromRadioGroup(infoDial, flower, kRadioFlower1, kRadioFlower6);
+
+ leaving = false;
+ doReturn = false;
+
+ while (!leaving)
+ {
+ ModalDialog(flowerFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ flower -= kRadioFlower1;
+ if (flower != thisRoom->objects[objActive].data.i.pict)
+ {
+ InvalWindowRect(mainWindow, &thisRoom->objects[objActive].data.i.bounds);
+ thisRoom->objects[objActive].data.i.bounds.right =
+ thisRoom->objects[objActive].data.i.bounds.left +
+ RectWide(&flowerSrc[flower]);
+ thisRoom->objects[objActive].data.i.bounds.top =
+ thisRoom->objects[objActive].data.i.bounds.bottom -
+ RectTall(&flowerSrc[flower]);
+ thisRoom->objects[objActive].data.i.pict = flower;
+ InvalWindowRect(mainWindow, &thisRoom->objects[objActive].data.i.bounds);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ fileDirty = true;
+ UpdateMenus(false);
+ wasFlower = flower;
+ }
+ leaving = true;
+ }
+ else if ((item >= kRadioFlower1) && (item <= kRadioFlower6))
+ {
+ flower = item;
+ SelectFromRadioGroup(infoDial, flower, kRadioFlower1, kRadioFlower6);
+ }
+ else if (item == kFlowerCancel)
+ {
+ leaving = true;
+ }
+ else if (item == 13) // Linked From? button.
+ {
+ flower -= kRadioFlower1;
+ if (flower != thisRoom->objects[objActive].data.i.pict)
+ {
+ InvalWindowRect(mainWindow, &thisRoom->objects[objActive].data.i.bounds);
+ thisRoom->objects[objActive].data.i.bounds.right =
+ thisRoom->objects[objActive].data.i.bounds.left +
+ RectWide(&flowerSrc[flower]);
+ thisRoom->objects[objActive].data.i.bounds.top =
+ thisRoom->objects[objActive].data.i.bounds.bottom -
+ RectTall(&flowerSrc[flower]);
+ thisRoom->objects[objActive].data.i.pict = flower;
+ InvalWindowRect(mainWindow, &thisRoom->objects[objActive].data.i.bounds);
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ fileDirty = true;
+ UpdateMenus(false);
+ wasFlower = flower;
+ }
+ leaving = true;
+ doReturn = true;
+ }
+ }
+
+ DisposeDialog(infoDial);
+ DisposeModalFilterUPP(flowerFilterUPP);
+
+ if (doReturn)
+ {
+ GoToObjectInRoomNum(retroLinkList[objActive].object,
+ retroLinkList[objActive].room);
+ }
+}
+
+//-------------------------------------------------------------- DoObjectInfo
+
+void DoObjectInfo (void)
+{
+ if ((objActive == kInitialGliderSelected) ||
+ (objActive == kLeftGliderSelected) ||
+ (objActive == kRightGliderSelected))
+ {
+ DoFurnitureObjectInfo();
+ return;
+ }
+
+ switch (thisRoom->objects[objActive].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:
+ DoBlowerObjectInfo(thisRoom->objects[objActive].what);
+ 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:
+ case kRedClock:
+ case kBlueClock:
+ case kYellowClock:
+ case kCuckoo:
+ case kPaper:
+ case kBattery:
+ case kBands:
+ case kFoil:
+ case kStar:
+ case kSparkle:
+ case kHelium:
+ case kSlider:
+ case kUpStairs:
+ case kDownStairs:
+ case kDoorInLf:
+ case kDoorInRt:
+ case kDoorExRt:
+ case kDoorExLf:
+ case kWindowInLf:
+ case kWindowInRt:
+ case kWindowExRt:
+ case kWindowExLf:
+ case kCinderBlock:
+ case kFlowerBox:
+ case kCDs:
+ case kGuitar:
+ case kStereo:
+ case kCobweb:
+ case kOzma:
+ case kMirror:
+ case kMousehole:
+ case kFireplace:
+ case kWallWindow:
+ case kBear:
+ case kCalendar:
+ case kVase1:
+ case kVase2:
+ case kBulletin:
+ case kCloud:
+ case kFaucet:
+ case kRug:
+ case kChimes:
+ DoFurnitureObjectInfo();
+ break;
+
+ case kGreaseRt:
+ case kGreaseLf:
+ DoGreaseObjectInfo();
+ break;
+
+ case kInvisBonus:
+ DoInvisBonusObjectInfo();
+ break;
+
+ case kMailboxLf:
+ case kMailboxRt:
+ case kFloorTrans:
+ case kCeilingTrans:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ DoTransObjectInfo(thisRoom->objects[objActive].what);
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ DoSwitchObjectInfo();
+ break;
+
+ case kTrigger:
+ case kLgTrigger:
+ DoTriggerObjectInfo();
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kTrackLight:
+ case kInvisLight:
+ DoLightObjectInfo();
+ break;
+
+ case kShredder:
+ case kToaster:
+ case kMacPlus:
+ case kTV:
+ case kCoffee:
+ case kOutlet:
+ case kVCR:
+ DoApplianceObjectInfo(thisRoom->objects[objActive].what);
+ break;
+
+ case kMicrowave:
+ DoMicrowaveObjectInfo();
+ break;
+
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kDartLf:
+ case kDartRt:
+ case kBall:
+ case kDrip:
+ case kFish:
+ DoEnemyObjectInfo(thisRoom->objects[objActive].what);
+ break;
+
+ case kFlower:
+ DoFlowerObjectInfo();
+ break;
+
+ case kSoundTrigger:
+ case kCustomPict:
+ DoCustPictObjectInfo();
+ break;
+
+ default:
+ SysBeep(1);
+ break;
+ }
+}
+
+#endif
+
diff --git a/GpApp/ObjectRects.cpp b/GpApp/ObjectRects.cpp
new file mode 100644
index 0000000..e3f8ab1
--- /dev/null
+++ b/GpApp/ObjectRects.cpp
@@ -0,0 +1,1188 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// ObjectRects.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "RectUtils.h"
+
+
+#define kFloorColumnWide 4
+#define kCeilingColumnWide 24
+#define kFanColumnThick 16
+#define kFanColumnDown 20
+#define kDeadlyFlameHeight 24
+#define kStoolThick 25
+#define kShredderActiveHigh 40
+
+
+short AddActiveRect (Rect *, short, short, Boolean, Boolean);
+
+
+extern hotPtr hotSpots;
+extern short nHotSpots, numChimes;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- GetObjectRect
+
+void GetObjectRect (objectPtr who, Rect *itsRect)
+{
+ PicHandle thePict;
+ short wide, tall;
+
+ switch (who->what)
+ {
+ case kObjectIsEmpty:
+ QSetRect(itsRect, 0, 0, 0, 0);
+ 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:
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect, who->data.a.topLeft.h, who->data.a.topLeft.v);
+ break;
+
+ case kLiftArea:
+ QSetRect(itsRect, 0, 0, who->data.a.distance, who->data.a.tall * 2);
+ QOffsetRect(itsRect, who->data.a.topLeft.h, who->data.a.topLeft.v);
+ break;
+
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect, who->data.a.topLeft.h, who->data.a.topLeft.v);
+ break;
+
+ case kTable:
+ case kShelf:
+ case kCabinet:
+ case kFilingCabinet:
+ case kWasteBasket:
+ case kMilkCrate:
+ case kCounter:
+ case kDresser:
+ case kStool:
+ case kTrunk:
+ case kDeckTable:
+ case kInvisObstacle:
+ case kManhole:
+ case kBooks:
+ case kInvisBounce:
+ *itsRect = who->data.b.bounds;
+ 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:
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect,
+ who->data.c.topLeft.h,
+ who->data.c.topLeft.v);
+ break;
+
+ case kSlider:
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect,
+ who->data.c.topLeft.h,
+ who->data.c.topLeft.v);
+ itsRect->right = itsRect->left + who->data.c.length;
+ 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:
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect,
+ who->data.d.topLeft.h,
+ who->data.d.topLeft.v);
+ break;
+
+ case kInvisTrans:
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect,
+ who->data.d.topLeft.h,
+ who->data.d.topLeft.v);
+ itsRect->bottom = itsRect->top + who->data.d.tall;
+ itsRect->right += (short)who->data.d.wide;
+ break;
+
+ case kDeluxeTrans:
+ wide = (who->data.d.tall & 0xFF00) >> 8; // Get high byte
+ tall = who->data.d.tall & 0x00FF; // Get low byte
+ QSetRect(itsRect, 0, 0, wide * 4, tall * 4); // Scale by 4
+ QOffsetRect(itsRect,
+ who->data.d.topLeft.h,
+ who->data.d.topLeft.v);
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ case kSoundTrigger:
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect,
+ who->data.e.topLeft.h,
+ who->data.e.topLeft.v);
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ case kHipLamp:
+ case kDecoLamp:
+ case kInvisLight:
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect,
+ who->data.f.topLeft.h,
+ who->data.f.topLeft.v);
+ break;
+
+ case kFlourescent:
+ case kTrackLight:
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ itsRect->right = who->data.f.length;
+ QOffsetRect(itsRect,
+ who->data.f.topLeft.h,
+ who->data.f.topLeft.v);
+ 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:
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect,
+ who->data.g.topLeft.h,
+ who->data.g.topLeft.v);
+ break;
+
+ case kCustomPict:
+ thePict = GetPicture(who->data.g.height);
+ if (thePict == nil)
+ {
+ who->data.g.height = 10000;
+ *itsRect = srcRects[who->what];
+ }
+ else
+ {
+ HLock((Handle)thePict);
+ *itsRect = (*thePict)->picFrame;
+ HUnlock((Handle)thePict);
+ }
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect,
+ who->data.g.topLeft.h,
+ who->data.g.topLeft.v);
+ break;
+
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kDartLf:
+ case kDartRt:
+ case kBall:
+ case kDrip:
+ case kFish:
+ case kCobweb:
+ *itsRect = srcRects[who->what];
+ ZeroRectCorner(itsRect);
+ QOffsetRect(itsRect,
+ who->data.h.topLeft.h,
+ who->data.h.topLeft.v);
+ 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:
+ *itsRect = who->data.i.bounds;
+ break;
+ }
+}
+
+//-------------------------------------------------------------- AddActiveRect
+
+short AddActiveRect (Rect *bounds, short action, short who, Boolean isOn,
+ Boolean doScrutinize)
+{
+ if (nHotSpots >= kMaxHotSpots)
+ return (-1);
+
+ hotSpots[nHotSpots].bounds = *bounds; // the active rect
+ hotSpots[nHotSpots].action = action; // what it does
+ hotSpots[nHotSpots].who = who; // local obj. linked to
+ hotSpots[nHotSpots].isOn = isOn; // is it active?
+ hotSpots[nHotSpots].stillOver = false;
+ hotSpots[nHotSpots].doScrutinize = doScrutinize;
+ nHotSpots++;
+
+ return (nHotSpots - 1);
+}
+
+//-------------------------------------------------------------- CreateActiveRects
+
+short CreateActiveRects (short who)
+{
+ objectType theObject;
+ Rect bounds;
+ short hotSpotNumber, wide, tall;
+ Boolean isOn;
+
+ hotSpotNumber = -1;
+ theObject = masterObjects[who].theObject;
+
+ switch (theObject.what)
+ {
+ case kObjectIsEmpty:
+ break;
+
+ case kFloorVent:
+ QSetRect(&bounds, 0, -theObject.data.a.distance, kFloorColumnWide, 0);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kFloorVent]) - kFloorColumnWide / 2, 0);
+ QOffsetRect(&bounds, theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who, theObject.data.a.state,
+ false);
+ break;
+
+ case kCeilingVent:
+ QSetRect(&bounds, 0, 0, kCeilingColumnWide, theObject.data.a.distance);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kCeilingVent]) - kCeilingColumnWide / 2,
+ 0);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kDropIt, who, theObject.data.a.state,
+ false);
+ break;
+
+ case kFloorBlower:
+ QSetRect(&bounds, 0, -theObject.data.a.distance, kFloorColumnWide, 0);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kFloorBlower]) - kFloorColumnWide / 2,
+ 0);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who, theObject.data.a.state,
+ false);
+ break;
+
+ case kCeilingBlower:
+ QSetRect(&bounds, 0, 0, kCeilingColumnWide, theObject.data.a.distance);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kCeilingBlower]) - kCeilingColumnWide / 2,
+ 0);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kDropIt, who, theObject.data.a.state,
+ false);
+ break;
+
+ case kSewerGrate:
+ QSetRect(&bounds, 0, -theObject.data.a.distance, kFloorColumnWide, 0);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kSewerGrate]) - kFloorColumnWide / 2,
+ 0);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who, theObject.data.a.state,
+ false);
+ break;
+
+ case kLeftFan:
+ QSetRect(&bounds, 0, 0, 13, 43);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h + 16,
+ theObject.data.a.topLeft.v + 12);
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ QSetRect(&bounds, 0, 0, theObject.data.a.distance, kFanColumnThick);
+ QOffsetRect(&bounds, -(theObject.data.a.distance), kFanColumnDown);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kPushItLeft, who,
+ theObject.data.a.state, false);
+ break;
+
+ case kRightFan:
+ QSetRect(&bounds, 0, 0, 13, 43);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h + 6,
+ theObject.data.a.topLeft.v + 12);
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ QSetRect(&bounds, 0, 0, theObject.data.a.distance, kFanColumnThick);
+ QOffsetRect(&bounds, RectWide(&srcRects[kRightFan]), kFanColumnDown);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kPushItRight, who,
+ theObject.data.a.state, false);
+ break;
+
+ case kTaper:
+ QSetRect(&bounds, 0, -theObject.data.a.distance, kFloorColumnWide, 0);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kTaper]) - kFloorColumnWide / 2,
+ 0);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ if ((bounds.bottom - bounds.top) > kDeadlyFlameHeight)
+ {
+ bounds.bottom -= kDeadlyFlameHeight;
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who, true, false);
+ bounds.bottom += kDeadlyFlameHeight;
+ bounds.top = bounds.bottom - kDeadlyFlameHeight + 2;
+ hotSpotNumber = AddActiveRect(&bounds, kBurnIt, who, true, false);
+ }
+ else
+ hotSpotNumber = AddActiveRect(&bounds, kBurnIt, who, true, false);
+ QSetRect(&bounds, 0, 0, 7, 48);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h + 6,
+ theObject.data.a.topLeft.v + 11);
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ break;
+
+ case kCandle:
+ QSetRect(&bounds, 0, -theObject.data.a.distance, kFloorColumnWide, 0);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kCandle]) - kFloorColumnWide / 2,
+ 0);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h - 2,
+ theObject.data.a.topLeft.v);
+ if ((bounds.bottom - bounds.top) > kDeadlyFlameHeight)
+ {
+ bounds.bottom -= kDeadlyFlameHeight;
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who, true, false);
+ bounds.bottom += kDeadlyFlameHeight;
+ bounds.top = bounds.bottom - kDeadlyFlameHeight + 2;
+ hotSpotNumber = AddActiveRect(&bounds, kBurnIt, who, true, false);
+ }
+ else
+ hotSpotNumber = AddActiveRect(&bounds, kBurnIt, who, true, false);
+ QSetRect(&bounds, 0, 0, 8, 20);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h + 9,
+ theObject.data.a.topLeft.v + 11);
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ break;
+
+ case kStubby:
+ QSetRect(&bounds, 0, -theObject.data.a.distance, kFloorColumnWide, 0);
+ QOffsetRect(&bounds,
+ (HalfRectWide(&srcRects[kStubby]) - kFloorColumnWide / 2) - 1,
+ 0);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ if ((bounds.bottom - bounds.top) > kDeadlyFlameHeight)
+ {
+ bounds.bottom -= kDeadlyFlameHeight;
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who, true, false);
+ bounds.bottom += kDeadlyFlameHeight;
+ bounds.top = bounds.bottom - kDeadlyFlameHeight + 2;
+ hotSpotNumber = AddActiveRect(&bounds, kBurnIt, who, true, false);
+ }
+ else
+ hotSpotNumber = AddActiveRect(&bounds, kBurnIt, who, true, false);
+ QSetRect(&bounds, 0, 0, 15, 26);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h + 1,
+ theObject.data.a.topLeft.v + 11);
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ break;
+
+ case kTiki:
+ QSetRect(&bounds, 0, -theObject.data.a.distance, kFloorColumnWide, 0);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kTiki]) - kFloorColumnWide / 2,
+ 0);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ if ((bounds.bottom - bounds.top) > kDeadlyFlameHeight)
+ {
+ bounds.bottom -= kDeadlyFlameHeight;
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who, true, false);
+ bounds.bottom += kDeadlyFlameHeight;
+ bounds.top = bounds.bottom - kDeadlyFlameHeight + 2;
+ hotSpotNumber = AddActiveRect(&bounds, kBurnIt, who, true, false);
+ }
+ else
+ hotSpotNumber = AddActiveRect(&bounds, kBurnIt, who, true, false);
+ QSetRect(&bounds, 0, 0, 15, 14);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h + 6,
+ theObject.data.a.topLeft.v + 6);
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ break;
+
+ case kBBQ:
+ QSetRect(&bounds, 0, -theObject.data.a.distance, kFloorColumnWide, 8);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kBBQ]) - kFloorColumnWide / 2, 0);
+ QOffsetRect(&bounds, theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ if ((bounds.bottom - bounds.top) > kDeadlyFlameHeight)
+ {
+ bounds.bottom -= kDeadlyFlameHeight;
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who, true, false);
+ bounds.bottom += kDeadlyFlameHeight;
+ bounds.top = bounds.bottom - kDeadlyFlameHeight + 2;
+ hotSpotNumber = AddActiveRect(&bounds, kBurnIt, who, true, false);
+ }
+ else
+ hotSpotNumber = AddActiveRect(&bounds, kBurnIt, who, true, false);
+ QSetRect(&bounds, 0, 0, 52, 17);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h + 6,
+ theObject.data.a.topLeft.v + 8);
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ break;
+
+ case kInvisBlower:
+ switch (theObject.data.a.vector & 0x0F)
+ {
+ case 1: // up
+ QSetRect(&bounds, 0, -theObject.data.a.distance - 24,
+ kFloorColumnWide, 0);
+ QOffsetRect(&bounds, 12 - kFloorColumnWide / 2, 24);
+ QOffsetRect(&bounds, theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who, theObject.data.a.state,
+ false);
+ break;
+
+ case 2: // right
+ QSetRect(&bounds, 0, 0, theObject.data.a.distance + 24,
+ kFanColumnThick);
+ QOffsetRect(&bounds, 0, 12 - kFanColumnThick / 2);
+ QOffsetRect(&bounds, theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kPushItRight, who,
+ theObject.data.a.state, false);
+ break;
+
+ case 4: // down
+ QSetRect(&bounds, 0, 0, kFloorColumnWide,
+ theObject.data.a.distance + 24);
+ QOffsetRect(&bounds, 12 - kFloorColumnWide / 2, 0);
+ QOffsetRect(&bounds, theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kDropIt, who,
+ theObject.data.a.state, false);
+ break;
+
+ case 8: // left
+ QSetRect(&bounds, 0, 0, theObject.data.a.distance + 24, kFanColumnThick);
+ QOffsetRect(&bounds, -(theObject.data.a.distance), 12 - kFanColumnThick / 2);
+ QOffsetRect(&bounds, theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kPushItLeft, who,
+ theObject.data.a.state, false);
+ break;
+ }
+ break;
+
+ case kGrecoVent:
+ QSetRect(&bounds, 0, -theObject.data.a.distance, kFloorColumnWide, 0);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kGrecoVent]) - kFloorColumnWide / 2,
+ 0);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who,
+ theObject.data.a.state, false);
+ break;
+
+ case kSewerBlower:
+ QSetRect(&bounds, 0, -theObject.data.a.distance, kFloorColumnWide, 0);
+ QOffsetRect(&bounds,
+ HalfRectWide(&srcRects[kSewerBlower]) - kFloorColumnWide / 2,
+ 0);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who,
+ theObject.data.a.state, false);
+ break;
+
+ case kLiftArea:
+ QSetRect(&bounds, 0, 0, theObject.data.a.distance, theObject.data.a.tall * 2);
+ QOffsetRect(&bounds,
+ theObject.data.a.topLeft.h,
+ theObject.data.a.topLeft.v);
+ switch (theObject.data.a.vector & 0x0F)
+ {
+ case 1: // up
+ hotSpotNumber = AddActiveRect(&bounds, kLiftIt, who, theObject.data.a.state,
+ false);
+ break;
+
+ case 2: // right
+ hotSpotNumber = AddActiveRect(&bounds, kPushItRight, who,
+ theObject.data.a.state, false);
+ break;
+
+ case 4: // down
+ hotSpotNumber = AddActiveRect(&bounds, kDropIt, who,
+ theObject.data.a.state, false);
+ break;
+
+ case 8: // left
+ hotSpotNumber = AddActiveRect(&bounds, kPushItLeft, who,
+ theObject.data.a.state, false);
+ break;
+ }
+ break;
+
+ case kTable:
+ case kShelf:
+ case kCabinet:
+ case kFilingCabinet:
+ case kWasteBasket:
+ case kMilkCrate:
+ case kCounter:
+ case kDresser:
+ case kDeckTable:
+ case kTrunk:
+ case kInvisObstacle:
+ bounds = theObject.data.b.bounds;
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ break;
+
+ case kBooks:
+ bounds = theObject.data.b.bounds;
+ bounds.right -= 2;
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ break;
+
+ case kManhole:
+ bounds = theObject.data.b.bounds;
+ bounds.left += kGliderWide + 3;
+ bounds.right -= kGliderWide + 3;
+ bounds.top = kFloorLimit - 1;
+ bounds.bottom = kTileHigh;
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreGround, who, true, false);
+ break;
+
+ case kInvisBounce:
+ bounds = theObject.data.b.bounds;
+ hotSpotNumber = AddActiveRect(&bounds, kBounceIt, who, true, true);
+ break;
+
+ case kStool:
+ bounds = theObject.data.b.bounds;
+ InsetRect(&bounds, 1, 1);
+ bounds.bottom = bounds.top + kStoolThick;
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ break;
+
+ case kRedClock:
+ case kBlueClock:
+ case kYellowClock:
+ case kCuckoo:
+ case kPaper:
+ case kBattery:
+ case kBands:
+ case kFoil:
+ case kInvisBonus:
+ case kStar:
+ case kHelium:
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds,
+ theObject.data.c.topLeft.h,
+ theObject.data.c.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kRewardIt, who,
+ theObject.data.c.state, false);
+ break;
+
+ case kGreaseRt:
+ if (theObject.data.c.state)
+ {
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds, theObject.data.c.topLeft.h,
+ theObject.data.c.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kRewardIt, who, true, false);
+ }
+ else
+ {
+ QSetRect(&bounds, 0, -2, theObject.data.c.length - 5, 0);
+ QOffsetRect(&bounds, 32 - 1, 27);
+ QOffsetRect(&bounds, theObject.data.c.topLeft.h,
+ theObject.data.c.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kSlideIt, who, true, false);
+ }
+ break;
+
+ case kGreaseLf:
+ if (theObject.data.c.state)
+ {
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds, theObject.data.c.topLeft.h,
+ theObject.data.c.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kRewardIt, who, true, false);
+ }
+ else
+ {
+ QSetRect(&bounds, -theObject.data.c.length + 5, -2, 0, 0);
+ QOffsetRect(&bounds, 1, 27);
+ QOffsetRect(&bounds, theObject.data.c.topLeft.h,
+ theObject.data.c.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kSlideIt, who, true, false);
+ }
+ break;
+
+ case kSparkle:
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds,
+ theObject.data.c.topLeft.h,
+ theObject.data.c.topLeft.v);
+ break;
+
+ case kSlider:
+ QSetRect(&bounds, 0, 0, theObject.data.c.length, 16);
+ QOffsetRect(&bounds, theObject.data.c.topLeft.h,
+ theObject.data.c.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kSlideIt, who, true, false);
+ break;
+
+ case kUpStairs:
+ QSetRect(&bounds, 0, 0, 112, 32);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kMoveItUp, who, true, false);
+ break;
+
+ case kDownStairs:
+ QSetRect(&bounds, -80, -56, 0, 0);
+ QOffsetRect(&bounds, srcRects[kDownStairs].right, 170);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kMoveItDown, who, true, false);
+ break;
+
+ case kMailboxLf:
+ if (theObject.data.d.who != 255)
+ {
+ QSetRect(&bounds, -72, 0, 0, 40);
+ QOffsetRect(&bounds, 30, 16);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kMailItLeft, who, true, false);
+ }
+ break;
+
+ case kMailboxRt:
+ if (theObject.data.d.who != 255)
+ {
+ QSetRect(&bounds, 0, 0, 72, 40);
+ QOffsetRect(&bounds, 79, 16);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kMailItRight, who, true, false);
+ }
+ break;
+
+ case kFloorTrans:
+ if (theObject.data.d.who != 255)
+ {
+ QSetRect(&bounds, 0, -48, 76, 0);
+ QOffsetRect(&bounds, -8, RectTall(&srcRects[kFloorTrans]));
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kDuctItDown, who, true, false);
+ }
+ break;
+
+ case kCeilingTrans:
+ if (theObject.data.d.who != 255)
+ {
+ QSetRect(&bounds, 0, 0, 76, 48);
+ QOffsetRect(&bounds, -8, 0);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kDuctItUp, who, true, false);
+ }
+ break;
+
+ case kDoorInLf:
+ QSetRect(&bounds, 0, 0, 16, 240);
+ QOffsetRect(&bounds, 0, 52);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreLeftWall, who, true, false);
+ break;
+
+ case kDoorInRt:
+ QSetRect(&bounds, 0, 0, 16, 240);
+ QOffsetRect(&bounds, 128, 52);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreRightWall, who, true, false);
+ break;
+
+ case kDoorExRt:
+ QSetRect(&bounds, 0, 0, 16, 240);
+ QOffsetRect(&bounds, 0, 52);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreRightWall, who, true, false);
+ break;
+
+ case kDoorExLf:
+ QSetRect(&bounds, 0, 0, 16, 240);
+ QOffsetRect(&bounds, 0, 52);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreLeftWall, who, true, false);
+ break;
+
+ case kWindowInLf:
+ QSetRect(&bounds, 0, 0, 16, 44);
+ QOffsetRect(&bounds, 0, 96);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreLeftWall, who, true, false);
+ break;
+
+ case kWindowInRt:
+ QSetRect(&bounds, 0, 0, 16, 44);
+ QOffsetRect(&bounds, 4, 96);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreRightWall, who, true, false);
+ break;
+
+ case kWindowExRt:
+ QSetRect(&bounds, 0, 0, 16, 44);
+ QOffsetRect(&bounds, 0, 96);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreRightWall, who, true, false);
+ break;
+
+ case kWindowExLf:
+ QSetRect(&bounds, 0, 0, 16, 44);
+ QOffsetRect(&bounds, 0, 96);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreLeftWall, who, true, false);
+ break;
+
+ case kInvisTrans:
+ if (theObject.data.d.who != 255)
+ {
+ QSetRect(&bounds, 0, 0, 64, 32);
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ bounds.bottom = bounds.top + theObject.data.d.tall;
+ bounds.right += (short)theObject.data.d.wide;
+ hotSpotNumber = AddActiveRect(&bounds, kTransportIt, who, true, false);
+ }
+ break;
+
+ case kDeluxeTrans:
+ if (theObject.data.d.who != 255)
+ {
+ wide = (theObject.data.d.tall & 0xFF00) >> 8; // Get high byte
+ tall = theObject.data.d.tall & 0x00FF; // Get low byte
+ QSetRect(&bounds, 0, 0, wide * 4, tall * 4); // Scale by 4
+ QOffsetRect(&bounds,
+ theObject.data.d.topLeft.h,
+ theObject.data.d.topLeft.v);
+ isOn = theObject.data.d.wide & 0x0F;
+ hotSpotNumber = AddActiveRect(&bounds, kTransportIt, who, isOn, false);
+ }
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds,
+ theObject.data.e.topLeft.h,
+ theObject.data.e.topLeft.v);
+ if ((theObject.what == kTrigger) || (theObject.what == kLgTrigger))
+ {
+ if (theObject.data.e.where != -1)
+ hotSpotNumber = AddActiveRect(&bounds, kTriggerIt, who, true, false);
+ }
+ else
+ {
+ if (theObject.data.e.where != -1)
+ hotSpotNumber = AddActiveRect(&bounds, kSwitchIt, who, true, false);
+ }
+ break;
+
+ case kSoundTrigger:
+ QSetRect(&bounds, 0, 0, 48, 48);
+ QOffsetRect(&bounds, theObject.data.e.topLeft.h, theObject.data.e.topLeft.v);
+ if (LoadTriggerSound(theObject.data.e.where) == noErr)
+ hotSpotNumber = AddActiveRect(&bounds, kSoundIt, who, true, false);
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kTrackLight:
+ case kInvisLight:
+ break;
+
+ case kShredder:
+ bounds = srcRects[theObject.what];
+ bounds.bottom = bounds.top + kShredderActiveHigh;
+ bounds.right += 48;
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds, theObject.data.g.topLeft.h,
+ theObject.data.g.topLeft.v);
+ QOffsetRect(&bounds, -24, -36);
+ hotSpotNumber = AddActiveRect(&bounds, kShredIt, who,
+ theObject.data.g.state, true);
+ break;
+
+ case kGuitar:
+ QSetRect(&bounds, 0, 0, 8, 96);
+ QOffsetRect(&bounds, theObject.data.g.topLeft.h + 34,
+ theObject.data.g.topLeft.v + 32);
+ hotSpotNumber = AddActiveRect(&bounds, kStrumIt, who, true, false);
+ break;
+
+ case kOutlet:
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds,
+ theObject.data.g.topLeft.h,
+ theObject.data.g.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreIt, who,
+ theObject.data.g.state, false);
+ break;
+
+ case kMicrowave:
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds,
+ theObject.data.g.topLeft.h,
+ theObject.data.g.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ bounds.bottom = bounds.top;
+ bounds.top = 0;
+ hotSpotNumber = AddActiveRect(&bounds, kMicrowaveIt, who, true, true);
+ break;
+
+ case kToaster:
+ case kMacPlus:
+ case kTV:
+ case kCoffee:
+ case kVCR:
+ case kStereo:
+ case kCinderBlock:
+ case kFlowerBox:
+ case kCDs:
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds,
+ theObject.data.g.topLeft.h,
+ theObject.data.g.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ break;
+
+ case kCustomPict:
+ break;
+
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kDartLf:
+ case kDartRt:
+ case kBall:
+ case kDrip:
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds,
+ theObject.data.h.topLeft.h,
+ theObject.data.h.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kIgnoreIt, who, true, false);
+ break;
+
+ case kFish:
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds,
+ theObject.data.h.topLeft.h,
+ theObject.data.h.topLeft.v);
+ hotSpotNumber = AddActiveRect(&bounds, kDissolveIt, who, true, true);
+ break;
+
+ case kCobweb:
+ bounds = srcRects[theObject.what];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds,
+ theObject.data.h.topLeft.h,
+ theObject.data.h.topLeft.v);
+ InsetRect(&bounds, -24, -10);
+ hotSpotNumber = AddActiveRect(&bounds, kWebIt, who, true, true);
+ 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:
+ break;
+
+ case kChimes:
+ numChimes++;
+ bounds = srcRects[kChimes];
+ ZeroRectCorner(&bounds);
+ QOffsetRect(&bounds,
+ theObject.data.i.bounds.left,
+ theObject.data.i.bounds.top);
+ hotSpotNumber = AddActiveRect(&bounds, kChimeIt, who, true, false);
+ break;
+ }
+
+ return (hotSpotNumber);
+}
+
+//-------------------------------------------------------------- VerticalRoomOffset
+
+short VerticalRoomOffset (short neighbor)
+{
+ short offset;
+
+ offset = 0;
+
+ switch (neighbor)
+ {
+ case kNorthRoom:
+ case kNorthEastRoom:
+ case kNorthWestRoom:
+ offset -= kVertLocalOffset;
+ break;
+
+ case kSouthEastRoom:
+ case kSouthRoom:
+ case kSouthWestRoom:
+ offset += kVertLocalOffset;
+ break;
+ }
+
+ return (offset);
+}
+
+//-------------------------------------------------------------- OffsetRectRoomRelative
+
+void OffsetRectRoomRelative (Rect *theRect, short neighbor)
+{
+ QOffsetRect(theRect, playOriginH, playOriginV);
+
+ switch (neighbor)
+ {
+ case kNorthRoom:
+ QOffsetRect(theRect, 0, -kVertLocalOffset);
+ break;
+
+ case kNorthEastRoom:
+ QOffsetRect(theRect, kRoomWide, -kVertLocalOffset);
+ break;
+
+ case kEastRoom:
+ QOffsetRect(theRect, kRoomWide, 0);
+ break;
+
+ case kSouthEastRoom:
+ QOffsetRect(theRect, kRoomWide, kVertLocalOffset);
+ break;
+
+ case kSouthRoom:
+ QOffsetRect(theRect, 0, kVertLocalOffset);
+ break;
+
+ case kSouthWestRoom:
+ QOffsetRect(theRect, -kRoomWide, kVertLocalOffset);
+ break;
+
+ case kWestRoom:
+ QOffsetRect(theRect, -kRoomWide, 0);
+ break;
+
+ case kNorthWestRoom:
+ QOffsetRect(theRect, -kRoomWide, -kVertLocalOffset);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- GetUpStairsRightEdge
+
+short GetUpStairsRightEdge (void)
+{
+ objectType thisObject;
+ short i, rightEdge;
+ char wasState;
+
+ rightEdge = kRoomWide;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ for (i = 0; i < kMaxRoomObs; i++)
+ {
+ thisObject = (*thisHouse)->rooms[thisRoomNumber].objects[i];
+ if (thisObject.what == kDownStairs)
+ {
+ rightEdge = thisObject.data.d.topLeft.h + srcRects[kDownStairs].right - 1;
+ break;
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ return (rightEdge);
+}
+
+//-------------------------------------------------------------- GetDownStairsLeftEdge
+
+short GetDownStairsLeftEdge (void)
+{
+ objectType thisObject;
+ short i, leftEdge;
+ char wasState;
+
+ leftEdge = 0;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ for (i = 0; i < kMaxRoomObs; i++)
+ {
+ thisObject = (*thisHouse)->rooms[thisRoomNumber].objects[i];
+ if (thisObject.what == kUpStairs)
+ {
+ leftEdge = thisObject.data.d.topLeft.h + 1;
+ break;
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ return (leftEdge);
+}
+
diff --git a/GpApp/Objects.cpp b/GpApp/Objects.cpp
new file mode 100644
index 0000000..6158186
--- /dev/null
+++ b/GpApp/Objects.cpp
@@ -0,0 +1,1001 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Objects.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "ObjectEdit.h"
+
+
+#define kMaxTempManholes 8
+
+
+short GetObjectLinked (objectType *);
+void ListOneRoomsObjects (short);
+
+
+Rect blowerSrcRect; // Blowers
+GWorldPtr blowerSrcMap;
+GWorldPtr blowerMaskMap;
+Rect flame[kNumCandleFlames], tikiFlame[kNumTikiFlames];
+Rect coals[kNumBBQCoals];
+Rect furnitureSrcRect; // Furniture
+GWorldPtr furnitureSrcMap;
+GWorldPtr furnitureMaskMap;
+Rect tableSrc, shelfSrc, hingeSrc, handleSrc, knobSrc;
+Rect leftFootSrc, rightFootSrc, deckSrc;
+Rect bonusSrcRect; // Bonuses
+GWorldPtr bonusSrcMap;
+GWorldPtr bonusMaskMap;
+Rect pointsSrcRect;
+GWorldPtr pointsSrcMap;
+GWorldPtr pointsMaskMap;
+Rect starSrc[6], sparkleSrc[kNumSparkleModes];
+Rect digits[11], pendulumSrc[3], greaseSrcRt[4], greaseSrcLf[4];
+Rect transSrcRect; // Transport
+GWorldPtr transSrcMap;
+GWorldPtr transMaskMap;
+Rect switchSrcRect; // Switches
+GWorldPtr switchSrcMap;
+Rect lightSwitchSrc[2], machineSwitchSrc[2], thermostatSrc[2];
+Rect powerSrc[2], knifeSwitchSrc[2];
+Rect lightSrcRect; // Lights
+GWorldPtr lightSrcMap;
+GWorldPtr lightMaskMap;
+Rect flourescentSrc1, flourescentSrc2, trackLightSrc[kNumTrackLights];
+Rect applianceSrcRect, toastSrcRect, shredSrcRect; // Appliances
+GWorldPtr applianceSrcMap, toastSrcMap, shredSrcMap;
+GWorldPtr applianceMaskMap, toastMaskMap, shredMaskMap;
+Rect plusScreen1, plusScreen2, tvScreen1, tvScreen2;
+Rect coffeeLight1, coffeeLight2, vcrTime1, vcrTime2;
+Rect stereoLight1, stereoLight2, microOn, microOff;
+Rect outletSrc[kNumOutletPicts];
+Rect balloonSrcRect, copterSrcRect, dartSrcRect; // Enemies
+Rect ballSrcRect, dripSrcRect, enemySrcRect;
+Rect fishSrcRect;
+GWorldPtr balloonSrcMap, copterSrcMap, dartSrcMap;
+GWorldPtr ballSrcMap, dripSrcMap, enemySrcMap;
+GWorldPtr fishSrcMap;
+GWorldPtr balloonMaskMap, copterMaskMap, dartMaskMap;
+GWorldPtr ballMaskMap, dripMaskMap, enemyMaskMap;
+GWorldPtr fishMaskMap;
+Rect balloonSrc[kNumBalloonFrames], copterSrc[kNumCopterFrames];
+Rect dartSrc[kNumDartFrames], ballSrc[kNumBallFrames];
+Rect dripSrc[kNumDripFrames], fishSrc[kNumFishFrames];
+GWorldPtr clutterSrcMap; // Clutter
+GWorldPtr clutterMaskMap;
+Rect clutterSrcRect;
+Rect flowerSrc[kNumFlowers];
+Rect *srcRects;
+Rect tempManholes[kMaxTempManholes];
+savedType savedMaps[kMaxSavedMaps];
+objDataPtr masterObjects;
+hotPtr hotSpots;
+short nLocalObj, nHotSpots, numMasterObjects, numLocalMasterObjects;
+short numTempManholes, tvWithMovieNumber;
+Boolean newState;
+
+extern linksPtr linksList;
+extern short srcLocations[], destLocations[];
+extern short localNumbers[];
+extern short numNeighbors;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- IsThisValid
+
+Boolean IsThisValid (short where, short who)
+{
+ char wasState;
+ Boolean itsGood;
+
+ itsGood = true;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ switch ((*thisHouse)->rooms[where].objects[who].what)
+ {
+ case kObjectIsEmpty:
+ itsGood = false;
+ break;
+
+ case kRedClock:
+ case kBlueClock:
+ case kYellowClock:
+ case kCuckoo:
+ case kPaper:
+ case kBattery:
+ case kBands:
+ case kFoil:
+ case kInvisBonus:
+ case kStar:
+ case kSparkle:
+ case kHelium:
+ itsGood = (*thisHouse)->rooms[where].objects[who].data.c.state;
+ break;
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ return (itsGood);
+}
+
+//-------------------------------------------------------------- GetRoomLinked
+
+short GetRoomLinked (objectType *who)
+{
+ short compoundRoomNumber, whereLinked;
+ short floor, suite;
+
+ switch (who->what)
+ {
+ case kMailboxLf:
+ case kMailboxRt:
+ case kFloorTrans:
+ case kCeilingTrans:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ compoundRoomNumber = who->data.d.where;
+ if (compoundRoomNumber != -1) // is object linked
+ {
+ ExtractFloorSuite(compoundRoomNumber, &floor, &suite);
+ whereLinked = GetRoomNumber(floor, suite);
+ }
+ else
+ whereLinked = -1; // not linked
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ compoundRoomNumber = who->data.e.where;
+ if (compoundRoomNumber != -1) // is object linked
+ {
+ ExtractFloorSuite(compoundRoomNumber, &floor, &suite);
+ whereLinked = GetRoomNumber(floor, suite);
+ }
+ else
+ whereLinked = -1; // not linked
+ break;
+
+ default:
+ whereLinked = -1;
+ break;
+ }
+
+ return (whereLinked);
+}
+
+//-------------------------------------------------------------- GetObjectLinked
+
+short GetObjectLinked (objectType *who)
+{
+ short whoLinked;
+
+ switch (who->what)
+ {
+ case kMailboxLf:
+ case kMailboxRt:
+ case kFloorTrans:
+ case kCeilingTrans:
+ case kInvisTrans:
+ case kDeluxeTrans:
+ if (who->data.d.who != 255) // is it linked?
+ whoLinked = (short)who->data.d.who;
+ else
+ whoLinked = -1; // object not linked
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ if (who->data.e.who != 255) // is it linked?
+ whoLinked = (short)who->data.e.who;
+ else
+ whoLinked = -1; // object not linked
+ break;
+
+ default:
+ whoLinked = -1;
+ break;
+ }
+
+ return (whoLinked);
+}
+
+//-------------------------------------------------------------- ObjectIsLinkTransport
+
+Boolean ObjectIsLinkTransport (objectType *who)
+{
+ Boolean itIs;
+
+ itIs = false;
+ if ((who->what == kMailboxLf) || (who->what == kMailboxRt) ||
+ (who->what == kFloorTrans) || (who->what == kCeilingTrans) ||
+ (who->what == kInvisTrans) || (who->what == kDeluxeTrans))
+ {
+ itIs = true;
+ }
+
+ return (itIs);
+}
+
+//-------------------------------------------------------------- ObjectIsLinkSwitch
+
+Boolean ObjectIsLinkSwitch (objectType *who)
+{
+ Boolean itIs;
+
+ itIs = false;
+ if ((who->what == kLightSwitch) || (who->what == kMachineSwitch) ||
+ (who->what == kThermostat) || (who->what == kPowerSwitch) ||
+ (who->what == kKnifeSwitch) || (who->what == kInvisSwitch) ||
+ (who->what == kTrigger) || (who->what == kLgTrigger))
+ {
+ itIs = true;
+ }
+
+ return (itIs);
+}
+
+//-------------------------------------------------------------- ListOneRoomsObjects
+
+void ListOneRoomsObjects (short where)
+{
+ objectType thisObject;
+ short roomNum, n;
+ char wasState;
+
+ roomNum = localNumbers[where];
+ if (roomNum == kRoomIsEmpty)
+ return;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ for (n = 0; n < kMaxRoomObs; n++)
+ {
+ if (numMasterObjects < kMaxMasterObjects)
+ {
+ thisObject = (*thisHouse)->rooms[roomNum].objects[n];
+
+ masterObjects[numMasterObjects].roomNum = roomNum;
+ masterObjects[numMasterObjects].objectNum = n;
+ masterObjects[numMasterObjects].roomLink =
+ GetRoomLinked(&thisObject);
+ masterObjects[numMasterObjects].objectLink =
+ GetObjectLinked(&thisObject);
+ masterObjects[numMasterObjects].localLink = -1;
+
+ masterObjects[numMasterObjects].theObject =
+ (*thisHouse)->rooms[roomNum].objects[n];
+
+ if ((where == kCentralRoom) && (IsThisValid(roomNum, n)))
+ masterObjects[numMasterObjects].hotNum = CreateActiveRects(n);
+ else
+ masterObjects[numMasterObjects].hotNum = -1;
+ masterObjects[numMasterObjects].dynaNum = -1;
+
+ numMasterObjects++;
+
+ if (where == kCentralRoom)
+ numLocalMasterObjects++;
+ }
+ }
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- ListAllLocalObjects
+
+void ListAllLocalObjects (void)
+{
+ short i, n;
+ char wasState;
+
+ numMasterObjects = 0;
+ numLocalMasterObjects = 0;
+ nHotSpots = 0;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ ListOneRoomsObjects(kCentralRoom);
+
+ if (numNeighbors > 1)
+ {
+ ListOneRoomsObjects(kEastRoom);
+ ListOneRoomsObjects(kWestRoom);
+ }
+
+ if (numNeighbors > 3)
+ {
+ ListOneRoomsObjects(kNorthRoom);
+ ListOneRoomsObjects(kNorthEastRoom);
+ ListOneRoomsObjects(kSouthEastRoom);
+ ListOneRoomsObjects(kSouthRoom);
+ ListOneRoomsObjects(kSouthWestRoom);
+ ListOneRoomsObjects(kNorthWestRoom);
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ for (i = 0; i < numMasterObjects; i++) // correlate links withÉ
+ { // index into this list
+ if ((masterObjects[i].roomLink != -1) && // if object has a link
+ (masterObjects[i].objectLink != -1))
+ {
+ for (n = 0; n < numMasterObjects; n++) // search for the objectÉ
+ { // linked to in this list
+ if ((masterObjects[i].roomLink == masterObjects[n].roomNum) &&
+ (masterObjects[i].objectLink == masterObjects[n].objectNum))
+ {
+ masterObjects[i].localLink = n; // log the index
+ }
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- AddTempManholeRect
+
+void AddTempManholeRect (Rect *manHole)
+{
+ Rect tempRect;
+
+ if (numTempManholes < kMaxTempManholes)
+ {
+ tempRect = *manHole;
+ tempRect.bottom = tempRect.top + kFloorSupportTall;
+ tempManholes[numTempManholes] = tempRect;
+ numTempManholes++;
+ }
+}
+
+//-------------------------------------------------------------- SetObjectState
+
+Boolean SetObjectState (short room, short object, short action, short local)
+{
+ char wasState;
+ Boolean changed;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ switch ((*thisHouse)->rooms[room].objects[object].what)
+ {
+ case kFloorVent:
+ case kCeilingVent:
+ case kFloorBlower:
+ case kCeilingBlower:
+ case kLeftFan:
+ case kRightFan:
+ case kSewerGrate:
+ case kInvisBlower:
+ case kGrecoVent:
+ case kSewerBlower:
+ case kLiftArea:
+ switch (action)
+ {
+ case kToggle:
+ newState = !(*thisHouse)->rooms[room].objects[object].data.a.state;
+ (*thisHouse)->rooms[room].objects[object].data.a.state = newState;
+ changed = true;
+ break;
+
+ case kForceOn:
+ changed = ((*thisHouse)->rooms[room].objects[object].data.a.state == false);
+ newState = true;
+ (*thisHouse)->rooms[room].objects[object].data.a.state = newState;
+ break;
+
+ case kForceOff:
+ changed = ((*thisHouse)->rooms[room].objects[object].data.a.state == PL_TRUE);
+ newState = false;
+ (*thisHouse)->rooms[room].objects[object].data.a.state = newState;
+ break;
+ }
+ if ((changed) && (local != -1))
+ {
+ masterObjects[local].theObject.data.a.state = newState;
+ if (room == thisRoomNumber)
+ thisRoom->objects[object].data.a.state = newState;
+ if (newState)
+ PlayPrioritySound(kBlowerOn, kBlowerOnPriority);
+ else
+ PlayPrioritySound(kBlowerOff, kBlowerOffPriority);
+ if (masterObjects[local].hotNum != -1)
+ hotSpots[masterObjects[local].hotNum].isOn = newState;
+ }
+ break;
+
+ case kTaper:
+ case kCandle:
+ case kStubby:
+ case kTiki:
+ case kBBQ:
+ changed = false; // Cannot switch on/off these
+ break;
+
+ case kTable:
+ case kShelf:
+ case kCabinet:
+ case kFilingCabinet:
+ case kWasteBasket:
+ case kMilkCrate:
+ case kCounter:
+ case kDresser:
+ case kStool:
+ case kTrunk:
+ case kDeckTable:
+ case kInvisObstacle:
+ case kManhole:
+ case kBooks:
+ case kInvisBounce:
+ changed = false; // Cannot switch on/off these
+ 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:
+ changed = ((*thisHouse)->rooms[room].objects[object].data.c.state == PL_TRUE);
+ newState = false;
+ (*thisHouse)->rooms[room].objects[object].data.c.state = newState;
+ if ((changed) && (local != -1))
+ {
+ masterObjects[local].theObject.data.a.state = false;
+ if (room == thisRoomNumber)
+ {
+ thisRoom->objects[object].data.c.state = false;
+ if (masterObjects[local].hotNum != -1)
+ hotSpots[masterObjects[local].hotNum].isOn = false;
+ }
+ }
+ break;
+
+ case kSlider:
+ 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:
+ changed = false;
+ break;
+
+ case kDeluxeTrans:
+ switch (action)
+ {
+ case kToggle:
+ newState = (*thisHouse)->rooms[room].objects[object].data.d.wide & 0x0F;
+ newState = !newState;
+ (*thisHouse)->rooms[room].objects[object].data.d.wide &= 0xF0;
+ (*thisHouse)->rooms[room].objects[object].data.d.wide += newState;
+ changed = true;
+ break;
+
+ case kForceOn:
+ changed = (((*thisHouse)->rooms[room].objects[object].data.d.wide & 0x0F) == 0x00);
+ newState = true;
+ (*thisHouse)->rooms[room].objects[object].data.d.wide &= 0xF0;
+ (*thisHouse)->rooms[room].objects[object].data.d.wide += newState;
+ break;
+
+ case kForceOff:
+ changed = (((*thisHouse)->rooms[room].objects[object].data.d.wide & 0x0F) != 0x00);
+ newState = false;
+ (*thisHouse)->rooms[room].objects[object].data.d.wide &= 0xF0;
+ (*thisHouse)->rooms[room].objects[object].data.d.wide += newState;
+ break;
+ }
+ if ((changed) && (local != -1))
+ {
+ masterObjects[local].theObject.data.d.wide =
+ (*thisHouse)->rooms[room].objects[object].data.d.wide;
+ if (room == thisRoomNumber)
+ thisRoom->objects[object].data.d.wide =
+ (*thisHouse)->rooms[room].objects[object].data.d.wide;
+ if (masterObjects[local].hotNum != -1)
+ hotSpots[masterObjects[local].hotNum].isOn = newState;
+ }
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ case kSoundTrigger:
+ changed = false;
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kTrackLight:
+ case kInvisLight:
+ switch (action)
+ {
+ case kToggle:
+ newState = !(*thisHouse)->rooms[room].objects[object].data.f.state;
+ (*thisHouse)->rooms[room].objects[object].data.f.state = newState;
+ changed = true;
+ break;
+
+ case kForceOn:
+ changed = ((*thisHouse)->rooms[room].objects[object].data.f.state == false);
+ newState = true;
+ (*thisHouse)->rooms[room].objects[object].data.f.state = newState;
+ break;
+
+ case kForceOff:
+ changed = ((*thisHouse)->rooms[room].objects[object].data.f.state == PL_TRUE);
+ newState = false;
+ (*thisHouse)->rooms[room].objects[object].data.f.state = newState;
+ break;
+ }
+ if ((changed) && (local != -1))
+ {
+ masterObjects[local].theObject.data.f.state = newState;
+ if (room == thisRoomNumber)
+ thisRoom->objects[object].data.f.state = newState;
+ }
+ break;
+
+ case kGuitar: // really no point to change this state
+ changed = false;
+ break;
+
+ case kStereo:
+ newState = !isPlayMusicGame;
+ isPlayMusicGame = newState;
+ changed = true;
+ break;
+
+ case kShredder:
+ case kToaster:
+ case kMacPlus:
+ case kTV:
+ case kCoffee:
+ case kOutlet:
+ case kVCR:
+ case kMicrowave:
+ switch (action)
+ {
+ case kToggle:
+ newState = !(*thisHouse)->rooms[room].objects[object].data.g.state;
+ (*thisHouse)->rooms[room].objects[object].data.g.state = newState;
+ changed = true;
+ break;
+
+ case kForceOn:
+ changed = ((*thisHouse)->rooms[room].objects[object].data.g.state == false);
+ newState = true;
+ (*thisHouse)->rooms[room].objects[object].data.g.state = newState;
+ break;
+
+ case kForceOff:
+ changed = ((*thisHouse)->rooms[room].objects[object].data.g.state == PL_TRUE);
+ newState = false;
+ (*thisHouse)->rooms[room].objects[object].data.g.state = newState;
+ break;
+ }
+ if ((changed) && (local != -1))
+ {
+ masterObjects[local].theObject.data.g.state = newState;
+ if (room == thisRoomNumber)
+ {
+ thisRoom->objects[object].data.g.state = newState;
+ if ((*thisHouse)->rooms[room].objects[object].what == kShredder)
+ hotSpots[masterObjects[local].hotNum].isOn = newState;
+ }
+ }
+ break;
+
+ case kCinderBlock:
+ case kFlowerBox:
+ case kCDs:
+ case kCustomPict:
+ changed = false;
+ break;
+
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kDartLf:
+ case kDartRt:
+ case kBall:
+ case kDrip:
+ case kFish:
+ switch (action)
+ {
+ case kToggle:
+ newState = !(*thisHouse)->rooms[room].objects[object].data.h.state;
+ (*thisHouse)->rooms[room].objects[object].data.h.state = newState;
+ changed = true;
+ break;
+
+ case kForceOn:
+ changed = ((*thisHouse)->rooms[room].objects[object].data.h.state == false);
+ newState = true;
+ (*thisHouse)->rooms[room].objects[object].data.h.state = newState;
+ break;
+
+ case kForceOff:
+ changed = ((*thisHouse)->rooms[room].objects[object].data.h.state == PL_TRUE);
+ newState = false;
+ (*thisHouse)->rooms[room].objects[object].data.h.state = newState;
+ break;
+ }
+ if ((changed) && (local != -1))
+ {
+ masterObjects[local].theObject.data.h.state = newState;
+ if (room == thisRoomNumber)
+ thisRoom->objects[object].data.h.state = newState;
+ }
+ break;
+
+ case kCobweb:
+ changed = 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:
+ changed = false;
+ break;
+
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ return (changed);
+}
+
+//-------------------------------------------------------------- GetObjectState
+
+Boolean GetObjectState (short room, short object)
+{
+ char wasState;
+ Boolean theState;
+
+ theState = true;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ switch ((*thisHouse)->rooms[room].objects[object].what)
+ {
+ case kFloorVent:
+ case kCeilingVent:
+ case kFloorBlower:
+ case kCeilingBlower:
+ case kLeftFan:
+ case kRightFan:
+ case kSewerGrate:
+ case kInvisBlower:
+ case kGrecoVent:
+ case kSewerBlower:
+ case kLiftArea:
+ theState = (*thisHouse)->rooms[room].objects[object].data.a.state;
+ break;
+
+ case kTaper:
+ case kCandle:
+ case kStubby:
+ case kTiki:
+ case kBBQ:
+ 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:
+ 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:
+ theState = (*thisHouse)->rooms[room].objects[object].data.c.state;
+ break;
+
+ case kSlider:
+ 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:
+ break;
+
+ case kDeluxeTrans:
+ theState = (*thisHouse)->rooms[room].objects[object].data.d.wide & 0x0F;
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ case kSoundTrigger:
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kTrackLight:
+ case kInvisLight:
+ theState = (*thisHouse)->rooms[room].objects[object].data.f.state;
+ break;
+
+ case kStereo:
+ theState = isPlayMusicGame;
+ break;
+
+ case kShredder:
+ case kToaster:
+ case kMacPlus:
+ case kGuitar:
+ case kTV:
+ case kCoffee:
+ case kOutlet:
+ case kVCR:
+ case kMicrowave:
+ theState = (*thisHouse)->rooms[room].objects[object].data.g.state;
+ break;
+
+ case kCinderBlock:
+ case kFlowerBox:
+ case kCDs:
+ case kCustomPict:
+ break;
+
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kDartLf:
+ case kDartRt:
+ case kBall:
+ case kDrip:
+ case kFish:
+ theState = (*thisHouse)->rooms[room].objects[object].data.h.state;
+ break;
+
+ case kCobweb:
+ 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:
+ break;
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ return (theState);
+}
+
+//-------------------------------------------------------------- SendObjectToBack
+
+#ifndef COMPILEDEMO
+void BringSendFrontBack (Boolean bringFront)
+{
+ houseType *thisHousePtr;
+ objectType savedObject;
+ short numLinks, i;
+ short srcRoom, srcObj;
+ short sorting[kMaxRoomObs];
+ short sorted[kMaxRoomObs];
+ char wasState;
+
+ if (bringFront) // No need to bring to frontÉ
+ { // or send to back if the objectÉ
+ if (objActive == (kMaxRoomObs - 1)) // in question is already front-
+ return; // most or backmost.
+ }
+ else
+ {
+ if (objActive == 0)
+ return;
+ }
+
+ CopyThisRoomToRoom(); // Any changes to room writtenÉ
+ // back to the house handle.
+ numLinks = CountHouseLinks(); // Determine space needed for all links.
+ if (numLinks != 0) // Create links list of ALL house links.
+ {
+ linksList = nil;
+ linksList = (linksPtr)NewPtr(sizeof(linksType) * numLinks);
+ if (linksList == nil)
+ {
+ YellowAlert(kYellowCantOrderLinks, MemError());
+ return;
+ }
+ GenerateLinksList(); // Fill in links list with src/destÉ
+ } // data on objects and room numbers.
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse); // Lock down house.
+ thisHousePtr = *thisHouse; // Get a pointer to house structure.
+
+ for (i = 0; i < kMaxRoomObs; i++) // Set up an ordered array.
+ sorting[i] = i;
+
+ savedObject = (*thisHouse)->rooms[thisRoomNumber].objects[objActive];
+
+ if (bringFront)
+ {
+ for (i = objActive; i < kMaxRoomObs - 1; i++)
+ { // Pull all objects down to fill hole.
+ (*thisHouse)->rooms[thisRoomNumber].objects[i] =
+ (*thisHouse)->rooms[thisRoomNumber].objects[i + 1];
+ sorting[i] = sorting[i + 1];
+ SpinCursor(2);
+ }
+ // Insert object at end of array.
+ (*thisHouse)->rooms[thisRoomNumber].objects[kMaxRoomObs - 1] = savedObject;
+ sorting[kMaxRoomObs - 1] = objActive;
+ }
+ else
+ {
+ for (i = objActive; i > 0; i--)
+ { // Move all objects up to fill hole.
+ (*thisHouse)->rooms[thisRoomNumber].objects[i] =
+ (*thisHouse)->rooms[thisRoomNumber].objects[i - 1];
+ sorting[i] = sorting[i - 1];
+ SpinCursor(2);
+ }
+ // Insert object at beginning of array.
+ (*thisHouse)->rooms[thisRoomNumber].objects[0] = savedObject;
+ sorting[0] = objActive;
+ }
+
+ for (i = 0; i < kMaxRoomObs; i++) // Set up retro-ordered array.
+ sorted[sorting[i]] = i;
+
+ for (i = 0; i < numLinks; i++) // Walk links list in order to assignÉ
+ { // corrected links to objects moved.
+ if (linksList[i].destRoom == thisRoomNumber)
+ { // Does link point to room we re-ordered?
+ srcRoom = linksList[i].srcRoom; // Room where-which an object is linked from.
+ if (srcRoom == thisRoomNumber) // Handle special case for local links.
+ srcObj = sorted[linksList[i].srcObj];
+ else
+ srcObj = linksList[i].srcObj;
+
+ switch ((*thisHouse)->rooms[srcRoom].objects[srcObj].what)
+ {
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ case kTrigger:
+ case kLgTrigger:
+ (*thisHouse)->rooms[srcRoom].objects[srcObj].data.d.who =
+ sorted[linksList[i].destObj];
+ break;
+
+ default:
+ (*thisHouse)->rooms[srcRoom].objects[srcObj].data.e.who =
+ sorted[linksList[i].destObj];
+ break;
+ }
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+ if (linksList != nil)
+ DisposePtr((Ptr)linksList);
+
+ ForceThisRoom(thisRoomNumber);
+
+ fileDirty = true;
+ UpdateMenus(false);
+ InvalWindowRect(mainWindow, &mainWindowRect);
+ DeselectObject();
+ GetThisRoomsObjRects();
+ ReadyBackground(thisRoom->background, thisRoom->tiles);
+ DrawThisRoomsObjects();
+ GenerateRetroLinks();
+
+ InitCursor();
+}
+#endif
+
diff --git a/GpApp/Objects.h b/GpApp/Objects.h
new file mode 100644
index 0000000..32aa0aa
--- /dev/null
+++ b/GpApp/Objects.h
@@ -0,0 +1,42 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Objects.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+extern GWorldPtr blowerSrcMap;
+extern GWorldPtr blowerMaskMap;
+extern GWorldPtr furnitureSrcMap;
+extern GWorldPtr furnitureMaskMap;
+extern GWorldPtr bonusSrcMap;
+extern GWorldPtr bonusMaskMap;
+extern GWorldPtr pointsSrcMap;
+extern GWorldPtr pointsMaskMap;
+extern GWorldPtr transSrcMap;
+extern GWorldPtr transMaskMap;
+extern GWorldPtr switchSrcMap;
+extern GWorldPtr lightSrcMap;
+extern GWorldPtr lightMaskMap;
+extern GWorldPtr applianceSrcMap;
+extern GWorldPtr applianceMaskMap;
+extern GWorldPtr toastSrcMap;
+extern GWorldPtr toastMaskMap;
+extern GWorldPtr shredSrcMap;
+extern GWorldPtr shredMaskMap;
+extern GWorldPtr balloonSrcMap;
+extern GWorldPtr balloonMaskMap;
+extern GWorldPtr copterSrcMap;
+extern GWorldPtr copterMaskMap;
+extern GWorldPtr dartSrcMap;
+extern GWorldPtr dartMaskMap;
+extern GWorldPtr ballSrcMap;
+extern GWorldPtr ballMaskMap;
+extern GWorldPtr dripSrcMap;
+extern GWorldPtr dripMaskMap;
+extern GWorldPtr enemySrcMap;
+extern GWorldPtr enemyMaskMap;
+extern GWorldPtr fishSrcMap;
+extern GWorldPtr fishMaskMap;
+extern GWorldPtr clutterSrcMap;
+extern GWorldPtr clutterMaskMap;
diff --git a/GpApp/Play.cpp b/GpApp/Play.cpp
new file mode 100644
index 0000000..f5a87d3
--- /dev/null
+++ b/GpApp/Play.cpp
@@ -0,0 +1,821 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Play.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLResources.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "House.h"
+#include "MainWindow.h"
+#include "RectUtils.h"
+#include "Scoreboard.h"
+
+
+#define kHouseBannerAlert 1009
+#define kInitialGliders 2
+#define kRingDelay 90
+#define kRingSpread 25000 // 25000
+#define kRingBaseDelay 5000 // 5000
+#define kChimeDelay 180
+
+
+typedef struct
+{
+ short nextRing;
+ short rings;
+ short delay;
+} phoneType, *phonePtr;
+
+
+void InitGlider (gliderPtr, short);
+void SetHouseToFirstRoom (void);
+void SetHouseToSavedRoom (void);
+void HandlePlayEvent (void);
+void PlayGame (void);
+void HandleRoomVisitation (void);
+void SetObjectsToDefaults (void);
+void InitTelephone (void);
+void HandleTelephone (void);
+Boolean DoesStarCodeExist (short);
+short GetNumStarsRemaining (short, short);
+
+
+phoneType thePhone, theChimes;
+Rect glidSrcRect, justRoomsRect;
+GWorldPtr glidSrcMap, glid2SrcMap;
+GWorldPtr glidMaskMap;
+long gameFrame;
+short batteryTotal, bandsTotal, foilTotal, mortals;
+Boolean playing, evenFrame, twoPlayerGame, showFoil, demoGoing;
+Boolean doBackground, playerSuicide, phoneBitSet, tvOn;
+
+extern WindowPtr menuWindow;
+extern FSSpecPtr theHousesSpecs;
+extern demoPtr demoData;
+extern gameType smallGame;
+extern Rect gliderSrc[kNumGliderSrcRects];
+extern Rect boardDestRect, boardSrcRect;
+extern long incrementModeTime;
+extern short numBands, otherPlayerEscaped, demoIndex, demoHouseIndex;
+extern short splashOriginH, splashOriginV, countDown, thisHouseIndex;
+extern short numStarsRemaining, numChimes, saidFollow;
+extern Boolean quitting, isMusicOn, gameOver, hasMirror, onePlayerLeft;
+extern Boolean isPlayMusicIdle, failedMusic, quickerTransitions;
+extern Boolean switchedOut;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- NewGame
+
+void NewGame (short mode)
+{
+ Rect tempRect;
+ Size freeBytes, growBytes;
+ OSErr theErr;
+ Boolean wasPlayMusicPref;
+
+ AdjustScoreboardHeight();
+ gameOver = false;
+ theMode = kPlayMode;
+ if (isPlayMusicGame)
+ {
+ if (!isMusicOn)
+ {
+ theErr = StartMusic();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowNoMusic, theErr);
+ failedMusic = true;
+ }
+ }
+ SetMusicalMode(kPlayGameScoreMode);
+ }
+ else
+ {
+ if (isMusicOn)
+ StopTheMusic();
+ }
+ if (mode != kResumeGameMode)
+ SetObjectsToDefaults();
+ HideCursor();
+ if (mode == kResumeGameMode)
+ SetHouseToSavedRoom();
+ else if (mode == kNewGameMode)
+ SetHouseToFirstRoom();
+ DetermineRoomOpenings();
+ NilSavedMaps();
+
+ gameFrame = 0L;
+ numBands = 0;
+ demoIndex = 0;
+ saidFollow = 0;
+ otherPlayerEscaped = kNoOneEscaped;
+ onePlayerLeft = false;
+ playerSuicide = false;
+
+ if (twoPlayerGame) // initialize glider(s)
+ {
+ InitGlider(&theGlider, kNewGameMode);
+ InitGlider(&theGlider2, kNewGameMode);
+ SetPort((GrafPtr)glidSrcMap);
+ LoadGraphic(kGliderPictID);
+ SetPort((GrafPtr)glid2SrcMap);
+ LoadGraphic(kGlider2PictID);
+ }
+ else
+ {
+ InitGlider(&theGlider, mode);
+ SetPort((GrafPtr)glidSrcMap);
+ LoadGraphic(kGliderPictID);
+ SetPort((GrafPtr)glid2SrcMap);
+ LoadGraphic(kGliderFoilPictID);
+ }
+
+#if !BUILD_ARCADE_VERSION
+// HideMenuBarOld(); // TEMP
+#endif
+
+ SetPort((GrafPtr)mainWindow); // paint strip on screen black
+ tempRect = thisMac.screen;
+ tempRect.top = tempRect.bottom - 20; // thisMac.menuHigh
+ PaintRect(&tempRect);
+
+#ifdef COMPILEQT
+ if ((thisMac.hasQT) && (hasMovie))
+ {
+ SetMovieGWorld(theMovie, (CGrafPtr)mainWindow, nil);
+ }
+#endif
+
+ SetPort((GrafPtr)workSrcMap);
+ PaintRect(&workSrcRect);
+// if (quickerTransitions)
+// DissBitsChunky(&workSrcRect);
+// else
+// DissBits(&workSrcRect);
+
+// DebugStr("\pIf screen isn't black, exit to shell."); // TEMP TEMP TEMP
+
+ DrawLocale();
+ RefreshScoreboard(kNormalTitleMode);
+// if (quickerTransitions)
+// DissBitsChunky(&justRoomsRect);
+// else
+// DissBits(&justRoomsRect);
+ if (mode == kNewGameMode)
+ {
+ BringUpBanner();
+ DumpScreenOn(&justRoomsRect);
+ }
+ else if (mode == kResumeGameMode)
+ {
+ DisplayStarsRemaining();
+ DumpScreenOn(&justRoomsRect);
+ }
+ else
+ {
+ DumpScreenOn(&justRoomsRect);
+ }
+
+ InitGarbageRects();
+ StartGliderFadingIn(&theGlider);
+ if (twoPlayerGame)
+ {
+ StartGliderFadingIn(&theGlider2);
+ TagGliderIdle(&theGlider2);
+ theGlider2.dontDraw = true;
+ }
+ InitTelephone();
+ wasPlayMusicPref = isPlayMusicGame;
+
+ freeBytes = MaxMem(&growBytes);
+
+#ifdef CREATEDEMODATA
+ SysBeep(1);
+#endif
+
+#ifdef COMPILEQT
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom))
+ {
+ SetMovieActive(theMovie, true);
+ if (tvOn)
+ {
+ StartMovie(theMovie);
+ MoviesTask(theMovie, 0);
+ }
+ }
+#endif
+
+ playing = true; // everything before this line is game set-up
+ PlayGame(); // everything following is after a game has ended
+
+#ifdef CREATEDEMODATA
+ DumpToResEditFile((Ptr)demoData, sizeof(demoType) * (long)demoIndex);
+#endif
+
+ isPlayMusicGame = wasPlayMusicPref;
+ ZeroMirrorRegion();
+
+#ifdef COMPILEQT
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom))
+ {
+ tvInRoom = false;
+ StopMovie(theMovie);
+ SetMovieActive(theMovie, false);
+ }
+#endif
+
+ twoPlayerGame = false;
+ theMode = kSplashMode;
+ InitCursor();
+ if (isPlayMusicIdle)
+ {
+ if (!isMusicOn)
+ {
+ theErr = StartMusic();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowNoMusic, theErr);
+ failedMusic = true;
+ }
+ }
+ SetMusicalMode(kPlayWholeScoreMode);
+ }
+ else
+ {
+ if (isMusicOn)
+ StopTheMusic();
+ }
+ NilSavedMaps();
+ SetPortWindowPort(mainWindow);
+ BlackenScoreboard();
+ UpdateMenus(false);
+
+ if (!gameOver)
+ {
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ InvalWindowRect(mainWindow, &mainWindowRect);
+
+ SetGWorld(workSrcMap, nil);
+ PaintRect(&workSrcRect);
+ QSetRect(&tempRect, 0, 0, 640, 460);
+ QOffsetRect(&tempRect, splashOriginH, splashOriginV);
+ LoadScaledGraphic(kSplash8BitPICT, &tempRect);
+
+ SetGWorld(wasCPort, wasWorld);
+ }
+ WaitCommandQReleased();
+ demoGoing = false;
+ incrementModeTime = TickCount() + kIdleSplashTicks;
+}
+
+//-------------------------------------------------------------- DoDemoGame
+
+void DoDemoGame (void)
+{
+ short wasHouseIndex;
+ Boolean whoCares;
+
+ wasHouseIndex = thisHouseIndex;
+ whoCares = CloseHouse();
+ thisHouseIndex = demoHouseIndex;
+ PasStringCopy(theHousesSpecs[thisHouseIndex].name, thisHouseName);
+ if (OpenHouse())
+ {
+ whoCares = ReadHouse();
+ demoGoing = true;
+ NewGame(kNewGameMode);
+ }
+ whoCares = CloseHouse();
+ thisHouseIndex = wasHouseIndex;
+ PasStringCopy(theHousesSpecs[thisHouseIndex].name, thisHouseName);
+ if (OpenHouse())
+ whoCares = ReadHouse();
+ incrementModeTime = TickCount() + kIdleSplashTicks;
+}
+
+//-------------------------------------------------------------- InitGlider
+
+void InitGlider (gliderPtr thisGlider, short mode)
+{
+ WhereDoesGliderBegin(&thisGlider->dest, mode);
+
+ if (mode == kResumeGameMode)
+ numStarsRemaining = smallGame.wasStarsLeft;
+ else if (mode == kNewGameMode)
+ numStarsRemaining = CountStarsInHouse();
+
+ if (mode == kResumeGameMode)
+ {
+ theScore = smallGame.score;
+ mortals = smallGame.numGliders;
+ batteryTotal = smallGame.energy;
+ bandsTotal = smallGame.bands;
+ foilTotal = smallGame.foil;
+ thisGlider->mode = smallGame.gliderState;
+ thisGlider->facing = smallGame.facing;
+ showFoil = smallGame.showFoil;
+
+ switch (thisGlider->mode)
+ {
+ case kGliderBurning:
+ FlagGliderBurning(thisGlider);
+ break;
+
+ default:
+ FlagGliderNormal(thisGlider);
+ break;
+ }
+ }
+ else
+ {
+ theScore = 0L;
+ mortals = kInitialGliders;
+ if (twoPlayerGame)
+ mortals += kInitialGliders;
+ batteryTotal = 0;
+ bandsTotal = 0;
+ foilTotal = 0;
+ thisGlider->mode = kGliderNormal;
+ thisGlider->facing = kFaceRight;
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ showFoil = false;
+ }
+
+ QSetRect(&thisGlider->destShadow, 0, 0, kGliderWide, kShadowHigh);
+ QOffsetRect(&thisGlider->destShadow, thisGlider->dest.left, kShadowTop);
+ thisGlider->wholeShadow = thisGlider->destShadow;
+
+ thisGlider->hVel = 0;
+ thisGlider->vVel = 0;
+ thisGlider->hDesiredVel = 0;
+ thisGlider->vDesiredVel = 0;
+
+ thisGlider->tipped = false;
+ thisGlider->sliding = false;
+ thisGlider->dontDraw = false;
+}
+
+//-------------------------------------------------------------- SetHouseToFirstRoom
+
+void SetHouseToFirstRoom (void)
+{
+ short firstRoom;
+
+ firstRoom = GetFirstRoomNumber();
+ ForceThisRoom(firstRoom);
+}
+
+//-------------------------------------------------------------- SetHouseToSavedRoom
+
+void SetHouseToSavedRoom (void)
+{
+ ForceThisRoom(smallGame.roomNumber);
+}
+
+//-------------------------------------------------------------- HandlePlayEvent
+
+void HandlePlayEvent (void)
+{
+ EventRecord theEvent;
+ GrafPtr wasPort;
+ long sleep = 2;
+
+ if (WaitNextEvent(everyEvent, &theEvent, sleep, nil))
+ {
+ if ((theEvent.what == updateEvt) &&
+ ((WindowPtr)theEvent.message == mainWindow))
+ {
+ GetPort(&wasPort);
+ SetPortWindowPort(mainWindow);
+ BeginUpdate(mainWindow);
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &justRoomsRect, &justRoomsRect, srcCopy, nil);
+ RefreshScoreboard(kNormalTitleMode);
+ EndUpdate(mainWindow);
+ SetPort(wasPort);
+ }
+ else if ((theEvent.what == osEvt) && (theEvent.message & 0x01000000))
+ {
+ if (theEvent.message & 0x00000001) // resume event
+ {
+ switchedOut = false;
+ ToggleMusicWhilePlaying();
+ HideCursor();
+// HideMenuBarOld(); // TEMP
+ }
+ else // suspend event
+ {
+ InitCursor();
+ switchedOut = true;
+ ToggleMusicWhilePlaying();
+// ShowMenuBarOld(); // TEMP replace with Carbon calls
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- PlayGame
+
+void PlayGame (void)
+{
+ while ((playing) && (!quitting))
+ {
+ gameFrame++;
+ evenFrame = !evenFrame;
+
+ if (doBackground)
+ {
+ do
+ {
+ HandlePlayEvent();
+ } while (switchedOut);
+ }
+
+ HandleTelephone();
+
+ if (twoPlayerGame)
+ {
+ HandleDynamics();
+ if (!gameOver)
+ {
+ GetInput(&theGlider);
+ GetInput(&theGlider2);
+ HandleInteraction();
+ }
+ HandleTriggers();
+ HandleBands();
+ if (!gameOver)
+ {
+ HandleGlider(&theGlider);
+ HandleGlider(&theGlider2);
+ }
+ if (playing)
+ {
+#ifdef COMPILEQT
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom) && (tvOn))
+ MoviesTask(theMovie, 0);
+#endif
+ RenderFrame();
+ HandleDynamicScoreboard();
+ }
+ }
+ else
+ {
+ HandleDynamics();
+ if (!gameOver)
+ {
+ if (demoGoing)
+ GetDemoInput(&theGlider);
+ else
+ GetInput(&theGlider);
+ HandleInteraction();
+ }
+ HandleTriggers();
+ HandleBands();
+ if (!gameOver)
+ HandleGlider(&theGlider);
+ if (playing)
+ {
+#ifdef COMPILEQT
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom) && (tvOn))
+ MoviesTask(theMovie, 0);
+#endif
+ RenderFrame();
+ HandleDynamicScoreboard();
+ }
+ }
+
+ if (gameOver)
+ {
+ countDown--;
+ if (countDown <= 0)
+ {
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ HideGlider(&theGlider);
+ RefreshScoreboard(kNormalTitleMode);
+
+#if BUILD_ARCADE_VERSION
+ // Need to paint over the scoreboard black.
+
+ SetGWorld(boardSrcMap, nil);
+ PaintRect(&boardSrcRect);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(boardSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &boardSrcRect, &boardDestRect, srcCopy, 0L);
+
+ {
+ Rect bounds;
+ PicHandle thePicture;
+ SInt16 hOffset;
+
+ if (boardSrcRect.right >= 640)
+ hOffset = (RectWide(&boardSrcRect) - kMaxViewWidth) / 2;
+ else
+ hOffset = -576;
+ thePicture = GetPicture(kScoreboardPictID);
+ if (!thePicture)
+ RedAlert(kErrFailedGraphicLoad);
+ HLock((Handle)thePicture);
+ bounds = (*thePicture)->picFrame;
+ HUnlock((Handle)thePicture);
+ QOffsetRect(&bounds, -bounds.left, -bounds.top);
+ QOffsetRect(&bounds, hOffset, 0);
+ DrawPicture(thePicture, &bounds);
+ ReleaseResource((Handle)thePicture);
+ }
+#else
+// ShowMenuBarOld(); // TEMP
+#endif
+
+ if (mortals < 0)
+ DoDiedGameOver();
+ else
+ DoGameOver();
+
+ SetGWorld(wasCPort, wasWorld);
+ }
+ }
+ }
+
+#if BUILD_ARCADE_VERSION
+ {
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ SetGWorld(boardSrcMap, nil);
+ PaintRect(&boardSrcRect);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(boardSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &boardSrcRect, &boardDestRect, srcCopy, 0L);
+
+ SetGWorld(wasCPort, wasWorld);
+ }
+
+ {
+ Rect bounds;
+ PicHandle thePicture;
+ SInt16 hOffset;
+
+ if (boardSrcRect.right >= 640)
+ hOffset = (RectWide(&boardSrcRect) - kMaxViewWidth) / 2;
+ else
+ hOffset = -576;
+ thePicture = GetPicture(kScoreboardPictID);
+ if (!thePicture)
+ RedAlert(kErrFailedGraphicLoad);
+ HLock((Handle)thePicture);
+ bounds = (*thePicture)->picFrame;
+ HUnlock((Handle)thePicture);
+ QOffsetRect(&bounds, -bounds.left, -bounds.top);
+ QOffsetRect(&bounds, hOffset, 0);
+ DrawPicture(thePicture, &bounds);
+ ReleaseResource((Handle)thePicture);
+ }
+
+#else
+
+// ShowMenuBarOld(); // TEMP
+
+#endif
+}
+
+//-------------------------------------------------------------- SetObjectsToDefaults
+
+void SetObjectsToDefaults (void)
+{
+ houseType *thisHousePtr;
+ short numRooms;
+ short r, i;
+ char wasState;
+ Boolean initState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ numRooms = thisHousePtr->nRooms;
+
+ for (r = 0; r < numRooms; r++)
+ {
+ thisHousePtr->rooms[r].visited = false;
+ for (i = 0; i < kMaxRoomObs; i++)
+ {
+ switch (thisHousePtr->rooms[r].objects[i].what)
+ {
+ case kFloorVent:
+ case kCeilingVent:
+ case kFloorBlower:
+ case kCeilingBlower:
+ case kLeftFan:
+ case kRightFan:
+ case kSewerGrate:
+ case kInvisBlower:
+ case kGrecoVent:
+ case kSewerBlower:
+ case kLiftArea:
+ thisHousePtr->rooms[r].objects[i].data.a.state =
+ thisHousePtr->rooms[r].objects[i].data.a.initial;
+ 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:
+ thisHousePtr->rooms[r].objects[i].data.c.state =
+ thisHousePtr->rooms[r].objects[i].data.c.initial;
+ break;
+
+ case kDeluxeTrans:
+ initState = (thisHousePtr->rooms[r].objects[i].data.d.wide & 0xF0) >> 4;
+ thisHousePtr->rooms[r].objects[i].data.d.wide &= 0xF0;
+ thisHousePtr->rooms[r].objects[i].data.d.wide += initState;
+ break;
+
+ case kCeilingLight:
+ case kLightBulb:
+ case kTableLamp:
+ case kHipLamp:
+ case kDecoLamp:
+ case kFlourescent:
+ case kTrackLight:
+ case kInvisLight:
+ thisHousePtr->rooms[r].objects[i].data.f.state =
+ thisHousePtr->rooms[r].objects[i].data.f.initial;
+ break;
+
+ case kStereo:
+ thisHousePtr->rooms[r].objects[i].data.g.state = isPlayMusicGame;
+ break;
+
+ case kShredder:
+ case kToaster:
+ case kMacPlus:
+ case kGuitar:
+ case kTV:
+ case kCoffee:
+ case kOutlet:
+ case kVCR:
+ case kMicrowave:
+ thisHousePtr->rooms[r].objects[i].data.g.state =
+ thisHousePtr->rooms[r].objects[i].data.g.initial;
+ break;
+
+ case kBalloon:
+ case kCopterLf:
+ case kCopterRt:
+ case kDartLf:
+ case kDartRt:
+ case kBall:
+ case kDrip:
+ case kFish:
+ thisHousePtr->rooms[r].objects[i].data.h.state =
+ thisHousePtr->rooms[r].objects[i].data.h.initial;
+ break;
+
+ }
+ }
+ }
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- HideGlider
+
+void HideGlider (gliderPtr thisGlider)
+{
+ Rect tempRect;
+
+ tempRect = thisGlider->whole;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+
+ if (hasMirror)
+ {
+ QOffsetRect(&tempRect, -20, -16);
+ CopyRectWorkToMain(&tempRect);
+ }
+
+ tempRect = thisGlider->wholeShadow;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+}
+
+//-------------------------------------------------------------- InitTelephone
+
+void InitTelephone (void)
+{
+ thePhone.nextRing = RandomInt(kRingSpread) + kRingBaseDelay;
+ thePhone.rings = RandomInt(3) + 3;
+ thePhone.delay = kRingDelay;
+
+ theChimes.nextRing = RandomInt(kChimeDelay) + 1;
+}
+
+//-------------------------------------------------------------- HandleTelephone
+
+void HandleTelephone (void)
+{
+ short delayTime;
+
+ if (!phoneBitSet)
+ {
+ if (thePhone.nextRing == 0)
+ {
+ if (thePhone.delay == 0)
+ {
+ thePhone.delay = kRingDelay;
+ PlayPrioritySound(kPhoneRingSound, kPhoneRingPriority);
+ thePhone.rings--;
+ if (thePhone.rings == 0)
+ {
+ thePhone.nextRing = RandomInt(kRingSpread) + kRingBaseDelay;
+ thePhone.rings = RandomInt(3) + 3;
+ }
+ }
+ else
+ thePhone.delay--;
+ }
+ else
+ thePhone.nextRing--;
+ }
+ // handle also the wind chimes (if they are present)
+
+ if (numChimes > 0)
+ {
+ if (theChimes.nextRing == 0)
+ {
+ if (RandomInt(2) == 0)
+ PlayPrioritySound(kChime1Sound, kChime1Priority);
+ else
+ PlayPrioritySound(kChime2Sound, kChime2Priority);
+
+ delayTime = kChimeDelay / numChimes;
+ if (delayTime < 2)
+ delayTime = 2;
+
+ theChimes.nextRing = RandomInt(delayTime) + 1;
+ }
+ else
+ theChimes.nextRing--;
+ }
+}
+
+//-------------------------------------------------------------- StrikeChime
+
+void StrikeChime (void)
+{
+ theChimes.nextRing = 0;
+}
+
+//-------------------------------------------------------------- RestoreEntireGameScreen
+
+void RestoreEntireGameScreen (void)
+{
+ Rect tempRect;
+
+ HideCursor();
+
+#if !BUILD_ARCADE_VERSION
+// HideMenuBarOld(); // TEMP
+#endif
+
+ SetPort((GrafPtr)mainWindow);
+ tempRect = thisMac.screen;
+ PaintRect(&tempRect);
+
+ DrawLocale();
+ RefreshScoreboard(kNormalTitleMode);
+// if (quickerTransitions)
+// DissBitsChunky(&justRoomsRect);
+// else
+// DissBits(&justRoomsRect);
+}
+
diff --git a/GpApp/Play.h b/GpApp/Play.h
new file mode 100644
index 0000000..2851a12
--- /dev/null
+++ b/GpApp/Play.h
@@ -0,0 +1,13 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Play.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+extern GWorldPtr glidSrcMap;
+extern GWorldPtr glid2SrcMap;
+extern GWorldPtr glidMaskMap;
diff --git a/GpApp/Player.cpp b/GpApp/Player.cpp
new file mode 100644
index 0000000..1e9597f
--- /dev/null
+++ b/GpApp/Player.cpp
@@ -0,0 +1,1605 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Player.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Play.h"
+#include "RectUtils.h"
+
+
+#define kGravity 3
+#define kHImpulse 2
+#define kVImpulse 2
+#define kMaxHVel 16
+#define kShredderCountdown -68
+
+
+void MoveGlider (gliderPtr);
+void MoveGliderNormal (gliderPtr);
+void MoveGliderBurning (gliderPtr);
+void FadeGliderIn (gliderPtr);
+void TransportGliderIn (gliderPtr);
+void FadeGliderOut (gliderPtr);
+void MoveGliderUpStairs (gliderPtr);
+void MoveGliderDownStairs (gliderPtr);
+void MoveGliderFaceLeft (gliderPtr);
+void MoveGliderFaceRight (gliderPtr);
+void TransportGliderOut (gliderPtr);
+void MoveGliderDownDuct (gliderPtr);
+void MoveGliderUpDuct (gliderPtr);
+void MoveGliderInMailLeft (gliderPtr);
+void MoveGliderInMailRight (gliderPtr);
+void FinishGliderMailingLeft (gliderPtr);
+void FinishGliderMailingRight (gliderPtr);
+void MoveGliderFoilGoing (gliderPtr);
+void MoveGliderFoilLosing (gliderPtr);
+void MoveGliderShredding (gliderPtr);
+void HandleIdleGlider (gliderPtr);
+
+
+gliderType theGlider, theGlider2;
+Rect shadowSrcRect;
+GWorldPtr shadowSrcMap;
+GWorldPtr shadowMaskMap;
+Rect shadowSrc[kNumShadowSrcRects];
+Rect gliderSrc[kNumGliderSrcRects];
+Rect transRect;
+long theScore;
+short fadeInSequence[kLastFadeSequence];
+short rightClip, leftClip, transRoom;
+Boolean shadowVisible, onePlayerLeft, playerDead;
+
+
+extern short numShredded, otherPlayerEscaped;
+extern Boolean playing, twoPlayerGame, gameOver, hasMirror;
+extern Boolean takingTheStairs, playerSuicide;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- MoveGlider
+
+void MoveGlider (gliderPtr thisGlider)
+{
+ if (thisGlider->hVel > thisGlider->hDesiredVel)
+ {
+ thisGlider->hVel -= kHImpulse;
+ if (thisGlider->hVel < thisGlider->hDesiredVel)
+ thisGlider->hVel = thisGlider->hDesiredVel;
+ }
+ else if (thisGlider->hVel < thisGlider->hDesiredVel)
+ {
+ thisGlider->hVel += kHImpulse;
+ if (thisGlider->hVel > thisGlider->hDesiredVel)
+ thisGlider->hVel = thisGlider->hDesiredVel;
+ }
+ thisGlider->hDesiredVel = 0;
+
+ if (thisGlider->vVel > thisGlider->vDesiredVel)
+ {
+ thisGlider->vVel -= kVImpulse;
+ if (thisGlider->vVel < thisGlider->vDesiredVel)
+ thisGlider->vVel = thisGlider->vDesiredVel;
+ }
+ else if (thisGlider->vVel < thisGlider->vDesiredVel)
+ {
+ thisGlider->vVel += kVImpulse;
+ if (thisGlider->vVel > thisGlider->vDesiredVel)
+ thisGlider->vVel = thisGlider->vDesiredVel;
+ }
+ thisGlider->vDesiredVel = kGravity;
+
+ if (thisGlider->hVel < 0)
+ {
+ if (thisGlider->hVel < -kMaxHVel)
+ thisGlider->hVel = -kMaxHVel;
+
+ thisGlider->wasHVel = thisGlider->hVel;
+
+ thisGlider->whole.right = thisGlider->dest.right;
+ thisGlider->dest.left += thisGlider->hVel;
+ thisGlider->dest.right += thisGlider->hVel;
+ thisGlider->whole.left = thisGlider->dest.left;
+
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+ thisGlider->destShadow.left += thisGlider->hVel;
+ thisGlider->destShadow.right += thisGlider->hVel;
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+ }
+ else
+ {
+ if (thisGlider->hVel > kMaxHVel)
+ thisGlider->hVel = kMaxHVel;
+
+ thisGlider->wasHVel = thisGlider->hVel;
+
+ thisGlider->whole.left = thisGlider->dest.left;
+ thisGlider->dest.left += thisGlider->hVel;
+ thisGlider->dest.right += thisGlider->hVel;
+ thisGlider->whole.right = thisGlider->dest.right;
+
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+ thisGlider->destShadow.left += thisGlider->hVel;
+ thisGlider->destShadow.right += thisGlider->hVel;
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+ }
+
+ if (thisGlider->vVel < 0)
+ {
+ thisGlider->wasVVel = thisGlider->vVel;
+
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+ thisGlider->dest.top += thisGlider->vVel;
+ thisGlider->dest.bottom += thisGlider->vVel;
+ thisGlider->whole.top = thisGlider->dest.top;
+ }
+ else
+ {
+ thisGlider->wasVVel = thisGlider->vVel;
+
+ thisGlider->whole.top = thisGlider->dest.top;
+ thisGlider->dest.top += thisGlider->vVel;
+ thisGlider->dest.bottom += thisGlider->vVel;
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderNormal
+
+void MoveGliderNormal (gliderPtr thisGlider)
+{
+ if (thisGlider->facing == kFaceLeft)
+ {
+ if (thisGlider->sliding)
+ {
+ thisGlider->src = gliderSrc[30];
+ thisGlider->mask = gliderSrc[30];
+ thisGlider->sliding = false;
+ }
+ else
+ {
+ if (thisGlider->tipped)
+ {
+ thisGlider->src = gliderSrc[3];
+ thisGlider->mask = gliderSrc[3];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ }
+ }
+ else
+ {
+ if (thisGlider->sliding)
+ {
+ thisGlider->src = gliderSrc[29];
+ thisGlider->mask = gliderSrc[29];
+ thisGlider->sliding = false;
+ }
+ else
+ {
+ if (thisGlider->tipped)
+ {
+ thisGlider->src = gliderSrc[1];
+ thisGlider->mask = gliderSrc[1];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ }
+ }
+ }
+
+ MoveGlider(thisGlider);
+}
+
+//-------------------------------------------------------------- MoveGliderBurning
+
+void MoveGliderBurning (gliderPtr thisGlider)
+{
+ thisGlider->frame++;
+ if (thisGlider->frame > 3)
+ thisGlider->frame = 0;
+
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[25 + thisGlider->frame];
+ thisGlider->mask = gliderSrc[25 + thisGlider->frame];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[21 + thisGlider->frame];
+ thisGlider->mask = gliderSrc[21 + thisGlider->frame];
+ }
+
+ thisGlider->wasMode--;
+ if (thisGlider->wasMode <= 0)
+ {
+ StartGliderFadingOut(thisGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ MoveGlider(thisGlider);
+}
+
+//-------------------------------------------------------------- FadeGliderIn
+
+void FadeGliderIn (gliderPtr thisGlider)
+{
+ if (thisGlider->frame == 0)
+ PlayPrioritySound(kFadeInSound, kFadeInPriority);
+
+ thisGlider->frame++;
+ if (thisGlider->frame >= kLastFadeSequence)
+ {
+ FlagGliderNormal(thisGlider);
+ thisGlider->enteredRect = thisGlider->dest;
+ }
+ else
+ {
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame] +
+ kLeftFadeOffset];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame] +
+ kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame]];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame]];
+ }
+ }
+}
+
+//-------------------------------------------------------------- TransportGliderIn
+
+void TransportGliderIn (gliderPtr thisGlider)
+{
+ if (thisGlider->frame == 0)
+ PlayPrioritySound(kTransInSound, kTransInPriority);
+
+ thisGlider->frame++;
+ if (thisGlider->frame >= kLastFadeSequence)
+ {
+ FlagGliderNormal(thisGlider);
+ thisGlider->enteredRect = thisGlider->dest;
+ }
+ else
+ {
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame] +
+ kLeftFadeOffset];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame] +
+ kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame]];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame]];
+ }
+ }
+}
+
+//-------------------------------------------------------------- FadeGliderOut
+
+void FadeGliderOut (gliderPtr thisGlider)
+{
+ thisGlider->frame--;
+ if (thisGlider->frame < 0)
+ OffAMortal(thisGlider);
+ else
+ {
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame] +
+ kLeftFadeOffset];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame] +
+ kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame]];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame]];
+ }
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderUpStairs
+
+void MoveGliderUpStairs (gliderPtr thisGlider)
+{
+ #define kClimbStairsSpeed -4
+ short vNotClipped;
+
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[1];
+ thisGlider->mask = gliderSrc[1];
+ }
+
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+ thisGlider->dest.top += kClimbStairsSpeed;
+ thisGlider->dest.bottom += kClimbStairsSpeed;
+ thisGlider->whole.top = thisGlider->dest.top;
+
+ vNotClipped = thisGlider->dest.bottom - 29;
+ if (vNotClipped < kGliderHigh)
+ {
+ if (vNotClipped <= 0)
+ {
+ thisGlider->dest.top = thisGlider->dest.bottom;
+ thisGlider->src.top = thisGlider->src.bottom;
+ thisGlider->mask.top = thisGlider->mask.bottom;
+ takingTheStairs = true;
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == kPlayer1)
+ MoveRoomToRoom(&theGlider2, kAbove);
+ else
+ MoveRoomToRoom(&theGlider, kAbove);
+ }
+ else
+ {
+ if (otherPlayerEscaped == kPlayerEscapedUpStairs)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveRoomToRoom(thisGlider, kAbove);
+ }
+ else
+ {
+ otherPlayerEscaped = kPlayerEscapedUpStairs;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ }
+ }
+ else
+ MoveRoomToRoom(thisGlider, kAbove);
+ }
+ else
+ {
+ thisGlider->dest.top = thisGlider->dest.bottom - vNotClipped;
+ thisGlider->src.top = thisGlider->src.bottom - vNotClipped;
+ thisGlider->mask.top = thisGlider->mask.bottom - vNotClipped;
+ }
+ }
+}
+
+//-------------------------------------------------------------- FinishGliderUpStairs
+
+void FinishGliderUpStairs (gliderPtr thisGlider)
+{
+ #define kVClimbStairsSpeed -4
+ #define kHClimbStairsSpeed -4
+ short hNotClipped;
+
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+ thisGlider->dest.top += kVClimbStairsSpeed;
+ thisGlider->dest.bottom += kVClimbStairsSpeed;
+ thisGlider->whole.top = thisGlider->dest.top;
+
+ thisGlider->whole.right = thisGlider->dest.right;
+ thisGlider->dest.left += kHClimbStairsSpeed;
+ thisGlider->dest.right += kHClimbStairsSpeed;
+ thisGlider->whole.left = thisGlider->dest.left;
+
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+ thisGlider->destShadow.left += kHClimbStairsSpeed;
+ thisGlider->destShadow.right += kHClimbStairsSpeed;
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+
+ hNotClipped = rightClip - thisGlider->dest.left;
+ if (hNotClipped < kGliderWide)
+ {
+ thisGlider->dest.right = thisGlider->dest.left + hNotClipped;
+ thisGlider->src.right = thisGlider->src.left + hNotClipped;
+ thisGlider->mask.right = thisGlider->mask.left + hNotClipped;
+ thisGlider->destShadow.right = thisGlider->dest.right;
+ }
+ else
+ {
+ if (thisGlider->frame == kWasBurning)
+ FlagGliderBurning(thisGlider);
+ else
+ FlagGliderNormal(thisGlider);
+ thisGlider->hVel = kHClimbStairsSpeed;
+ thisGlider->hDesiredVel = kHClimbStairsSpeed;
+ thisGlider->vVel = kVClimbStairsSpeed;
+ thisGlider->vDesiredVel = kVClimbStairsSpeed;
+ thisGlider->enteredRect = thisGlider->dest;
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderDownStairs
+
+void MoveGliderDownStairs (gliderPtr thisGlider)
+{
+ #define kVDropStairsSpeed 4
+ #define kHDropStairsSpeed 4
+ short hNotClipped;
+
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ }
+
+ thisGlider->whole.left = thisGlider->dest.left;
+ thisGlider->dest.left += kHDropStairsSpeed;
+ thisGlider->dest.right += kHDropStairsSpeed;
+ thisGlider->whole.right = thisGlider->dest.right;
+
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+ thisGlider->destShadow.left += kHDropStairsSpeed;
+ thisGlider->destShadow.right += kHDropStairsSpeed;
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+
+ thisGlider->whole.top = thisGlider->dest.top;
+ thisGlider->dest.top += kVDropStairsSpeed;
+ thisGlider->dest.bottom += kVDropStairsSpeed;
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+
+ hNotClipped = rightClip - thisGlider->dest.left;
+ if (hNotClipped < kGliderWide)
+ {
+ if (hNotClipped <= 0)
+ {
+ thisGlider->dest.right = thisGlider->dest.left;
+ thisGlider->src.right = thisGlider->src.left;
+ thisGlider->mask.right = thisGlider->mask.left;
+ thisGlider->destShadow.right = thisGlider->dest.right;
+ takingTheStairs = true;
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == kPlayer1)
+ MoveRoomToRoom(&theGlider2, kBelow);
+ else
+ MoveRoomToRoom(&theGlider, kBelow);
+ }
+ else
+ {
+ if (otherPlayerEscaped == kPlayerEscapedDownStairs)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ else
+ {
+ otherPlayerEscaped = kPlayerEscapedDownStairs;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ }
+ }
+ else
+ MoveRoomToRoom(thisGlider, kBelow);
+ }
+ else
+ {
+ thisGlider->dest.right = thisGlider->dest.left + hNotClipped;
+ thisGlider->src.right = thisGlider->src.left + hNotClipped;
+ thisGlider->mask.right = thisGlider->mask.left + hNotClipped;
+ thisGlider->destShadow.right = thisGlider->dest.right;
+ }
+ }
+}
+
+//-------------------------------------------------------------- FinishGliderDownStairs
+
+void FinishGliderDownStairs (gliderPtr thisGlider)
+{
+ #define kVDropStairsSpeed 4
+ #define kHDropStairsSpeed 4
+ short hNotClipped;
+
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+
+ thisGlider->whole.left = thisGlider->dest.left;
+ thisGlider->dest.left += kHDropStairsSpeed;
+ thisGlider->dest.right += kHDropStairsSpeed;
+ thisGlider->whole.right = thisGlider->dest.right;
+
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+ thisGlider->destShadow.left += kHDropStairsSpeed;
+ thisGlider->destShadow.right += kHDropStairsSpeed;
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+
+ thisGlider->whole.top = thisGlider->dest.top;
+ thisGlider->dest.top += kVDropStairsSpeed;
+ thisGlider->dest.bottom += kVDropStairsSpeed;
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+
+ hNotClipped = thisGlider->dest.right - leftClip;
+ if (hNotClipped < kGliderWide)
+ {
+ thisGlider->dest.left = thisGlider->dest.right - hNotClipped;
+ thisGlider->src.left = thisGlider->src.right - hNotClipped;
+ thisGlider->mask.left = thisGlider->mask.right - hNotClipped;
+ thisGlider->destShadow.left = thisGlider->dest.left;
+ }
+ else
+ {
+ if (thisGlider->frame == kWasBurning)
+ FlagGliderBurning(thisGlider);
+ else
+ FlagGliderNormal(thisGlider);
+ thisGlider->hVel = kHDropStairsSpeed;
+ thisGlider->hDesiredVel = kHDropStairsSpeed;
+ thisGlider->vVel = kVDropStairsSpeed;
+ thisGlider->vDesiredVel = kVDropStairsSpeed;
+ thisGlider->enteredRect = thisGlider->dest;
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderFaceLeft
+
+void MoveGliderFaceLeft (gliderPtr thisGlider)
+{
+ thisGlider->src = gliderSrc[thisGlider->frame];
+ thisGlider->mask = gliderSrc[thisGlider->frame];
+
+ MoveGlider(thisGlider);
+
+ thisGlider->frame--;
+ if (thisGlider->frame < kFirstAboutFaceFrame)
+ {
+ thisGlider->mode = kGliderNormal;
+ thisGlider->facing = kFaceLeft;
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderFaceRight
+
+void MoveGliderFaceRight (gliderPtr thisGlider)
+{
+ thisGlider->src = gliderSrc[thisGlider->frame];
+ thisGlider->mask = gliderSrc[thisGlider->frame];
+
+ MoveGlider(thisGlider);
+
+ thisGlider->frame++;
+ if (thisGlider->frame > kLastAboutFaceFrame)
+ {
+ thisGlider->mode = kGliderNormal;
+ thisGlider->facing = kFaceRight;
+ }
+}
+
+//-------------------------------------------------------------- TransportGliderOut
+
+void TransportGliderOut (gliderPtr thisGlider)
+{
+ Rect tempRect;
+
+ thisGlider->frame--;
+ if (thisGlider->frame < 0)
+ {
+ tempRect = thisGlider->whole;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+ tempRect = thisGlider->wholeShadow;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+ thisGlider->dontDraw = true;
+
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == kPlayer1)
+ TransportRoomToRoom(&theGlider2);
+ else
+ TransportRoomToRoom(&theGlider);
+ }
+ else
+ {
+ if (otherPlayerEscaped == kPlayerTransportedOut)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ TransportRoomToRoom(thisGlider);
+ }
+ else
+ {
+ otherPlayerEscaped = kPlayerTransportedOut;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ }
+ }
+ else
+ {
+ TransportRoomToRoom(thisGlider);
+ }
+ }
+ else
+ {
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame] +
+ kLeftFadeOffset];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame] +
+ kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[fadeInSequence[thisGlider->frame]];
+ thisGlider->mask = gliderSrc[fadeInSequence[thisGlider->frame]];
+ }
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderDownDuct
+
+void MoveGliderDownDuct (gliderPtr thisGlider)
+{
+ #define kVDropDuctSpeed 4
+ Rect tempRect;
+ short vNotClipped;
+
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ }
+
+ if (thisGlider->dest.left < thisGlider->clip.left)
+ {
+ thisGlider->whole.left = thisGlider->dest.left;
+ thisGlider->dest.left++;
+ thisGlider->dest.right++;
+ thisGlider->whole.right = thisGlider->dest.right;
+
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+ thisGlider->destShadow.left++;
+ thisGlider->destShadow.right++;
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+ }
+ else if (thisGlider->dest.left > thisGlider->clip.left)
+ {
+ thisGlider->whole.right = thisGlider->dest.right;
+ thisGlider->dest.left--;
+ thisGlider->dest.right--;
+ thisGlider->whole.left = thisGlider->dest.left;
+
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+ thisGlider->destShadow.left--;
+ thisGlider->destShadow.right--;
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+ }
+
+ thisGlider->whole.top = thisGlider->dest.top;
+ thisGlider->dest.top += kVDropDuctSpeed;
+ thisGlider->dest.bottom += kVDropDuctSpeed;
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+
+ vNotClipped = 315 - thisGlider->dest.top;
+ if (vNotClipped < kGliderHigh)
+ {
+ if (vNotClipped <= 0)
+ {
+ tempRect = thisGlider->whole;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+ tempRect = thisGlider->wholeShadow;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+ thisGlider->dontDraw = true;
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == kPlayer1)
+ MoveDuctToDuct(&theGlider2);
+ else
+ MoveDuctToDuct(&theGlider);
+ }
+ else
+ {
+ if (otherPlayerEscaped == kPlayerDuckedOut)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveDuctToDuct(thisGlider);
+ }
+ else
+ {
+ otherPlayerEscaped = kPlayerDuckedOut;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ }
+ }
+ else
+ MoveDuctToDuct(thisGlider);
+ }
+ else
+ {
+ thisGlider->dest.bottom = thisGlider->dest.top + vNotClipped;
+ thisGlider->src.bottom = thisGlider->src.top + vNotClipped;
+ thisGlider->mask.bottom = thisGlider->mask.top + vNotClipped;
+ }
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderUpDuct
+
+void MoveGliderUpDuct (gliderPtr thisGlider)
+{
+ #define kVRiseDuctSpeed -4
+ Rect tempRect;
+ short vNotClipped;
+
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ }
+
+ if (thisGlider->dest.left < thisGlider->clip.left)
+ {
+ thisGlider->whole.left = thisGlider->dest.left;
+ thisGlider->dest.left++;
+ thisGlider->dest.right++;
+ thisGlider->whole.right = thisGlider->dest.right;
+
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+ thisGlider->destShadow.left++;
+ thisGlider->destShadow.right++;
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+ }
+ else if (thisGlider->dest.left > thisGlider->clip.left)
+ {
+ thisGlider->whole.right = thisGlider->dest.right;
+ thisGlider->dest.left--;
+ thisGlider->dest.right--;
+ thisGlider->whole.left = thisGlider->dest.left;
+
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+ thisGlider->destShadow.left--;
+ thisGlider->destShadow.right--;
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+ }
+
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+ thisGlider->dest.top += kVRiseDuctSpeed;
+ thisGlider->dest.bottom += kVRiseDuctSpeed;
+ thisGlider->whole.top = thisGlider->dest.top;
+
+ vNotClipped = thisGlider->dest.bottom - (kCeilingTransTop + 1);
+ if (vNotClipped < kGliderHigh)
+ {
+ if (vNotClipped <= 0)
+ {
+ tempRect = thisGlider->whole;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+ tempRect = thisGlider->wholeShadow;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+ thisGlider->dontDraw = true;
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == kPlayer1)
+ MoveDuctToDuct(&theGlider2);
+ else
+ MoveDuctToDuct(&theGlider);
+ }
+ else
+ {
+ if (otherPlayerEscaped == kPlayerDuckedOut)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveDuctToDuct(thisGlider);
+ }
+ else
+ {
+ otherPlayerEscaped = kPlayerDuckedOut;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ }
+ }
+ else
+ MoveDuctToDuct(thisGlider);
+ }
+ else
+ {
+ thisGlider->dest.top = thisGlider->dest.bottom - vNotClipped;
+ thisGlider->src.top = thisGlider->src.bottom - vNotClipped;
+ thisGlider->mask.top = thisGlider->mask.bottom - vNotClipped;
+ }
+ }
+}
+
+//-------------------------------------------------------------- FinishGliderMailingLeft
+
+void FinishGliderMailingLeft (gliderPtr thisGlider)
+{
+ #define kHPushMailSpeed -4
+ short hNotClipped;
+
+ if (thisGlider->dest.left == thisGlider->dest.right)
+ PlayPrioritySound(kTransInSound, kTransInPriority);
+
+ thisGlider->whole.right = thisGlider->dest.right;
+ thisGlider->dest.left += kHPushMailSpeed;
+ thisGlider->dest.right += kHPushMailSpeed;
+ thisGlider->whole.left = thisGlider->dest.left;
+
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+ thisGlider->destShadow.left += kHPushMailSpeed;
+ thisGlider->destShadow.right += kHPushMailSpeed;
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+
+ hNotClipped = thisGlider->clip.right - thisGlider->dest.left;
+ if (hNotClipped < kGliderWide)
+ {
+ thisGlider->dest.right = thisGlider->dest.left + hNotClipped;
+ thisGlider->src.right = thisGlider->src.left + hNotClipped;
+ thisGlider->mask.right = thisGlider->mask.left + hNotClipped;
+ thisGlider->destShadow.right = thisGlider->dest.right;
+ }
+ else
+ {
+ if (thisGlider->frame == kWasBurning)
+ FlagGliderBurning(thisGlider);
+ else
+ FlagGliderNormal(thisGlider);
+ thisGlider->enteredRect = thisGlider->dest;
+ }
+}
+
+//-------------------------------------------------------------- FinishGliderMailingRight
+
+void FinishGliderMailingRight (gliderPtr thisGlider)
+{
+ #define kHPushMailRtSpeed 4
+ short hNotClipped;
+
+ if (thisGlider->dest.left == thisGlider->dest.right)
+ PlayPrioritySound(kTransInSound, kTransInPriority);
+
+ thisGlider->whole.left = thisGlider->dest.left;
+ thisGlider->dest.left += kHPushMailRtSpeed;
+ thisGlider->dest.right += kHPushMailRtSpeed;
+ thisGlider->whole.right = thisGlider->dest.right;
+
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+ thisGlider->destShadow.left += kHPushMailRtSpeed;
+ thisGlider->destShadow.right += kHPushMailRtSpeed;
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+
+ hNotClipped = thisGlider->dest.right - thisGlider->clip.left;
+ if (hNotClipped < kGliderWide)
+ {
+ thisGlider->dest.left = thisGlider->dest.right - hNotClipped;
+ thisGlider->src.left = thisGlider->src.right - hNotClipped;
+ thisGlider->mask.left = thisGlider->mask.right - hNotClipped;
+ thisGlider->destShadow.left = thisGlider->dest.left;
+ }
+ else
+ {
+ if (thisGlider->frame == kWasBurning)
+ FlagGliderBurning(thisGlider);
+ else
+ FlagGliderNormal(thisGlider);
+ thisGlider->enteredRect = thisGlider->dest;
+ }
+}
+
+//-------------------------------------------------------------- FinishGliderDuctingIn
+
+void FinishGliderDuctingIn (gliderPtr thisGlider)
+{
+ #define kVDropStairsSpeed 4
+ short vNotClipped;
+
+ if (thisGlider->dest.top == thisGlider->dest.bottom)
+ PlayPrioritySound(kTransInSound, kTransInPriority);
+
+ thisGlider->whole.top = thisGlider->dest.top;
+ thisGlider->dest.top += kVDropDuctSpeed;
+ thisGlider->dest.bottom += kVDropDuctSpeed;
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+
+ vNotClipped = thisGlider->dest.bottom - (kCeilingTransTop + 1);
+ if (vNotClipped < kGliderHigh)
+ {
+ thisGlider->dest.top = thisGlider->dest.bottom - vNotClipped;
+ thisGlider->src.top = thisGlider->src.bottom - vNotClipped;
+ thisGlider->mask.top = thisGlider->mask.bottom - vNotClipped;
+ }
+ else
+ {
+ if (thisGlider->frame == kWasBurning)
+ FlagGliderBurning(thisGlider);
+ else
+ FlagGliderNormal(thisGlider);
+ thisGlider->enteredRect = thisGlider->dest;
+ FlagStillOvers(thisGlider);
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderInMailLeft
+
+void MoveGliderInMailLeft (gliderPtr thisGlider)
+{
+ #define kHMailPullSpeed 4
+ #define kVMailDropSpeed 2
+ Rect tempRect;
+ short fromIdealTop, hNotClipped;
+
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ }
+
+ if (thisGlider->dest.top < thisGlider->clip.top)
+ {
+ fromIdealTop = thisGlider->clip.top - thisGlider->dest.top;
+ if (fromIdealTop > kVMailDropSpeed)
+ fromIdealTop = kVMailDropSpeed;
+
+ thisGlider->whole.top = thisGlider->dest.top;
+ thisGlider->dest.top += fromIdealTop;
+ thisGlider->dest.bottom += fromIdealTop;
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+ }
+
+ thisGlider->whole.left = thisGlider->dest.left;
+ thisGlider->dest.left += kHMailPullSpeed;
+ thisGlider->dest.right += kHMailPullSpeed;
+ thisGlider->whole.right = thisGlider->dest.right;
+
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+ thisGlider->destShadow.left += kHMailPullSpeed;
+ thisGlider->destShadow.right += kHMailPullSpeed;
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+
+ hNotClipped = thisGlider->clip.right - thisGlider->dest.left;
+ if (hNotClipped < kGliderWide)
+ {
+ if (hNotClipped <= 0)
+ {
+ tempRect = thisGlider->whole;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+ tempRect = thisGlider->wholeShadow;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+ thisGlider->dontDraw = true;
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == kPlayer1)
+ MoveMailToMail(&theGlider2);
+ else
+ MoveMailToMail(&theGlider);
+ }
+ else
+ {
+ if (otherPlayerEscaped == kPlayerMailedOut)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveMailToMail(thisGlider);
+ }
+ else
+ {
+ otherPlayerEscaped = kPlayerMailedOut;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ }
+ }
+ else
+ MoveMailToMail(thisGlider);
+ }
+ else
+ {
+ thisGlider->dest.right = thisGlider->dest.left + hNotClipped;
+ thisGlider->src.right = thisGlider->src.left + hNotClipped;
+ thisGlider->mask.right = thisGlider->mask.left + hNotClipped;
+ thisGlider->destShadow.right = thisGlider->dest.right;
+ }
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderInMailRight
+
+void MoveGliderInMailRight (gliderPtr thisGlider)
+{
+ #define kHMailPullRtSpeed -4
+ #define kVMailDropSpeed 2
+ Rect tempRect;
+ short fromIdealTop, hNotClipped;
+
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ }
+
+ if (thisGlider->dest.top < thisGlider->clip.top)
+ {
+ fromIdealTop = thisGlider->clip.top - thisGlider->dest.top;
+ if (fromIdealTop > kVMailDropSpeed)
+ fromIdealTop = kVMailDropSpeed;
+
+ thisGlider->whole.top = thisGlider->dest.top;
+ thisGlider->dest.top += fromIdealTop;
+ thisGlider->dest.bottom += fromIdealTop;
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+ }
+
+ thisGlider->whole.right = thisGlider->dest.right;
+ thisGlider->dest.left += kHMailPullRtSpeed;
+ thisGlider->dest.right += kHMailPullRtSpeed;
+ thisGlider->whole.left = thisGlider->dest.left;
+
+ thisGlider->wholeShadow.right = thisGlider->destShadow.right;
+ thisGlider->destShadow.left += kHMailPullRtSpeed;
+ thisGlider->destShadow.right += kHMailPullRtSpeed;
+ thisGlider->wholeShadow.left = thisGlider->destShadow.left;
+
+ hNotClipped = thisGlider->dest.right - thisGlider->clip.left;
+ if (hNotClipped < kGliderWide)
+ {
+ if (hNotClipped <= 0)
+ {
+ tempRect = thisGlider->whole;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+ tempRect = thisGlider->wholeShadow;
+ QOffsetRect(&tempRect, playOriginH, playOriginV);
+ CopyRectWorkToMain(&tempRect);
+ thisGlider->dontDraw = true;
+ if (twoPlayerGame)
+ {
+ if (onePlayerLeft)
+ {
+ if (playerDead == kPlayer1)
+ MoveMailToMail(&theGlider2);
+ else
+ MoveMailToMail(&theGlider);
+ }
+ else
+ {
+ if (otherPlayerEscaped == kPlayerMailedOut)
+ {
+ otherPlayerEscaped = kNoOneEscaped;
+ MoveMailToMail(thisGlider);
+ }
+ else
+ {
+ otherPlayerEscaped = kPlayerMailedOut;
+ RefreshScoreboard(kEscapedTitleMode);
+ FlagGliderInLimbo(thisGlider, true);
+ }
+ }
+ }
+ else
+ MoveMailToMail(thisGlider);
+ }
+ else
+ {
+ thisGlider->dest.left = thisGlider->dest.right - hNotClipped;
+ thisGlider->src.left = thisGlider->src.right - hNotClipped;
+ thisGlider->mask.left = thisGlider->mask.right - hNotClipped;
+ thisGlider->destShadow.left = thisGlider->dest.left;
+ }
+ }
+}
+
+//-------------------------------------------------------------- DeckGliderInFoil
+
+void DeckGliderInFoil (gliderPtr thisGlider)
+{
+ showFoil = true;
+
+ if (twoPlayerGame)
+ {
+ SetPort((GrafPtr)glidSrcMap);
+ LoadGraphic(kGliderFoilPictID);
+ SetPort((GrafPtr)glid2SrcMap);
+ LoadGraphic(kGliderFoil2PictID);
+ }
+
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[(thisGlider->frame + 2) +
+ kLeftFadeOffset];
+ thisGlider->mask = gliderSrc[(thisGlider->frame + 2) +
+ kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[thisGlider->frame + 2];
+ thisGlider->mask = gliderSrc[thisGlider->frame + 2];
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderFoilGoing
+
+void MoveGliderFoilGoing (gliderPtr thisGlider)
+{
+ thisGlider->frame++;
+ if (thisGlider->frame > 8)
+ {
+ FlagGliderNormal(thisGlider);
+ }
+ else
+ {
+ if (thisGlider->frame < 5)
+ {
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[(10 - thisGlider->frame) +
+ kLeftFadeOffset];
+ thisGlider->mask = gliderSrc[(10 - thisGlider->frame) +
+ kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[10 - thisGlider->frame];
+ thisGlider->mask = gliderSrc[10 - thisGlider->frame];
+ }
+ }
+ else
+ DeckGliderInFoil(thisGlider);
+ }
+ MoveGlider(thisGlider);
+}
+
+//-------------------------------------------------------------- xxxx
+
+void RemoveFoilFromGlider (gliderPtr thisGlider)
+{
+ showFoil = false;
+
+ if (twoPlayerGame)
+ {
+ SetPort((GrafPtr)glidSrcMap);
+ LoadGraphic(kGliderPictID);
+ SetPort((GrafPtr)glid2SrcMap);
+ LoadGraphic(kGlider2PictID);
+ }
+
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[(thisGlider->frame + 2) +
+ kLeftFadeOffset];
+ thisGlider->mask = gliderSrc[(thisGlider->frame + 2) +
+ kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[thisGlider->frame + 2];
+ thisGlider->mask = gliderSrc[thisGlider->frame + 2];
+ }
+}
+
+//-------------------------------------------------------------- MoveGliderFoilLosing
+
+void MoveGliderFoilLosing (gliderPtr thisGlider)
+{
+ thisGlider->frame++;
+ if (thisGlider->frame > 8)
+ FlagGliderNormal(thisGlider);
+ else
+ {
+ if (thisGlider->frame < 5)
+ {
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[(10 - thisGlider->frame) +
+ kLeftFadeOffset];
+ thisGlider->mask = gliderSrc[(10 - thisGlider->frame) +
+ kLeftFadeOffset];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[10 - thisGlider->frame];
+ thisGlider->mask = gliderSrc[10 - thisGlider->frame];
+ }
+ }
+ else
+ RemoveFoilFromGlider(thisGlider);
+ }
+ MoveGlider(thisGlider);
+}
+
+//-------------------------------------------------------------- MoveGliderShredding
+
+void MoveGliderShredding (gliderPtr thisGlider)
+{
+ #define kDropShredSlow 1
+ #define kDropShredFast 4
+ short vNotClipped;
+
+ if (thisGlider->frame > 0)
+ {
+ if (thisGlider->facing == kFaceLeft)
+ {
+ thisGlider->src = gliderSrc[2];
+ thisGlider->mask = gliderSrc[2];
+ }
+ else
+ {
+ thisGlider->src = gliderSrc[0];
+ thisGlider->mask = gliderSrc[0];
+ }
+
+ vNotClipped = thisGlider->frame - thisGlider->dest.top;
+ if (vNotClipped < kGliderHigh)
+ {
+ thisGlider->whole.top = thisGlider->dest.top;
+ thisGlider->dest.top += kDropShredSlow;
+ thisGlider->dest.bottom += kDropShredSlow;
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+ shadowVisible = false;
+ PlayPrioritySound(kShredSound, kShredPriority);
+ }
+ else
+ {
+ thisGlider->whole.top = thisGlider->dest.top;
+ thisGlider->dest.top += kDropShredFast;
+ thisGlider->dest.bottom += kDropShredFast;
+ thisGlider->whole.bottom = thisGlider->dest.bottom;
+ }
+
+ vNotClipped = thisGlider->frame - thisGlider->dest.top;
+ if (vNotClipped < kGliderHigh)
+ {
+ if (vNotClipped <= 0)
+ {
+ AddAShreddedGlider(&thisGlider->dest);
+ thisGlider->frame = kShredderCountdown;
+ }
+ else
+ {
+ thisGlider->dest.bottom = thisGlider->dest.top + vNotClipped;
+ thisGlider->src.bottom = thisGlider->src.top + vNotClipped;
+ thisGlider->mask.bottom = thisGlider->mask.top + vNotClipped;
+ }
+ }
+ }
+ else
+ {
+ thisGlider->frame++;
+ if (thisGlider->frame >= 0)
+ OffAMortal(thisGlider);
+ }
+}
+
+//-------------------------------------------------------------- HandleIdleGlider
+
+void HandleIdleGlider (gliderPtr thisGlider)
+{
+ thisGlider->hVel--;
+ if (thisGlider->hVel <= 0)
+ {
+ thisGlider->mode = thisGlider->wasMode;
+ thisGlider->dontDraw = false;
+ }
+}
+
+//-------------------------------------------------------------- HandleGlider
+
+void HandleGlider (gliderPtr thisGlider)
+{
+ switch (thisGlider->mode)
+ {
+ case kGliderNormal:
+ MoveGliderNormal(thisGlider);
+ break;
+
+ case kGliderFadingIn:
+ FadeGliderIn(thisGlider);
+ break;
+
+ case kGliderFadingOut:
+ FadeGliderOut(thisGlider);
+ break;
+
+ case kGliderGoingUp:
+ MoveGliderUpStairs(thisGlider);
+ break;
+
+ case kGliderComingUp:
+ FinishGliderUpStairs(thisGlider);
+ break;
+
+ case kGliderGoingDown:
+ MoveGliderDownStairs(thisGlider);
+ break;
+
+ case kGliderComingDown:
+ FinishGliderDownStairs(thisGlider);
+ break;
+
+ case kGliderFaceLeft:
+ MoveGliderFaceLeft(thisGlider);
+ break;
+
+ case kGliderFaceRight:
+ MoveGliderFaceRight(thisGlider);
+ break;
+
+ case kGliderBurning:
+ MoveGliderBurning(thisGlider);
+ break;
+
+ case kGliderTransporting:
+ TransportGliderOut(thisGlider);
+ break;
+
+ case kGliderDuctingDown:
+ MoveGliderDownDuct(thisGlider);
+ break;
+
+ case kGliderDuctingUp:
+ MoveGliderUpDuct(thisGlider);
+ break;
+
+ case kGliderDuctingIn:
+ FinishGliderDuctingIn(thisGlider);
+ break;
+
+ case kGliderMailInLeft:
+ MoveGliderInMailLeft(thisGlider);
+ break;
+
+ case kGliderMailOutLeft: // <-- G _[]
+ FinishGliderMailingLeft(thisGlider);
+ break;
+
+ case kGliderMailInRight:
+ MoveGliderInMailRight(thisGlider);
+ break;
+
+ case kGliderMailOutRight: // []_ G -->
+ FinishGliderMailingRight(thisGlider);
+ break;
+
+ case kGliderGoingFoil:
+ MoveGliderFoilGoing(thisGlider);
+ break;
+
+ case kGliderLosingFoil:
+ MoveGliderFoilLosing(thisGlider);
+ break;
+
+ case kGliderShredding:
+ MoveGliderShredding(thisGlider);
+ break;
+
+ case kGliderInLimbo:
+ break;
+
+ case kGliderIdle:
+ HandleIdleGlider(thisGlider);
+ break;
+
+ case kGliderTransportingIn:
+ TransportGliderIn(thisGlider);
+ break;
+
+ }
+
+ thisGlider->ignoreLeft = false;
+ thisGlider->ignoreRight = false;
+ thisGlider->ignoreGround = false;
+}
+
+//-------------------------------------------------------------- OffsetGlider
+
+void OffsetGlider (gliderPtr thisGlider, short where)
+{
+ if ((twoPlayerGame) && (onePlayerLeft) && (thisGlider->which == playerDead))
+ return;
+
+ switch (where)
+ {
+ case kToRight:
+ thisGlider->dest.left += kRoomWide;
+ thisGlider->dest.right += kRoomWide;
+ thisGlider->destShadow.left += kRoomWide;
+ thisGlider->destShadow.right += kRoomWide;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->wholeShadow = thisGlider->destShadow;
+ break;
+
+ case kToLeft:
+ thisGlider->dest.left -= kRoomWide;
+ thisGlider->dest.right -= kRoomWide;
+ thisGlider->destShadow.left -= kRoomWide;
+ thisGlider->destShadow.right -= kRoomWide;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->wholeShadow = thisGlider->destShadow;
+ break;
+
+ case kAbove:
+ thisGlider->dest.top -= kTileHigh;
+ thisGlider->dest.bottom -= kTileHigh;
+ thisGlider->whole = thisGlider->dest;
+ break;
+
+ case kBelow:
+ thisGlider->dest.top += kTileHigh;
+ thisGlider->dest.bottom += kTileHigh;
+ thisGlider->whole = thisGlider->dest;
+ break;
+ }
+}
+
+//-------------------------------------------------------------- OffAMortal
+
+void OffAMortal (gliderPtr thisGlider)
+{
+ if (gameOver)
+ return;
+
+ if (numShredded > 0)
+ RemoveShreds();
+
+ mortals--;
+ if (mortals < 0)
+ {
+ HideGlider(thisGlider);
+ if (twoPlayerGame)
+ {
+ if (mortals < -1) // both players are now dead
+ {
+ FlagGameOver();
+ thisGlider->dontDraw = true;
+ }
+ else
+ {
+ FlagGliderInLimbo(thisGlider, false);
+ thisGlider->dontDraw = true;
+ onePlayerLeft = true;
+ playerDead = thisGlider->which;
+ }
+ }
+ else
+ {
+ FlagGameOver();
+ thisGlider->dontDraw = true;
+ }
+ }
+ else
+ {
+ QuickGlidersRefresh();
+ HideGlider(thisGlider);
+ }
+
+ if (mortals >= 0)
+ {
+ if (thisGlider->mode == kGliderGoingFoil)
+ DeckGliderInFoil(thisGlider);
+
+ FlagGliderNormal(thisGlider);
+ if (playerSuicide)
+ FollowTheLeader();
+ else
+ {
+ StartGliderFadingIn(thisGlider);
+ thisGlider->dest = thisGlider->enteredRect;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->destShadow.left = thisGlider->dest.left;
+ thisGlider->destShadow.right = thisGlider->dest.right;
+ thisGlider->wholeShadow = thisGlider->destShadow;
+ }
+ }
+ else if ((mortals == -1) && (onePlayerLeft) && (!gameOver))
+ {
+ switch (otherPlayerEscaped)
+ {
+ case kPlayerEscapedUp:
+ case kPlayerEscapingUpStairs:
+ case kPlayerEscapedUpStairs:
+ if (playerDead == kPlayer1)
+ MoveRoomToRoom(&theGlider2, kAbove);
+ else
+ MoveRoomToRoom(&theGlider, kAbove);
+ break;
+
+ case kPlayerEscapedDown:
+ case kPlayerEscapingDownStairs:
+ case kPlayerEscapedDownStairs:
+ if (playerDead == kPlayer1)
+ MoveRoomToRoom(&theGlider2, kBelow);
+ else
+ MoveRoomToRoom(&theGlider, kBelow);
+ break;
+
+ case kPlayerEscapedLeft:
+ if (playerDead == kPlayer1)
+ MoveRoomToRoom(&theGlider2, kToLeft);
+ else
+ MoveRoomToRoom(&theGlider, kToLeft);
+ break;
+
+ case kPlayerEscapedRight:
+ if (playerDead == kPlayer1)
+ MoveRoomToRoom(&theGlider2, kToRight);
+ else
+ MoveRoomToRoom(&theGlider, kToRight);
+ break;
+
+ case kPlayerTransportedOut:
+ if (playerDead == kPlayer1)
+ TransportRoomToRoom(&theGlider2);
+ else
+ TransportRoomToRoom(&theGlider);
+ break;
+
+ case kPlayerMailedOut:
+ if (playerDead == kPlayer1)
+ MoveMailToMail(&theGlider2);
+ else
+ MoveMailToMail(&theGlider);
+ break;
+
+ case kPlayerDuckedOut:
+ if (playerDead == kPlayer1)
+ MoveDuctToDuct(&theGlider2);
+ else
+ MoveDuctToDuct(&theGlider);
+ break;
+
+ default:
+ break;
+ }
+
+ otherPlayerEscaped = kPlayerIsDeadForever;
+ }
+}
+
diff --git a/GpApp/Player.h b/GpApp/Player.h
new file mode 100644
index 0000000..669f23a
--- /dev/null
+++ b/GpApp/Player.h
@@ -0,0 +1,12 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Player.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+extern GWorldPtr shadowSrcMap;
+extern GWorldPtr shadowMaskMap;
diff --git a/Prefix.h b/GpApp/Prefix.h
old mode 100755
new mode 100644
similarity index 100%
rename from Prefix.h
rename to GpApp/Prefix.h
diff --git a/GpApp/Prefs.cpp b/GpApp/Prefs.cpp
new file mode 100644
index 0000000..10cd308
--- /dev/null
+++ b/GpApp/Prefs.cpp
@@ -0,0 +1,269 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Prefs.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+
+
+#define kPrefCreatorType 'ozm5'
+#define kPrefFileType 'gliP'
+#define kPrefFileName PSTR("Glider Prefs")
+#define kDefaultPrefFName PSTR("Preferences")
+#define kPrefsStringsID 160
+#define kNewPrefsAlertID 160
+#define kPrefsFNameIndex 1
+
+
+Boolean CanUseFindFolder (void);
+Boolean GetPrefsFPath (long *, short *);
+Boolean CreatePrefsFolder (short *);
+Boolean WritePrefs (long *, short *, prefsInfo *);
+OSErr ReadPrefs (long *, short *, prefsInfo *);
+Boolean DeletePrefs (long *, short *);
+void BringUpDeletePrefsAlert (void);
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- CanUseFindFolder
+
+Boolean CanUseFindFolder (void)
+{
+ return true;
+}
+
+//-------------------------------------------------------------- GetPrefsFPath
+
+Boolean GetPrefsFPath (long *prefDirID, short *systemVolRef)
+{
+ OSErr theErr;
+
+ theErr = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
+ systemVolRef, prefDirID);
+ if (theErr != noErr)
+ return(false);
+
+ return(true);
+}
+
+//-------------------------------------------------------------- CreatePrefsFolder
+
+Boolean CreatePrefsFolder (short *systemVolRef)
+{
+ HFileParam fileParamBlock;
+ Str255 folderName;
+ OSErr theErr;
+
+ GetIndString(folderName, kPrefsStringsID, kPrefsFNameIndex);
+
+ fileParamBlock.ioVRefNum = *systemVolRef;
+ fileParamBlock.ioDirID = 0;
+ fileParamBlock.ioNamePtr = folderName;
+ fileParamBlock.ioCompletion = nil;
+
+ theErr = PBDirCreate(&fileParamBlock, false);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, PSTR("Preferences"));
+ return(false);
+ }
+ return(true);
+}
+
+//-------------------------------------------------------------- WritePrefs
+
+Boolean WritePrefs (long *prefDirID, short *systemVolRef, prefsInfo *thePrefs)
+{
+ OSErr theErr;
+ short fileRefNum;
+ long byteCount;
+ FSSpec theSpecs;
+ Str255 fileName;
+
+ PasStringCopy(kPrefFileName, fileName);
+
+ theErr = FSMakeFSSpec(*systemVolRef, *prefDirID, fileName, &theSpecs);
+ if (theErr != noErr)
+ {
+ if (theErr != fnfErr)
+ {
+ CheckFileError(theErr, PSTR("Preferences"));
+ return(false);
+ }
+ theErr = FSpCreate(&theSpecs, kPrefCreatorType, kPrefFileType, smSystemScript);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, PSTR("Preferences"));
+ return(false);
+ }
+ }
+ theErr = FSpOpenDF(&theSpecs, fsRdWrPerm, &fileRefNum);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, PSTR("Preferences"));
+ return(false);
+ }
+
+ byteCount = sizeof(*thePrefs);
+
+ theErr = FSWrite(fileRefNum, &byteCount, thePrefs);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, PSTR("Preferences"));
+ return(false);
+ }
+
+ theErr = FSClose(fileRefNum);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, PSTR("Preferences"));
+ return(false);
+ }
+
+ return(true);
+}
+
+//-------------------------------------------------------------- SavePrefs
+
+Boolean SavePrefs (prefsInfo *thePrefs, short versionNow)
+{
+ long prefDirID;
+ short systemVolRef;
+
+ thePrefs->prefVersion = versionNow;
+
+ if (!GetPrefsFPath(&prefDirID, &systemVolRef))
+ return(false);
+
+ if (!WritePrefs(&prefDirID, &systemVolRef, thePrefs))
+ return(false);
+
+ return(true);
+}
+
+//-------------------------------------------------------------- ReadPrefs
+
+OSErr ReadPrefs (long *prefDirID, short *systemVolRef, prefsInfo *thePrefs)
+{
+ OSErr theErr;
+ short fileRefNum;
+ long byteCount;
+ FSSpec theSpecs;
+ Str255 fileName;
+
+ PasStringCopy(kPrefFileName, fileName);
+
+ theErr = FSMakeFSSpec(*systemVolRef, *prefDirID, fileName, &theSpecs);
+ if (theErr != noErr)
+ {
+ if (theErr == fnfErr)
+ return(theErr);
+ else
+ {
+ CheckFileError(theErr, PSTR("Preferences"));
+ return(theErr);
+ }
+ }
+
+ theErr = FSpOpenDF(&theSpecs, fsRdWrPerm, &fileRefNum);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, PSTR("Preferences"));
+ return(theErr);
+ }
+
+ byteCount = sizeof(*thePrefs);
+
+ theErr = FSRead(fileRefNum, &byteCount, thePrefs);
+ if (theErr != noErr)
+ {
+ if (theErr == eofErr)
+ theErr = FSClose(fileRefNum);
+ else
+ {
+ CheckFileError(theErr, PSTR("Preferences"));
+ theErr = FSClose(fileRefNum);
+ }
+ return(theErr);
+ }
+
+ theErr = FSClose(fileRefNum);
+ if (theErr != noErr)
+ {
+ CheckFileError(theErr, PSTR("Preferences"));
+ return(theErr);
+ }
+
+ return(theErr);
+}
+
+//-------------------------------------------------------------- DeletePrefs
+
+Boolean DeletePrefs (long *dirID, short *volRef)
+{
+ FSSpec theSpecs;
+ Str255 fileName;
+ OSErr theErr;
+
+ PasStringCopy(kPrefFileName, fileName);
+
+ theErr = FSMakeFSSpec(*volRef, *dirID, fileName, &theSpecs);
+ if (theErr != noErr)
+ return(false);
+ else
+ theErr = FSpDelete(&theSpecs);
+
+ if (theErr != noErr)
+ return(false);
+
+ return(true);
+}
+
+//-------------------------------------------------------------- LoadPrefs
+
+Boolean LoadPrefs (prefsInfo *thePrefs, short versionNeed)
+{
+ long prefDirID;
+ OSErr theErr;
+ short systemVolRef;
+ Boolean noProblems;
+
+ noProblems = GetPrefsFPath(&prefDirID, &systemVolRef);
+ if (!noProblems)
+ return(false);
+
+ theErr = ReadPrefs(&prefDirID, &systemVolRef, thePrefs);
+ if (theErr == eofErr)
+ {
+ BringUpDeletePrefsAlert();
+ noProblems = DeletePrefs(&prefDirID, &systemVolRef);
+ return (false);
+ }
+ else if (theErr != noErr)
+ return (false);
+
+ if (thePrefs->prefVersion != versionNeed)
+ {
+ BringUpDeletePrefsAlert();
+ noProblems = DeletePrefs(&prefDirID, &systemVolRef);
+ return(false);
+ }
+
+ return (true);
+}
+
+//-------------------------------------------------------------- BringUpDeletePrefsAlert
+
+void BringUpDeletePrefsAlert (void)
+{
+ short whoCares;
+
+ InitCursor();
+// CenterAlert(kNewPrefsAlertID);
+ whoCares = Alert(kNewPrefsAlertID, nil);
+}
+
diff --git a/GpApp/RectUtils.cpp b/GpApp/RectUtils.cpp
new file mode 100644
index 0000000..c001c2b
--- /dev/null
+++ b/GpApp/RectUtils.cpp
@@ -0,0 +1,318 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// RectUtils.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+
+#include "Externs.h"
+#include "RectUtils.h"
+
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- FrameWHRect
+// Given the top left corner and a width and height, this functionÉ
+// simply creates the necessary rectangle and frames it.
+
+void FrameWHRect (short left, short top, short wide, short high)
+{
+ Rect theRect;
+
+ theRect.left = left;
+ theRect.top = top;
+ theRect.right = left + wide;
+ theRect.bottom = top + high;
+ FrameRect(&theRect);
+}
+
+//-------------------------------------------------------------- NormalizeRect
+// 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)
+{
+ short tempSide;
+
+ if (theRect->left > theRect->right)
+ {
+ tempSide = theRect->left;
+ theRect->left = theRect->right;
+ theRect->right = tempSide;
+ }
+
+ if (theRect->top > theRect->bottom)
+ {
+ tempSide = theRect->top;
+ theRect->top = theRect->bottom;
+ theRect->bottom = tempSide;
+ }
+}
+
+//-------------------------------------------------------------- ZeroRectCorner
+// The rect passed in is slid over so that its top left corner isÉ
+// at coordinates (0, 0).
+
+void ZeroRectCorner (Rect *theRect) // Offset rect to (0, 0)
+{
+ theRect->right -= theRect->left;
+ theRect->bottom -= theRect->top;
+ theRect->left = 0;
+ theRect->top = 0;
+}
+
+//-------------------------------------------------------------- CenterRectOnPoint
+// Given a rectangle and a point, this function centers the rectangleÉ
+// on that point.
+
+void CenterRectOnPoint (Rect *theRect, Point where)
+{
+ ZeroRectCorner(theRect);
+ QOffsetRect(theRect, -HalfRectWide(theRect), -HalfRectTall(theRect));
+ QOffsetRect(theRect, where.h, where.v);
+}
+
+//-------------------------------------------------------------- HalfRectWide
+// Given a rectangle, this function returns the rect's width divided by 2.
+
+short HalfRectWide (Rect *theRect)
+{
+ return ((theRect->right - theRect->left) / 2);
+}
+
+//-------------------------------------------------------------- HalfRectTall
+// Given a rectangle, this function returns the rect's height divided by 2.
+
+short HalfRectTall (Rect *theRect)
+{
+ return ((theRect->bottom - theRect->top) / 2);
+}
+
+//-------------------------------------------------------------- RectWide
+// Given a rectangle, this simple function returns the rect's width.
+
+short RectWide (Rect *theRect)
+{
+ return (theRect->right - theRect->left);
+}
+
+//-------------------------------------------------------------- RectTall
+// Given a rectangle, this simple function returns the rect's height.
+
+short RectTall (Rect *theRect)
+{
+ return (theRect->bottom - theRect->top);
+}
+
+//-------------------------------------------------------------- GlobalToLocalRect
+
+// This function offsets a rectangle from global to local coordinates.
+// The "local" coordinate system is assumed to be the current port (window).
+
+void GlobalToLocalRect (Rect *theRect)
+{
+ Point upperLeftPt;
+
+ upperLeftPt.h = 0;
+ upperLeftPt.v = 0;
+ GlobalToLocal(&upperLeftPt);
+ QOffsetRect(theRect, upperLeftPt.h, upperLeftPt.v);
+}
+
+//-------------------------------------------------------------- LocalToGlobalRect
+
+// This function offsets a rectangle from local to global coordinates.
+// The "local" coordinate system is assumed to be the current port (window).
+
+void LocalToGlobalRect (Rect *theRect)
+{
+ Point upperLeftPt;
+
+ upperLeftPt.h = 0;
+ upperLeftPt.v = 0;
+ LocalToGlobal(&upperLeftPt);
+ QOffsetRect(theRect, upperLeftPt.h, upperLeftPt.v);
+}
+
+//-------------------------------------------------------------- CenterRectInRect
+// Given two rectangles, this function centers the first rectangleÉ
+// within the second. The second rect is unchanged.
+
+void CenterRectInRect (Rect *rectA, Rect *rectB)
+{
+ short widthA, tallA;
+
+ widthA = RectWide(rectA);
+ tallA = RectTall(rectA);
+
+ rectA->left = rectB->left + (RectWide(rectB) - widthA) / 2;
+ rectA->right = rectA->left + widthA;
+
+ rectA->top = rectB->top + (RectTall(rectB) - tallA) / 2;
+ rectA->bottom = rectA->top + tallA;
+}
+
+//-------------------------------------------------------------- HOffsetRect
+
+// Just a simple function to offset a rectangle horizontally only.
+
+void HOffsetRect (Rect *theRect, short h)
+{
+ theRect->left += h;
+ theRect->right += h;
+}
+
+//-------------------------------------------------------------- VOffsetRect
+
+// Just a simple function to offset a rectangle vertically only.
+
+void VOffsetRect (Rect *theRect, short v)
+{
+ theRect->top += v;
+ theRect->bottom += v;
+}
+
+//-------------------------------------------------------------- IsRectLeftOfRect
+
+// Given two rects, this function returns true if the first rectangleÉ
+// is to the left of the second.
+
+Boolean IsRectLeftOfRect (Rect *rect1, Rect *rect2)
+{
+ short offset;
+
+ offset = (rect1->right - rect1->left) - (rect2->right - rect2->left) / 2;
+ if ((rect1->left) < (rect2->left + offset))
+ return (true);
+ else
+ return (false);
+}
+
+//-------------------------------------------------------------- QOffsetRect
+
+// This duplicates a Mac ToolBox call, but since it's local, it's faster.
+// It offsets a rectangle both vertically and horizontally.
+
+void QOffsetRect (Rect *theRect, short h, short v)
+{
+ theRect->right += h;
+ theRect->left += h;
+ theRect->bottom += v;
+ theRect->top += v;
+}
+
+//-------------------------------------------------------------- QSetRect
+
+// This also duplicates a ToolBox call. It's needed often though, soÉ
+// any gains in speed are nice. It sets up a rect structure.
+
+void QSetRect (Rect *theRect, short l, short t, short r, short b)
+{
+ theRect->left = l;
+ theRect->top = t;
+ theRect->right = r;
+ theRect->bottom = b;
+}
+
+//-------------------------------------------------------------- ForceRectInRect
+// Given a source rectangle and a bounding rectangle, this functionÉ
+// will clip the source rect so that it is entirely within the boundingÉ
+// rect. It returns true if any clippiung was necessary.
+
+Boolean ForceRectInRect (Rect *small, Rect *large)
+{
+ SInt16 hOff, vOff;
+ Boolean changed;
+
+ changed = false;
+
+ NormalizeRect(small);
+
+ if ((small->bottom - small->top) > (large->bottom - large->top))
+ {
+ small->bottom = small->top + (large->bottom - large->top);
+ changed = true;
+ }
+
+ if ((small->right - small->left) > (large->right - large->left))
+ {
+ small->right = small->left + (large->right - large->left);
+ changed = true;
+ }
+
+ hOff = large->left - small->left;
+ if (hOff > 0)
+ {
+ OffsetRect(small, hOff, 0);
+ changed = true;
+ }
+ hOff = large->right - small->right;
+ if (hOff < 0)
+ {
+ OffsetRect(small, hOff, 0);
+ changed = true;
+ }
+ vOff = large->top - small->top;
+ if (vOff > 0)
+ {
+ OffsetRect(small, 0, vOff);
+ changed = true;
+ }
+ vOff = large->bottom - small->bottom;
+ if (vOff < 0)
+ {
+ OffsetRect(small, 0, vOff);
+ changed = true;
+ }
+
+ return changed;
+}
+
+//-------------------------------------------------------------- QUnionSimilarRect
+
+// Given 2 rects that are assumed to have the same width and height,É
+// this function returns a 3rd rect that is the union of those two.
+
+void QUnionSimilarRect (Rect *rectA, Rect *rectB, Rect *rectC)
+{
+ if (rectA->left < rectB->left)
+ rectC->left = rectA->left;
+ else
+ rectC->left = rectB->left;
+
+ if (rectA->top < rectB->top)
+ rectC->top = rectA->top;
+ else
+ rectC->top = rectB->top;
+
+ if (rectA->right > rectB->right)
+ rectC->right = rectA->right;
+ else
+ rectC->right = rectB->right;
+
+ if (rectA->bottom > rectB->bottom)
+ rectC->bottom = rectA->bottom;
+ else
+ rectC->bottom = rectB->bottom;
+}
+
+//-------------------------------------------------------------- FrameRectSansCorners
+// This is similar to the ToolBox FrameRect() call. However, it doesn'tÉ
+// draw the pixels in the 4 corners of the Rect.
+
+void FrameRectSansCorners (Rect *theRect)
+{
+ MoveTo(theRect->left + 1, theRect->top);
+ LineTo(theRect->right - 2, theRect->top);
+
+ MoveTo(theRect->right - 1, theRect->top + 1);
+ LineTo(theRect->right - 1, theRect->bottom - 2);
+
+ MoveTo(theRect->left + 1, theRect->bottom - 1);
+ LineTo(theRect->right - 2, theRect->bottom - 1);
+
+ MoveTo(theRect->left, theRect->top + 1);
+ LineTo(theRect->left, theRect->bottom - 2);
+}
+
diff --git a/GpApp/RectUtils.h b/GpApp/RectUtils.h
new file mode 100644
index 0000000..7184e01
--- /dev/null
+++ b/GpApp/RectUtils.h
@@ -0,0 +1,33 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// RectUtils.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#pragma once
+
+
+#include "PLQuickdraw.h"
+
+
+void FrameWHRect (short, short, short, short);
+void NormalizeRect (Rect *);
+void ZeroRectCorner (Rect *);
+void CenterRectOnPoint (Rect *, Point);
+short HalfRectWide (Rect *);
+short HalfRectTall (Rect *);
+short RectWide (Rect *);
+short RectTall (Rect *);
+void GlobalToLocalRect (Rect *);
+void LocalToGlobalRect (Rect *);
+void CenterRectInRect (Rect *, Rect *);
+void HOffsetRect (Rect *, short);
+void VOffsetRect (Rect *, short);
+Boolean IsRectLeftOfRect (Rect *, Rect *);
+void QOffsetRect (Rect *, short, short);
+void QSetRect (Rect *, short, short, short, short);
+Boolean ForceRectInRect (Rect *, Rect *);
+void QUnionSimilarRect (Rect *, Rect *, Rect *);
+void FrameRectSansCorners (Rect *);
+void SetEraseRect (short, short, short, short);
diff --git a/GpApp/Render.cpp b/GpApp/Render.cpp
new file mode 100644
index 0000000..94a3b87
--- /dev/null
+++ b/GpApp/Render.cpp
@@ -0,0 +1,772 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Render.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Environ.h"
+#include "MainWindow.h"
+#include "Objects.h"
+#include "Play.h"
+#include "Player.h"
+#include "RectUtils.h"
+#include "Room.h"
+#include "RubberBands.h"
+
+
+#define kMaxGarbageRects 48
+
+
+void DrawReflection (gliderPtr, Boolean);
+void RenderFlames (void);
+void RenderPendulums (void);
+void RenderFlyingPoints (void);
+void RenderSparkles (void);
+void RenderStars (void);
+void RenderBands (void);
+void RenderShreds (void);
+void CopyRectsQD (void);
+void CopyRectsAssm (void);
+
+
+Rect work2MainRects[kMaxGarbageRects];
+Rect back2WorkRects[kMaxGarbageRects];
+Rect shieldRect;
+RgnHandle mirrorRgn;
+Point shieldPt;
+long nextFrame;
+short numWork2Main, numBack2Work;
+Boolean hasMirror;
+
+extern bandPtr bands;
+extern sparklePtr sparkles;
+extern flyingPtPtr flyingPoints;
+extern flamePtr flames, tikiFlames, bbqCoals;
+extern pendulumPtr pendulums;
+extern starPtr theStars;
+extern shredPtr shreds;
+extern Rect sparkleSrc[];
+extern Rect pointsSrc[];
+extern Rect bandRects[];
+extern savedType savedMaps[];
+extern Rect shadowSrc[], justRoomsRect, movieRect;
+extern short numBands, numStars, numShredded;
+extern short numSparkles, numFlyingPts, numPendulums, clockFrame;
+extern short numFlames, numSavedMaps, numTikiFlames, numCoals;
+extern Boolean evenFrame, shadowVisible, twoPlayerGame, tvOn;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- AddRectToWorkRects
+
+void AddRectToWorkRects (Rect *theRect)
+{
+ if (numWork2Main < (kMaxGarbageRects - 1))
+ {
+ work2MainRects[numWork2Main] = *theRect;
+ if (work2MainRects[numWork2Main].left < justRoomsRect.left)
+ work2MainRects[numWork2Main].left = justRoomsRect.left;
+ else if (work2MainRects[numWork2Main].right > justRoomsRect.right)
+ work2MainRects[numWork2Main].right = justRoomsRect.right;
+ if (work2MainRects[numWork2Main].top < justRoomsRect.top)
+ work2MainRects[numWork2Main].top = justRoomsRect.top;
+ else if (work2MainRects[numWork2Main].bottom > justRoomsRect.bottom)
+ work2MainRects[numWork2Main].bottom = justRoomsRect.bottom;
+ numWork2Main++;
+ }
+}
+
+//-------------------------------------------------------------- AddRectToBackRects
+
+void AddRectToBackRects (Rect *theRect)
+{
+ if (numBack2Work < (kMaxGarbageRects - 1))
+ {
+ back2WorkRects[numBack2Work] = *theRect;
+ if (back2WorkRects[numBack2Work].left < 0)
+ back2WorkRects[numBack2Work].left = 0;
+ else if (back2WorkRects[numBack2Work].right > workSrcRect.right)
+ back2WorkRects[numBack2Work].right = workSrcRect.right;
+ if (back2WorkRects[numBack2Work].top < 0)
+ back2WorkRects[numBack2Work].top = 0;
+ else if (back2WorkRects[numBack2Work].bottom > workSrcRect.bottom)
+ back2WorkRects[numBack2Work].bottom = workSrcRect.bottom;
+ numBack2Work++;
+ }
+}
+
+//-------------------------------------------------------------- AddRectToWorkRectsWhole
+
+void AddRectToWorkRectsWhole (Rect *theRect)
+{
+ if (numWork2Main < (kMaxGarbageRects - 1))
+ {
+ if ((theRect->right <= workSrcRect.left) ||
+ (theRect->bottom <= workSrcRect.top) ||
+ (theRect->left >= workSrcRect.right) ||
+ (theRect->top >= workSrcRect.bottom))
+ return;
+
+ work2MainRects[numWork2Main] = *theRect;
+
+ if (work2MainRects[numWork2Main].left < workSrcRect.left)
+ work2MainRects[numWork2Main].left = workSrcRect.left;
+ else if (work2MainRects[numWork2Main].right > workSrcRect.right)
+ work2MainRects[numWork2Main].right = workSrcRect.right;
+ if (work2MainRects[numWork2Main].top < workSrcRect.top)
+ work2MainRects[numWork2Main].top = workSrcRect.top;
+ else if (work2MainRects[numWork2Main].bottom > workSrcRect.bottom)
+ work2MainRects[numWork2Main].bottom = workSrcRect.bottom;
+
+ if ((work2MainRects[numWork2Main].right ==
+ work2MainRects[numWork2Main].left) ||
+ (work2MainRects[numWork2Main].top ==
+ work2MainRects[numWork2Main].bottom))
+ return;
+
+ numWork2Main++;
+ }
+}
+
+//-------------------------------------------------------------- DrawReflection
+
+void DrawReflection (gliderPtr thisGlider, Boolean oneOrTwo)
+{
+ RgnHandle wasClip;
+ Rect src, dest;
+ short which;
+
+ if (thisGlider->dontDraw)
+ return;
+
+ if (thisGlider->facing == kFaceRight)
+ which = 0;
+ else
+ which = 1;
+
+ dest = thisGlider->dest;
+ QOffsetRect(&dest, playOriginH - 20, playOriginV - 16);
+
+ wasClip = NewRgn();
+ if (wasClip == nil)
+ return;
+
+ SetPort((GrafPtr)workSrcMap);
+ GetClip(wasClip);
+ SetClip(mirrorRgn);
+
+ if (oneOrTwo)
+ {
+ if (showFoil)
+ CopyMask((BitMap *)*GetGWorldPixMap(glid2SrcMap),
+ (BitMap *)*GetGWorldPixMap(glidMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &thisGlider->src, &thisGlider->mask, &dest);
+ else
+ CopyMask((BitMap *)*GetGWorldPixMap(glidSrcMap),
+ (BitMap *)*GetGWorldPixMap(glidMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &thisGlider->src, &thisGlider->mask, &dest);
+ }
+ else
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(glid2SrcMap),
+ (BitMap *)*GetGWorldPixMap(glidMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &thisGlider->src, &thisGlider->mask, &dest);
+ }
+
+ SetClip(wasClip);
+ DisposeRgn(wasClip);
+
+ src =thisGlider->whole;
+ QOffsetRect(&src, playOriginH - 20, playOriginV - 16);
+ AddRectToWorkRects(&src);
+ AddRectToBackRects(&dest);
+}
+
+//-------------------------------------------------------------- RenderFlames
+
+void RenderFlames (void)
+{
+ short i;
+
+ if ((numFlames == 0) && (numTikiFlames == 0) && (numCoals == 0))
+ return;
+
+ for (i = 0; i < numFlames; i++)
+ {
+ flames[i].mode++;
+ flames[i].src.top += 15;
+ flames[i].src.bottom += 15;
+ if (flames[i].mode >= kNumCandleFlames)
+ {
+ flames[i].mode = 0;
+ flames[i].src.top = 0;
+ flames[i].src.bottom = 15;
+ }
+
+ CopyBits((BitMap *)*GetGWorldPixMap(savedMaps[flames[i].who].map),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &flames[i].src, &flames[i].dest, srcCopy, nil);
+
+ AddRectToWorkRects(&flames[i].dest);
+ }
+
+ for (i = 0; i < numTikiFlames; i++)
+ {
+ tikiFlames[i].mode++;
+ tikiFlames[i].src.top += 10;
+ tikiFlames[i].src.bottom += 10;
+ if (tikiFlames[i].mode >= kNumTikiFlames)
+ {
+ tikiFlames[i].mode = 0;
+ tikiFlames[i].src.top = 0;
+ tikiFlames[i].src.bottom = 10;
+ }
+
+ CopyBits((BitMap *)*GetGWorldPixMap(savedMaps[tikiFlames[i].who].map),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &tikiFlames[i].src, &tikiFlames[i].dest, srcCopy, nil);
+
+ AddRectToWorkRects(&tikiFlames[i].dest);
+ }
+
+ for (i = 0; i < numCoals; i++)
+ {
+ bbqCoals[i].mode++;
+ bbqCoals[i].src.top += 9;
+ bbqCoals[i].src.bottom += 9;
+ if (bbqCoals[i].mode >= kNumBBQCoals)
+ {
+ bbqCoals[i].mode = 0;
+ bbqCoals[i].src.top = 0;
+ bbqCoals[i].src.bottom = 9;
+ }
+
+ CopyBits((BitMap *)*GetGWorldPixMap(savedMaps[bbqCoals[i].who].map),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &bbqCoals[i].src, &bbqCoals[i].dest, srcCopy, nil);
+
+ AddRectToWorkRects(&bbqCoals[i].dest);
+ }
+}
+
+//-------------------------------------------------------------- RenderPendulums
+
+void RenderPendulums (void)
+{
+ short i;
+ Boolean playedTikTok;
+
+ playedTikTok = false;
+
+ if (numPendulums == 0)
+ return;
+
+ clockFrame++;
+ if ((clockFrame == 10) || (clockFrame == 15))
+ {
+ if (clockFrame >= 15)
+ clockFrame = 0;
+
+ for (i = 0; i < numPendulums; i++)
+ {
+ if (pendulums[i].active)
+ {
+ if (pendulums[i].toOrFro)
+ {
+ pendulums[i].mode++;
+ pendulums[i].src.top += 28;
+ pendulums[i].src.bottom += 28;
+
+ if (pendulums[i].mode >= 2)
+ {
+ pendulums[i].toOrFro = !pendulums[i].toOrFro;
+ if (!playedTikTok)
+ {
+ PlayPrioritySound(kTikSound, kTikPriority);
+ playedTikTok = true;
+ }
+ }
+ }
+ else
+ {
+ pendulums[i].mode--;
+ pendulums[i].src.top -= 28;
+ pendulums[i].src.bottom -= 28;
+
+ if (pendulums[i].mode <= 0)
+ {
+ pendulums[i].toOrFro = !pendulums[i].toOrFro;
+ if (!playedTikTok)
+ {
+ PlayPrioritySound(kTokSound, kTokPriority);
+ playedTikTok = true;
+ }
+ }
+ }
+
+ CopyBits((BitMap *)*GetGWorldPixMap(savedMaps[pendulums[i].who].map),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &pendulums[i].src, &pendulums[i].dest, srcCopy, nil);
+
+ AddRectToWorkRects(&pendulums[i].dest);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- RenderFlyingPoints
+
+void RenderFlyingPoints (void)
+{
+ short i;
+
+ if (numFlyingPts == 0)
+ return;
+
+ for (i = 0; i < kMaxFlyingPts; i++)
+ {
+ if (flyingPoints[i].mode != -1)
+ {
+ if (flyingPoints[i].mode > flyingPoints[i].stop)
+ {
+ flyingPoints[i].mode = flyingPoints[i].start;
+ flyingPoints[i].loops++;
+ }
+
+ if (flyingPoints[i].loops >= kMaxFlyingPointsLoop)
+ {
+ AddRectToWorkRects(&flyingPoints[i].dest);
+ flyingPoints[i].mode = -1;
+ numFlyingPts--;
+ }
+ else
+ {
+ flyingPoints[i].dest.left += flyingPoints[i].hVel;
+ flyingPoints[i].dest.right += flyingPoints[i].hVel;
+
+ if (flyingPoints[i].hVel > 0)
+ flyingPoints[i].whole.right = flyingPoints[i].dest.right;
+ else
+ flyingPoints[i].whole.left = flyingPoints[i].dest.left;
+
+ flyingPoints[i].dest.top += flyingPoints[i].vVel;
+ flyingPoints[i].dest.bottom += flyingPoints[i].vVel;
+
+ if (flyingPoints[i].vVel > 0)
+ flyingPoints[i].whole.bottom = flyingPoints[i].dest.bottom;
+ else
+ flyingPoints[i].whole.top = flyingPoints[i].dest.top;
+
+ CopyMask((BitMap *)*GetGWorldPixMap(pointsSrcMap),
+ (BitMap *)*GetGWorldPixMap(pointsMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &pointsSrc[flyingPoints[i].mode],
+ &pointsSrc[flyingPoints[i].mode],
+ &flyingPoints[i].dest);
+
+ AddRectToWorkRects(&flyingPoints[i].whole);
+ AddRectToBackRects(&flyingPoints[i].dest);
+ flyingPoints[i].whole = flyingPoints[i].dest;
+ flyingPoints[i].mode++;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- RenderSparkles
+
+void RenderSparkles (void)
+{
+ short i;
+
+ if (numSparkles == 0)
+ return;
+
+ for (i = 0; i < kMaxSparkles; i++)
+ {
+ if (sparkles[i].mode != -1)
+ {
+ if (sparkles[i].mode >= kNumSparkleModes)
+ {
+ AddRectToWorkRects(&sparkles[i].bounds);
+ sparkles[i].mode = -1;
+ numSparkles--;
+ }
+ else
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(bonusSrcMap),
+ (BitMap *)*GetGWorldPixMap(bonusMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &sparkleSrc[sparkles[i].mode],
+ &sparkleSrc[sparkles[i].mode],
+ &sparkles[i].bounds);
+
+ AddRectToWorkRects(&sparkles[i].bounds);
+ AddRectToBackRects(&sparkles[i].bounds);
+ sparkles[i].mode++;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- RenderStars
+
+void RenderStars (void)
+{
+ short i;
+
+ if (numStars == 0)
+ return;
+
+ for (i = 0; i < numStars; i++)
+ {
+ if (theStars[i].mode != -1)
+ {
+ theStars[i].mode++;
+ theStars[i].src.top += 31;
+ theStars[i].src.bottom += 31;
+ if (theStars[i].mode >= 6)
+ {
+ theStars[i].mode = 0;
+ theStars[i].src.top = 0;
+ theStars[i].src.bottom = 31;
+ }
+
+ CopyBits((BitMap *)*GetGWorldPixMap(savedMaps[theStars[i].who].map),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &theStars[i].src, &theStars[i].dest, srcCopy, nil);
+
+ AddRectToWorkRects(&theStars[i].dest);
+ }
+ }
+}
+
+//-------------------------------------------------------------- RenderGlider
+
+void RenderGlider (gliderPtr thisGlider, Boolean oneOrTwo)
+{
+ Rect src, dest;
+ short which;
+
+ if (thisGlider->dontDraw)
+ return;
+
+ if (thisGlider->facing == kFaceRight)
+ which = 0;
+ else
+ which = 1;
+
+ if (shadowVisible)
+ {
+ dest = thisGlider->destShadow;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+
+ if ((thisGlider->mode == kGliderComingUp) ||
+ (thisGlider->mode == kGliderGoingDown))
+ {
+ src = shadowSrc[which];
+ src.right = src.left + (dest.right - dest.left);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(shadowSrcMap),
+ (BitMap *)*GetGWorldPixMap(shadowMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &src, &dest);
+ }
+ else if (thisGlider->mode == kGliderComingDown)
+ {
+ src = shadowSrc[which];
+ src.left = src.right - (dest.right - dest.left);
+
+ CopyMask((BitMap *)*GetGWorldPixMap(shadowSrcMap),
+ (BitMap *)*GetGWorldPixMap(shadowMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &src, &dest);
+ }
+ else
+ CopyMask((BitMap *)*GetGWorldPixMap(shadowSrcMap),
+ (BitMap *)*GetGWorldPixMap(shadowMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &shadowSrc[which], &shadowSrc[which], &dest);
+ src =thisGlider->wholeShadow;
+ QOffsetRect(&src, playOriginH, playOriginV);
+ AddRectToWorkRects(&src);
+ AddRectToBackRects(&dest);
+ }
+
+ dest = thisGlider->dest;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+
+ if (oneOrTwo)
+ {
+ if ((!twoPlayerGame) && (showFoil))
+ CopyMask((BitMap *)*GetGWorldPixMap(glid2SrcMap),
+ (BitMap *)*GetGWorldPixMap(glidMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &thisGlider->src, &thisGlider->mask, &dest);
+ else
+ CopyMask((BitMap *)*GetGWorldPixMap(glidSrcMap),
+ (BitMap *)*GetGWorldPixMap(glidMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &thisGlider->src, &thisGlider->mask, &dest);
+ }
+ else
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(glid2SrcMap),
+ (BitMap *)*GetGWorldPixMap(glidMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &thisGlider->src, &thisGlider->mask, &dest);
+ }
+
+ src =thisGlider->whole;
+ QOffsetRect(&src, playOriginH, playOriginV);
+ AddRectToWorkRects(&src);
+ AddRectToBackRects(&dest);
+}
+
+//-------------------------------------------------------------- RenderBands
+
+void RenderBands (void)
+{
+ Rect dest;
+ short i;
+
+ if (numBands == 0)
+ return;
+
+ for (i = 0; i < numBands; i++)
+ {
+ dest = bands[i].dest;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ CopyMask((BitMap *)*GetGWorldPixMap(bandsSrcMap),
+ (BitMap *)*GetGWorldPixMap(bandsMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &bandRects[bands[i].mode],
+ &bandRects[bands[i].mode], &dest);
+
+ AddRectToWorkRects(&dest);
+ AddRectToBackRects(&dest);
+ }
+}
+
+//-------------------------------------------------------------- RenderShreds
+
+void RenderShreds (void)
+{
+ Rect src, dest;
+ short i, high;
+
+ if (numShredded > 0)
+ {
+ for (i = 0; i < numShredded; i++)
+ {
+ if (shreds[i].frame == 0)
+ {
+ shreds[i].bounds.bottom += 1;
+ high = shreds[i].bounds.bottom - shreds[i].bounds.top;
+ if (high >= 35)
+ shreds[i].frame = 1;
+ src = shredSrcRect;
+ src.top = src.bottom - high;
+ dest = shreds[i].bounds;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ CopyMask((BitMap *)*GetGWorldPixMap(shredSrcMap),
+ (BitMap *)*GetGWorldPixMap(shredMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &src, &src, &dest);
+ AddRectToBackRects(&dest);
+ dest.top--;
+ AddRectToWorkRects(&dest);
+ PlayPrioritySound(kShredSound, kShredPriority);
+ }
+ else if (shreds[i].frame < 20)
+ {
+ shreds[i].bounds.top += 4;
+ shreds[i].bounds.bottom += 4;
+ dest = shreds[i].bounds;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ shreds[i].frame++;
+ if (shreds[i].frame < 20)
+ {
+ CopyMask((BitMap *)*GetGWorldPixMap(shredSrcMap),
+ (BitMap *)*GetGWorldPixMap(shredMaskMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &shredSrcRect, &shredSrcRect, &dest);
+ }
+ else
+ {
+ AddSparkle(&shreds[i].bounds);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ }
+ AddRectToBackRects(&dest);
+ dest.top -= 4;
+ AddRectToWorkRects(&dest);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- CopyRectsQD
+
+void CopyRectsQD (void)
+{
+ short i;
+
+ for (i = 0; i < numWork2Main; i++)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &work2MainRects[i], &work2MainRects[i],
+ srcCopy, nil);
+ }
+
+ for (i = 0; i < numBack2Work; i++)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &back2WorkRects[i], &back2WorkRects[i],
+ srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- RenderFrame
+
+void RenderFrame (void)
+{
+ if (hasMirror)
+ {
+ DrawReflection(&theGlider, true);
+ if (twoPlayerGame)
+ DrawReflection(&theGlider2, false);
+ }
+ HandleGrease();
+ RenderPendulums();
+ if (evenFrame)
+ RenderFlames();
+ else
+ RenderStars();
+ RenderDynamics();
+ RenderFlyingPoints();
+ RenderSparkles();
+ RenderGlider(&theGlider, true);
+ if (twoPlayerGame)
+ RenderGlider(&theGlider2, false);
+ RenderShreds();
+ RenderBands();
+
+ while (TickCount() < nextFrame)
+ {
+ }
+ nextFrame = TickCount() + kTicksPerFrame;
+
+ CopyRectsQD();
+
+ numWork2Main = 0;
+ numBack2Work = 0;
+}
+
+//-------------------------------------------------------------- InitGarbageRects
+
+void InitGarbageRects (void)
+{
+ short i;
+
+ numWork2Main = 0;
+ numBack2Work = 0;
+
+ numSparkles = 0;
+ for (i = 0; i < kMaxSparkles; i++)
+ sparkles[i].mode = -1;
+
+ numFlyingPts = 0;
+ for (i = 0; i < kMaxFlyingPts; i++)
+ flyingPoints[i].mode = -1;
+
+ nextFrame = TickCount() + kTicksPerFrame;
+}
+
+//-------------------------------------------------------------- CopyRectBackToWork
+
+void CopyRectBackToWork (Rect *theRect)
+{
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ theRect, theRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- CopyRectWorkToBack
+
+void CopyRectWorkToBack (Rect *theRect)
+{
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ theRect, theRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- CopyRectWorkToMain
+
+void CopyRectWorkToMain (Rect *theRect)
+{
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ theRect, theRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- CopyRectMainToWork
+
+void CopyRectMainToWork (Rect *theRect)
+{
+ CopyBits(GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ theRect, theRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- CopyRectMainToBack
+
+void CopyRectMainToBack (Rect *theRect)
+{
+ CopyBits(GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ theRect, theRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- AddToMirrorRegion
+
+void AddToMirrorRegion (Rect *theRect)
+{
+ RgnHandle tempRgn;
+
+ if (mirrorRgn == nil)
+ {
+ mirrorRgn = NewRgn();
+ if (mirrorRgn != nil)
+ RectRgn(mirrorRgn, theRect);
+ }
+ else
+ {
+ tempRgn = NewRgn();
+ if (tempRgn != nil)
+ {
+ RectRgn(tempRgn, theRect);
+ UnionRgn(mirrorRgn, tempRgn, mirrorRgn);
+ DisposeRgn(tempRgn);
+ }
+ }
+ hasMirror = true;
+}
+
+//-------------------------------------------------------------- ZeroMirrorRegion
+
+void ZeroMirrorRegion (void)
+{
+ if (mirrorRgn != nil)
+ DisposeRgn(mirrorRgn);
+ mirrorRgn = nil;
+ hasMirror = false;
+}
+
diff --git a/GpApp/Room.cpp b/GpApp/Room.cpp
new file mode 100644
index 0000000..a72e742
--- /dev/null
+++ b/GpApp/Room.cpp
@@ -0,0 +1,1207 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Room.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLResources.h"
+#include "PLToolUtils.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "House.h"
+#include "MainWindow.h"
+#include "RectUtils.h"
+
+
+#define kDeleteRoomAlert 1005
+#define kYesDoDeleteRoom 1
+
+
+Boolean QueryDeleteRoom (void);
+void SetToNearestNeighborRoom (short, short);
+
+
+roomPtr thisRoom;
+Rect backSrcRect;
+GWorldPtr 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)
+{
+ KeyMap theKeys;
+ long howMuch;
+ OSErr 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;
+
+ wasState = HGetState((Handle)thisHouse);
+ MoveHHi((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ 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
+ {
+ HUnlock((Handle)thisHouse);
+ howMuch = sizeof(roomType); // add new room to end of house
+ theErr = PtrAndHand((Ptr)thisRoom, (Handle)thisHouse, howMuch);
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowUnaccounted, theErr);
+ MoveHHi((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ return (false);
+ }
+ MoveHHi((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ (*thisHouse)->nRooms++; // increment nRooms
+ numberRooms = (*thisHouse)->nRooms;
+ previousRoom = thisRoomNumber;
+ thisRoomNumber = numberRooms - 1;
+ }
+ else
+ {
+ previousRoom = thisRoomNumber;
+ thisRoomNumber = availableRoom;
+ }
+
+ if (noRoomAtAll)
+ (*thisHouse)->firstRoom = thisRoomNumber;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ CopyThisRoomToRoom();
+ UpdateEditWindowTitle();
+ noRoomAtAll = false;
+ fileDirty = true;
+ UpdateMenus(false);
+
+ GetKeys(theKeys);
+ if (BitTst(&theKeys, kShiftKeyMap))
+ newRoomNow = false;
+ else
+ newRoomNow = autoRoomEdit; // Flag to bring up RoomInfo
+
+ return (true);
+}
+#endif
+
+//-------------------------------------------------------------- ReadyBackground
+
+void ReadyBackground (short theID, short *theTiles)
+{
+ Rect src, dest;
+ PicHandle thePicture;
+ short i;
+
+ SetPort((GrafPtr)workSrcMap);
+
+ if ((noRoomAtAll) || (!houseUnlocked))
+ {
+ LtGrayForeColor();
+ PaintRect(&workSrcRect);
+ ForeColor(blackColor);
+ MoveTo(10, 20);
+ if (houseUnlocked)
+ DrawString(PSTR("No rooms"));
+ else
+ DrawString(PSTR("Nothing to show"));
+
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &workSrcRect, &workSrcRect, srcCopy, nil);
+ return;
+ }
+
+ thePicture = GetPicture(theID);
+ if (thePicture == nil)
+ {
+ thePicture = (PicHandle)GetResource('Date', theID);
+ if (thePicture == nil)
+ {
+ YellowAlert(kYellowNoBackground, 0);
+ return;
+ }
+ }
+
+ HLock((Handle)thePicture);
+ dest = (*thePicture)->picFrame;
+ HUnlock((Handle)thePicture);
+ QOffsetRect(&dest, -dest.left, -dest.top);
+ DrawPicture(thePicture, &dest);
+ ReleaseResource((Handle)thePicture);
+
+ 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, nil);
+ 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, nil);
+}
+
+//-------------------------------------------------------------- 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();
+ InvalWindowRect(mainWindow, &mainWindowRect);
+#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;
+
+ tagByte = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse); // copy back to house
+ (*thisHouse)->rooms[thisRoomNumber] = *thisRoom;
+ HSetState((Handle)thisHouse, tagByte);
+}
+
+//-------------------------------------------------------------- ForceThisRoom
+
+void ForceThisRoom (short roomNumber)
+{
+ char tagByte;
+
+ if (roomNumber == -1)
+ return;
+
+ tagByte = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ if (roomNumber < (*thisHouse)->nRooms)
+ *thisRoom = (*thisHouse)->rooms[roomNumber];
+ else
+ YellowAlert(kYellowIllegalRoomNum, 0);
+ HSetState((Handle)thisHouse, tagByte);
+
+ 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);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ for (i = 0; i < numberRooms; i++)
+ {
+ if ((thisHousePtr->rooms[i].floor == floor) &&
+ (thisHousePtr->rooms[i].suite == suite))
+ {
+ foundIt = true;
+ *roomNum = i;
+ break;
+ }
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ 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();
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ 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;
+ HSetState((Handle)thisHouse, wasState);
+
+ noRoomAtAll = (RealRoomNumberCount() == 0); // see if now no rooms
+ if (noRoomAtAll)
+ thisRoomNumber = kRoomIsEmpty;
+ else
+ SetToNearestNeighborRoom(wasFloor, wasSuite);
+
+ if (firstDeleted)
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ (*thisHouse)->firstRoom = thisRoomNumber;
+ HSetState((Handle)thisHouse, wasState);
+ }
+
+ newRoomNow = false;
+ fileDirty = true;
+ UpdateMenus(false);
+ ReflectCurrentRoom(false);
+#endif
+}
+
+//-------------------------------------------------------------- QueryDeleteRoom
+
+#ifndef COMPILEDEMO
+Boolean QueryDeleteRoom (void)
+{
+ short hitWhat;
+
+// CenterAlert(kDeleteRoomAlert);
+ hitWhat = Alert(kDeleteRoomAlert, nil);
+ 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;
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ 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;
+ }
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ 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;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+
+ 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);
+
+ HSetState((Handle)thisHouse, wasState);
+}
+
+//-------------------------------------------------------------- GetRoomFloorSuite
+
+Boolean GetRoomFloorSuite (short room, short *floor, short *suite)
+{
+ char wasState;
+ Boolean isRoom;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ 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;
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ 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;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ for (i = 0; i < numberRooms; i++)
+ {
+ if (((*thisHouse)->rooms[i].suite == suite) &&
+ ((*thisHouse)->rooms[i].floor == floor))
+ {
+ roomNum = i;
+ break;
+ }
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ return (roomNum);
+}
+
+//-------------------------------------------------------------- IsRoomAStructure
+
+Boolean IsRoomAStructure (short roomNum)
+{
+ char wasState;
+ Boolean isStructure;
+
+ if (roomNum == kRoomIsEmpty)
+ return (false);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ 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;
+ }
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ 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 = (boundsHand)GetResource('bnds', theID);
+ if (boundsRes == nil)
+ {
+ if (PictIDExists(theID))
+ YellowAlert(kYellowNoBoundsRes, 0);
+ boundCode = 0;
+ }
+ else
+ {
+ boundCode = 0;
+ HLock((Handle)boundsRes);
+ if ((*boundsRes)->left)
+ boundCode += 1;
+ if ((*boundsRes)->top)
+ boundCode += 2;
+ if ((*boundsRes)->right)
+ boundCode += 4;
+ if ((*boundsRes)->bottom)
+ boundCode += 8;
+ HUnlock((Handle)boundsRes);
+ ReleaseResource((Handle)boundsRes);
+ }
+
+ 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
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ 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;
+ }
+ }
+ }
+ HSetState((Handle)thisHouse, wasState);
+ }
+ 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);
+}
+
diff --git a/GpApp/Room.h b/GpApp/Room.h
new file mode 100644
index 0000000..740fcc5
--- /dev/null
+++ b/GpApp/Room.h
@@ -0,0 +1,12 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Room.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+extern GWorldPtr backSrcMap;
+
diff --git a/GpApp/RoomGraphics.cpp b/GpApp/RoomGraphics.cpp
new file mode 100644
index 0000000..724865d
--- /dev/null
+++ b/GpApp/RoomGraphics.cpp
@@ -0,0 +1,461 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// RoomGraphics.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLResources.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "MainWindow.h"
+#include "RectUtils.h"
+#include "Room.h"
+
+
+#define kManholeThruFloor 3957
+
+
+void LoadGraphicSpecial (short);
+void DrawRoomBackground (short, short, short);
+void DrawFloorSupport (void);
+void ReadyBackMap (void);
+void RestoreWorkMap (void);
+void DrawLighting (void);
+
+
+Rect suppSrcRect;
+GWorldPtr suppSrcMap;
+Rect localRoomsDest[9];
+Rect houseRect;
+short numNeighbors, numLights, thisTiles[kNumTiles];
+short localNumbers[9], thisBackground;
+Boolean isStructure[9], wardBitSet;
+
+extern Rect tempManholes[];
+extern short numTempManholes, tvWithMovieNumber;
+extern Boolean shadowVisible, takingTheStairs;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- DrawLocale
+
+void DrawLocale (void)
+{
+ short i, roomV;
+ char wasState;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ ZeroFlamesAndTheLike();
+ ZeroDinahs();
+ KillAllBands();
+ ZeroMirrorRegion();
+ ZeroTriggers();
+ numTempManholes = 0;
+ FlushAnyTriggerPlaying();
+ DumpTriggerSound();
+ tvInRoom = false;
+ tvWithMovieNumber = -1;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ roomV = (*thisHouse)->rooms[thisRoomNumber].floor;
+ HSetState((Handle)thisHouse, wasState);
+
+ for (i = 0; i < 9; i++)
+ {
+ localNumbers[i] = GetNeighborRoomNumber(i);
+ isStructure[i] = IsRoomAStructure(localNumbers[i]);
+ }
+ ListAllLocalObjects();
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ PaintRect(&backSrcRect);
+
+ if (numNeighbors > 3)
+ {
+ numLights = GetNumberOfLights(localNumbers[kNorthWestRoom]);
+ DrawRoomBackground(localNumbers[kNorthWestRoom], kNorthWestRoom, roomV + 1);
+ DrawARoomsObjects(kNorthWestRoom, false);
+
+ numLights = GetNumberOfLights(localNumbers[kNorthEastRoom]);
+ DrawRoomBackground(localNumbers[kNorthEastRoom], kNorthEastRoom, roomV + 1);
+ DrawARoomsObjects(kNorthEastRoom, false);
+
+ numLights = GetNumberOfLights(localNumbers[kNorthRoom]);
+ DrawRoomBackground(localNumbers[kNorthRoom], kNorthRoom, roomV + 1);
+ DrawARoomsObjects(kNorthRoom, false);
+
+ numLights = GetNumberOfLights(localNumbers[kSouthWestRoom]);
+ DrawRoomBackground(localNumbers[kSouthWestRoom], kSouthWestRoom, roomV - 1);
+ DrawARoomsObjects(kSouthWestRoom, false);
+
+ numLights = GetNumberOfLights(localNumbers[kSouthEastRoom]);
+ DrawRoomBackground(localNumbers[kSouthEastRoom], kSouthEastRoom, roomV - 1);
+ DrawARoomsObjects(kSouthEastRoom, false);
+
+ numLights = GetNumberOfLights(localNumbers[kSouthRoom]);
+ DrawRoomBackground(localNumbers[kSouthRoom], kSouthRoom, roomV - 1);
+ DrawARoomsObjects(kSouthRoom, false);
+ }
+
+ if (numNeighbors > 1)
+ {
+ numLights = GetNumberOfLights(localNumbers[kWestRoom]);
+ DrawRoomBackground(localNumbers[kWestRoom], kWestRoom, roomV);
+ DrawARoomsObjects(kWestRoom, false);
+ DrawLighting();
+
+ numLights = GetNumberOfLights(localNumbers[kEastRoom]);
+ DrawRoomBackground(localNumbers[kEastRoom], kEastRoom, roomV);
+ DrawARoomsObjects(kEastRoom, false);
+ DrawLighting();
+ }
+
+ numLights = GetNumberOfLights(localNumbers[kCentralRoom]);
+ DrawRoomBackground(localNumbers[kCentralRoom], kCentralRoom, roomV);
+ DrawARoomsObjects(kCentralRoom, false);
+ DrawLighting();
+
+ if (numNeighbors > 3)
+ DrawFloorSupport();
+ RestoreWorkMap();
+ shadowVisible = IsShadowVisible();
+ takingTheStairs = false;
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- LoadGraphicSpecial
+
+void LoadGraphicSpecial (short resID)
+{
+ Rect bounds;
+ PicHandle thePicture;
+
+ thePicture = GetPicture(resID);
+ if (thePicture == nil)
+ {
+ thePicture = (PicHandle)GetResource('Date', resID);
+ if (thePicture == nil)
+ {
+ thePicture = GetPicture(2000);
+ if (thePicture == nil)
+ RedAlert(kErrFailedGraphicLoad);
+ }
+ }
+
+ HLock((Handle)thePicture);
+ bounds = (*thePicture)->picFrame;
+ HUnlock((Handle)thePicture);
+ OffsetRect(&bounds, -bounds.left, -bounds.top);
+ DrawPicture(thePicture, &bounds);
+
+ ReleaseResource((Handle)thePicture);
+}
+
+//-------------------------------------------------------------- DrawRoomBackground
+
+void DrawRoomBackground (short who, short where, short elevation)
+{
+ Rect src, dest;
+ short i, pictID;
+ short tiles[kNumTiles];
+ char wasState;
+
+ if (where == kCentralRoom)
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisBackground = (*thisHouse)->rooms[who].background;
+ for (i = 0; i < kNumTiles; i++)
+ thisTiles[i] = (*thisHouse)->rooms[who].tiles[i];
+ HSetState((Handle)thisHouse, wasState);
+ }
+
+ if ((numLights == 0) && (who != kRoomIsEmpty))
+ {
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ PaintRect(&localRoomsDest[where]);
+
+ SetGWorld(wasCPort, wasWorld);
+ return;
+ }
+
+ if (who == kRoomIsEmpty) // This call should be smarter than this
+ {
+ if (wardBitSet)
+ {
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+
+ PaintRect(&localRoomsDest[where]);
+
+ SetGWorld(wasCPort, wasWorld);
+ return;
+ }
+
+ if (elevation > 1)
+ {
+ pictID = kSky;
+ for (i = 0; i < kNumTiles; i++)
+ tiles[i] = 2;
+ }
+ else if (elevation == 1)
+ {
+ pictID = kMeadow;
+ for (i = 0; i < kNumTiles; i++)
+ tiles[i] = 0;
+ }
+ else
+ {
+ pictID = kDirt;
+ for (i = 0; i < kNumTiles; i++)
+ tiles[i] = 0;
+ }
+ }
+ else
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ pictID = (*thisHouse)->rooms[who].background;
+ for (i = 0; i < kNumTiles; i++)
+ tiles[i] = (*thisHouse)->rooms[who].tiles[i];
+ HSetState((Handle)thisHouse, wasState);
+ }
+
+ SetPort((GrafPtr)workSrcMap);
+ LoadGraphicSpecial(pictID);
+
+ QSetRect(&src, 0, 0, kTileWide, kTileHigh);
+ QSetRect(&dest, 0, 0, kTileWide, kTileHigh);
+ QOffsetRect(&dest, localRoomsDest[where].left, localRoomsDest[where].top);
+ for (i = 0; i < kNumTiles; i++)
+ {
+ src.left = tiles[i] * kTileWide;
+ src.right = src.left + kTileWide;
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &src, &dest, srcCopy, nil);
+ QOffsetRect(&dest, kTileWide, 0);
+ }
+}
+
+//-------------------------------------------------------------- DrawFloorSupport
+
+void DrawFloorSupport (void)
+{
+ Rect src, dest, whoCares;
+ short i;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ SetGWorld(backSrcMap, nil);
+ src = suppSrcRect;
+
+ if (isStructure[kNorthWestRoom])
+ {
+ dest = suppSrcRect; // left room's ceiling
+ QOffsetRect(&dest, localRoomsDest[kWestRoom].left,
+ localRoomsDest[kCentralRoom].top - suppSrcRect.bottom);
+ CopyBits((BitMap *)*GetGWorldPixMap(suppSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &src, &dest, srcCopy, nil);
+
+ for (i = 0; i < numTempManholes; i++)
+ if (SectRect(&dest, &tempManholes[i], &whoCares))
+ {
+ tempManholes[i].top = dest.top;
+ tempManholes[i].bottom = dest.bottom;
+ LoadScaledGraphic(kManholeThruFloor, &tempManholes[i]);
+ }
+ }
+
+ if (isStructure[kWestRoom])
+ {
+ dest = suppSrcRect; // left room's floor
+ QOffsetRect(&dest, localRoomsDest[kWestRoom].left,
+ localRoomsDest[kCentralRoom].bottom);
+ CopyBits((BitMap *)*GetGWorldPixMap(suppSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &src, &dest, srcCopy, nil);
+
+ for (i = 0; i < numTempManholes; i++)
+ if (SectRect(&dest, &tempManholes[i], &whoCares))
+ {
+ tempManholes[i].top = dest.top;
+ tempManholes[i].bottom = dest.bottom;
+ LoadScaledGraphic(kManholeThruFloor, &tempManholes[i]);
+ }
+ }
+
+ if (isStructure[kNorthRoom])
+ {
+ dest = suppSrcRect; // directly above main room
+ QOffsetRect(&dest, localRoomsDest[kCentralRoom].left,
+ localRoomsDest[kCentralRoom].top - suppSrcRect.bottom);
+ CopyBits((BitMap *)*GetGWorldPixMap(suppSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &src, &dest, srcCopy, nil);
+ for (i = 0; i < numTempManholes; i++)
+ if (SectRect(&dest, &tempManholes[i], &whoCares))
+ {
+ tempManholes[i].top = dest.top;
+ tempManholes[i].bottom = dest.bottom;
+ LoadScaledGraphic(kManholeThruFloor, &tempManholes[i]);
+ }
+ }
+
+ if (isStructure[kCentralRoom])
+ {
+ dest = suppSrcRect; // directly below main room
+ QOffsetRect(&dest, localRoomsDest[kCentralRoom].left,
+ localRoomsDest[kCentralRoom].bottom);
+ CopyBits((BitMap *)*GetGWorldPixMap(suppSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &src, &dest, srcCopy, nil);
+
+ for (i = 0; i < numTempManholes; i++)
+ if (SectRect(&dest, &tempManholes[i], &whoCares))
+ {
+ tempManholes[i].top = dest.top;
+ tempManholes[i].bottom = dest.bottom;
+ LoadScaledGraphic(kManholeThruFloor, &tempManholes[i]);
+ }
+ }
+
+ if (isStructure[kNorthEastRoom])
+ {
+ dest = suppSrcRect;
+ QOffsetRect(&dest, localRoomsDest[kEastRoom].left,
+ localRoomsDest[kCentralRoom].top - suppSrcRect.bottom);
+ CopyBits((BitMap *)*GetGWorldPixMap(suppSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &src, &dest, srcCopy, nil);
+
+ for (i = 0; i < numTempManholes; i++)
+ if (SectRect(&dest, &tempManholes[i], &whoCares))
+ {
+ tempManholes[i].top = dest.top;
+ tempManholes[i].bottom = dest.bottom;
+ LoadScaledGraphic(kManholeThruFloor, &tempManholes[i]);
+ }
+ }
+
+ if (isStructure[kEastRoom])
+ {
+ dest = suppSrcRect;
+ QOffsetRect(&dest, localRoomsDest[kEastRoom].left,
+ localRoomsDest[kCentralRoom].bottom);
+ CopyBits((BitMap *)*GetGWorldPixMap(suppSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &src, &dest, srcCopy, nil);
+
+ for (i = 0; i < numTempManholes; i++)
+ if (SectRect(&dest, &tempManholes[i], &whoCares))
+ {
+ tempManholes[i].top = dest.top;
+ tempManholes[i].bottom = dest.bottom;
+ LoadScaledGraphic(kManholeThruFloor, &tempManholes[i]);
+ }
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- ReadyBackMap
+
+void ReadyBackMap (void)
+{
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ (BitMap *)*GetGWorldPixMap(backSrcMap),
+ &workSrcRect, &workSrcRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- RestoreWorkMap
+
+void RestoreWorkMap (void)
+{
+ Rect dest;
+
+ dest = backSrcRect;
+
+ CopyBits((BitMap *)*GetGWorldPixMap(backSrcMap),
+ (BitMap *)*GetGWorldPixMap(workSrcMap),
+ &backSrcRect, &backSrcRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- ReadyLevel
+
+void ReadyLevel (void)
+{
+ NilSavedMaps();
+
+#ifdef COMPILEQT
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom))
+ {
+ tvInRoom = false;
+ tvWithMovieNumber = -1;
+ StopMovie(theMovie);
+ }
+#endif
+
+ DetermineRoomOpenings();
+ DrawLocale();
+ InitGarbageRects();
+}
+
+//-------------------------------------------------------------- DrawLighting
+
+void DrawLighting (void)
+{
+ if (numLights == 0)
+ return;
+ else
+ {
+ // for future construction
+ }
+}
+
+//-------------------------------------------------------------- RedrawRoomLighting
+
+void RedrawRoomLighting (void)
+{
+ short roomV;
+ char wasState;
+ Boolean wasLit, isLit;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ roomV = (*thisHouse)->rooms[thisRoomNumber].floor;
+ HSetState((Handle)thisHouse, wasState);
+
+ wasLit = numLights > 0;
+ numLights = GetNumberOfLights(localNumbers[kCentralRoom]);
+ isLit = numLights > 0;
+ if (wasLit != isLit)
+ {
+ DrawRoomBackground(localNumbers[kCentralRoom], kCentralRoom, roomV);
+ DrawARoomsObjects(kCentralRoom, true);
+ DrawLighting();
+ UpdateOutletsLighting(localNumbers[kCentralRoom], numLights);
+
+ if (numNeighbors > 3)
+ DrawFloorSupport();
+ RestoreWorkMap();
+ AddRectToWorkRects(&localRoomsDest[kCentralRoom]);
+ shadowVisible = IsShadowVisible();
+ }
+}
+
diff --git a/GpApp/RoomGraphics.h b/GpApp/RoomGraphics.h
new file mode 100644
index 0000000..bda7b47
--- /dev/null
+++ b/GpApp/RoomGraphics.h
@@ -0,0 +1,11 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// RoomGraphics.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+extern GWorldPtr suppSrcMap;
diff --git a/GpApp/RoomInfo.cpp b/GpApp/RoomInfo.cpp
new file mode 100644
index 0000000..36cbb39
--- /dev/null
+++ b/GpApp/RoomInfo.cpp
@@ -0,0 +1,908 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// RoomInfo.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLNumberFormatting.h"
+#include "PLResources.h"
+#include "PLSound.h"
+#include "PLPasStr.h"
+#include "DialogUtils.h"
+#include "Externs.h"
+#include "RectUtils.h"
+#include "Utilities.h"
+
+
+#define kRoomInfoDialogID 1003
+#define kOriginalArtDialogID 1016
+#define kNoPICTFoundAlert 1036
+#define kRoomNameItem 3
+#define kRoomLocationBox 6
+#define kRoomTilesBox 10
+#define kRoomPopupItem 11
+#define kRoomDividerLine 12
+#define kRoomTilesBox2 15
+#define kRoomFirstCheck 17
+#define kLitUnlitText 18
+#define kMiniTileWide 16
+#define kBoundsButton 19
+#define kOriginalArtworkItem 19
+#define kPICTIDItem 5
+#define kFloorSupportCheck 12
+
+
+void UpdateRoomInfoDialog (DialogPtr);
+void DragMiniTile (Point, short *);
+void HiliteTileOver (Point);
+Boolean RoomFilter (DialogPtr, EventRecord *, short *);
+short ChooseOriginalArt (short);
+void UpdateOriginalArt (DialogPtr);
+Boolean OriginalArtFilter (DialogPtr, EventRecord *, short *);
+Boolean PictIDExists (short);
+short GetFirstPICT (void);
+void BitchAboutPICTNotFound (void);
+
+
+Rect tileSrc, tileDest, tileSrcRect, editTETextBox;
+Rect leftBound, topBound, rightBound, bottomBound;
+CGrafPtr tileSrcMap;
+short tempTiles[kNumTiles];
+short tileOver, tempBack, cursorIs;
+Boolean originalLeftOpen, originalTopOpen, originalRightOpen, originalBottomOpen;
+Boolean originalFloor;
+
+extern Cursor handCursor, beamCursor;
+extern short houseResFork, lastBackground;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- UpdateRoomInfoDialog
+
+#ifndef COMPILEDEMO
+void UpdateRoomInfoDialog (DialogPtr theDialog)
+{
+ Rect src, dest;
+ short i;
+
+ DrawDialog(theDialog);
+ if (tempBack >= kUserBackground)
+ SetPopUpMenuValue(theDialog, kRoomPopupItem, kOriginalArtworkItem);
+ else
+ SetPopUpMenuValue(theDialog, kRoomPopupItem,
+ (tempBack - kBaseBackgroundID) + 1);
+
+
+
+ CopyBits(GetPortBitMapForCopyBits(tileSrcMap),
+ GetPortBitMapForCopyBits(GetDialogPort(theDialog)),
+ &tileSrcRect, &tileSrc, srcCopy, nil);
+ /*
+ CopyBits(&((GrafPtr)tileSrcMap)->portBits,
+ &(((GrafPtr)theDialog)->portBits),
+ &tileSrcRect, &tileSrc, srcCopy, nil);
+ */
+ dest = tileDest;
+ dest.right = dest.left + kMiniTileWide;
+ for (i = 0; i < kNumTiles; i++)
+ {
+ QSetRect(&src, 0, 0, kMiniTileWide, 80);
+ QOffsetRect(&src, tempTiles[i] * kMiniTileWide, 0);
+
+ CopyBits(GetPortBitMapForCopyBits(tileSrcMap),
+ GetPortBitMapForCopyBits(GetDialogPort(theDialog)),
+ &src, &dest, srcCopy, nil);
+ /*
+ CopyBits(&((GrafPtr)tileSrcMap)->portBits,
+ &(((GrafPtr)theDialog)->portBits),
+ &src, &dest, srcCopy, nil);
+ */
+ QOffsetRect(&dest, kMiniTileWide, 0);
+ }
+
+ if (GetNumberOfLights(thisRoomNumber) == 0)
+ SetDialogString(theDialog, kLitUnlitText, PSTR("(Room Is Dark)"));
+ else
+ SetDialogString(theDialog, kLitUnlitText, PSTR("(Room Is Lit)"));
+
+ FrameDialogItemC(theDialog, kRoomLocationBox, kRedOrangeColor8);
+ FrameDialogItem(theDialog, kRoomTilesBox);
+ FrameDialogItemC(theDialog, kRoomDividerLine, kRedOrangeColor8);
+ FrameDialogItem(theDialog, kRoomTilesBox2);
+}
+#endif
+
+//-------------------------------------------------------------- DragMiniTile
+
+#ifndef COMPILEDEMO
+void DragMiniTile (Point mouseIs, short *newTileOver)
+{
+ Rect dragRect;
+ Point mouseWas;
+ short wasTileOver;
+ Pattern dummyPattern;
+
+ tileOver = (mouseIs.h - tileSrc.left) / kMiniTileWide;
+ wasTileOver = -1;
+ QSetRect(&dragRect, 0, 0, kMiniTileWide, 80);
+ QOffsetRect(&dragRect,
+ tileSrc.left + (tileOver * kMiniTileWide),
+ tileSrc.top);
+ PenMode(patXor);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ FrameRect(&dragRect);
+ mouseWas = mouseIs;
+ while (WaitMouseUp()) // loop until mouse button let up
+ {
+ GetMouse(&mouseIs); // get mouse coords
+ if (DeltaPoint(mouseWas, mouseIs) != 0L) // the mouse has moved
+ {
+ FrameRect(&dragRect);
+ QOffsetRect(&dragRect, mouseIs.h - mouseWas.h, 0);
+ FrameRect(&dragRect);
+
+ if (PtInRect(mouseIs, &tileDest)) // is cursor in the drop rect
+ {
+ *newTileOver = (mouseIs.h - tileDest.left) / kMiniTileWide;
+ if (*newTileOver != wasTileOver)
+ {
+ PenNormal();
+ PenSize(1, 2);
+ ForeColor(blueColor);
+ MoveTo(tileDest.left + (*newTileOver * kMiniTileWide),
+ tileDest.top - 3);
+ Line(kMiniTileWide, 0);
+ MoveTo(tileDest.left + (*newTileOver * kMiniTileWide),
+ tileDest.bottom + 1);
+ Line(kMiniTileWide, 0);
+
+ if (wasTileOver != -1)
+ {
+ ForeColor(whiteColor);
+ MoveTo(tileDest.left + (wasTileOver * kMiniTileWide),
+ tileDest.top - 3);
+ Line(kMiniTileWide, 0);
+ MoveTo(tileDest.left + (wasTileOver * kMiniTileWide),
+ tileDest.bottom + 1);
+ Line(kMiniTileWide, 0);
+ }
+ ForeColor(blackColor);
+ PenNormal();
+ PenMode(patXor);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ wasTileOver = *newTileOver;
+ }
+ }
+ else
+ {
+ *newTileOver = -1; // we're not in the drop zone
+ if (wasTileOver != -1)
+ {
+ PenNormal();
+ PenSize(1, 2);
+ ForeColor(whiteColor);
+ MoveTo(tileDest.left + (wasTileOver * kMiniTileWide),
+ tileDest.top - 3);
+ Line(kMiniTileWide, 0);
+ MoveTo(tileDest.left + (wasTileOver * kMiniTileWide),
+ tileDest.bottom + 1);
+ Line(kMiniTileWide, 0);
+ ForeColor(blackColor);
+ PenNormal();
+ PenMode(patXor);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ wasTileOver = -1;
+ }
+ }
+
+ mouseWas = mouseIs;
+ }
+ }
+ if (wasTileOver != -1)
+ {
+ PenNormal();
+ PenSize(1, 2);
+ ForeColor(whiteColor);
+ MoveTo(tileDest.left + (wasTileOver * kMiniTileWide), tileDest.top - 3);
+ Line(kMiniTileWide, 0);
+ MoveTo(tileDest.left + (wasTileOver * kMiniTileWide), tileDest.bottom + 1);
+ Line(kMiniTileWide, 0);
+ ForeColor(blackColor);
+ PenNormal();
+ PenMode(patXor);
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ wasTileOver = -1;
+ }
+ FrameRect(&dragRect);
+ PenNormal();
+}
+#endif
+
+//-------------------------------------------------------------- HiliteTileOver
+
+#ifndef COMPILEDEMO
+void HiliteTileOver (Point mouseIs)
+{
+ short newTileOver;
+
+ if (PtInRect(mouseIs, &tileSrc))
+ {
+ if (cursorIs != kHandCursor)
+ {
+ SetCursor(&handCursor);
+ cursorIs = kHandCursor;
+ }
+
+ newTileOver = (mouseIs.h - tileSrc.left) / kMiniTileWide;
+ if (newTileOver != tileOver)
+ {
+ PenSize(1, 2);
+ ForeColor(redColor);
+ MoveTo(tileSrc.left + (newTileOver * kMiniTileWide), tileSrc.top - 3);
+ Line(kMiniTileWide, 0);
+ MoveTo(tileSrc.left + (newTileOver * kMiniTileWide), tileSrc.bottom + 1);
+ Line(kMiniTileWide, 0);
+
+ if (tileOver != -1)
+ {
+ ForeColor(whiteColor);
+ MoveTo(tileSrc.left + (tileOver * kMiniTileWide), tileSrc.top - 3);
+ Line(kMiniTileWide, 0);
+ MoveTo(tileSrc.left + (tileOver * kMiniTileWide), tileSrc.bottom + 1);
+ Line(kMiniTileWide, 0);
+ }
+ ForeColor(blackColor);
+ PenNormal();
+
+ tileOver = newTileOver;
+ }
+ }
+ else
+ {
+ if (tileOver != -1)
+ {
+ PenSize(1, 2);
+ ForeColor(whiteColor);
+ MoveTo(tileSrc.left + (tileOver * kMiniTileWide), tileSrc.top - 3);
+ Line(kMiniTileWide, 0);
+ MoveTo(tileSrc.left + (tileOver * kMiniTileWide), tileSrc.bottom + 1);
+ Line(kMiniTileWide, 0);
+ ForeColor(blackColor);
+ PenNormal();
+ tileOver = -1;
+ }
+
+ if (PtInRect(mouseIs, &editTETextBox))
+ {
+ if (cursorIs != kBeamCursor)
+ {
+ SetCursor(&beamCursor);
+ cursorIs = kBeamCursor;
+ }
+ }
+ else
+ {
+ if (cursorIs != kArrowCursor)
+ {
+ InitCursor();
+ cursorIs = kArrowCursor;
+ }
+ }
+ }
+}
+#endif
+
+//-------------------------------------------------------------- RoomFilter
+#ifndef COMPILEDEMO
+
+Boolean RoomFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ Point mouseIs;
+ short newTileOver;
+
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ case kTabKeyASCII:
+ SelectDialogItemText(dial, kRoomNameItem, 0, 1024);
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ mouseIs = event->where;
+ GlobalToLocal(&mouseIs);
+ if (PtInRect(mouseIs, &tileSrc))
+ {
+ if (StillDown())
+ {
+ DragMiniTile(mouseIs, &newTileOver);
+ if ((newTileOver >= 0) && (newTileOver < kNumTiles))
+ {
+ tempTiles[newTileOver] = tileOver;
+ UpdateRoomInfoDialog(dial);
+ }
+ }
+ return(true);
+ }
+ else
+ return(false);
+ break;
+
+ case mouseUp:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateRoomInfoDialog(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ GetMouse(&mouseIs);
+ HiliteTileOver(mouseIs);
+ return(false);
+ break;
+ }
+}
+#endif
+
+//-------------------------------------------------------------- DoRoomInfo
+
+void DoRoomInfo (void)
+{
+#ifndef COMPILEDEMO
+ #define kBackgroundsMenuID 140
+ DialogPtr roomInfoDialog;
+ MenuHandle backgroundsMenu;
+ Str255 floorStr, suiteStr, objectsStr, tempStr;
+ short item, i, newBack;
+ char wasState;
+ Boolean leaving, wasFirstRoom, forceDraw;
+ ModalFilterUPP roomFilterUPP;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+ roomFilterUPP = NewModalFilterUPP(RoomFilter);
+
+ tileOver = -1;
+ cursorIs = kArrowCursor;
+ tempBack = thisRoom->background;
+ backgroundsMenu = GetMenu(kBackgroundsMenuID);
+// SetMenuItemTextStyle(backgroundsMenu, kOriginalArtworkItem, italic);
+ if (HouseHasOriginalPicts())
+ EnableMenuItem(backgroundsMenu, kOriginalArtworkItem);
+
+ NumToString(thisRoom->floor, floorStr);
+ NumToString(thisRoom->suite, suiteStr);
+ NumToString(thisRoom->numObjects, objectsStr);
+ ParamText(floorStr, suiteStr, objectsStr, PSTR(""));
+
+ theErr = CreateOffScreenGWorld(&tileSrcMap, &tileSrcRect, kPreferredDepth);
+ SetGWorld(tileSrcMap, nil);
+// CreateOffScreenPixMap(&tileSrcRect, &tileSrcMap);
+// SetPort((GrafPtr)tileSrcMap);
+ if ((tempBack > kStars) && (!PictIDExists(tempBack)))
+ {
+ BitchAboutPICTNotFound();
+ tempBack = kSimpleRoom;
+ }
+ if ((tempBack == 2002) || (tempBack == 2011) ||
+ (tempBack == 2016) || (tempBack == 2017))
+ LoadScaledGraphic(tempBack - 800, &tileSrcRect);
+ else
+ LoadScaledGraphic(tempBack, &tileSrcRect);
+
+ SetGWorld(wasCPort, wasWorld);
+
+ for (i = 0; i < kNumTiles; i++)
+ tempTiles[i] = thisRoom->tiles[i];
+
+// CenterDialog(kRoomInfoDialogID);
+ roomInfoDialog = GetNewDialog(kRoomInfoDialogID, nil, kPutInFront);
+ if (roomInfoDialog == nil)
+ RedAlert(kErrDialogDidntLoad);
+ SetPort((GrafPtr)roomInfoDialog);
+
+ // Fix this later. TEMP
+// AddMenuToPopUp(roomInfoDialog, kRoomPopupItem, backgroundsMenu);
+ if (tempBack >= kUserBackground)
+ SetPopUpMenuValue(roomInfoDialog, kRoomPopupItem, kOriginalArtworkItem);
+ else
+ SetPopUpMenuValue(roomInfoDialog, kRoomPopupItem,
+ (tempBack - kBaseBackgroundID) + 1);
+ SetDialogString(roomInfoDialog, kRoomNameItem, thisRoom->name);
+ GetDialogItemRect(roomInfoDialog, kRoomTilesBox, &tileSrc);
+ GetDialogItemRect(roomInfoDialog, kRoomTilesBox2, &tileDest);
+ GetDialogItemRect(roomInfoDialog, kRoomNameItem, &editTETextBox);
+ SelectDialogItemText(roomInfoDialog, kRoomNameItem, 0, 1024);
+
+ ShowWindow(GetDialogWindow(roomInfoDialog));
+ DrawDefaultButton(roomInfoDialog);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ wasFirstRoom = ((*thisHouse)->firstRoom == thisRoomNumber);
+ HSetState((Handle)thisHouse, wasState);
+ SetDialogItemValue(roomInfoDialog, kRoomFirstCheck, (short)wasFirstRoom);
+
+ if (tempBack >= kUserBackground)
+ MyEnableControl(roomInfoDialog, kBoundsButton);
+ else
+ MyDisableControl(roomInfoDialog, kBoundsButton);
+
+ leaving = false;
+
+ while (!leaving)
+ {
+ ModalDialog(roomFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ for (i = 0; i < kNumTiles; i++)
+ thisRoom->tiles[i] = tempTiles[i];
+
+ GetDialogString(roomInfoDialog, kRoomNameItem, tempStr);
+ PasStringCopyNum(tempStr, thisRoom->name, 27);
+ if (wasFirstRoom)
+ {
+ HLock((Handle)thisHouse);
+ (*thisHouse)->firstRoom = thisRoomNumber;
+ HUnlock((Handle)thisHouse);
+ }
+ thisRoom->background = tempBack;
+ if (tempBack < kUserBackground)
+ lastBackground = tempBack;
+ CopyThisRoomToRoom();
+ ReflectCurrentRoom(false);
+ fileDirty = true;
+ UpdateMenus(false);
+ leaving = true;
+ }
+ else if (item == kCancelButton)
+ {
+ leaving = true;
+ }
+ else if (item == kRoomFirstCheck)
+ {
+ wasFirstRoom = !wasFirstRoom;
+ SetDialogItemValue(roomInfoDialog, kRoomFirstCheck, (short)wasFirstRoom);
+ }
+ else if (item == kRoomPopupItem)
+ {
+ GetPopUpMenuValue(roomInfoDialog, kRoomPopupItem, &newBack);
+ if (newBack == kOriginalArtworkItem) // original art item selected?
+ {
+ if (tempBack < kUserBackground) // was previous bg built-in?
+ {
+ tempBack = GetFirstPICT(); // then assign 1st PICT
+ forceDraw = true;
+ }
+ else
+ forceDraw = false;
+ newBack = ChooseOriginalArt(tempBack); // bring up dialog
+ if ((tempBack != newBack) || (forceDraw))
+ {
+ tempBack = newBack;
+ SetPort((GrafPtr)tileSrcMap);
+ LoadScaledGraphic(tempBack, &tileSrcRect);
+ InvalWindowRect(GetDialogWindow(roomInfoDialog), &tileSrc);
+ InvalWindowRect(GetDialogWindow(roomInfoDialog), &tileDest);
+ }
+ }
+ else
+ {
+ newBack += (kBaseBackgroundID - 1); // adjust to get real PICT ID
+ if (newBack != tempBack) // if background has changed
+ SetInitialTiles(newBack, false);
+ }
+
+ if (newBack >= kUserBackground)
+ {
+ MyEnableControl(roomInfoDialog, kBoundsButton);
+ if (newBack != tempBack) // if background has changed
+ SetInitialTiles(newBack, false);
+ }
+ else
+ MyDisableControl(roomInfoDialog, kBoundsButton);
+
+ if (newBack != tempBack)
+ {
+ tempBack = newBack;
+ SetPort((GrafPtr)tileSrcMap);
+ if ((tempBack == 2002) || (tempBack == 2011) ||
+ (tempBack == 2016) || (tempBack == 2017))
+ LoadScaledGraphic(tempBack - 800, &tileSrcRect);
+ else
+ LoadScaledGraphic(tempBack, &tileSrcRect);
+ InvalWindowRect(GetDialogWindow(roomInfoDialog), &tileSrc);
+ InvalWindowRect(GetDialogWindow(roomInfoDialog), &tileDest);
+ }
+ }
+ else if (item == kBoundsButton)
+ {
+ newBack = ChooseOriginalArt(tempBack);
+ if (tempBack != newBack)
+ {
+ tempBack = newBack;
+ SetPort((GrafPtr)tileSrcMap);
+ LoadScaledGraphic(tempBack, &tileSrcRect);
+ InvalWindowRect(GetDialogWindow(roomInfoDialog), &tileSrc);
+ InvalWindowRect(GetDialogWindow(roomInfoDialog), &tileDest);
+ }
+ }
+ }
+
+ InitCursor();
+ DisposeDialog(roomInfoDialog);
+ DisposeModalFilterUPP(roomFilterUPP);
+
+// KillOffScreenPixMap(tileSrcMap);
+ DisposeGWorld(tileSrcMap);
+ tileSrcMap = nil;
+#endif
+}
+
+//-------------------------------------------------------------- UpdateOriginalArt
+
+#ifndef COMPILEDEMO
+void UpdateOriginalArt (DialogPtr theDialog)
+{
+ Pattern dummyPattern;
+
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+
+ PenSize(2, 1);
+ if (!originalLeftOpen)
+ BorderDialogItem(theDialog, 7, 8);
+ else
+ {
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ BorderDialogItem(theDialog, 7, 8);
+ PenPat(GetQDGlobalsBlack(&dummyPattern));
+ }
+
+ PenSize(1, 2);
+ if (!originalTopOpen)
+ BorderDialogItem(theDialog, 8, 4);
+ else
+ {
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ BorderDialogItem(theDialog, 8, 4);
+ PenPat(GetQDGlobalsBlack(&dummyPattern));
+ }
+
+ PenSize(2, 1);
+ if (!originalRightOpen)
+ BorderDialogItem(theDialog, 9, 1);
+ else
+ {
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ BorderDialogItem(theDialog, 9, 1);
+ PenPat(GetQDGlobalsBlack(&dummyPattern));
+ }
+
+ PenSize(1, 2);
+ if (!originalBottomOpen)
+ BorderDialogItem(theDialog, 10, 2);
+ else
+ {
+ PenPat(GetQDGlobalsGray(&dummyPattern));
+ BorderDialogItem(theDialog, 10, 2);
+ PenPat(GetQDGlobalsBlack(&dummyPattern));
+ }
+
+ PenSize(1, 1);
+}
+#endif
+
+//-------------------------------------------------------------- OriginalArtFilter
+#ifndef COMPILEDEMO
+
+Boolean OriginalArtFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ Point mouseIs;
+
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ case kTabKeyASCII:
+ SelectDialogItemText(dial, kPICTIDItem, 0, 1024);
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ mouseIs = event->where;
+ GlobalToLocal(&mouseIs);
+ if (PtInRect(mouseIs, &leftBound))
+ {
+ *item = 7;
+ return(true);
+ }
+ else if (PtInRect(mouseIs, &topBound))
+ {
+ *item = 8;
+ return(true);
+ }
+ else if (PtInRect(mouseIs, &rightBound))
+ {
+ *item = 9;
+ return(true);
+ }
+ else if (PtInRect(mouseIs, &bottomBound))
+ {
+ *item = 10;
+ return(true);
+ }
+ else
+ return(false);
+ break;
+
+ case mouseUp:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateOriginalArt(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+#endif
+
+//-------------------------------------------------------------- ChooseOriginalArt
+
+#ifndef COMPILEDEMO
+short ChooseOriginalArt (short was)
+{
+ DialogPtr theDialog;
+ long longID;
+ short item, newPictID, tempShort, wasPictID;
+ Boolean leaving;
+ ModalFilterUPP originalArtFilterUPP;
+
+ originalArtFilterUPP = NewModalFilterUPP(OriginalArtFilter);
+
+ if (was < kUserBackground)
+ was = kUserBackground;
+
+ InitCursor();
+ BringUpDialog(&theDialog, kOriginalArtDialogID);
+ if (was >= kOriginalArtworkItem)
+ {
+ newPictID = was;
+ wasPictID = was;
+ }
+ else
+ {
+ newPictID = kUserBackground;
+ wasPictID = 0;
+ }
+ SetDialogNumToStr(theDialog, kPICTIDItem, (long)newPictID);
+ SelectDialogItemText(theDialog, kPICTIDItem, 0, 16);
+
+ GetDialogItemRect(theDialog, 7, &leftBound);
+ GetDialogItemRect(theDialog, 8, &topBound);
+ GetDialogItemRect(theDialog, 9, &rightBound);
+ GetDialogItemRect(theDialog, 10, &bottomBound);
+
+ tempShort = thisRoom->bounds >> 1; // version 2.0 house
+ originalLeftOpen = ((tempShort & 1) == 1);
+ originalTopOpen = ((tempShort & 2) == 2);
+ originalRightOpen = ((tempShort & 4) == 4);
+ originalBottomOpen = ((tempShort & 8) == 8);
+ originalFloor = ((tempShort & 16) == 16);
+
+ SetDialogItemValue(theDialog, kFloorSupportCheck, (short)originalFloor);
+
+ leaving = false;
+
+ while (!leaving)
+ {
+ ModalDialog(originalArtFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ GetDialogNumFromStr(theDialog, kPICTIDItem, &longID);
+ if ((longID >= 3000) && (longID < 3800) && (PictIDExists((short)longID)))
+ {
+ newPictID = (short)longID;
+ if (newPictID != wasPictID)
+ SetInitialTiles(tempBack, false);
+ tempShort = 0;
+ if (originalLeftOpen)
+ tempShort += 1;
+ if (originalTopOpen)
+ tempShort += 2;
+ if (originalRightOpen)
+ tempShort += 4;
+ if (originalBottomOpen)
+ tempShort += 8;
+ if (originalFloor)
+ tempShort += 16;
+ tempShort = tempShort << 1; // shift left 1 bit
+ tempShort += 1; // flag that says orginal bounds used
+ thisRoom->bounds = tempShort;
+ leaving = true;
+ }
+ else
+ {
+ SysBeep(1);
+ SetDialogNumToStr(theDialog, kPICTIDItem, (long)newPictID);
+ }
+ }
+ else if (item == kCancelButton)
+ {
+ newPictID = was;
+ leaving = true;
+ }
+ else if (item == 7)
+ {
+ originalLeftOpen = !originalLeftOpen;
+ UpdateOriginalArt(theDialog);
+ }
+ else if (item == 8)
+ {
+ originalTopOpen = !originalTopOpen;
+ UpdateOriginalArt(theDialog);
+ }
+ else if (item == 9)
+ {
+ originalRightOpen = !originalRightOpen;
+ UpdateOriginalArt(theDialog);
+ }
+ else if (item == 10)
+ {
+ originalBottomOpen = !originalBottomOpen;
+ UpdateOriginalArt(theDialog);
+ }
+ else if (item == kFloorSupportCheck)
+ {
+ originalFloor = !originalFloor;
+ ToggleDialogItemValue(theDialog, kFloorSupportCheck);
+ }
+ }
+
+ DisposeDialog(theDialog);
+ DisposeModalFilterUPP(originalArtFilterUPP);
+
+ return (newPictID);
+}
+#endif
+
+//-------------------------------------------------------------- PictIDExists
+
+Boolean PictIDExists (short theID)
+{
+ PicHandle thePicture;
+// Handle resHandle;
+// Str255 resName;
+// ResType resType;
+// short numPicts, i;
+// short resID;
+ Boolean foundIt;
+
+ foundIt = true;
+
+ thePicture = GetPicture(theID);
+ if (thePicture == nil)
+ {
+ thePicture = (PicHandle)GetResource('Date', theID);
+ if (thePicture == nil)
+ {
+ foundIt = false;
+ }
+ else
+ ReleaseResource((Handle)thePicture);
+ }
+ else
+ ReleaseResource((Handle)thePicture);
+
+// foundIt = false;
+// numPicts = Count1Resources('PICT');
+// for (i = 1; i <= numPicts; i++)
+// {
+// resHandle = Get1IndResource('PICT', i);
+// if (resHandle != nil)
+// {
+// GetResInfo(resHandle, &resID, &resType, resName);
+// ReleaseResource(resHandle);
+// if (resID == theID)
+// {
+// foundIt = true;
+// break;
+// }
+// }
+// }
+
+ return (foundIt);
+}
+
+//-------------------------------------------------------------- GetFirstPICT
+
+short GetFirstPICT (void)
+{
+ Handle resHandle;
+ Str255 resName;
+ ResType resType;
+ short resID;
+
+ resHandle = Get1IndResource('PICT', 1);
+ if (resHandle != nil)
+ {
+ GetResInfo(resHandle, &resID, &resType, resName);
+ ReleaseResource(resHandle);
+ return (resID);
+ }
+ else
+ return (-1);
+}
+
+//-------------------------------------------------------------- BitchAboutPICTNotFound
+
+#ifndef COMPILEDEMO
+void BitchAboutPICTNotFound (void)
+{
+ short hitWhat;
+
+// CenterAlert(kNoPICTFoundAlert);
+ hitWhat = Alert(kNoPICTFoundAlert, nil);
+}
+#endif
+
diff --git a/GpApp/RubberBands.cpp b/GpApp/RubberBands.cpp
new file mode 100644
index 0000000..43c8f49
--- /dev/null
+++ b/GpApp/RubberBands.cpp
@@ -0,0 +1,318 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// RubberBands.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "RectUtils.h"
+
+
+#define kRubberBandVelocity 20
+#define kBandFallCount 4
+#define kKillBandMode -1
+
+
+void CheckBandCollision (short);
+void KillBand (short);
+
+
+bandPtr bands;
+Rect bandsSrcRect;
+Rect bandRects[3];
+GWorldPtr bandsSrcMap;
+GWorldPtr bandsMaskMap;
+short numBands, bandHitLast;
+
+extern hotPtr hotSpots;
+extern long gameFrame;
+extern short nHotSpots, leftThresh, rightThresh;
+extern Boolean twoPlayerGame, onePlayerLeft, playerDead;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- CheckBandCollision
+
+void CheckBandCollision (short who)
+{
+ short i, action, whoLinked;
+ Boolean collided, nothingCollided;
+
+ nothingCollided = true;
+
+ if ((leftThresh == kLeftWallLimit) && (bands[who].dest.left < kLeftWallLimit))
+ {
+ if (bands[who].hVel < 0)
+ bands[who].hVel = -bands[who].hVel;
+ bands[who].dest.left = kLeftWallLimit;
+ bands[who].dest.right = bands[who].dest.left + 16;
+ PlayPrioritySound(kBandReboundSound, kBandReboundPriority);
+ collided = true;
+ }
+ else if ((rightThresh == kRightWallLimit) && (bands[who].dest.right > kRightWallLimit))
+ {
+ if (bands[who].hVel > 0)
+ bands[who].hVel = -bands[who].hVel;
+ bands[who].dest.right = kRightWallLimit;
+ bands[who].dest.left = bands[who].dest.right - 16;
+ PlayPrioritySound(kBandReboundSound, kBandReboundPriority);
+ collided = true;
+ }
+
+ for (i = 0; i < nHotSpots; i++)
+ {
+ if (hotSpots[i].isOn)
+ {
+ action = hotSpots[i].action;
+ if ((action == kDissolveIt) || (action == kRewardIt) ||
+ (action == kSwitchIt) || (action == kTriggerIt) ||
+ (action == kBounceIt))
+ {
+ if (bands[who].dest.bottom < hotSpots[i].bounds.top)
+ collided = false;
+ else if (bands[who].dest.top > hotSpots[i].bounds.bottom)
+ collided = false;
+ else if (bands[who].dest.right < hotSpots[i].bounds.left)
+ collided = false;
+ else if (bands[who].dest.left > hotSpots[i].bounds.right)
+ collided = false;
+ else
+ collided = true;
+
+ if (collided)
+ {
+ nothingCollided = false; // we have detected a collision
+ if (bandHitLast != i) // don't count it if same as last frame
+ { // we don't want rapid on/off toggles
+ bandHitLast = i; // note who so we don't double-toggle it
+ if ((action == kDissolveIt) || (action == kBounceIt))
+ {
+ if (bands[who].hVel > 0)
+ {
+ if ((bands[who].dest.right - bands[who].hVel) <
+ hotSpots[i].bounds.left)
+ {
+ bands[who].hVel = -bands[who].hVel;
+ bands[who].dest.right = hotSpots[i].bounds.left;
+ bands[who].dest.left = bands[who].dest.right - 16;
+ }
+ else
+ bands[who].mode = kKillBandMode;
+ }
+ else
+ {
+ if ((bands[who].dest.left - bands[who].hVel) >
+ hotSpots[i].bounds.right)
+ {
+ bands[who].hVel = -bands[who].hVel;
+ bands[who].dest.left = hotSpots[i].bounds.right;
+ bands[who].dest.right = bands[who].dest.left + 16;
+ }
+ else
+ bands[who].mode = kKillBandMode;
+ }
+ PlayPrioritySound(kBandReboundSound, kBandReboundPriority);
+ break;
+ }
+ else if (action == kRewardIt)
+ {
+ whoLinked = hotSpots[i].who;
+ if ((masterObjects[whoLinked].theObject.what == kGreaseRt) ||
+ (masterObjects[whoLinked].theObject.what == kGreaseLf))
+ {
+ if (SetObjectState(thisRoomNumber,
+ masterObjects[whoLinked].objectNum, 0, whoLinked))
+ SpillGrease(masterObjects[whoLinked].dynaNum,
+ masterObjects[whoLinked].hotNum);
+ hotSpots[i].isOn = false;
+ }
+ }
+ else if (action == kSwitchIt)
+ {
+ HandleSwitches(&hotSpots[i]);
+ }
+ else if (action == kTriggerIt)
+ {
+ ArmTrigger(&hotSpots[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (nothingCollided) // the rubberband has hit nothing
+ bandHitLast = -1; // so make note of that for the next time
+
+ if (bands[who].hVel != 0)
+ {
+ if (bands[who].dest.bottom < theGlider.dest.top)
+ collided = false;
+ else if (bands[who].dest.top > theGlider.dest.bottom)
+ collided = false;
+ else if (bands[who].dest.right < theGlider.dest.left)
+ collided = false;
+ else if (bands[who].dest.left > theGlider.dest.right)
+ collided = false;
+ else
+ collided = true;
+
+ if (collided)
+ {
+ if ((!twoPlayerGame) || (!onePlayerLeft) || (playerDead == kPlayer2))
+ {
+ theGlider.hVel += (bands[who].hVel / 2);
+ bands[who].hVel = 0;
+ PlayPrioritySound(kHitWallSound, kHitWallPriority);
+ }
+ }
+
+ if (twoPlayerGame)
+ {
+ if (bands[who].dest.bottom < theGlider2.dest.top)
+ collided = false;
+ else if (bands[who].dest.top > theGlider2.dest.bottom)
+ collided = false;
+ else if (bands[who].dest.right < theGlider2.dest.left)
+ collided = false;
+ else if (bands[who].dest.left > theGlider2.dest.right)
+ collided = false;
+ else
+ collided = true;
+
+ if (collided)
+ {
+ if ((!onePlayerLeft) || (playerDead == kPlayer1))
+ {
+ theGlider2.hVel += (bands[who].hVel / 2);
+ bands[who].hVel = 0;
+ PlayPrioritySound(kHitWallSound, kHitWallPriority);
+ }
+ }
+ }
+ }
+ if ((bands[who].dest.left < kLeftWallLimit) ||
+ (bands[who].dest.right > kRightWallLimit))
+ {
+ bands[who].mode = kKillBandMode;
+ }
+ else if (bands[who].dest.bottom > kFloorLimit)
+ {
+ bands[who].mode = kKillBandMode;
+ }
+}
+
+//-------------------------------------------------------------- HandleBands
+
+void HandleBands (void)
+{
+ Rect dest;
+ short i, count;
+
+ if (numBands == 0)
+ return;
+
+ for (i = 0; i < numBands; i++)
+ {
+ bands[i].mode++;
+ if (bands[i].mode > 2)
+ bands[i].mode = 0;
+
+ bands[i].count++;
+ if (bands[i].count >= kBandFallCount)
+ {
+ bands[i].vVel++;
+ bands[i].count = 0;
+ }
+
+ dest = bands[i].dest;
+ QOffsetRect(&dest, playOriginH, playOriginV);
+ AddRectToWorkRects(&dest);
+
+ bands[i].dest.left += bands[i].hVel;
+ bands[i].dest.right += bands[i].hVel;
+ bands[i].dest.top += bands[i].vVel;
+ bands[i].dest.bottom += bands[i].vVel;
+
+ CheckBandCollision(i);
+ }
+
+ count = 0;
+ do
+ {
+ while (bands[count].mode == kKillBandMode)
+ {
+ bands[count].mode = 0;
+ KillBand(count);
+ }
+ count++;
+ }
+ while (count < numBands);
+}
+
+//-------------------------------------------------------------- AddBand
+
+Boolean AddBand (gliderPtr thisGlider, short h, short v, Boolean direction)
+{
+ if (numBands >= kMaxRubberBands)
+ return (false);
+
+ bands[numBands].mode = 0;
+ bands[numBands].count = 0;
+ if (thisGlider->tipped)
+ bands[numBands].vVel = -2;
+ else
+ bands[numBands].vVel = 0;
+ bands[numBands].dest.left = h - 8;
+ bands[numBands].dest.right = h + 8;
+ bands[numBands].dest.top = v - 3;
+ bands[numBands].dest.bottom = v + 3;
+
+ if (direction == kFaceLeft)
+ {
+ bands[numBands].dest.left -= 32;
+ bands[numBands].dest.right -= 32;
+ bands[numBands].hVel = -kRubberBandVelocity;
+ }
+ else
+ {
+ bands[numBands].dest.left += 32;
+ bands[numBands].dest.right += 32;
+ bands[numBands].hVel = kRubberBandVelocity;
+ }
+
+ thisGlider->hVel -= (bands[numBands].hVel / 2);
+ numBands++;
+
+ PlayPrioritySound(kFireBandSound, kFireBandPriority);
+ return (true);
+}
+
+//-------------------------------------------------------------- KillBand
+
+void KillBand (short which)
+{
+ short lastBand;
+
+ lastBand = numBands - 1;
+ if (which != lastBand)
+ bands[which] = bands[lastBand];
+
+ numBands--;
+}
+
+//-------------------------------------------------------------- KillAllBands
+
+void KillAllBands (void)
+{
+ short i;
+
+ for (i = 0; i < kMaxRubberBands; i++)
+ {
+ bands[i].mode = 0;
+ }
+
+ numBands = 0;
+}
+
diff --git a/GpApp/RubberBands.h b/GpApp/RubberBands.h
new file mode 100644
index 0000000..3f1a1e9
--- /dev/null
+++ b/GpApp/RubberBands.h
@@ -0,0 +1,12 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// RubberBands.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+extern GWorldPtr bandsSrcMap;
+extern GWorldPtr bandsMaskMap;
diff --git a/GpApp/SavedGames.cpp b/GpApp/SavedGames.cpp
new file mode 100644
index 0000000..42d0586
--- /dev/null
+++ b/GpApp/SavedGames.cpp
@@ -0,0 +1,352 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// SavedGames.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLStringCompare.h"
+#include "Externs.h"
+#include "House.h"
+
+
+#define kSavedGameVersion 0x0200
+
+
+void SavedGameMismatchError (StringPtr);
+
+
+gameType smallGame;
+
+extern FSSpecPtr theHousesSpecs;
+extern short numStarsRemaining, thisHouseIndex;
+extern Boolean twoPlayerGame;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- SaveGame2
+
+void SaveGame2 (void)
+{
+ // Add NavServices later.
+/*
+ StandardFileReply theReply;
+ FSSpec tempSpec;
+ Str255 gameNameStr;
+ Size byteCount;
+ OSErr theErr;
+ houseType *thisHousePtr;
+ roomType *srcRoom;
+ savedRoom *destRoom;
+ gamePtr savedGame;
+ short r, i, numRooms, gameRefNum;
+ char wasState;
+
+ FlushEvents(everyEvent, 0);
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ numRooms = thisHousePtr->nRooms;
+
+ HSetState((Handle)thisHouse, wasState);
+
+ byteCount = sizeof(game2Type) + sizeof(savedRoom) * numRooms;
+ savedGame = (gamePtr)NewPtr(byteCount);
+ if (savedGame == nil)
+ {
+ YellowAlert(kYellowFailedSaveGame, MemError());
+ return;
+ }
+
+ GetFirstWordOfString(thisHouseName, gameNameStr);
+ if (gameNameStr[0] > 23)
+ gameNameStr[0] = 23;
+ PasStringConcat(gameNameStr, "\p Game");
+
+ StandardPutFile("\pSave Game As:", gameNameStr, &theReply);
+ if (!theReply.sfGood)
+ return;
+
+ if (theReply.sfReplacing)
+ {
+ theErr = FSMakeFSSpec(theReply.sfFile.vRefNum, theReply.sfFile.parID,
+ theReply.sfFile.name, &tempSpec);
+ if (!CheckFileError(theErr, "\pSaved Game"))
+ return;
+
+ theErr = FSpDelete(&tempSpec);
+ if (!CheckFileError(theErr, "\pSaved Game"))
+ return;
+ }
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ savedGame->house = theHousesSpecs[thisHouseIndex];
+ savedGame->version = kSavedGameVersion;
+ savedGame->wasStarsLeft = numStarsRemaining;
+ savedGame->timeStamp = thisHousePtr->timeStamp;
+ savedGame->where.h = theGlider.dest.left;
+ savedGame->where.v = theGlider.dest.top;
+ savedGame->score = theScore;
+ savedGame->unusedLong = 0L;
+ savedGame->unusedLong2 = 0L;
+ savedGame->energy = batteryTotal;
+ savedGame->bands = bandsTotal;
+ savedGame->roomNumber = thisRoomNumber;
+ savedGame->gliderState = theGlider.mode;
+ savedGame->numGliders = mortals;
+ savedGame->foil = foilTotal;
+ savedGame->nRooms = numRooms;
+ savedGame->facing = theGlider.facing;
+ savedGame->showFoil = showFoil;
+
+ for (r = 0; r < numRooms; r++)
+ {
+ destRoom = &(savedGame->savedData[r]);
+ srcRoom = &(thisHousePtr->rooms[r]);
+
+ destRoom->unusedShort = 0;
+ destRoom->unusedByte = 0;
+ destRoom->visited = srcRoom->visited;
+ for (i = 0; i < kMaxRoomObs; i++)
+ destRoom->objects[i] = srcRoom->objects[i];
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ theErr = FSpCreate(&theReply.sfFile, 'ozm5', 'gliG', theReply.sfScript);
+ if (CheckFileError(theErr, "\pSaved Game"))
+ {
+ theErr = FSpOpenDF(&theReply.sfFile, fsCurPerm, &gameRefNum);
+ if (CheckFileError(theErr, "\pSaved Game"))
+ {
+ theErr = SetFPos(gameRefNum, fsFromStart, 0L);
+ if (CheckFileError(theErr, "\pSaved Game"))
+ {
+ theErr = FSWrite(gameRefNum, &byteCount, (Ptr)savedGame);
+ if (CheckFileError(theErr, "\pSaved Game"))
+ {
+ theErr = SetEOF(gameRefNum, byteCount);
+ if (CheckFileError(theErr, "\pSaved Game"))
+ {
+ }
+ }
+ }
+ theErr = FSClose(gameRefNum);
+ if (CheckFileError(theErr, "\pSaved Game"))
+ {
+ }
+ }
+ }
+ DisposePtr((Ptr)savedGame);
+ */
+}
+
+//-------------------------------------------------------------- SavedGameMismatchError
+
+void SavedGameMismatchError (StringPtr gameName)
+{
+ #define kSavedGameErrorAlert 1044
+ short whoCares;
+
+ InitCursor();
+
+// CenterAlert(kSavedGameErrorAlert);
+ ParamText(gameName, thisHouseName, PSTR(""), PSTR(""));
+
+ whoCares = Alert(kSavedGameErrorAlert, nil);
+}
+
+//-------------------------------------------------------------- OpenSavedGame
+
+Boolean OpenSavedGame (void)
+{
+return false; // TEMP fix this iwth NavServices
+/*
+ StandardFileReply theReply;
+ SFTypeList theList;
+ houseType *thisHousePtr;
+ roomType *destRoom;
+ savedRoom *srcRoom;
+ gamePtr savedGame;
+ long byteCount;
+ OSErr theErr;
+ short r, i, gameRefNum;
+ char wasState;
+
+ theList[0] = 'gliG';
+
+ StandardGetFile(nil, 1, theList, &theReply);
+ if (!theReply.sfGood)
+ return(false);
+
+ theErr = FSpOpenDF(&theReply.sfFile, fsCurPerm, &gameRefNum);
+ if (!CheckFileError(theErr, "\pSaved Game"))
+ return(false);
+
+ theErr = GetEOF(gameRefNum, &byteCount);
+ if (!CheckFileError(theErr, "\pSaved Game"))
+ {
+ theErr = FSClose(gameRefNum);
+ return(false);
+ }
+
+ savedGame = (gamePtr)NewPtr(byteCount);
+ if (savedGame == nil)
+ {
+ YellowAlert(kYellowFailedSaveGame, MemError());
+ theErr = FSClose(gameRefNum);
+ return(false);
+ }
+
+ theErr = SetFPos(gameRefNum, fsFromStart, 0L);
+ if (!CheckFileError(theErr, "\pSaved Game"))
+ {
+ DisposePtr((Ptr)savedGame);
+ theErr = FSClose(gameRefNum);
+ return(false);
+ }
+
+ theErr = FSRead(gameRefNum, &byteCount, savedGame);
+ if (!CheckFileError(theErr, "\pSaved Game"))
+ {
+ DisposePtr((Ptr)savedGame);
+ theErr = FSClose(gameRefNum);
+ return(false);
+ }
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ if (!EqualString(savedGame->house.name, thisHouseName, true, true))
+ {
+ SavedGameMismatchError(savedGame->house.name);
+ HSetState((Handle)thisHouse, wasState);
+ DisposePtr((Ptr)savedGame);
+ theErr = FSClose(gameRefNum);
+ return(false);
+ }
+ else if (thisHousePtr->timeStamp != savedGame->timeStamp)
+ {
+ YellowAlert(kYellowSavedTimeWrong, 0);
+ HSetState((Handle)thisHouse, wasState);
+ DisposePtr((Ptr)savedGame);
+ theErr = FSClose(gameRefNum);
+ return(false);
+ }
+ else if (savedGame->version != kSavedGameVersion)
+ {
+ YellowAlert(kYellowSavedVersWrong, kSavedGameVersion);
+ HSetState((Handle)thisHouse, wasState);
+ DisposePtr((Ptr)savedGame);
+ theErr = FSClose(gameRefNum);
+ return(false);
+ }
+ else if (savedGame->nRooms != thisHousePtr->nRooms)
+ {
+ YellowAlert(kYellowSavedRoomsWrong, savedGame->nRooms - thisHousePtr->nRooms);
+ HSetState((Handle)thisHouse, wasState);
+ DisposePtr((Ptr)savedGame);
+ theErr = FSClose(gameRefNum);
+ return(false);
+ }
+ else
+ {
+ smallGame.wasStarsLeft = savedGame->wasStarsLeft;
+ smallGame.where.h = savedGame->where.h;
+ smallGame.where.v = savedGame->where.v;
+ smallGame.score = savedGame->score;
+ smallGame.unusedLong = savedGame->unusedLong;
+ smallGame.unusedLong2 = savedGame->unusedLong2;
+ smallGame.energy = savedGame->energy;
+ smallGame.bands = savedGame->bands;
+ smallGame.roomNumber = savedGame->roomNumber;
+ smallGame.gliderState = savedGame->gliderState;
+ smallGame.numGliders = savedGame->numGliders;
+ smallGame.foil = savedGame->foil;
+ smallGame.unusedShort = 0;
+ smallGame.facing = savedGame->facing;
+ smallGame.showFoil = savedGame->showFoil;
+
+ for (r = 0; r < savedGame->nRooms; r++)
+ {
+ srcRoom = &(savedGame->savedData[r]);
+ destRoom = &(thisHousePtr->rooms[r]);
+ destRoom->visited = srcRoom->visited;
+ for (i = 0; i < kMaxRoomObs; i++)
+ destRoom->objects[i] = srcRoom->objects[i];
+ }
+ }
+ HSetState((Handle)thisHouse, wasState);
+
+ DisposePtr((Ptr)savedGame);
+
+ theErr = FSClose(gameRefNum);
+ if (!CheckFileError(theErr, "\pSaved Game"))
+ return (false);
+
+ return (true);
+ */
+}
+
+//-------------------------------------------------------------- SaveGame
+
+// This is probably about 3 days away from becoming the "old" functionÉ
+// for saving games.
+
+void SaveGame (Boolean doSave)
+{
+ houseType *thisHousePtr;
+ UInt32 stamp;
+ char wasState;
+
+ if (twoPlayerGame)
+ return;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+
+ if (doSave)
+ {
+ thisHousePtr->savedGame.version = kSavedGameVersion;
+ thisHousePtr->savedGame.wasStarsLeft = numStarsRemaining;
+ GetDateTime(&stamp);
+ thisHousePtr->savedGame.timeStamp = (long)stamp;
+ thisHousePtr->savedGame.where.h = theGlider.dest.left;
+ thisHousePtr->savedGame.where.v = theGlider.dest.top;
+ thisHousePtr->savedGame.score = theScore;
+ thisHousePtr->savedGame.unusedLong = 0L;
+ thisHousePtr->savedGame.unusedLong2 = 0L;
+ thisHousePtr->savedGame.energy = batteryTotal;
+ thisHousePtr->savedGame.bands = bandsTotal;
+ thisHousePtr->savedGame.roomNumber = thisRoomNumber;
+ thisHousePtr->savedGame.gliderState = theGlider.mode;
+ thisHousePtr->savedGame.numGliders = mortals;
+ thisHousePtr->savedGame.foil = foilTotal;
+ thisHousePtr->savedGame.unusedShort = 0;
+ thisHousePtr->savedGame.facing = theGlider.facing;
+ thisHousePtr->savedGame.showFoil = showFoil;
+
+ thisHousePtr->hasGame = true;
+ }
+ else
+ {
+ thisHousePtr->hasGame = false;
+ }
+
+ HSetState((Handle)thisHouse, wasState);
+
+ if (doSave)
+ {
+ if (!WriteHouse(theMode == kEditMode))
+ YellowAlert(kYellowFailedWrite, 0);
+ }
+}
+
diff --git a/GpApp/Scoreboard.cpp b/GpApp/Scoreboard.cpp
new file mode 100644
index 0000000..4bb6418
--- /dev/null
+++ b/GpApp/Scoreboard.cpp
@@ -0,0 +1,458 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Scoreboard.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLNumberFormatting.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "RectUtils.h"
+
+
+#define kGrayBackgroundColor 251
+#define kGrayBackgroundColor4 10
+#define kFoilBadge 0
+#define kBandsBadge 1
+#define kBatteryBadge 2
+#define kHeliumBadge 3
+#define kScoreRollAmount 13
+
+
+void RefreshRoomTitle (short);
+void RefreshNumGliders (void);
+void RefreshPoints (void);
+
+
+Rect boardSrcRect, badgeSrcRect, boardDestRect;
+GWorldPtr boardSrcMap, badgeSrcMap;
+Rect boardTSrcRect, boardTDestRect;
+GWorldPtr boardTSrcMap;
+Rect boardGSrcRect, boardGDestRect;
+GWorldPtr boardGSrcMap;
+Rect boardPSrcRect, boardPDestRect;
+Rect boardPQDestRect, boardGQDestRect;
+Rect badgesBlankRects[4], badgesBadgesRects[4];
+Rect badgesDestRects[4];
+GWorldPtr boardPSrcMap;
+long displayedScore;
+short wasScoreboardMode;
+Boolean doRollScore;
+
+extern Rect localRoomsDest[], justRoomsRect;
+extern long gameFrame;
+extern short numNeighbors, otherPlayerEscaped;
+extern Boolean evenFrame, onePlayerLeft;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- RefreshScoreboard
+
+void RefreshScoreboard (short mode)
+{
+ doRollScore = true;
+
+ RefreshRoomTitle(mode);
+ RefreshNumGliders();
+ RefreshPoints();
+
+ CopyBits((BitMap *)*GetGWorldPixMap(boardSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &boardSrcRect, &boardDestRect, srcCopy, 0L);
+
+ QuickBatteryRefresh(false);
+ QuickBandsRefresh(false);
+ QuickFoilRefresh(false);
+}
+
+//-------------------------------------------------------------- HandleDynamicScoreboard
+
+ void HandleDynamicScoreboard (void)
+ {
+ #define kFoilLow 2 // 25%
+ #define kBatteryLow 17 // 25%
+ #define kHeliumLow -38 // 25%
+ #define kBandsLow 2 // 25%
+ long whosTurn;
+
+ if (theScore > displayedScore)
+ {
+ if (doRollScore)
+ {
+ displayedScore += kScoreRollAmount;
+ if (displayedScore > theScore)
+ displayedScore = theScore;
+ }
+ else
+ displayedScore = theScore;
+
+ PlayPrioritySound(kScoreTikSound, kScoreTikPriority);
+ QuickScoreRefresh();
+ }
+
+ whosTurn = gameFrame & 0x00000007;
+ switch (whosTurn)
+ {
+ case 0: // show foil
+ if ((foilTotal > 0) && (foilTotal < kFoilLow))
+ QuickFoilRefresh(false);
+ break;
+
+ case 1: // hide battery
+ if ((batteryTotal > 0) && (batteryTotal < kBatteryLow))
+ QuickBatteryRefresh(true);
+ else if ((batteryTotal < 0) && (batteryTotal > kHeliumLow))
+ QuickBatteryRefresh(true);
+ break;
+
+ case 2: // show rubber bands
+ if ((bandsTotal > 0) && (bandsTotal < kBandsLow))
+ QuickBandsRefresh(false);
+ break;
+
+ case 4: // show battery
+ if ((batteryTotal > 0) && (batteryTotal < kBatteryLow))
+ QuickBatteryRefresh(false);
+ else if ((batteryTotal < 0) && (batteryTotal > kHeliumLow))
+ QuickBatteryRefresh(false);
+ break;
+
+ case 5: // hide foil
+ if ((foilTotal > 0) && (foilTotal < kFoilLow))
+ QuickFoilRefresh(true);
+ break;
+
+ case 7: // hide rubber bands
+ if ((bandsTotal > 0) && (bandsTotal < kBandsLow))
+ QuickBandsRefresh(true);
+ break;
+ }
+ }
+
+//-------------------------------------------------------------- RefreshRoomTitle
+
+void RefreshRoomTitle (short mode)
+{
+ RGBColor theRGBColor, wasColor;
+
+ SetPort((GrafPtr)boardTSrcMap);
+
+ GetForeColor(&wasColor);
+ if (thisMac.isDepth == 4)
+ Index2Color(kGrayBackgroundColor4, &theRGBColor);
+ else
+ Index2Color(kGrayBackgroundColor, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ PaintRect(&boardTSrcRect);
+ RGBForeColor(&wasColor);
+
+ MoveTo(1, 10);
+ ForeColor(blackColor);
+ switch (mode)
+ {
+ case kEscapedTitleMode:
+ DrawString(PSTR("Hit Delete key if unable to Follow"));
+ break;
+
+ case kSavingTitleMode:
+ DrawString(PSTR("Saving GameÉ"));
+ break;
+
+ default:
+ DrawString(thisRoom->name);
+ break;
+ }
+ MoveTo(0, 9);
+ ForeColor(whiteColor);
+ switch (mode)
+ {
+ case kEscapedTitleMode:
+ DrawString(PSTR("Hit Delete key if unable to Follow"));
+ break;
+
+ case kSavingTitleMode:
+ DrawString(PSTR("Saving GameÉ"));
+ break;
+
+ default:
+ DrawString(thisRoom->name);
+ break;
+ }
+ ForeColor(blackColor);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(boardTSrcMap),
+ (BitMap *)*GetGWorldPixMap(boardSrcMap),
+ &boardTSrcRect, &boardTDestRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- RefreshNumGliders
+
+void RefreshNumGliders (void)
+{
+ RGBColor theRGBColor, wasColor;
+ Str255 nGlidersStr;
+ long displayMortals;
+
+ SetPort((GrafPtr)boardGSrcMap);
+
+ GetForeColor(&wasColor);
+ if (thisMac.isDepth == 4)
+ Index2Color(kGrayBackgroundColor4, &theRGBColor);
+ else
+ Index2Color(kGrayBackgroundColor, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ PaintRect(&boardGSrcRect);
+ RGBForeColor(&wasColor);
+
+ displayMortals = mortals;
+ if (displayMortals < 0)
+ displayMortals = 0;
+ NumToString(displayMortals, nGlidersStr);
+
+ MoveTo(1, 10);
+ ForeColor(blackColor);
+ DrawString(nGlidersStr);
+
+ MoveTo(0, 9);
+ ForeColor(whiteColor);
+ DrawString(nGlidersStr);
+
+ ForeColor(blackColor);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(boardGSrcMap),
+ (BitMap *)*GetGWorldPixMap(boardSrcMap),
+ &boardGSrcRect, &boardGDestRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- RefreshPoints
+
+void RefreshPoints (void)
+{
+ RGBColor theRGBColor, wasColor;
+ Str255 scoreStr;
+
+ SetPort((GrafPtr)boardPSrcMap);
+
+ GetForeColor(&wasColor);
+ if (thisMac.isDepth == 4)
+ Index2Color(kGrayBackgroundColor4, &theRGBColor);
+ else
+ Index2Color(kGrayBackgroundColor, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ PaintRect(&boardPSrcRect);
+ RGBForeColor(&wasColor);
+
+ NumToString(theScore, scoreStr);
+
+ MoveTo(1, 10);
+ ForeColor(blackColor);
+ DrawString(scoreStr);
+
+ MoveTo(0, 9);
+ ForeColor(whiteColor);
+ DrawString(scoreStr);
+
+ ForeColor(blackColor);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(boardPSrcMap),
+ (BitMap *)*GetGWorldPixMap(boardSrcMap),
+ &boardPSrcRect, &boardPDestRect, srcCopy, nil);
+
+ displayedScore = theScore;
+}
+
+//-------------------------------------------------------------- QuickGlidersRefresh
+
+void QuickGlidersRefresh (void)
+{
+ RGBColor theRGBColor, wasColor;
+ Str255 nGlidersStr;
+
+ SetPort((GrafPtr)boardGSrcMap);
+
+ GetForeColor(&wasColor);
+ if (thisMac.isDepth == 4)
+ Index2Color(kGrayBackgroundColor4, &theRGBColor);
+ else
+ Index2Color(kGrayBackgroundColor, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ PaintRect(&boardGSrcRect);
+ RGBForeColor(&wasColor);
+
+ NumToString((long)mortals, nGlidersStr);
+
+ MoveTo(1, 10);
+ ForeColor(blackColor);
+ DrawString(nGlidersStr);
+
+ MoveTo(0, 9);
+ ForeColor(whiteColor);
+ DrawString(nGlidersStr);
+
+ ForeColor(blackColor);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(boardGSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &boardGSrcRect, &boardGQDestRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- QuickScoreRefresh
+
+void QuickScoreRefresh (void)
+{
+ RGBColor theRGBColor, wasColor;
+ Str255 scoreStr;
+
+ SetPort((GrafPtr)boardPSrcMap);
+
+ GetForeColor(&wasColor);
+ if (thisMac.isDepth == 4)
+ Index2Color(kGrayBackgroundColor4, &theRGBColor);
+ else
+ Index2Color(kGrayBackgroundColor, &theRGBColor);
+ RGBForeColor(&theRGBColor);
+ PaintRect(&boardPSrcRect);
+ RGBForeColor(&wasColor);
+
+ NumToString(displayedScore, scoreStr);
+
+ MoveTo(1, 10);
+ ForeColor(blackColor);
+ DrawString(scoreStr);
+
+ MoveTo(0, 9);
+ ForeColor(whiteColor);
+ DrawString(scoreStr);
+
+ ForeColor(blackColor);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(boardPSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &boardPSrcRect, &boardPQDestRect, srcCopy, nil);
+}
+
+//-------------------------------------------------------------- QuickBatteryRefresh
+
+void QuickBatteryRefresh (Boolean flash)
+{
+ if ((batteryTotal > 0) && (!flash))
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(badgeSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &badgesBadgesRects[kBatteryBadge],
+ &badgesDestRects[kBatteryBadge],
+ srcCopy, nil);
+ }
+ else if ((batteryTotal < 0) && (!flash))
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(badgeSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &badgesBadgesRects[kHeliumBadge],
+ &badgesDestRects[kHeliumBadge],
+ srcCopy, nil);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(badgeSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &badgesBlankRects[kBatteryBadge],
+ &badgesDestRects[kBatteryBadge],
+ srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- QuickBandsRefresh
+
+void QuickBandsRefresh (Boolean flash)
+{
+ if ((bandsTotal > 0) && (!flash))
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(badgeSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &badgesBadgesRects[kBandsBadge],
+ &badgesDestRects[kBandsBadge],
+ srcCopy, nil);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(badgeSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &badgesBlankRects[kBandsBadge],
+ &badgesDestRects[kBandsBadge],
+ srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- QuickFoilRefresh
+
+void QuickFoilRefresh (Boolean flash)
+{
+ if ((foilTotal > 0) && (!flash))
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(badgeSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &badgesBadgesRects[kFoilBadge],
+ &badgesDestRects[kFoilBadge],
+ srcCopy, nil);
+ }
+ else
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(badgeSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &badgesBlankRects[kFoilBadge],
+ &badgesDestRects[kFoilBadge],
+ srcCopy, nil);
+ }
+}
+
+//-------------------------------------------------------------- AdjustScoreboardHeight
+
+void AdjustScoreboardHeight (void)
+{
+ short offset, newMode;
+
+ if (numNeighbors == 9)
+ newMode = kScoreboardHigh;
+ else
+ newMode = kScoreboardLow;
+
+ if (wasScoreboardMode != newMode)
+ {
+ switch (newMode)
+ {
+ case kScoreboardHigh: // 9 neighbors
+ offset = localRoomsDest[kCentralRoom].top;
+ offset = -offset;
+ justRoomsRect = workSrcRect;
+ break;
+
+ case kScoreboardLow: // 1 or 3 neighbors
+ offset = localRoomsDest[kCentralRoom].top;
+ justRoomsRect = workSrcRect;
+ justRoomsRect.top = localRoomsDest[kCentralRoom].top;
+ justRoomsRect.bottom = localRoomsDest[kCentralRoom].bottom;
+ break;
+ }
+
+ QOffsetRect(&boardDestRect, 0, offset);
+ QOffsetRect(&boardGQDestRect, 0, offset);
+ QOffsetRect(&boardPQDestRect, 0, offset);
+ QOffsetRect(&badgesDestRects[kBatteryBadge], 0, offset);
+ QOffsetRect(&badgesDestRects[kBandsBadge], 0, offset);
+ QOffsetRect(&badgesDestRects[kFoilBadge], 0, offset);
+ QOffsetRect(&badgesDestRects[kHeliumBadge], 0, offset);
+
+ wasScoreboardMode = newMode;
+ }
+}
+
+//-------------------------------------------------------------- BlackenScoreboard
+
+void BlackenScoreboard (void)
+{
+ UpdateMenuBarWindow();
+}
+
diff --git a/GpApp/Scoreboard.h b/GpApp/Scoreboard.h
new file mode 100644
index 0000000..23d19ab
--- /dev/null
+++ b/GpApp/Scoreboard.h
@@ -0,0 +1,15 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Scoreboard.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+extern GWorldPtr boardSrcMap;
+extern GWorldPtr badgeSrcMap;
+extern GWorldPtr boardTSrcMap;
+extern GWorldPtr boardGSrcMap;
+extern GWorldPtr boardPSrcMap;
diff --git a/Sources/Scrap.c b/GpApp/Scrap.c
old mode 100755
new mode 100644
similarity index 100%
rename from Sources/Scrap.c
rename to GpApp/Scrap.c
diff --git a/GpApp/SelectHouse.cpp b/GpApp/SelectHouse.cpp
new file mode 100644
index 0000000..c3e0a77
--- /dev/null
+++ b/GpApp/SelectHouse.cpp
@@ -0,0 +1,676 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// SelectHouse.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLAliases.h"
+#include "PLResources.h"
+#include "PLSound.h"
+#include "PLStringCompare.h"
+#include "DialogUtils.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "House.h"
+#include "RectUtils.h"
+
+
+#define kLoadHouseDialogID 1000
+#define kDispFiles 12
+#define kLoadTitlePictItem 3
+#define kLoadNameFirstItem 5
+#define kLoadNameLastItem 16
+#define kLoadIconFirstItem 17
+#define kLoadIconLastItem 28
+#define kScrollUpItem 29
+#define kScrollDownItem 30
+#define kLoadTitlePict1 1001
+#define kLoadTitlePict8 1002
+#define kDefaultHousePict1 1003
+#define kDefaultHousePict8 1004
+#define kGrayedOutUpArrow 1052
+#define kGrayedOutDownArrow 1053
+#define kMaxExtraHouses 8
+
+
+void UpdateLoadDialog (DialogPtr);
+void PageUpHouses (DialogPtr);
+void PageDownHouses (DialogPtr);
+Boolean LoadFilter (DialogPtr, EventRecord *, short *);
+void SortHouseList (void);
+void DoDirSearch (void);
+
+
+Rect loadHouseRects[12];
+FSSpecPtr theHousesSpecs;
+FSSpec extraHouseSpecs[kMaxExtraHouses];
+long lastWhenClick;
+Point lastWhereClick;
+short housesFound, thisHouseIndex, maxFiles, willMaxFiles;
+short housePage, demoHouseIndex, numExtraHouses;
+char fileFirstChar[12];
+
+extern UInt32 doubleTime;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- UpdateLoadWindow
+
+#ifndef COMPILEDEMO
+void UpdateLoadDialog (DialogPtr theDialog)
+{
+ Rect tempRect, dialogRect, dummyRect;
+ short houseStart, houseStop, i, wasResFile, isResFile, count;
+// char wasState;
+ WindowRef theWindow;
+// RgnHandle theRegion;
+
+ theWindow = GetDialogWindow(theDialog);
+ GetWindowBounds(theWindow, kWindowContentRgn, &dialogRect);
+ /*
+ wasState = HGetState((Handle)(((DialogPeek)theDialog)->window).port.visRgn);
+ HLock((Handle)(((DialogPeek)theDialog)->window).port.visRgn);
+ dialogRect = (**((((DialogPeek)theDialog)->window).port.visRgn)).rgnBBox;
+ HSetState((Handle)(((DialogPeek)theDialog)->window).port.visRgn, wasState);
+ */
+
+ DrawDialog(theDialog);
+ ColorFrameWHRect(8, 39, 413, 184, kRedOrangeColor8); // box around files
+
+ houseStart = housePage;
+ houseStop = housesFound;
+ if ((houseStop - houseStart) > kDispFiles)
+ houseStop = houseStart + kDispFiles;
+
+ wasResFile = CurResFile();
+ count = 0;
+
+ for (i = 0; i < 12; i++)
+ fileFirstChar[i] = 0x7F;
+
+ for (i = houseStart; i < houseStop; i++)
+ {
+ SpinCursor(1);
+
+ GetDialogItemRect(theDialog, kLoadIconFirstItem + i - housePage,
+ &tempRect);
+
+ if (SectRect(&dialogRect, &tempRect, &dummyRect))
+ {
+ isResFile = HOpenResFile(theHousesSpecs[i].vRefNum,
+ theHousesSpecs[i].parID, theHousesSpecs[i].name, fsRdPerm);
+ if (isResFile != -1)
+ {
+ if (Get1Resource('icl8', -16455) != nil)
+ {
+ LargeIconPlot(&tempRect, -16455);
+ }
+ else
+ LoadDialogPICT(theDialog, kLoadIconFirstItem + i - housePage,
+ kDefaultHousePict8);
+ CloseResFile(isResFile);
+ }
+ else
+ LoadDialogPICT(theDialog, kLoadIconFirstItem + i - housePage,
+ kDefaultHousePict8);
+ }
+
+ fileFirstChar[count] = theHousesSpecs[i].name[1];
+ if ((fileFirstChar[count] <= 0x7A) && (fileFirstChar[count] > 0x60))
+ fileFirstChar[count] -= 0x20;
+ count++;
+
+ DrawDialogUserText(theDialog, kLoadNameFirstItem + i - housePage,
+ theHousesSpecs[i].name, i == (thisHouseIndex + housePage));
+
+ }
+
+ InitCursor();
+ UseResFile(wasResFile);
+}
+#endif
+
+//-------------------------------------------------------------- PageUpHouses
+
+#ifndef COMPILEDEMO
+void PageUpHouses (DialogPtr theDial)
+{
+ Rect tempRect;
+
+ if (housePage < kDispFiles)
+ {
+ SysBeep(1);
+ return;
+ }
+
+ housePage -= kDispFiles;
+ thisHouseIndex = kDispFiles - 1;
+
+ ShowDialogItem(theDial, kScrollDownItem);
+ if (housePage < kDispFiles)
+ {
+ GetDialogItemRect(theDial, kScrollUpItem, &tempRect);
+ HideDialogItem(theDial, kScrollUpItem);
+ DrawCIcon(kGrayedOutUpArrow, tempRect.left, tempRect.top);
+ }
+
+ QSetRect(&tempRect, 8, 39, 421, 223);
+ EraseRect(&tempRect);
+ InvalWindowRect(GetDialogWindow(theDial), &tempRect);
+}
+#endif
+
+//-------------------------------------------------------------- PageDownHouses
+
+#ifndef COMPILEDEMO
+void PageDownHouses (DialogPtr theDial)
+{
+ Rect tempRect;
+
+ if (housePage >= (housesFound - kDispFiles))
+ {
+ SysBeep(1);
+ return;
+ }
+
+ housePage += kDispFiles;
+ thisHouseIndex = 0;
+
+ ShowDialogItem(theDial, kScrollUpItem);
+ if (housePage >= (housesFound - kDispFiles))
+ {
+ GetDialogItemRect(theDial, kScrollDownItem, &tempRect);
+ HideDialogItem(theDial, kScrollDownItem);
+ DrawCIcon(kGrayedOutDownArrow, tempRect.left, tempRect.top);
+ }
+
+ QSetRect(&tempRect, 8, 39, 421, 223);
+ EraseRect(&tempRect);
+ InvalWindowRect(GetDialogWindow(theDial), &tempRect);
+}
+#endif
+
+//-------------------------------------------------------------- LoadFilter
+#ifndef COMPILEDEMO
+
+Boolean LoadFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ short screenCount, i, wasIndex;
+ char theChar;
+
+ switch (event->what)
+ {
+ case keyDown:
+ theChar = (event->message) & charCodeMask;
+ switch (theChar)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ case kPageUpKeyASCII:
+ *item = kScrollUpItem;
+ return (true);
+ break;
+
+ case kPageDownKeyASCII:
+ *item = kScrollDownItem;
+ return (true);
+ break;
+
+ case kUpArrowKeyASCII:
+ InvalWindowRect(GetDialogWindow(dial), &loadHouseRects[thisHouseIndex]);
+ thisHouseIndex -= 4;
+ if (thisHouseIndex < 0)
+ {
+ screenCount = housesFound - housePage;
+ if (screenCount > kDispFiles)
+ screenCount = kDispFiles;
+
+ thisHouseIndex += 4;
+ thisHouseIndex = (((screenCount - 1) / 4) * 4) +
+ (thisHouseIndex % 4);
+ if (thisHouseIndex >= screenCount)
+ thisHouseIndex -= 4;
+ }
+ InvalWindowRect(GetDialogWindow(dial), &loadHouseRects[thisHouseIndex]);
+ return(true);
+ break;
+
+ case kDownArrowKeyASCII:
+ InvalWindowRect(GetDialogWindow(dial), &loadHouseRects[thisHouseIndex]);
+ thisHouseIndex += 4;
+ screenCount = housesFound - housePage;
+ if (screenCount > kDispFiles)
+ screenCount = kDispFiles;
+ if (thisHouseIndex >= screenCount)
+ thisHouseIndex %= 4;
+ InvalWindowRect(GetDialogWindow(dial), &loadHouseRects[thisHouseIndex]);
+ return(true);
+ break;
+
+ case kLeftArrowKeyASCII:
+ InvalWindowRect(GetDialogWindow(dial), &loadHouseRects[thisHouseIndex]);
+ thisHouseIndex--;
+ if (thisHouseIndex < 0)
+ {
+ screenCount = housesFound - housePage;
+ if (screenCount > kDispFiles)
+ screenCount = kDispFiles;
+ thisHouseIndex = screenCount - 1;
+ }
+ InvalWindowRect(GetDialogWindow(dial), &loadHouseRects[thisHouseIndex]);
+ return(true);
+ break;
+
+ case kTabKeyASCII:
+ case kRightArrowKeyASCII:
+ InvalWindowRect(GetDialogWindow(dial), &loadHouseRects[thisHouseIndex]);
+ thisHouseIndex++;
+ screenCount = housesFound - housePage;
+ if (screenCount > kDispFiles)
+ screenCount = kDispFiles;
+ if (thisHouseIndex >= screenCount)
+ thisHouseIndex = 0;
+ InvalWindowRect(GetDialogWindow(dial), &loadHouseRects[thisHouseIndex]);
+ return(true);
+ break;
+
+ default:
+ if (((theChar > 0x40) && (theChar <= 0x5A)) ||
+ ((theChar > 0x60) && (theChar <= 0x7A)))
+ {
+ if ((theChar > 0x60) && (theChar <= 0x7A))
+ theChar -= 0x20;
+ wasIndex = thisHouseIndex;
+ thisHouseIndex = -1;
+ i = 0;
+ do
+ {
+ if ((fileFirstChar[i] >= theChar) && (fileFirstChar[i] != 0x7F))
+ thisHouseIndex = i;
+ i++;
+ }
+ while ((thisHouseIndex == -1) && (i < 12));
+ if (thisHouseIndex == -1)
+ {
+ screenCount = housesFound - housePage;
+ if (screenCount > kDispFiles)
+ screenCount = kDispFiles;
+ thisHouseIndex = screenCount - 1;
+ }
+ if (wasIndex != thisHouseIndex)
+ {
+ InvalWindowRect(GetDialogWindow(dial), &loadHouseRects[wasIndex]);
+ InvalWindowRect(GetDialogWindow(dial), &loadHouseRects[thisHouseIndex]);
+ }
+ return(true);
+ }
+ else
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ lastWhenClick = event->when - lastWhenClick;
+ SubPt(event->where, &lastWhereClick);
+ return(false);
+ break;
+
+ case mouseUp:
+ lastWhenClick = event->when;
+ lastWhereClick = event->where;
+ return(false);
+ break;
+
+ case updateEvt:
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateLoadDialog(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+#endif
+
+//-------------------------------------------------------------- DoLoadHouse
+
+#ifndef COMPILEDEMO
+void DoLoadHouse (void)
+{
+ Rect tempRect;
+ DialogPtr theDial;
+ short i, item, wasIndex, screenCount;
+ Boolean leaving, whoCares;
+ ModalFilterUPP loadFilterUPP;
+
+ loadFilterUPP = NewModalFilterUPP(LoadFilter);
+
+ BringUpDialog(&theDial, kLoadHouseDialogID);
+ if (housesFound <= kDispFiles)
+ {
+ GetDialogItemRect(theDial, kScrollUpItem, &tempRect);
+ HideDialogItem(theDial, kScrollUpItem);
+ DrawCIcon(kGrayedOutUpArrow, tempRect.left, tempRect.top);
+
+ GetDialogItemRect(theDial, kScrollDownItem, &tempRect);
+ HideDialogItem(theDial, kScrollDownItem);
+ DrawCIcon(kGrayedOutDownArrow, tempRect.left, tempRect.top);
+ }
+ else
+ {
+ if (thisHouseIndex < kDispFiles)
+ {
+ GetDialogItemRect(theDial, kScrollUpItem, &tempRect);
+ HideDialogItem(theDial, kScrollUpItem);
+ DrawCIcon(kGrayedOutUpArrow, tempRect.left, tempRect.top);
+ }
+ else if (thisHouseIndex > (housesFound - kDispFiles))
+ {
+ GetDialogItemRect(theDial, kScrollDownItem, &tempRect);
+ HideDialogItem(theDial, kScrollDownItem);
+ DrawCIcon(kGrayedOutDownArrow, tempRect.left, tempRect.top);
+ }
+ }
+ wasIndex = thisHouseIndex;
+ housePage = (thisHouseIndex / kDispFiles) * kDispFiles;
+ thisHouseIndex -= housePage;
+
+ for (i = 0; i < 12; i++)
+ {
+ GetDialogItemRect(theDial, kLoadNameFirstItem + i,
+ &loadHouseRects[i]);
+ GetDialogItemRect(theDial, kLoadIconFirstItem + i,
+ &tempRect);
+ loadHouseRects[i].top = tempRect.top;
+ loadHouseRects[i].bottom++;
+ }
+
+ leaving = false;
+
+ while (!leaving)
+ {
+ ModalDialog(loadFilterUPP, &item);
+
+ if (item == kOkayButton)
+ {
+ thisHouseIndex += housePage;
+ if (thisHouseIndex != wasIndex)
+ {
+ whoCares = CloseHouse();
+ PasStringCopy(theHousesSpecs[thisHouseIndex].name,
+ thisHouseName);
+ if (OpenHouse())
+ whoCares = ReadHouse();
+ }
+ leaving = true;
+ }
+ else if (item == kCancelButton)
+ {
+ thisHouseIndex = wasIndex;
+ leaving = true;
+ }
+ else if ((item >= kLoadNameFirstItem) &&
+ (item <= kLoadNameLastItem))
+ {
+ screenCount = housesFound - housePage;
+ if (screenCount > kDispFiles)
+ screenCount = kDispFiles;
+ if ((item - kLoadNameFirstItem != thisHouseIndex) &&
+ (item - kLoadNameFirstItem < screenCount))
+ {
+ InvalWindowRect(GetDialogWindow(theDial), &loadHouseRects[thisHouseIndex]);
+ thisHouseIndex = item - kLoadNameFirstItem;
+ InvalWindowRect(GetDialogWindow(theDial), &loadHouseRects[thisHouseIndex]);
+ }
+
+ if (lastWhereClick.h < 0)
+ lastWhereClick.h = -lastWhereClick.h;
+ if (lastWhereClick.v < 0)
+ lastWhereClick.v = -lastWhereClick.v;
+ if ((lastWhenClick < doubleTime) && (lastWhereClick.h < 5) &&
+ (lastWhereClick.v < 5))
+ {
+ thisHouseIndex += housePage;
+ if (thisHouseIndex != wasIndex)
+ {
+ MyDisableControl(theDial, kOkayButton);
+ MyDisableControl(theDial, kCancelButton);
+ whoCares = CloseHouse();
+ PasStringCopy(theHousesSpecs[thisHouseIndex].name,
+ thisHouseName);
+ if (OpenHouse())
+ whoCares = ReadHouse();
+ }
+ leaving = true;
+ }
+ }
+ else if ((item >= kLoadIconFirstItem) &&
+ (item <= kLoadIconLastItem))
+ {
+ screenCount = housesFound - housePage;
+ if (screenCount > kDispFiles)
+ screenCount = kDispFiles;
+ if ((item - kLoadIconFirstItem != thisHouseIndex) &&
+ (item - kLoadIconFirstItem < screenCount))
+ {
+ InvalWindowRect(GetDialogWindow(theDial), &loadHouseRects[thisHouseIndex]);
+ thisHouseIndex = item - kLoadIconFirstItem;
+ InvalWindowRect(GetDialogWindow(theDial), &loadHouseRects[thisHouseIndex]);
+ }
+
+ if (lastWhereClick.h < 0)
+ lastWhereClick.h = -lastWhereClick.h;
+ if (lastWhereClick.v < 0)
+ lastWhereClick.v = -lastWhereClick.v;
+ if ((lastWhenClick < doubleTime) && (lastWhereClick.h < 5) &&
+ (lastWhereClick.v < 5))
+ {
+ thisHouseIndex += housePage;
+ if (thisHouseIndex != wasIndex)
+ {
+ MyDisableControl(theDial, kOkayButton);
+ MyDisableControl(theDial, kCancelButton);
+ whoCares = CloseHouse();
+ PasStringCopy(theHousesSpecs[thisHouseIndex].name,
+ thisHouseName);
+ if (OpenHouse())
+ whoCares = ReadHouse();
+ }
+ leaving = true;
+ }
+ }
+ else if (item == kScrollUpItem)
+ {
+ PageUpHouses(theDial);
+ }
+ else if (item == kScrollDownItem)
+ {
+ PageDownHouses(theDial);
+ }
+ }
+
+ DisposeDialog(theDial);
+ DisposeModalFilterUPP(loadFilterUPP);
+}
+#endif
+
+//-------------------------------------------------------------- SortHouseList
+
+void SortHouseList (void)
+{
+ FSSpec tempSpec;
+ short i, h, whosFirst;
+
+ i = 0; // remove exact duplicate houses
+ while (i < housesFound)
+ {
+ h = i + 1;
+ while (h < housesFound)
+ {
+ if ((EqualString(theHousesSpecs[i].name, theHousesSpecs[h].name, true, true)) &&
+ (theHousesSpecs[i].vRefNum == theHousesSpecs[i].vRefNum) &&
+ (theHousesSpecs[i].parID == theHousesSpecs[i].parID))
+ {
+ theHousesSpecs[h] = theHousesSpecs[housesFound - 1];
+ housesFound--;
+ }
+ h++;
+ }
+ i++;
+ }
+
+ for (i = 0; i < housesFound - 1; i++)
+ {
+ for (h = 0; h < (housesFound - i - 1); h++)
+ {
+ whosFirst = WhichStringFirst(theHousesSpecs[h].name,
+ theHousesSpecs[h + 1].name);
+ if (whosFirst == 1)
+ {
+ tempSpec = theHousesSpecs[h + 1];
+ theHousesSpecs[h + 1] = theHousesSpecs[h];
+ theHousesSpecs[h] = tempSpec;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- DoDirSearch
+
+void DoDirSearch (void)
+{
+ #define kMaxDirectories 32
+ CInfoPBRec theBlock;
+ Str255 nameString;
+ long theDirs[kMaxDirectories];
+ OSErr theErr, notherErr;
+ short count, i, currentDir, numDirs;
+
+ for (i = 0; i < kMaxDirectories; i++)
+ theDirs[i] = 0L;
+ currentDir = 0;
+ theDirs[currentDir] = thisMac.dirID;
+ numDirs = 1;
+
+ theBlock.hFileInfo.ioCompletion = nil;
+ theBlock.hFileInfo.ioVRefNum = thisMac.vRefNum;
+ theBlock.hFileInfo.ioNamePtr = nameString;
+
+ while ((currentDir < numDirs) && (currentDir < kMaxDirectories))
+ {
+ count = 1;
+ theErr = noErr;
+
+ while (theErr == noErr)
+ {
+ SpinCursor(1);
+ theBlock.hFileInfo.ioFDirIndex = count;
+ theBlock.hFileInfo.ioDirID = theDirs[currentDir];
+ theErr = PBGetCatInfo(&theBlock, false);
+
+ if (theErr == noErr)
+ {
+ if ((theBlock.hFileInfo.ioFlAttrib & 0x10) == 0x00)
+ {
+ if ((theBlock.hFileInfo.ioFlFndrInfo.fdType == 'gliH') &&
+ (theBlock.hFileInfo.ioFlFndrInfo.fdCreator == 'ozm5') &&
+ (housesFound < maxFiles))
+ {
+ notherErr = FSMakeFSSpec(thisMac.vRefNum,
+ theBlock.hFileInfo.ioFlParID, nameString,
+ &theHousesSpecs[housesFound]);
+ if (notherErr == noErr)
+ housesFound++;
+ }
+ }
+ else if ((theBlock.hFileInfo.ioFlAttrib & 0x10) == 0x10)
+ {
+ if (numDirs < kMaxDirectories)
+ {
+ theDirs[numDirs] = theBlock.hFileInfo.ioDirID;
+ numDirs++;
+ }
+ }
+ count++;
+ }
+ }
+ currentDir++;
+ }
+
+ if (housesFound < 1)
+ {
+ thisHouseIndex = -1;
+ YellowAlert(kYellowNoHouses, 0);
+ }
+ else
+ {
+ SortHouseList();
+ thisHouseIndex = 0;
+ for (i = 0; i < housesFound; i++)
+ {
+ if (EqualString(theHousesSpecs[i].name, thisHouseName, false, true))
+ {
+ thisHouseIndex = i;
+ break;
+ }
+ }
+ PasStringCopy(theHousesSpecs[thisHouseIndex].name, thisHouseName);
+
+ demoHouseIndex = -1;
+ for (i = 0; i < housesFound; i++)
+ {
+ if (EqualString(theHousesSpecs[i].name, PSTR("Demo House"), false, true))
+ {
+ demoHouseIndex = i;
+ break;
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- BuildHouseList
+
+void BuildHouseList (void)
+{
+ short i;
+
+ if (thisMac.hasSystem7)
+ {
+ housesFound = 0; // zero the number of houses found
+ for (i = 0; i < numExtraHouses; i++) // 1st, insert extra houses into list
+ {
+ theHousesSpecs[housesFound] = extraHouseSpecs[i];
+ housesFound++;
+ }
+ DoDirSearch(); // now, search folders for the rest
+ }
+}
+
+//-------------------------------------------------------------- AddExtraHouse
+
+void AddExtraHouse (FSSpec *newHouse)
+{
+ if (numExtraHouses >= kMaxExtraHouses)
+ return;
+
+ extraHouseSpecs[numExtraHouses] = *newHouse;
+ numExtraHouses++;
+}
+
diff --git a/GpApp/Settings.cpp b/GpApp/Settings.cpp
new file mode 100644
index 0000000..3738e84
--- /dev/null
+++ b/GpApp/Settings.cpp
@@ -0,0 +1,1482 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Settings.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLSound.h"
+#include "PLTextUtils.h"
+#include "DialogUtils.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "House.h"
+
+
+#define kMainPrefsDialID 1012
+#define kDisplayPrefsDialID 1017
+#define kSoundPrefsDialID 1018
+#define kControlPrefsDialID 1023
+#define kBrainsPrefsDialID 1024
+#define kDisplayButton 3
+#define kSoundButton 4
+#define kControlsButton 5
+#define kBrainsButton 6
+#define kDisplay1Item 3
+#define kDisplay3Item 4
+#define kDisplay9Item 5
+#define kDoColorFadeItem 9
+#define kCurrentDepth 10
+#define k256Depth 11
+#define k16Depth 12
+#define kDispDefault 15
+#define kUseQDItem 16
+#define kUseScreen2Item 17
+#define kSofterItem 4
+#define kLouderItem 5
+#define kVolNumberItem 7
+#define kIdleMusicItem 8
+#define kPlayMusicItem 9
+#define kSoundDefault 13
+#define kRightControl 5
+#define kLeftControl 6
+#define kBattControl 7
+#define kBandControl 8
+#define kControlDefaults 13
+#define kESCPausesRadio 14
+#define kTABPausesRadio 15
+#define kMaxFilesItem 5
+#define kQuickTransitCheck 7
+#define kDoZoomsCheck 8
+#define kBrainsDefault 9
+#define kDoDemoCheck 10
+#define kDoBackgroundCheck 11
+#define kDoErrorCheck 12
+#define kDoPrettyMapCheck 13
+#define kDoBitchDlgsCheck 14
+
+
+void SetBrainsToDefaults (DialogPtr);
+void UpdateSettingsBrains (DialogPtr);
+Boolean BrainsFilter (DialogPtr, EventRecord *, short *);
+void DoBrainsPrefs (void);
+void SetControlsToDefaults (DialogPtr);
+void UpdateControlKeyName (DialogPtr);
+void UpdateSettingsControl (DialogPtr);
+Boolean ControlFilter (DialogPtr, EventRecord *, short *);
+void DoControlPrefs (void);
+void SoundDefaults (DialogPtr);
+void UpdateSettingsSound (DialogPtr);
+void HandleSoundMusicChange (short, Boolean);
+Boolean SoundFilter (DialogPtr, EventRecord *, short *);
+void DoSoundPrefs (void);
+void DisplayDefaults (void);
+void FrameDisplayIcon (DialogPtr);
+void DisplayUpdate (DialogPtr);
+Boolean DisplayFilter (DialogPtr, EventRecord *, short *);
+void DoDisplayPrefs (void);
+void SetAllDefaults (void);
+void FlashSettingsButton (short);
+void UpdateSettingsMain (DialogPtr);
+Boolean PrefsFilter (DialogPtr, EventRecord *, short *);
+void BitchAboutChanges (void);
+
+
+Rect prefButton[4], controlRects[4];
+Str15 leftName, rightName, batteryName, bandName;
+Str15 tempLeftStr, tempRightStr, tempBattStr, tempBandStr;
+long tempLeftMap, tempRightMap, tempBattMap, tempBandMap;
+short whichCtrl, wasDepthPref;
+Boolean wasFade, wasIdle, wasPlay, wasTransit, wasZooms, wasBackground;
+Boolean wasEscPauseKey, wasDemos, wasScreen2, nextRestartChange, wasErrorCheck;
+Boolean wasPrettyMap, wasBitchDialogs;
+
+extern short numNeighbors, isDepthPref, maxFiles, willMaxFiles;
+extern Boolean isDoColorFade, isPlayMusicIdle, isUseSecondScreen;
+extern Boolean isHouseChecks, doBitchDialogs;
+extern Boolean isEscPauseKey, failedMusic, isSoundOn, doBackground;
+extern Boolean isMusicOn, quickerTransitions, doAutoDemo;
+extern Boolean changeLockStateOfHouse, saveHouseLocked, doPrettyMap;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- SetBrainsToDefaults
+
+void SetBrainsToDefaults (DialogPtr theDialog)
+{
+ SetDialogNumToStr(theDialog, kMaxFilesItem, 24L);
+#ifdef powerc
+ wasTransit = false;
+#else
+ wasTransit = true;
+#endif
+ wasZooms = true;
+ wasDemos = true;
+ wasBackground = false;
+ wasErrorCheck = true;
+ wasPrettyMap = true;
+ wasBitchDialogs = true;
+ SetDialogItemValue(theDialog, kQuickTransitCheck, (short)wasTransit);
+ SetDialogItemValue(theDialog, kDoZoomsCheck, (short)wasZooms);
+ SetDialogItemValue(theDialog, kDoDemoCheck, (short)wasDemos);
+ SetDialogItemValue(theDialog, kDoBackgroundCheck, (short)wasBackground);
+ SetDialogItemValue(theDialog, kDoErrorCheck, (short)wasErrorCheck);
+ SetDialogItemValue(theDialog, kDoPrettyMapCheck, (short)wasPrettyMap);
+ SetDialogItemValue(theDialog, kDoBitchDlgsCheck, (short)wasBitchDialogs);
+}
+
+//-------------------------------------------------------------- UpdateSettingsBrains
+
+void UpdateSettingsBrains (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+
+ SetDialogNumToStr(theDialog, kMaxFilesItem, (long)willMaxFiles);
+ SelectDialogItemText(theDialog, kMaxFilesItem, 0, 1024);
+
+ FrameDialogItemC(theDialog, 3, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- BrainsFilter
+
+Boolean BrainsFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ case kCapAKeyASCII:
+ case kAKeyASCII:
+ *item = kDoDemoCheck;
+ return(true);
+ break;
+
+ case kCapBKeyASCII:
+ case kBKeyASCII:
+ *item = kDoBackgroundCheck;
+ return(true);
+ break;
+
+ case kCapDKeyASCII:
+ case kDKeyASCII:
+ *item = kBrainsDefault;
+ FlashDialogButton(dial, kBrainsDefault);
+ return(true);
+ break;
+
+ case kCapEKeyASCII:
+ case kEKeyASCII:
+ *item = kDoErrorCheck;
+ return(true);
+ break;
+
+ case kCapQKeyASCII:
+ case kQKeyASCII:
+ *item = kQuickTransitCheck;
+ return(true);
+ break;
+
+ case kCapZKeyASCII:
+ case kZKeyASCII:
+ *item = kDoZoomsCheck;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateSettingsBrains(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoBrainsPrefs
+
+void DoBrainsPrefs (void)
+{
+ DialogPtr prefDlg;
+ long tempLong;
+ short itemHit, wasMaxFiles;
+ Boolean leaving;
+ ModalFilterUPP brainsFilterUPP;
+
+ brainsFilterUPP = NewModalFilterUPP(BrainsFilter);
+
+ BringUpDialog(&prefDlg, kBrainsPrefsDialID);
+ leaving = false;
+ wasMaxFiles = willMaxFiles;
+
+ wasTransit = quickerTransitions;
+ wasZooms = doZooms;
+ wasDemos = doAutoDemo;
+ wasBackground = doBackground;
+ wasErrorCheck = isHouseChecks;
+ wasPrettyMap = doPrettyMap;
+ wasBitchDialogs = doBitchDialogs;
+
+ SetDialogItemValue(prefDlg, kQuickTransitCheck, (short)wasTransit);
+ SetDialogItemValue(prefDlg, kDoZoomsCheck, (short)wasZooms);
+ SetDialogItemValue(prefDlg, kDoDemoCheck, (short)wasDemos);
+ SetDialogItemValue(prefDlg, kDoBackgroundCheck, (short)wasBackground);
+ SetDialogItemValue(prefDlg, kDoErrorCheck, (short)wasErrorCheck);
+ SetDialogItemValue(prefDlg, kDoPrettyMapCheck, (short)wasPrettyMap);
+ SetDialogItemValue(prefDlg, kDoBitchDlgsCheck, (short)wasBitchDialogs);
+
+ while (!leaving)
+ {
+ ModalDialog(brainsFilterUPP, &itemHit);
+ switch (itemHit)
+ {
+ case kOkayButton:
+ GetDialogNumFromStr(prefDlg, kMaxFilesItem, &tempLong);
+ if (tempLong > 500)
+ tempLong = 500;
+ else if (tempLong < 12)
+ tempLong = 12;
+ willMaxFiles = static_cast(tempLong);
+ if (willMaxFiles != wasMaxFiles)
+ nextRestartChange = true;
+ quickerTransitions = wasTransit;
+ doZooms = wasZooms;
+ doAutoDemo = wasDemos;
+ doBackground = wasBackground;
+ isHouseChecks = wasErrorCheck;
+ doPrettyMap = wasPrettyMap;
+ doBitchDialogs = wasBitchDialogs;
+ leaving = true;
+ break;
+
+ case kCancelButton:
+ willMaxFiles = wasMaxFiles;
+ leaving = true;
+ break;
+
+ case kQuickTransitCheck:
+ wasTransit = !wasTransit;
+ SetDialogItemValue(prefDlg, kQuickTransitCheck, (short)wasTransit);
+ break;
+
+ case kDoZoomsCheck:
+ wasZooms = !wasZooms;
+ SetDialogItemValue(prefDlg, kDoZoomsCheck, (short)wasZooms);
+ break;
+
+ case kDoDemoCheck:
+ wasDemos = !wasDemos;
+ SetDialogItemValue(prefDlg, kDoDemoCheck, (short)wasDemos);
+ break;
+
+ case kDoBackgroundCheck:
+ wasBackground = !wasBackground;
+ SetDialogItemValue(prefDlg, kDoBackgroundCheck, (short)wasBackground);
+ break;
+
+ case kBrainsDefault:
+ SetBrainsToDefaults(prefDlg);
+ break;
+
+ case kDoErrorCheck:
+ wasErrorCheck = !wasErrorCheck;
+ SetDialogItemValue(prefDlg, kDoErrorCheck, (short)wasErrorCheck);
+ break;
+
+ case kDoPrettyMapCheck:
+ wasPrettyMap = !wasPrettyMap;
+ SetDialogItemValue(prefDlg, kDoPrettyMapCheck, (short)wasPrettyMap);
+ break;
+
+ case kDoBitchDlgsCheck:
+ wasBitchDialogs = !wasBitchDialogs;
+ SetDialogItemValue(prefDlg, kDoBitchDlgsCheck, (short)wasBitchDialogs);
+ break;
+ }
+ }
+
+ DisposeDialog(prefDlg);
+ DisposeModalFilterUPP(brainsFilterUPP);
+}
+
+//-------------------------------------------------------------- SetControlsToDefaults
+
+void SetControlsToDefaults (DialogPtr theDialog)
+{
+ PasStringCopy(PSTR("lf arrow"), tempLeftStr);
+ PasStringCopy(PSTR("rt arrow"), tempRightStr);
+ PasStringCopy(PSTR("dn arrow"), tempBattStr);
+ PasStringCopy(PSTR("up arrow"), tempBandStr);
+ tempLeftMap = kLeftArrowKeyMap;
+ tempRightMap = kRightArrowKeyMap;
+ tempBattMap = kDownArrowKeyMap;
+ tempBandMap = kUpArrowKeyMap;
+ wasEscPauseKey = false;
+ SelectFromRadioGroup(theDialog, kTABPausesRadio,
+ kESCPausesRadio, kTABPausesRadio);
+}
+
+//-------------------------------------------------------------- UpdateControlKeyName
+
+void UpdateControlKeyName (DialogPtr theDialog)
+{
+ DrawDialogUserText(theDialog, kRightControl + 4, tempRightStr, whichCtrl == 0);
+ DrawDialogUserText(theDialog, kLeftControl + 4, tempLeftStr, whichCtrl == 1);
+ DrawDialogUserText(theDialog, kBattControl + 4, tempBattStr, whichCtrl == 2);
+ DrawDialogUserText(theDialog, kBandControl + 4, tempBandStr, whichCtrl == 3);
+}
+
+//-------------------------------------------------------------- UpdateSettingsControl
+
+void UpdateSettingsControl (DialogPtr theDialog)
+{
+ short i;
+
+ DrawDialog(theDialog);
+
+ PenSize(2, 2);
+ ForeColor(whiteColor);
+ for (i = 0; i < 4; i++)
+ FrameRect(&controlRects[i]);
+ ForeColor(redColor);
+ FrameRect(&controlRects[whichCtrl]);
+ ForeColor(blackColor);
+ PenNormal();
+ UpdateControlKeyName(theDialog);
+ FrameDialogItemC(theDialog, 3, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- ControlFilter
+
+Boolean ControlFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ long wasKeyMap;
+
+ switch (event->what)
+ {
+ case keyDown:
+ switch (whichCtrl)
+ {
+ case 0:
+ wasKeyMap = (long)GetKeyMapFromMessage(event->message);
+ if ((wasKeyMap == tempLeftMap) || (wasKeyMap == tempBattMap) ||
+ (wasKeyMap == tempBandMap) || (wasKeyMap == kTabKeyMap) ||
+ (wasKeyMap == kEscKeyMap) || (wasKeyMap == kDeleteKeyMap))
+ {
+ if (wasKeyMap == kEscKeyMap)
+ {
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ }
+ else
+ SysBeep(1);
+ }
+ else
+ {
+ GetKeyName(event->message, tempRightStr);
+ tempRightMap = wasKeyMap;
+ }
+ break;
+
+ case 1:
+ wasKeyMap = (long)GetKeyMapFromMessage(event->message);
+ if ((wasKeyMap == tempRightMap) || (wasKeyMap == tempBattMap) ||
+ (wasKeyMap == tempBandMap) || (wasKeyMap == kTabKeyMap) ||
+ (wasKeyMap == kEscKeyMap) || (wasKeyMap == kDeleteKeyMap))
+ {
+ if (wasKeyMap == kEscKeyMap)
+ {
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ }
+ else
+ SysBeep(1);
+ }
+ else
+ {
+ GetKeyName(event->message, tempLeftStr);
+ tempLeftMap = wasKeyMap;
+ }
+ break;
+
+ case 2:
+ wasKeyMap = (long)GetKeyMapFromMessage(event->message);
+ if ((wasKeyMap == tempRightMap) || (wasKeyMap == tempLeftMap) ||
+ (wasKeyMap == tempBandMap) || (wasKeyMap == kTabKeyMap) ||
+ (wasKeyMap == kEscKeyMap) || (wasKeyMap == kDeleteKeyMap))
+ {
+ if (wasKeyMap == kEscKeyMap)
+ {
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ }
+ else
+ SysBeep(1);
+ }
+ else
+ {
+ GetKeyName(event->message, tempBattStr);
+ tempBattMap = wasKeyMap;
+ }
+ break;
+
+ case 3:
+ wasKeyMap = (long)GetKeyMapFromMessage(event->message);
+ if ((wasKeyMap == tempRightMap) || (wasKeyMap == tempLeftMap) ||
+ (wasKeyMap == tempBattMap) || (wasKeyMap == kTabKeyMap) ||
+ (wasKeyMap == kEscKeyMap) || (wasKeyMap == kDeleteKeyMap))
+ {
+ if (wasKeyMap == kEscKeyMap)
+ {
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ }
+ else
+ SysBeep(1);
+ }
+ else
+ {
+ GetKeyName(event->message, tempBandStr);
+ tempBandMap = wasKeyMap;
+ }
+ break;
+ }
+ UpdateControlKeyName(dial);
+ return(false);
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateSettingsControl(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoControlPrefs
+
+void DoControlPrefs (void)
+{
+ DialogPtr prefDlg;
+ short i, itemHit;
+ Boolean leaving;
+ ModalFilterUPP controlFilterUPP;
+
+ controlFilterUPP = NewModalFilterUPP(ControlFilter);
+
+// CenterDialog(kControlPrefsDialID);
+ prefDlg = GetNewDialog(kControlPrefsDialID, nil, kPutInFront);
+ if (prefDlg == nil)
+ RedAlert(kErrDialogDidntLoad);
+ SetPort((GrafPtr)prefDlg);
+ for (i = 0; i < 4; i++)
+ {
+ GetDialogItemRect(prefDlg, i + kRightControl, &controlRects[i]);
+ InsetRect(&controlRects[i], -3, -3);
+ }
+ whichCtrl = 1;
+
+ PasStringCopy(leftName, tempLeftStr);
+ PasStringCopy(rightName, tempRightStr);
+ PasStringCopy(batteryName, tempBattStr);
+ PasStringCopy(bandName, tempBandStr);
+ tempLeftMap = theGlider.leftKey;
+ tempRightMap = theGlider.rightKey;
+ tempBattMap = theGlider.battKey;
+ tempBandMap = theGlider.bandKey;
+ wasEscPauseKey = isEscPauseKey;
+
+ leaving = false;
+
+ ShowWindow(GetDialogWindow(prefDlg));
+ if (isEscPauseKey)
+ SelectFromRadioGroup(prefDlg, kESCPausesRadio,
+ kESCPausesRadio, kTABPausesRadio);
+ else
+ SelectFromRadioGroup(prefDlg, kTABPausesRadio,
+ kESCPausesRadio, kTABPausesRadio);
+
+ while (!leaving)
+ {
+ ModalDialog(controlFilterUPP, &itemHit);
+ switch (itemHit)
+ {
+ case kOkayButton:
+ PasStringCopy(tempLeftStr, leftName);
+ PasStringCopy(tempRightStr, rightName);
+ PasStringCopy(tempBattStr, batteryName);
+ PasStringCopy(tempBandStr, bandName);
+ theGlider.leftKey = tempLeftMap;
+ theGlider.rightKey = tempRightMap;
+ theGlider.battKey = tempBattMap;
+ theGlider.bandKey = tempBandMap;
+ isEscPauseKey = wasEscPauseKey;
+ leaving = true;
+ break;
+
+ case kCancelButton:
+ leaving = true;
+ break;
+
+ case kRightControl:
+ case kLeftControl:
+ case kBattControl:
+ case kBandControl:
+ PenSize(2, 2);
+ ForeColor(whiteColor);
+ FrameRect(&controlRects[whichCtrl]);
+ whichCtrl = itemHit - kRightControl;
+ ForeColor(redColor);
+ FrameRect(&controlRects[whichCtrl]);
+ ForeColor(blackColor);
+ PenNormal();
+ UpdateControlKeyName(prefDlg);
+ break;
+
+ case kESCPausesRadio:
+ case kTABPausesRadio:
+ SelectFromRadioGroup(prefDlg, itemHit, kESCPausesRadio, kTABPausesRadio);
+ wasEscPauseKey = !wasEscPauseKey;
+ break;
+
+ case kControlDefaults:
+ SetControlsToDefaults(prefDlg);
+ UpdateControlKeyName(prefDlg);
+ break;
+ }
+ }
+
+ DisposeDialog(prefDlg);
+ DisposeModalFilterUPP(controlFilterUPP);
+}
+
+//-------------------------------------------------------------- SoundDefaults
+
+void SoundDefaults (DialogPtr theDialog)
+{
+ wasIdle = true;
+ wasPlay = true;
+ SetDialogItemValue(theDialog, kIdleMusicItem, (short)wasIdle);
+ SetDialogItemValue(theDialog, kPlayMusicItem, (short)wasPlay);
+ UnivSetSoundVolume(3, thisMac.hasSM3);
+ SetDialogNumToStr(theDialog, kVolNumberItem, 3L);
+ HandleSoundMusicChange(3, true);
+}
+
+//-------------------------------------------------------------- UpdateSettingsSound
+
+void UpdateSettingsSound (DialogPtr theDialog)
+{
+ short howLoudNow;
+
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+
+ UnivGetSoundVolume(&howLoudNow, thisMac.hasSM3);
+
+ if (howLoudNow >= 7)
+ SetDialogNumToStr(theDialog, kVolNumberItem, 11L);
+ else
+ SetDialogNumToStr(theDialog, kVolNumberItem, (long)howLoudNow);
+
+ FrameDialogItemC(theDialog, 11, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- HandleSoundMusicChange
+
+void HandleSoundMusicChange (short newVolume, Boolean sayIt)
+{
+ OSErr theErr;
+
+ isSoundOn = (newVolume != 0);
+
+ if (wasIdle)
+ {
+ if (newVolume == 0)
+ StopTheMusic();
+ else
+ {
+ if (!isMusicOn)
+ {
+ theErr = StartMusic();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowNoMusic, theErr);
+ failedMusic = true;
+ }
+ }
+ }
+ }
+
+ if ((newVolume != 0) && (sayIt))
+ PlayPrioritySound(kChord2Sound, kChord2Priority);
+}
+
+//-------------------------------------------------------------- SoundFilter
+
+Boolean SoundFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ short newVolume;
+
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ case kUpArrowKeyASCII:
+ *item = kLouderItem;
+ return(true);
+ break;
+
+ case kDownArrowKeyASCII:
+ *item = kSofterItem;
+ return(true);
+ break;
+
+ case k0KeyASCII:
+ case k1KeyASCII:
+ case k2KeyASCII:
+ case k3KeyASCII:
+ case k4KeyASCII:
+ case k5KeyASCII:
+ case k6KeyASCII:
+ case k7KeyASCII:
+ newVolume = (((event->message) & charCodeMask) - k0KeyASCII);
+ if (newVolume == 7L)
+ SetDialogNumToStr(dial, kVolNumberItem, 11L);
+ else
+ SetDialogNumToStr(dial, kVolNumberItem, (long)newVolume);
+
+ UnivSetSoundVolume(newVolume, thisMac.hasSM3);
+
+ HandleSoundMusicChange(newVolume, true);
+ return(false);
+ break;
+
+ case kCapDKeyASCII:
+ case kDKeyASCII:
+ *item = kSoundDefault;
+ FlashDialogButton(dial, kSoundDefault);
+ return(true);
+ break;
+
+ case kCapGKeyASCII:
+ case kGKeyASCII:
+ *item = kPlayMusicItem;
+ return(true);
+ break;
+
+ case kCapIKeyASCII:
+ case kIKeyASCII:
+ *item = kIdleMusicItem;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateSettingsSound(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoSettingsMain
+
+void DoSoundPrefs (void)
+{
+ Rect tempRect;
+ DialogPtr prefDlg;
+ short wasLoudness, tempVolume;
+ OSErr theErr;
+ short itemHit;
+ Boolean leaving;
+ ModalFilterUPP soundFilterUPP;
+
+ soundFilterUPP = NewModalFilterUPP(SoundFilter);
+
+ BringUpDialog(&prefDlg, kSoundPrefsDialID);
+
+ UnivGetSoundVolume(&wasLoudness, thisMac.hasSM3);
+
+ wasIdle = isPlayMusicIdle;
+ wasPlay = isPlayMusicGame;
+ SetDialogItemValue(prefDlg, kIdleMusicItem, (short)wasIdle);
+ SetDialogItemValue(prefDlg, kPlayMusicItem, (short)wasPlay);
+ leaving = false;
+
+ while (!leaving)
+ {
+ ModalDialog(soundFilterUPP, &itemHit);
+ switch (itemHit)
+ {
+ case kOkayButton:
+ isPlayMusicIdle = wasIdle;
+ isPlayMusicGame = wasPlay;
+ leaving = true;
+ UnivGetSoundVolume(&tempVolume, thisMac.hasSM3);
+ isSoundOn = (tempVolume != 0);
+ break;
+
+ case kCancelButton:
+ UnivSetSoundVolume(wasLoudness, thisMac.hasSM3);
+ HandleSoundMusicChange(wasLoudness, false);
+ if (isPlayMusicIdle != wasIdle)
+ {
+ if (isPlayMusicIdle)
+ {
+ if (wasLoudness != 0)
+ {
+ theErr = StartMusic();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowNoMusic, theErr);
+ failedMusic = true;
+ }
+ }
+ }
+ else
+ StopTheMusic();
+ }
+ leaving = true;
+ break;
+
+ case kSofterItem:
+ UnivGetSoundVolume(&tempVolume, thisMac.hasSM3);
+ if (tempVolume > 0)
+ {
+ GetDialogItemRect(prefDlg, kSofterItem, &tempRect);
+ DrawCIcon(1034, tempRect.left, tempRect.top);
+ tempVolume--;
+ SetDialogNumToStr(prefDlg, kVolNumberItem, (long)tempVolume);
+ UnivSetSoundVolume(tempVolume, thisMac.hasSM3);
+ HandleSoundMusicChange(tempVolume, true);
+ InvalWindowRect(GetDialogWindow(prefDlg), &tempRect);
+ DelayTicks(8);
+ }
+ break;
+
+ case kLouderItem:
+ UnivGetSoundVolume(&tempVolume, thisMac.hasSM3);
+ if (tempVolume < 7)
+ {
+ GetDialogItemRect(prefDlg, kLouderItem, &tempRect);
+ DrawCIcon(1033, tempRect.left, tempRect.top);
+ tempVolume++;
+ if (tempVolume == 7)
+ SetDialogNumToStr(prefDlg, kVolNumberItem, 11L);
+ else
+ SetDialogNumToStr(prefDlg, kVolNumberItem, tempVolume);
+ UnivSetSoundVolume(tempVolume, thisMac.hasSM3);
+ HandleSoundMusicChange(tempVolume, true);
+ InvalWindowRect(GetDialogWindow(prefDlg), &tempRect);
+ DelayTicks(8);
+ }
+ break;
+
+ case kIdleMusicItem:
+ wasIdle = !wasIdle;
+ SetDialogItemValue(prefDlg, kIdleMusicItem, (short)wasIdle);
+ if (wasIdle)
+ {
+ UnivGetSoundVolume(&tempVolume, thisMac.hasSM3);
+ if (tempVolume != 0)
+ {
+ theErr = StartMusic();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowNoMusic, theErr);
+ failedMusic = true;
+ }
+ }
+ }
+ else
+ StopTheMusic();
+ break;
+
+ case kPlayMusicItem:
+ wasPlay = !wasPlay;
+ SetDialogItemValue(prefDlg, kPlayMusicItem, (short)wasPlay);
+ break;
+
+ case kSoundDefault:
+ SoundDefaults(prefDlg);
+ break;
+ }
+ }
+
+ DisposeDialog(prefDlg);
+ DisposeModalFilterUPP(soundFilterUPP);
+}
+
+//-------------------------------------------------------------- DisplayDefaults
+
+void DisplayDefaults (void)
+{
+ numNeighbors = 9;
+ wasDepthPref = kSwitchIfNeeded;
+ wasFade = true;
+ wasScreen2 = false;
+}
+
+//-------------------------------------------------------------- FrameDisplayIcon
+
+void FrameDisplayIcon (DialogPtr theDialog)
+{
+ Rect theRect;
+
+ switch (numNeighbors)
+ {
+ case 1:
+ GetDialogItemRect(theDialog, kDisplay1Item, &theRect);
+ break;
+
+ case 3:
+ GetDialogItemRect(theDialog, kDisplay3Item, &theRect);
+ break;
+
+ default:
+ GetDialogItemRect(theDialog, kDisplay9Item, &theRect);
+ break;
+ }
+
+ theRect.left -= 3;
+ theRect.top += 0;
+ theRect.right += 3;
+ theRect.bottom -= 1;
+ FrameRect(&theRect);
+ InsetRect(&theRect, 1, 1);
+ FrameRect(&theRect);
+}
+
+//-------------------------------------------------------------- DisplayUpdate
+
+void DisplayUpdate (DialogPtr theDialog)
+{
+ DrawDialog(theDialog);
+ DrawDefaultButton(theDialog);
+
+ SetDialogItemValue(theDialog, kDoColorFadeItem, (short)wasFade);
+ SelectFromRadioGroup(theDialog, kCurrentDepth + wasDepthPref,
+ kCurrentDepth, k16Depth);
+// SetDialogItemValue(theDialog, kUseQDItem, (short)wasQD);
+ SetDialogItemValue(theDialog, kUseScreen2Item, (short)wasScreen2);
+
+ ForeColor(redColor);
+ FrameDisplayIcon(theDialog);
+ ForeColor(blackColor);
+ FrameDialogItemC(theDialog, 8, kRedOrangeColor8);
+ FrameDialogItemC(theDialog, 13, kRedOrangeColor8);
+ FrameDialogItemC(theDialog, 14, kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- DisplayFilter
+
+Boolean DisplayFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kEscapeKeyASCII:
+ FlashDialogButton(dial, kCancelButton);
+ *item = kCancelButton;
+ return(true);
+ break;
+
+ case kLeftArrowKeyASCII:
+ switch (numNeighbors)
+ {
+ case 1:
+ *item = kDisplay9Item;
+ break;
+
+ case 3:
+ *item = kDisplay1Item;
+ break;
+
+ case 9:
+ *item = kDisplay3Item;
+ break;
+ }
+ return(true);
+ break;
+
+ case kRightArrowKeyASCII:
+ switch (numNeighbors)
+ {
+ case 1:
+ *item = kDisplay3Item;
+ break;
+
+ case 3:
+ *item = kDisplay9Item;
+ break;
+
+ case 9:
+ *item = kDisplay1Item;
+ break;
+ }
+ return(true);
+ break;
+
+ case kUpArrowKeyASCII:
+ switch (wasDepthPref)
+ {
+ case kSwitchIfNeeded:
+ *item = k16Depth;
+ break;
+
+ case kSwitchTo256Colors:
+ *item = kCurrentDepth;
+ break;
+
+ case kSwitchTo16Grays:
+ *item = k256Depth;
+ break;
+ }
+ return(true);
+ break;
+
+ case kDownArrowKeyASCII:
+ switch (wasDepthPref)
+ {
+ case kSwitchIfNeeded:
+ *item = k256Depth;
+ break;
+
+ case kSwitchTo256Colors:
+ *item = k16Depth;
+ break;
+
+ case kSwitchTo16Grays:
+ *item = kCurrentDepth;
+ break;
+ }
+ return(true);
+ break;
+
+ case k1KeyASCII:
+ *item = kDisplay1Item;
+ return(true);
+ break;
+
+ case k3KeyASCII:
+ *item = kDisplay3Item;
+ return(true);
+ break;
+
+ case k9KeyASCII:
+ *item = kDisplay9Item;
+ return(true);
+ break;
+
+ case kCapBKeyASCII:
+ case kBKeyASCII:
+ *item = kDoColorFadeItem;
+ return(true);
+ break;
+
+ case kCapDKeyASCII:
+ case kDKeyASCII:
+ *item = kDispDefault;
+ FlashDialogButton(dial, kDispDefault);
+ return(true);
+ break;
+
+ case kCapRKeyASCII:
+ case kRKeyASCII:
+ *item = kUseScreen2Item;
+ FlashDialogButton(dial, kUseQDItem);
+ return(true);
+ break;
+
+ case kCapUKeyASCII:
+ case kUKeyASCII:
+ *item = kUseQDItem;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ return(false);
+ break;
+
+ case updateEvt:
+ SetPort((GrafPtr)dial);
+ BeginUpdate(GetDialogWindow(dial));
+ DisplayUpdate(dial);
+ EndUpdate(GetDialogWindow(dial));
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoDisplayPrefs
+
+void DoDisplayPrefs (void)
+{
+ DialogPtr prefDlg;
+ short itemHit, wasNeighbors;
+ Boolean leaving;
+ ModalFilterUPP displayFilterUPP;
+
+ displayFilterUPP = NewModalFilterUPP(DisplayFilter);
+
+ BringUpDialog(&prefDlg, kDisplayPrefsDialID);
+ if (!thisMac.can8Bit)
+ {
+ MyDisableControl(prefDlg, kDoColorFadeItem);
+ MyDisableControl(prefDlg, k256Depth);
+ }
+ if (!thisMac.can4Bit)
+ MyDisableControl(prefDlg, k16Depth);
+ if (thisMac.numScreens < 2)
+ MyDisableControl(prefDlg, kUseScreen2Item);
+ wasNeighbors = numNeighbors;
+ wasFade = isDoColorFade;
+ wasDepthPref = isDepthPref;
+ wasScreen2 = isUseSecondScreen;
+ leaving = false;
+
+ while (!leaving)
+ {
+ ModalDialog(displayFilterUPP, &itemHit);
+ switch (itemHit)
+ {
+ case kOkayButton:
+ isDoColorFade = wasFade;
+ isDepthPref = wasDepthPref;
+ if (isUseSecondScreen != wasScreen2)
+ nextRestartChange = true;
+ isUseSecondScreen = wasScreen2;
+ leaving = true;
+ break;
+
+ case kCancelButton:
+ numNeighbors = wasNeighbors;
+ leaving = true;
+ break;
+
+ case kDisplay1Item:
+ ForeColor(whiteColor);
+ FrameDisplayIcon(prefDlg);
+ numNeighbors = 1;
+ ForeColor(redColor);
+ FrameDisplayIcon(prefDlg);
+ ForeColor(blackColor);
+ break;
+
+ case kDisplay3Item:
+ if (thisMac.screen.right > 512)
+ {
+ ForeColor(whiteColor);
+ FrameDisplayIcon(prefDlg);
+ numNeighbors = 3;
+ ForeColor(redColor);
+ FrameDisplayIcon(prefDlg);
+ ForeColor(blackColor);
+ }
+ break;
+
+ case kDisplay9Item:
+ if (thisMac.screen.right > 512)
+ {
+ ForeColor(whiteColor);
+ FrameDisplayIcon(prefDlg);
+ numNeighbors = 9;
+ ForeColor(redColor);
+ FrameDisplayIcon(prefDlg);
+ ForeColor(blackColor);
+ }
+ break;
+
+ case kDoColorFadeItem:
+ wasFade = !wasFade;
+ SetDialogItemValue(prefDlg, kDoColorFadeItem, (short)wasFade);
+ break;
+
+ case kCurrentDepth:
+ case k256Depth:
+ case k16Depth:
+ wasDepthPref = itemHit - kCurrentDepth;
+ SelectFromRadioGroup(prefDlg, itemHit, kCurrentDepth, k16Depth);
+ break;
+
+ case kDispDefault:
+ ForeColor(whiteColor);
+ FrameDisplayIcon(prefDlg);
+ ForeColor(blackColor);
+ DisplayDefaults();
+ DisplayUpdate(prefDlg);
+ break;
+
+ case kUseQDItem:
+// wasQD = !wasQD;
+// SetDialogItemValue(prefDlg, kUseQDItem, (short)wasQD);
+ break;
+
+ case kUseScreen2Item:
+ wasScreen2 = !wasScreen2;
+ SetDialogItemValue(prefDlg, kUseScreen2Item, (short)wasScreen2);
+ break;
+ }
+ }
+
+ DisposeDialog(prefDlg);
+ DisposeModalFilterUPP(displayFilterUPP);
+}
+
+//-------------------------------------------------------------- SetAllDefaults
+
+void SetAllDefaults (void)
+{
+ OSErr theErr;
+ // Default brain settings
+ willMaxFiles = 48;
+ doZooms = true;
+ doAutoDemo = true;
+ doBackground = false;
+ isHouseChecks = true;
+ doPrettyMap = true;
+ doBitchDialogs = true;
+ // Default control settings
+ PasStringCopy(PSTR("lf arrow"), leftName);
+ PasStringCopy(PSTR("rt arrow"), rightName);
+ PasStringCopy(PSTR("dn arrow"), batteryName);
+ PasStringCopy(PSTR("up arrow"), bandName);
+ theGlider.leftKey = kLeftArrowKeyMap;
+ theGlider.rightKey = kRightArrowKeyMap;
+ theGlider.battKey = kDownArrowKeyMap;
+ theGlider.bandKey = kUpArrowKeyMap;
+ isEscPauseKey = false;
+ // Default sound settings
+ isPlayMusicIdle = true;
+ isPlayMusicGame = true;
+ UnivSetSoundVolume(3, thisMac.hasSM3);
+ isSoundOn = true;
+ if (!isMusicOn)
+ {
+ theErr = StartMusic();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowNoMusic, theErr);
+ failedMusic = true;
+ }
+ }
+ // Default display settings
+ numNeighbors = 9;
+ quickerTransitions = false;
+ isDepthPref = kSwitchIfNeeded;
+ isDoColorFade = true;
+}
+
+//-------------------------------------------------------------- FlashSettingsButton
+
+void FlashSettingsButton (short who)
+{
+ #define kNormalSettingsIcon 1010
+ #define kInvertedSettingsIcon 1014
+ short theID;
+
+ theID = kInvertedSettingsIcon + who;
+ DrawCIcon (theID, prefButton[who].left + 4, prefButton[who].top + 4);
+ DelayTicks(8);
+ theID = kNormalSettingsIcon + who;
+ DrawCIcon (theID, prefButton[who].left + 4, prefButton[who].top + 4);
+}
+
+//-------------------------------------------------------------- UpdateSettingsMain
+
+void UpdateSettingsMain (DialogPtr theDialog)
+{
+ Str255 theStr;
+
+ DrawDialog(theDialog);
+
+ DrawDefaultButton(theDialog);
+
+ GetIndString(theStr, 129, 1);
+ DrawDialogUserText(theDialog, 7, theStr, false);
+ GetIndString(theStr, 129, 2);
+ DrawDialogUserText(theDialog, 8, theStr, false);
+ GetIndString(theStr, 129, 3);
+ DrawDialogUserText(theDialog, 9, theStr, false);
+ GetIndString(theStr, 129, 4);
+ DrawDialogUserText(theDialog, 10, theStr, false);
+
+ ColorFrameRect(&prefButton[0], kRedOrangeColor8);
+ ColorFrameRect(&prefButton[1], kRedOrangeColor8);
+ ColorFrameRect(&prefButton[2], kRedOrangeColor8);
+ ColorFrameRect(&prefButton[3], kRedOrangeColor8);
+}
+
+//-------------------------------------------------------------- PrefsFilter
+
+Boolean PrefsFilter (DialogPtr dial, EventRecord *event, short *item)
+{
+ Point testPt;
+ short i;
+ Boolean foundHit;
+
+ switch (event->what)
+ {
+ case keyDown:
+ switch ((event->message) & charCodeMask)
+ {
+ case kReturnKeyASCII:
+ case kEnterKeyASCII:
+ FlashDialogButton(dial, kOkayButton);
+ *item = kOkayButton;
+ return(true);
+ break;
+
+ case kCapBKeyASCII:
+ case kBKeyASCII:
+ *item = kBrainsButton;
+ return(true);
+ break;
+
+ case kCapCKeyASCII:
+ case kCKeyASCII:
+ *item = kControlsButton;
+ return(true);
+ break;
+
+ case kCapDKeyASCII:
+ case kDKeyASCII:
+ *item = kDisplayButton;
+ return(true);
+ break;
+
+ case kCapSKeyASCII:
+ case kSKeyASCII:
+ *item = kSoundButton;
+ return(true);
+ break;
+
+ default:
+ return(false);
+ }
+ break;
+
+ case mouseDown:
+ testPt = event->where;
+ GlobalToLocal(&testPt);
+ foundHit = false;
+ for (i = 0; i < 4; i++)
+ {
+ if (PtInRect(testPt, &prefButton[i]))
+ {
+ *item = kDisplayButton + i;
+ foundHit = true;
+ }
+ }
+ return(foundHit);
+ break;
+
+ case updateEvt:
+ if ((WindowPtr)event->message == (WindowPtr)mainWindow)
+ {
+ SetPortWindowPort(mainWindow);
+ BeginUpdate(mainWindow);
+ UpdateMainWindow();
+ EndUpdate(mainWindow);
+ SetPort((GrafPtr)dial);
+ }
+ else if ((WindowPtr)event->message == GetDialogWindow(dial))
+ {
+ SetPortDialogPort(dial);
+ BeginUpdate(GetDialogWindow(dial));
+ UpdateSettingsMain(dial);
+ EndUpdate(GetDialogWindow(dial));
+ }
+ event->what = nullEvent;
+ return(false);
+ break;
+
+ default:
+ return(false);
+ break;
+ }
+}
+
+//-------------------------------------------------------------- DoSettingsMain
+
+void DoSettingsMain (void)
+{
+ #define kAllDefaultsButton 11
+ DialogPtr prefDlg;
+ short itemHit;
+ Boolean leaving;
+ ModalFilterUPP prefsFilterUPP;
+
+ prefsFilterUPP = NewModalFilterUPP(PrefsFilter);
+
+ BringUpDialog(&prefDlg, kMainPrefsDialID);
+
+ GetDialogItemRect(prefDlg, kDisplayButton, &prefButton[0]);
+ InsetRect(&prefButton[0], -4, -4);
+ GetDialogItemRect(prefDlg, 4, &prefButton[1]);
+ InsetRect(&prefButton[1], -4, -4);
+ GetDialogItemRect(prefDlg, 5, &prefButton[2]);
+ InsetRect(&prefButton[2], -4, -4);
+ GetDialogItemRect(prefDlg, 6, &prefButton[3]);
+ InsetRect(&prefButton[3], -4, -4);
+
+ leaving = false;
+ nextRestartChange = false;
+
+ while (!leaving)
+ {
+ ModalDialog(prefsFilterUPP, &itemHit);
+ switch (itemHit)
+ {
+ case kOkayButton:
+ leaving = true;
+ break;
+
+ case kDisplayButton:
+ FlashSettingsButton(0);
+ DoDisplayPrefs();
+ SetPort((GrafPtr)prefDlg);
+ break;
+
+ case kSoundButton:
+ FlashSettingsButton(1);
+ DoSoundPrefs();
+ SetPort((GrafPtr)prefDlg);
+ FlushEvents(everyEvent, 0);
+ break;
+
+ case kControlsButton:
+ FlashSettingsButton(2);
+ DoControlPrefs();
+ SetPort((GrafPtr)prefDlg);
+ break;
+
+ case kBrainsButton:
+ if ((OptionKeyDown()) && (!houseUnlocked))
+ {
+ houseUnlocked = true;
+ changeLockStateOfHouse = true;
+ saveHouseLocked = false;
+ }
+ FlashSettingsButton(3);
+ DoBrainsPrefs();
+ SetPort((GrafPtr)prefDlg);
+ break;
+
+ case kAllDefaultsButton:
+ SetAllDefaults();
+ break;
+ }
+ }
+
+ DisposeDialog(prefDlg);
+ DisposeModalFilterUPP(prefsFilterUPP);
+
+ if (nextRestartChange)
+ BitchAboutChanges();
+}
+
+//-------------------------------------------------------------- BitchAboutChanges
+
+void BitchAboutChanges (void)
+{
+ #define kChangesEffectAlert 1040
+ short hitWhat;
+
+// CenterAlert(kChangesEffectAlert);
+ hitWhat = Alert(kChangesEffectAlert, nil);
+}
+
diff --git a/GpApp/Sound.cpp b/GpApp/Sound.cpp
new file mode 100644
index 0000000..778a62f
--- /dev/null
+++ b/GpApp/Sound.cpp
@@ -0,0 +1,511 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Sound.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLResources.h"
+#include "PLSound.h"
+#include "Externs.h"
+
+
+#define kBaseBufferSoundID 1000
+#define kMaxSounds 64
+#define kNoSoundPlaying -1
+
+
+void CallBack0 (SndChannelPtr, SndCommand *);
+void CallBack1 (SndChannelPtr, SndCommand *);
+void CallBack2 (SndChannelPtr, SndCommand *);
+OSErr LoadBufferSounds (void);
+void DumpBufferSounds (void);
+OSErr OpenSoundChannels (void);
+OSErr CloseSoundChannels (void);
+
+
+SndCallBackUPP callBack0UPP, callBack1UPP, callBack2UPP;
+SndChannelPtr channel0, channel1, channel2;
+Ptr theSoundData[kMaxSounds];
+short numSoundsLoaded, priority0, priority1, priority2;
+short soundPlaying0, soundPlaying1, soundPlaying2;
+Boolean soundLoaded[kMaxSounds], dontLoadSounds;
+Boolean channelOpen, isSoundOn, failedSound;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- PlayPrioritySound
+
+void PlayPrioritySound (short which, short priority)
+{
+ short lowestPriority, whosLowest;
+
+ if (failedSound || dontLoadSounds)
+ return;
+
+ if ((priority == kTriggerPriority) &&
+ ((priority0 == kTriggerPriority) ||
+ ((priority1 == kTriggerPriority)) ||
+ ((priority2 == kTriggerPriority))))
+ return;
+
+ whosLowest = 0;
+ lowestPriority = priority0;
+
+ if (priority1 < lowestPriority)
+ {
+ lowestPriority = priority1;
+ whosLowest = 1;
+ }
+
+ if (priority2 < lowestPriority)
+ {
+ lowestPriority = priority2;
+ whosLowest = 2;
+ }
+
+ if (priority >= lowestPriority)
+ {
+ switch (whosLowest)
+ {
+ case 0:
+ PlaySound0(which, priority);
+ break;
+
+ case 1:
+ PlaySound1(which, priority);
+ break;
+
+ case 2:
+ PlaySound2(which, priority);
+ break;
+ }
+ }
+}
+
+//-------------------------------------------------------------- FlushAnyTriggerPlaying
+
+void FlushAnyTriggerPlaying (void)
+{
+ SndCommand theCommand;
+ OSErr theErr;
+
+ if (priority0 == kTriggerPriority)
+ {
+ theCommand.cmd = quietCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0;
+ theErr = SndDoImmediate(channel0, &theCommand);
+ theCommand.cmd = flushCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0;
+ theErr = SndDoImmediate(channel0, &theCommand);
+ }
+
+ if (priority1 == kTriggerPriority)
+ {
+ theCommand.cmd = quietCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0;
+ theErr = SndDoImmediate(channel1, &theCommand);
+ theCommand.cmd = flushCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0;
+ theErr = SndDoImmediate(channel1, &theCommand);
+ }
+
+ if (priority2 == kTriggerPriority)
+ {
+ theCommand.cmd = quietCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0;
+ theErr = SndDoImmediate(channel2, &theCommand);
+ theCommand.cmd = flushCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0;
+ theErr = SndDoImmediate(channel2, &theCommand);
+ }
+}
+
+//-------------------------------------------------------------- PlaySound0
+
+void PlaySound0 (short soundID, short priority)
+{
+ SndCommand theCommand;
+ OSErr theErr;
+
+ if (failedSound || dontLoadSounds)
+ return;
+
+ theErr = noErr;
+ if (isSoundOn)
+ {
+ priority0 = priority;
+ soundPlaying0 = soundID;
+
+ theCommand.cmd = bufferCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = (intptr_t)(theSoundData[soundID]);
+ theErr = SndDoImmediate(channel0, &theCommand);
+
+ theCommand.cmd = callBackCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0;
+ theErr = SndDoCommand(channel0, &theCommand, true);
+ }
+}
+
+//-------------------------------------------------------------- PlaySound1
+
+void PlaySound1 (short soundID, short priority)
+{
+ SndCommand theCommand;
+ OSErr theErr;
+
+ if (failedSound || dontLoadSounds)
+ return;
+
+ theErr = noErr;
+ if (isSoundOn)
+ {
+ priority1 = priority;
+ soundPlaying1 = soundID;
+
+ theCommand.cmd = bufferCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = (intptr_t)(theSoundData[soundID]);
+ theErr = SndDoImmediate(channel1, &theCommand);
+
+ theCommand.cmd = callBackCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0;
+ theErr = SndDoCommand(channel1, &theCommand, true);
+ }
+}
+
+//-------------------------------------------------------------- PlaySound2
+
+void PlaySound2 (short soundID, short priority)
+{
+ SndCommand theCommand;
+ OSErr theErr;
+
+ if (failedSound || dontLoadSounds)
+ return;
+
+ theErr = noErr;
+ if (isSoundOn)
+ {
+ theCommand.cmd = bufferCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = (intptr_t)(theSoundData[soundID]);
+ theErr = SndDoImmediate(channel2, &theCommand);
+
+ theCommand.cmd = callBackCmd;
+ theCommand.param1 = 0;
+ theCommand.param2 = 0;
+ theErr = SndDoCommand(channel2, &theCommand, true);
+
+ priority2 = priority;
+ soundPlaying2 = soundID;
+ }
+}
+
+//-------------------------------------------------------------- CallBack0
+
+void CallBack0 (SndChannelPtr theChannel, SndCommand *theCommand)
+{
+ priority0 = 0;
+ soundPlaying0 = kNoSoundPlaying;
+}
+
+//-------------------------------------------------------------- CallBack1
+
+void CallBack1 (SndChannelPtr theChannel, SndCommand *theCommand)
+{
+ priority1 = 0;
+ soundPlaying1 = kNoSoundPlaying;
+}
+
+//-------------------------------------------------------------- CallBack2
+
+void CallBack2 (SndChannelPtr theChannel, SndCommand *theCommand)
+{
+ priority2 = 0;
+ soundPlaying2 = kNoSoundPlaying;
+}
+
+//-------------------------------------------------------------- LoadTriggerSound
+
+OSErr LoadTriggerSound (short soundID)
+{
+ Handle theSound;
+ long soundDataSize;
+ OSErr theErr;
+
+ if ((dontLoadSounds) || (theSoundData[kMaxSounds - 1] != nil))
+ theErr = -1;
+ else
+ {
+// FlushAnyTriggerPlaying();
+
+ theErr = noErr;
+
+ theSound = GetResource('snd ', soundID);
+ if (theSound == nil)
+ {
+ theErr = -1;
+ }
+ else
+ {
+ soundDataSize = GetHandleSize(theSound) - 20L;
+ theSoundData[kMaxSounds - 1] = NewPtr(soundDataSize);
+ HLock(theSound);
+ if (theSoundData[kMaxSounds - 1] == nil)
+ {
+ ReleaseResource(theSound);
+ theErr = MemError();
+ }
+ else
+ {
+ BlockMove((Ptr)((Byte*)(*theSound) + 20L), theSoundData[kMaxSounds - 1], soundDataSize);
+ ReleaseResource(theSound);
+ }
+ }
+ }
+
+ return (theErr);
+}
+
+//-------------------------------------------------------------- DumpTriggerSound
+
+void DumpTriggerSound (void)
+{
+ if (theSoundData[kMaxSounds - 1] != nil)
+ DisposePtr(theSoundData[kMaxSounds - 1]);
+ theSoundData[kMaxSounds - 1] = nil;
+}
+
+//-------------------------------------------------------------- LoadBufferSounds
+
+OSErr LoadBufferSounds (void)
+{
+ Handle theSound;
+ long soundDataSize;
+ OSErr theErr;
+ short i;
+
+ theErr = noErr;
+
+ for (i = 0; i < kMaxSounds - 1; i++)
+ {
+ theSound = GetResource('snd ', i + kBaseBufferSoundID);
+ if (theSound == nil)
+ return (MemError());
+
+ HLock(theSound);
+ soundDataSize = GetHandleSize(theSound) - 20L;
+ HUnlock(theSound);
+
+ theSoundData[i] = NewPtr(soundDataSize);
+ if (theSoundData[i] == nil)
+ return (MemError());
+
+ HLock(theSound);
+ BlockMove((Ptr)((Byte*)(*theSound) + 20L), theSoundData[i], soundDataSize);
+ ReleaseResource(theSound);
+ }
+
+ theSoundData[kMaxSounds - 1] = nil;
+
+ return (theErr);
+}
+
+//-------------------------------------------------------------- DumpBufferSounds
+
+void DumpBufferSounds (void)
+{
+ short i;
+
+ for (i = 0; i < kMaxSounds; i++)
+ {
+ if (theSoundData[i] != nil)
+ DisposePtr(theSoundData[i]);
+ theSoundData[i] = nil;
+ }
+}
+
+//-------------------------------------------------------------- OpenSoundChannels
+
+OSErr OpenSoundChannels (void)
+{
+ OSErr theErr;
+
+ callBack0UPP = NewSndCallBackProc(CallBack0);
+ callBack1UPP = NewSndCallBackProc(CallBack1);
+ callBack2UPP = NewSndCallBackProc(CallBack2);
+
+ theErr = noErr;
+
+ if (channelOpen)
+ return (theErr);
+
+ theErr = SndNewChannel(&channel0,
+ sampledSynth, initNoInterp + initMono,
+ (SndCallBackUPP)callBack0UPP);
+ if (theErr == noErr)
+ channelOpen = true;
+ else
+ return (theErr);
+
+ theErr = SndNewChannel(&channel1,
+ sampledSynth, initNoInterp + initMono,
+ (SndCallBackUPP)callBack1UPP);
+ if (theErr == noErr)
+ channelOpen = true;
+ else
+ return (theErr);
+
+ theErr = SndNewChannel(&channel2,
+ sampledSynth, initNoInterp + initMono,
+ (SndCallBackUPP)callBack2UPP);
+ if (theErr == noErr)
+ channelOpen = true;
+
+ return (theErr);
+}
+
+//-------------------------------------------------------------- CloseSoundChannels
+
+OSErr CloseSoundChannels (void)
+{
+ OSErr theErr;
+
+ theErr = noErr;
+
+ if (!channelOpen)
+ return (theErr);
+
+ if (channel0 != nil)
+ theErr = SndDisposeChannel(channel0, true);
+ channel0 = nil;
+
+ if (channel1 != nil)
+ theErr = SndDisposeChannel(channel1, true);
+ channel1 = nil;
+
+ if (channel2 != nil)
+ theErr = SndDisposeChannel(channel2, true);
+ channel2 = nil;
+
+ if (theErr == noErr)
+ channelOpen = false;
+
+ DisposeSndCallBackUPP(callBack0UPP);
+ DisposeSndCallBackUPP(callBack1UPP);
+ DisposeSndCallBackUPP(callBack2UPP);
+
+ return (theErr);
+}
+
+//-------------------------------------------------------------- InitSound
+
+void InitSound (void)
+{
+ OSErr theErr;
+
+ if (dontLoadSounds)
+ return;
+
+ failedSound = false;
+
+ channel0 = nil;
+ channel1 = nil;
+ channel2 = nil;
+
+ priority0 = 0;
+ priority1 = 0;
+ priority2 = 0;
+ soundPlaying0 = kNoSoundPlaying;
+ soundPlaying1 = kNoSoundPlaying;
+ soundPlaying2 = kNoSoundPlaying;
+
+ theErr = LoadBufferSounds();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowFailedSound, theErr);
+ failedSound = true;
+ }
+
+ if (!failedSound)
+ {
+ theErr = OpenSoundChannels();
+ if (theErr != noErr)
+ {
+ YellowAlert(kYellowFailedSound, theErr);
+ failedSound = true;
+ }
+ }
+}
+
+//-------------------------------------------------------------- KillSound
+
+void KillSound (void)
+{
+ OSErr theErr;
+
+ if (dontLoadSounds)
+ return;
+
+ DumpBufferSounds();
+ theErr = CloseSoundChannels();
+}
+
+//-------------------------------------------------------------- SoundBytesNeeded
+
+long SoundBytesNeeded (void)
+{
+ Handle theSound;
+ long totalBytes;
+ short i;
+
+ totalBytes = 0L;
+ SetResLoad(false);
+ for (i = 0; i < kMaxSounds - 1; i++)
+ {
+ theSound = GetResource('snd ', i + kBaseBufferSoundID);
+ if (theSound == nil)
+ {
+ SetResLoad(true);
+ return ((long)ResError());
+ }
+ totalBytes += GetMaxResourceSize(theSound);
+// ReleaseResource(theSound);
+ }
+ SetResLoad(true);
+ return totalBytes;
+}
+
+//-------------------------------------------------------------- TellHerNoSounds
+
+void TellHerNoSounds (void)
+{
+ #define kNoMemForSoundsAlert 1039
+ short hitWhat;
+
+// CenterAlert(kNoMemForSoundsAlert);
+ hitWhat = Alert(kNoMemForSoundsAlert, nil);
+}
+
+//-------------------------------------------------------------- BitchAboutSM3
+
+void BitchAboutSM3 (void)
+{
+ #define kNoSoundManager3Alert 1030
+ short hitWhat;
+
+// CenterAlert(kNoSoundManager3Alert);
+ hitWhat = Alert(kNoSoundManager3Alert, nil);
+}
+
diff --git a/GpApp/StringUtils.cpp b/GpApp/StringUtils.cpp
new file mode 100644
index 0000000..05c0d36
--- /dev/null
+++ b/GpApp/StringUtils.cpp
@@ -0,0 +1,304 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// StringUtils.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+#include "PLPasStr.h"
+#include "Externs.h"
+
+#include
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- PasStringCopy
+// Given a source string and storage for a second, this functionÉ
+// copies from one to the other. It assumes Pascal style strings.
+
+void PasStringCopy (StringPtr p1, StringPtr p2)
+{
+ register short stringLength;
+
+ stringLength = *p2++ = *p1++;
+ while (--stringLength >= 0)
+ *p2++ = *p1++;
+}
+
+//-------------------------------------------------------------- WhichStringFirst
+
+// This is a sorting function that handles two Pascal strings. ItÉ
+// will return a 1 to indicate the 1st string is "greater", a 1 toÉ
+// indicate the 2nd was greater and a 0 to indicate that the stringsÉ
+// are equal.
+
+short WhichStringFirst (StringPtr p1, StringPtr p2)
+{
+ short smallestLength, seek, greater;
+ char char1, char2;
+ Boolean foundIt;
+
+ smallestLength = p1[0];
+ if (p2[0] < smallestLength)
+ smallestLength = p2[0];
+
+ greater = 0; // neither are greater, they are equal
+ seek = 1; // start at character #1
+ foundIt = false;
+ do
+ {
+ char1 = p1[seek]; // make upper case (if applicable)
+ if ((char1 > 0x60) && (char1 < 0x7B))
+ char1 -= 0x20;
+ char2 = p2[seek]; // make upper case (if applicable)
+ if ((char2 > 0x60) && (char2 < 0x7B))
+ char2 -= 0x20;
+
+ if (char1 > char2) // first string is greater
+ {
+ greater = 1;
+ foundIt = true;
+ }
+ else if (char1 < char2) // second string is greater
+ {
+ greater = 2;
+ foundIt = true;
+ }
+ seek++;
+ if (seek > smallestLength) // we've reached the end of the line
+ {
+ if (!foundIt)
+ {
+ if (p1[0] < p2[0]) // shortest string wins
+ greater = 1;
+ else if (p1[0] > p2[0])
+ greater = 2;
+ }
+ foundIt = true;
+ }
+ }
+ while (!foundIt);
+
+ return (greater);
+}
+
+//-------------------------------------------------------------- PasStringCopyNum
+
+// This function copies a specified number of characters from oneÉ
+// Pascal string to another.
+
+void PasStringCopyNum (StringPtr p1, StringPtr p2, short charsToCopy)
+{
+ short i;
+
+ if (charsToCopy > *p1) // if trying to copy more chars than there are
+ charsToCopy = *p1; // reduce the number of chars to copy to this size
+
+ *p2 = static_cast(charsToCopy);
+
+ *p2++;
+ *p1++;
+
+ for (i = 0; i < charsToCopy; i++)
+ *p2++ = *p1++;
+}
+
+//-------------------------------------------------------------- PasStringConcat
+// This function concatenates the second Pascal string to the end ofÉ
+// the first Pascal string.
+
+void PasStringConcat (StringPtr p1, const PLPasStr &p2)
+{
+ short wasLength, addedLength;
+
+ wasLength = *p1;
+ if (wasLength > 255)
+ wasLength = 255;
+
+ addedLength = p2.Length();
+ if ((wasLength + addedLength) > 255)
+ addedLength = 255 - wasLength;
+
+ *p1 = wasLength + addedLength;
+
+ p1 += (1 + wasLength);
+
+ memcpy(p1, p2.Chars(), addedLength);
+}
+
+//-------------------------------------------------------------- GetLineOfText
+
+// This function walks through a source string and looks for anÉ
+// entire line of text. A "line" of text is assumed to be boundedÉ
+// by carriage returns. The index variable indicates which lineÉ
+// is sought.
+
+void GetLineOfText (StringPtr srcStr, short index, StringPtr textLine)
+{
+ short i, srcLength, count, start, stop;
+ Boolean foundIt;
+
+ PasStringCopy(PSTR(""), textLine);
+ srcLength = srcStr[0];
+
+ if (index == 0) // walk through to "index"
+ start = 1;
+ else
+ {
+ start = 0;
+ count = 0;
+ i = 0;
+ foundIt = false;
+ do
+ {
+ i++;
+ if (srcStr[i] == kReturnKeyASCII)
+ {
+ count++;
+ if (count == index)
+ {
+ start = i + 1;
+ foundIt = true;
+ }
+ }
+ }
+ while ((i < srcLength) && (!foundIt));
+ }
+
+ if (start != 0)
+ {
+ i = start;
+
+ foundIt = false;
+ do
+ {
+ if (srcStr[i] == kReturnKeyASCII)
+ {
+ stop = i;
+ foundIt = true;
+ }
+ i++;
+ }
+ while ((i < srcLength) && (!foundIt));
+
+ if (!foundIt)
+ {
+ if (start > srcLength)
+ {
+ start = srcLength;
+ stop = srcLength - 1;
+ }
+ else
+ stop = i;
+ }
+
+ count = 0;
+
+ for (i = start; i <= stop; i++)
+ {
+ count++;
+ textLine[count] = srcStr[i];
+ }
+ textLine[0] = static_cast(count);
+ }
+}
+
+//-------------------------------------------------------------- WrapText
+
+// Given a string and the maximum number of characters to put onÉ
+// one line, this function goes through and inserts carriage returnsÉ
+// in order to ensure that no line of text exceeds maxChars.
+
+void WrapText (StringPtr theText, short maxChars)
+{
+ short lastChar, count, chars, spaceIs;
+ Boolean foundEdge, foundSpace;
+
+ lastChar = theText[0];
+ count = 0;
+
+ do
+ {
+ chars = 0;
+ foundEdge = false;
+ foundSpace = false;
+ do
+ {
+ count++;
+ chars++;
+ if (theText[count] == kReturnKeyASCII)
+ foundEdge = true;
+ else if (theText[count] == kSpaceBarASCII)
+ {
+ foundSpace = true;
+ spaceIs = count;
+ }
+ }
+ while ((count < lastChar) && (chars < maxChars) && (!foundEdge));
+
+ if ((!foundEdge) && (count < lastChar) && (foundSpace))
+ {
+ theText[spaceIs] = kReturnKeyASCII;
+ count = spaceIs + 1;
+ }
+ }
+ while (count < lastChar);
+}
+
+//-------------------------------------------------------------- GetFirstWordOfString
+
+// Walks a string looking for a space (denoting first word of string).
+
+void GetFirstWordOfString (StringPtr stringIn, StringPtr stringOut)
+{
+ short isLong, spaceAt, i;
+
+ isLong = stringIn[0];
+ spaceAt = isLong;
+
+ for (i = 1; i < isLong; i++)
+ {
+ if ((stringIn[i] == ' ') && (spaceAt == isLong))
+ spaceAt = i - 1;
+ }
+
+ if (spaceAt <= 0)
+ PasStringCopy(PSTR(""), stringOut);
+ else
+ PasStringCopyNum(stringIn, stringOut, spaceAt);
+}
+
+//-------------------------------------------------------------- CollapseStringToWidth
+
+// Given a string and a maximum width (in pixels), this functionÉ
+// calculates how wide the text would be drawn with the currentÉ
+// font. If the text would exceed our width limit, charactersÉ
+// are dropped off the end of the string and "É" appended.
+
+void CollapseStringToWidth (StringPtr theStr, short wide)
+{
+ short dotsWide;
+ Boolean tooWide;
+
+ dotsWide = StringWidth(PSTR("É"));
+ tooWide = StringWidth(theStr) > wide;
+ while (tooWide)
+ {
+ theStr[0]--;
+ tooWide = ((StringWidth(theStr) + dotsWide) > wide);
+ if (!tooWide)
+ PasStringConcat(theStr, PSTR("É"));
+ }
+}
+
+//-------------------------------------------------------------- GetLocalizedString
+
+StringPtr GetLocalizedString (short index, StringPtr theString)
+{
+ #define kLocalizedStringsID 150
+
+ GetIndString(theString, kLocalizedStringsID, index);
+ return (theString);
+}
+
+
diff --git a/GpApp/StructuresInit.cpp b/GpApp/StructuresInit.cpp
new file mode 100644
index 0000000..9851222
--- /dev/null
+++ b/GpApp/StructuresInit.cpp
@@ -0,0 +1,726 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// StructuresInit.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLResources.h"
+#include "Externs.h"
+#include "Objects.h"
+#include "Play.h"
+#include "Player.h"
+#include "RectUtils.h"
+#include "RubberBands.h"
+#include "Scoreboard.h"
+#include "Utilities.h"
+
+
+#define kShadowPictID 3998
+#define kBlowerPictID 4000
+#define kFurniturePictID 4001
+#define kBonusPictID 4002
+#define kSwitchPictID 4003
+#define kLightPictID 4004
+#define kAppliancePictID 4005
+#define kPointsPictID 4006
+#define kRubberBandsPictID 4007
+#define kTransportPictID 4008
+#define kToastPictID 4009
+#define kShreddedPictID 4010
+#define kBalloonPictID 4011
+#define kCopterPictID 4012
+#define kDartPictID 4013
+#define kBallPictID 4014
+#define kDripPictID 4015
+#define kEnemyPictID 4016
+#define kFishPictID 4017
+
+#define kBadgePictID 1996
+
+
+extern Rect glidSrcRect, leftStartGliderSrc, rightStartGliderSrc;
+extern Rect gliderSrc[], shadowSrcRect, shadowSrc[];
+extern Rect bandsSrcRect, bandRects[], boardSrcRect, boardDestRect;
+extern Rect boardTSrcRect, boardTDestRect, badgeSrcRect;
+extern Rect boardGSrcRect, boardGDestRect, boardPSrcRect, boardPDestRect;
+extern Rect boardPQDestRect, boardGQDestRect, badgesBlankRects[];
+extern Rect badgesBadgesRects[], badgesDestRects[];
+extern Rect nailSrcRect, sparkleSrc[];
+extern Rect pointsSrc[], breadSrc[];
+extern short wasScoreboardMode;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- InitScoreboardMap
+// Any graphics and structures relating to the scoreboard that appearsÉ
+// across the top of the game are initialized and loaded up here.
+
+void InitScoreboardMap (void)
+{
+ Rect bounds;
+ PicHandle thePicture;
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+ short hOffset;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ wasScoreboardMode = kScoreboardHigh;
+ boardSrcRect = houseRect;
+ ZeroRectCorner(&boardSrcRect);
+ boardSrcRect.bottom = kScoreboardTall;
+ theErr = CreateOffScreenGWorld(&boardSrcMap, &boardSrcRect, kPreferredDepth);
+ SetGWorld(boardSrcMap, nil);
+
+ if (boardSrcRect.right >= 640)
+ hOffset = (RectWide(&boardSrcRect) - kMaxViewWidth) / 2;
+ else
+ hOffset = -576;
+ thePicture = GetPicture(kScoreboardPictID);
+ if (thePicture == nil)
+ RedAlert(kErrFailedGraphicLoad);
+ HLock((Handle)thePicture);
+ bounds = (*thePicture)->picFrame;
+ HUnlock((Handle)thePicture);
+ QOffsetRect(&bounds, -bounds.left, -bounds.top);
+ QOffsetRect(&bounds, hOffset, 0);
+ DrawPicture(thePicture, &bounds);
+ ReleaseResource((Handle)thePicture);
+
+ QSetRect(&badgeSrcRect, 0, 0, 32, 66); // 2144 pixels
+ theErr = CreateOffScreenGWorld(&badgeSrcMap, &badgeSrcRect, kPreferredDepth);
+ SetGWorld(badgeSrcMap, nil);
+ LoadGraphic(kBadgePictID);
+
+ boardDestRect = boardSrcRect;
+ QOffsetRect(&boardDestRect, 0, -kScoreboardTall);
+
+ hOffset = (RectWide(&houseRect) - 640) / 2;
+ if (hOffset < 0)
+ hOffset = -128;
+
+ QSetRect(&boardTSrcRect, 0, 0, 256, 12); // room title
+ theErr = CreateOffScreenGWorld(&boardTSrcMap, &boardTSrcRect, kPreferredDepth);
+ SetGWorld(boardTSrcMap, nil);
+ boardTDestRect = boardTSrcRect;
+ QOffsetRect(&boardTDestRect, 137 + hOffset, 5);
+ TextFont(applFont);
+ TextSize(12);
+ TextFace(bold);
+
+ QSetRect(&boardGSrcRect, 0, 0, 20, 10); // # gliders
+ theErr = CreateOffScreenGWorld(&boardGSrcMap, &boardGSrcRect, kPreferredDepth);
+ SetGWorld(boardGSrcMap, nil);
+ boardGDestRect = boardGSrcRect;
+ QOffsetRect(&boardGDestRect, 526 + hOffset, 5);
+ TextFont(applFont);
+ TextSize(12);
+ TextFace(bold);
+
+ QSetRect(&boardPSrcRect, 0, 0, 64, 10); // points
+ theErr = CreateOffScreenGWorld(&boardPSrcMap, &boardPSrcRect, kPreferredDepth);
+ SetGWorld(boardPSrcMap, nil);
+ boardPDestRect = boardPSrcRect;
+ QOffsetRect(&boardPDestRect, 570 + hOffset, 5); // total = 6396 pixels
+ boardPQDestRect = boardPDestRect;
+ QOffsetRect(&boardPQDestRect, 0, -kScoreboardTall);
+ boardGQDestRect = boardGDestRect;
+ QOffsetRect(&boardGQDestRect, 0, -kScoreboardTall);
+ TextFont(applFont);
+ TextSize(12);
+ TextFace(bold);
+
+ QSetRect(&badgesBlankRects[0], 0, 0, 16, 16); // foil
+ QOffsetRect(&badgesBlankRects[0], 0, 0);
+ QSetRect(&badgesBlankRects[1], 0, 0, 16, 16); // rubber bands
+ QOffsetRect(&badgesBlankRects[1], 0, 16);
+ QSetRect(&badgesBlankRects[2], 0, 0, 16, 17); // battery
+ QOffsetRect(&badgesBlankRects[2], 0, 32);
+ QSetRect(&badgesBlankRects[3], 0, 0, 16, 17); // helium
+ QOffsetRect(&badgesBlankRects[3], 0, 49);
+
+ QSetRect(&badgesBadgesRects[0], 0, 0, 16, 16); // foil
+ QOffsetRect(&badgesBadgesRects[0], 16, 0);
+ QSetRect(&badgesBadgesRects[1], 0, 0, 16, 16); // rubber bands
+ QOffsetRect(&badgesBadgesRects[1], 16, 16);
+ QSetRect(&badgesBadgesRects[2], 0, 0, 16, 17); // battery
+ QOffsetRect(&badgesBadgesRects[2], 16, 32);
+ QSetRect(&badgesBadgesRects[3], 0, 0, 16, 17); // helium
+ QOffsetRect(&badgesBadgesRects[3], 16, 49);
+
+ QSetRect(&badgesDestRects[0], 0, 0, 16, 16); // foil
+ QOffsetRect(&badgesDestRects[0], 432 + hOffset, 2 - kScoreboardTall);
+ QSetRect(&badgesDestRects[1], 0, 0, 16, 16); // rubber bands
+ QOffsetRect(&badgesDestRects[1], 449 + hOffset, 2 - kScoreboardTall);
+ QSetRect(&badgesDestRects[2], 0, 0, 16, 17); // battery
+ QOffsetRect(&badgesDestRects[2], 467 + hOffset, 1 - kScoreboardTall);
+ QSetRect(&badgesDestRects[3], 0, 0, 16, 17); // helium
+ QOffsetRect(&badgesDestRects[3], 467 + hOffset, 1 - kScoreboardTall);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitGliderMap
+// Graphics and structures relating to the little paper glider (theÉ
+// player) are cretaed, loaded up and initialized here.
+
+void InitGliderMap (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+ short i;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&glidSrcRect, 0, 0, kGliderWide, 668); // 32112 pixels
+ theErr = CreateOffScreenGWorld(&glidSrcMap, &glidSrcRect, kPreferredDepth);
+ SetGWorld(glidSrcMap, nil);
+ LoadGraphic(kGliderPictID);
+
+ theErr = CreateOffScreenGWorld(&glid2SrcMap, &glidSrcRect, kPreferredDepth);
+ SetGWorld(glid2SrcMap, nil);
+ LoadGraphic(kGlider2PictID);
+
+ theErr = CreateOffScreenGWorld(&glidMaskMap, &glidSrcRect, 1);
+ SetGWorld(glidMaskMap, nil);
+ LoadGraphic(kGliderPictID + 1000);
+
+ for (i = 0; i <= 20; i++)
+ {
+ QSetRect(&gliderSrc[i], 0, 0, kGliderWide, kGliderHigh);
+ QOffsetRect(&gliderSrc[i], 0, kGliderHigh * i);
+ }
+ for (i = 21; i <= 28; i++)
+ {
+ QSetRect(&gliderSrc[i], 0, 0, kGliderWide, kGliderBurningHigh);
+ QOffsetRect(&gliderSrc[i], 0, 420 + (kGliderBurningHigh * (i - 21)));
+ }
+
+ QSetRect(&gliderSrc[29], 0, 0, kGliderWide, kGliderHigh);
+ QOffsetRect(&gliderSrc[29], 0, 628);
+ QSetRect(&gliderSrc[30], 0, 0, kGliderWide, kGliderHigh);
+ QOffsetRect(&gliderSrc[30], 0, 648);
+
+ QSetRect(&shadowSrcRect, 0, 0, kGliderWide, kShadowHigh * kNumShadowSrcRects);
+ theErr = CreateOffScreenGWorld(&shadowSrcMap, &shadowSrcRect, kPreferredDepth);
+ SetGWorld(shadowSrcMap, nil);
+ LoadGraphic(kShadowPictID);
+
+ theErr = CreateOffScreenGWorld(&shadowMaskMap, &shadowSrcRect, 1);
+ SetGWorld(shadowMaskMap, nil);
+ LoadGraphic(kShadowPictID + 1000);
+
+ for (i = 0; i < kNumShadowSrcRects; i++)
+ {
+ QSetRect(&shadowSrc[i], 0, 0, kGliderWide, kShadowHigh);
+ QOffsetRect(&shadowSrc[i], 0, kShadowHigh * i);
+ }
+
+ QSetRect(&bandsSrcRect, 0, 0, 16, 18); // 304 pixels
+ theErr = CreateOffScreenGWorld(&bandsSrcMap, &bandsSrcRect, kPreferredDepth);
+ SetGWorld(bandsSrcMap, nil);
+ LoadGraphic(kRubberBandsPictID);
+
+ theErr = CreateOffScreenGWorld(&bandsMaskMap, &bandsSrcRect, 1);
+ SetGWorld(bandsMaskMap, nil);
+ LoadGraphic(kRubberBandsPictID + 1000);
+
+ for (i = 0; i < 3; i++)
+ {
+ QSetRect(&bandRects[i], 0, 0, 16, 6);
+ QOffsetRect(&bandRects[i], 0, 6 * i);
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitBlowers
+// All blower graphics and structures are loaded up and initialized here.
+// Blowers include vents, ducts, candles, fans, etc.
+
+void InitBlowers (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ short i;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&blowerSrcRect, 0, 0, 48, 402); // 19344 pixels
+ theErr = CreateOffScreenGWorld(&blowerSrcMap, &blowerSrcRect, kPreferredDepth);
+ SetGWorld(blowerSrcMap, nil);
+ LoadGraphic(kBlowerPictID);
+
+ theErr = CreateOffScreenGWorld(&blowerMaskMap, &blowerSrcRect, 1);
+ SetGWorld(blowerMaskMap, nil);
+ LoadGraphic(kBlowerPictID + 1000);
+
+ for (i = 0; i < kNumCandleFlames; i++)
+ {
+ QSetRect(&flame[i], 0, 0, 16, 15);
+ QOffsetRect(&flame[i], 32, 179 + (i * 15));
+ }
+
+ for (i = 0; i < kNumTikiFlames; i++)
+ {
+ QSetRect(&tikiFlame[i], 0, 0, 8, 10);
+ QOffsetRect(&tikiFlame[i], 40, 69 + (i * 10));
+ }
+
+ for (i = 0; i < kNumBBQCoals; i++)
+ {
+ QSetRect(&coals[i], 0, 0, 32, 9);
+ QOffsetRect(&coals[i], 0, 304 + (i * 9));
+ }
+
+ QSetRect(&leftStartGliderSrc, 0, 0, 48, 16);
+ QOffsetRect(&leftStartGliderSrc, 0, 358);
+
+ QSetRect(&rightStartGliderSrc, 0, 0, 48, 16);
+ QOffsetRect(&rightStartGliderSrc, 0, 374);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitFurniture
+// Structures and graphics relating to the furniture is loaded up.
+// Furniture includes tables, cabinets, shelves, etc.
+
+void InitFurniture (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&furnitureSrcRect, 0, 0, 64, 278); // 17856 pixels
+ theErr = CreateOffScreenGWorld(&furnitureSrcMap, &furnitureSrcRect, kPreferredDepth);
+ SetGWorld(furnitureSrcMap, nil);
+ LoadGraphic(kFurniturePictID);
+
+ theErr = CreateOffScreenGWorld(&furnitureMaskMap, &furnitureSrcRect, 1);
+ SetGWorld(furnitureMaskMap, nil);
+ LoadGraphic(kFurniturePictID + 1000);
+
+ QSetRect(&tableSrc, 0, 0, 64, 22);
+ QOffsetRect(&tableSrc, 0, 0);
+
+ QSetRect(&shelfSrc, 0, 0, 16, 21);
+ QOffsetRect(&shelfSrc, 0, 22);
+
+ QSetRect(&hingeSrc, 0, 0, 4, 16);
+ QOffsetRect(&hingeSrc, 16, 22);
+
+ QSetRect(&handleSrc, 0, 0, 4, 21);
+ QOffsetRect(&handleSrc, 20, 22);
+
+ QSetRect(&knobSrc, 0, 0, 8, 8);
+ QOffsetRect(&knobSrc, 24, 22);
+
+ QSetRect(&leftFootSrc, 0, 0, 16, 16);
+ QOffsetRect(&leftFootSrc, 32, 22);
+
+ QSetRect(&rightFootSrc, 0, 0, 16, 16);
+ QOffsetRect(&rightFootSrc, 48, 22);
+
+ QSetRect(&deckSrc, 0, 0, 64, 21);
+ QOffsetRect(&deckSrc, 0, 162);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitPrizes
+// Structures and graphics relating to the prizes (bonuses) are loaded up.
+// Prizes includes clocks, rubber bands, extra gliders, etc.
+
+void InitPrizes (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ short i;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&bonusSrcRect, 0, 0, 88, 378); // 33264 pixels
+ theErr = CreateOffScreenGWorld(&bonusSrcMap, &bonusSrcRect, kPreferredDepth);
+ SetGWorld(bonusSrcMap, nil);
+ LoadGraphic(kBonusPictID);
+
+ theErr = CreateOffScreenGWorld(&bonusMaskMap, &bonusSrcRect, 1);
+ SetGWorld(bonusMaskMap, nil);
+ LoadGraphic(kBonusPictID + 1000);
+
+ for (i = 0; i < 11; i++)
+ {
+ QSetRect(&digits[i], 0, 0, 4, 6);
+ QOffsetRect(&digits[i], 28, i * 6);
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ QSetRect(&pendulumSrc[i], 0, 0, 32, 28);
+ QOffsetRect(&pendulumSrc[i], 56, 186 + (i * 28));
+ }
+
+ QSetRect(&greaseSrcRt[0], 0, 0, 32, 27);
+ QOffsetRect(&greaseSrcRt[0], 0, 243);
+ QSetRect(&greaseSrcRt[1], 0, 0, 32, 27);
+ QOffsetRect(&greaseSrcRt[1], 0, 270);
+ QSetRect(&greaseSrcRt[2], 0, 0, 32, 27);
+ QOffsetRect(&greaseSrcRt[2], 0, 297);
+ QSetRect(&greaseSrcRt[3], 0, 0, 32, 27);
+ QOffsetRect(&greaseSrcRt[3], 32, 297);
+
+ QSetRect(&greaseSrcLf[0], 0, 0, 32, 27);
+ QOffsetRect(&greaseSrcLf[0], 0, 324);
+ QSetRect(&greaseSrcLf[1], 0, 0, 32, 27);
+ QOffsetRect(&greaseSrcLf[1], 32, 324);
+ QSetRect(&greaseSrcLf[2], 0, 0, 32, 27);
+ QOffsetRect(&greaseSrcLf[2], 0, 351);
+ QSetRect(&greaseSrcLf[3], 0, 0, 32, 27);
+ QOffsetRect(&greaseSrcLf[3], 32, 351);
+
+ for (i = 0; i < 6; i++)
+ {
+ QSetRect(&starSrc[i], 0, 0, 32, 31);
+ QOffsetRect(&starSrc[i], 48, i * 31);
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ QSetRect(&sparkleSrc[i + 2], 0, 0, 20, 19);
+ QOffsetRect(&sparkleSrc[i + 2], 0, 70 + (i * 19));
+ }
+ sparkleSrc[0] = sparkleSrc[4];
+ sparkleSrc[1] = sparkleSrc[3];
+
+ QSetRect(&pointsSrcRect, 0, 0, 24, 120); // 2880 pixels
+ theErr = CreateOffScreenGWorld(&pointsSrcMap, &pointsSrcRect, kPreferredDepth);
+ SetGWorld(pointsSrcMap, nil);
+ LoadGraphic(kPointsPictID);
+
+ theErr = CreateOffScreenGWorld(&pointsMaskMap, &pointsSrcRect, 1);
+ SetGWorld(pointsMaskMap, nil);
+ LoadGraphic(kPointsPictID + 1000);
+
+ for (i = 0; i < 15; i++)
+ {
+ QSetRect(&pointsSrc[i], 0, 0, 24, 8);
+ QOffsetRect(&pointsSrc[i], 0, i * 8);
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitTransports
+// Structures and graphics relating to the transports is loaded up.
+// Transports includes transport ducts, mailboxes, etc.
+
+void InitTransports (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld); // GlidePort: this line was missing?
+
+ QSetRect(&transSrcRect, 0, 0, 56, 32); // 1848 pixels
+ theErr = CreateOffScreenGWorld(&transSrcMap, &transSrcRect, kPreferredDepth);
+ SetGWorld(transSrcMap, nil);
+ LoadGraphic(kTransportPictID);
+
+ theErr = CreateOffScreenGWorld(&transMaskMap, &transSrcRect, 1);
+ SetGWorld(transMaskMap, nil);
+ LoadGraphic(kTransportPictID + 1000);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitSwitches
+// Structures and graphics relating to switches are loaded up.
+// Switches includes triggers, light switches, etc.
+
+void InitSwitches (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&switchSrcRect, 0, 0, 32, 104); // 3360 pixels
+ theErr = CreateOffScreenGWorld(&switchSrcMap, &switchSrcRect, kPreferredDepth);
+ SetGWorld(switchSrcMap, nil);
+ LoadGraphic(kSwitchPictID);
+
+ QSetRect(&lightSwitchSrc[0], 0, 0, 15, 24);
+ QOffsetRect(&lightSwitchSrc[0], 0, 0);
+ QSetRect(&lightSwitchSrc[1], 0, 0, 15, 24);
+ QOffsetRect(&lightSwitchSrc[1], 16, 0);
+
+ QSetRect(&machineSwitchSrc[0], 0, 0, 16, 24);
+ QOffsetRect(&machineSwitchSrc[0], 0, 24);
+ QSetRect(&machineSwitchSrc[1], 0, 0, 16, 24);
+ QOffsetRect(&machineSwitchSrc[1], 16, 24);
+
+ QSetRect(&thermostatSrc[0], 0, 0, 15, 24);
+ QOffsetRect(&thermostatSrc[0], 0, 48);
+ QSetRect(&thermostatSrc[1], 0, 0, 15, 24);
+ QOffsetRect(&thermostatSrc[1], 16, 48);
+
+ QSetRect(&powerSrc[0], 0, 0, 8, 8);
+ QOffsetRect(&powerSrc[0], 0, 72);
+ QSetRect(&powerSrc[1], 0, 0, 8, 8);
+ QOffsetRect(&powerSrc[1], 8, 72);
+
+ QSetRect(&knifeSwitchSrc[0], 0, 0, 16, 24);
+ QOffsetRect(&knifeSwitchSrc[0], 0, 80);
+ QSetRect(&knifeSwitchSrc[1], 0, 0, 16, 24);
+ QOffsetRect(&knifeSwitchSrc[1], 16, 80);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitLights
+// Structures and graphics relating to lights are loaded up.
+// Lights includes table lamps, flourescent lights, track lights, etc.
+
+void InitLights (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ short i;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&lightSrcRect, 0, 0, 72, 126); // 9144 pixels
+ theErr = CreateOffScreenGWorld(&lightSrcMap, &lightSrcRect, kPreferredDepth);
+ SetGWorld(lightSrcMap, nil);
+ LoadGraphic(kLightPictID);
+
+ theErr = CreateOffScreenGWorld(&lightMaskMap, &lightSrcRect, 1);
+ SetGWorld(lightMaskMap, nil);
+ LoadGraphic(kLightPictID + 1000);
+
+ QSetRect(&flourescentSrc1, 0, 0, 16, 12);
+ QOffsetRect(&flourescentSrc1, 0, 78);
+
+ QSetRect(&flourescentSrc2, 0, 0, 16, 12);
+ QOffsetRect(&flourescentSrc2, 0, 90);
+
+ for (i = 0; i < kNumTrackLights; i++)
+ {
+ QSetRect(&trackLightSrc[i], 0, 0, 24, 24);
+ QOffsetRect(&trackLightSrc[i], 24 * i, 102);
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitAppliances
+// Structures and graphics relating to appliances are loaded up.
+// Appliances includes toasters, T.V.s, etc.
+
+void InitAppliances (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ short i;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&applianceSrcRect, 0, 0, 80, 269); // 21600 pixels
+ theErr = CreateOffScreenGWorld(&applianceSrcMap, &applianceSrcRect, kPreferredDepth);
+ SetGWorld(applianceSrcMap, nil);
+ LoadGraphic(kAppliancePictID);
+
+ theErr = CreateOffScreenGWorld(&applianceMaskMap, &applianceSrcRect, 1);
+ SetGWorld(applianceMaskMap, nil);
+ LoadGraphic(kAppliancePictID + 1000);
+
+ QSetRect(&toastSrcRect, 0, 0, 32, 174); // 5600 pixels
+ theErr = CreateOffScreenGWorld(&toastSrcMap, &toastSrcRect, kPreferredDepth);
+ SetGWorld(toastSrcMap, nil);
+ LoadGraphic(kToastPictID);
+
+ theErr = CreateOffScreenGWorld(&toastMaskMap, &toastSrcRect, 1);
+ SetGWorld(toastMaskMap, nil);
+ LoadGraphic(kToastPictID + 1000);
+
+ QSetRect(&shredSrcRect, 0, 0, 40, 35); // 1440 pixels
+ theErr = CreateOffScreenGWorld(&shredSrcMap, &shredSrcRect, kPreferredDepth);
+ SetGWorld(shredSrcMap, nil);
+ LoadGraphic(kShreddedPictID);
+
+ theErr = CreateOffScreenGWorld(&shredMaskMap, &shredSrcRect, 1);
+ SetGWorld(shredMaskMap, nil);
+ LoadGraphic(kShreddedPictID + 1000);
+
+ QSetRect(&plusScreen1, 0, 0, 32, 22);
+ QOffsetRect(&plusScreen1, 48, 127);
+ QSetRect(&plusScreen2, 0, 0, 32, 22);
+ QOffsetRect(&plusScreen2, 48, 149);
+
+ QSetRect(&tvScreen1, 0, 0, 64, 49);
+ QOffsetRect(&tvScreen1, 0, 171);
+ QSetRect(&tvScreen2, 0, 0, 64, 49);
+ QOffsetRect(&tvScreen2, 0, 220);
+
+ QSetRect(&coffeeLight1, 0, 0, 8, 4);
+ QOffsetRect(&coffeeLight1, 72, 171);
+ QSetRect(&coffeeLight2, 0, 0, 8, 4);
+ QOffsetRect(&coffeeLight2, 72, 175);
+
+ for (i = 0; i < kNumOutletPicts; i++)
+ {
+ QSetRect(&outletSrc[i], 0, 0, 16, 24);
+ QOffsetRect(&outletSrc[i], 64, 22 + (i * 24));
+ }
+
+ for (i = 0; i < kNumBreadPicts; i++)
+ {
+ QSetRect(&breadSrc[i], 0, 0, 32, 29);
+ QOffsetRect(&breadSrc[i], 0, i * 29);
+ }
+
+ QSetRect(&vcrTime1, 0, 0, 16, 4);
+ QOffsetRect(&vcrTime1, 64, 179);
+ QSetRect(&vcrTime2, 0, 0, 16, 4);
+ QOffsetRect(&vcrTime2, 64, 183);
+
+ QSetRect(&stereoLight1, 0, 0, 4, 1);
+ QOffsetRect(&stereoLight1, 68, 171);
+ QSetRect(&stereoLight2, 0, 0, 4, 1);
+ QOffsetRect(&stereoLight2, 68, 172);
+
+ QSetRect(µOn, 0, 0, 16, 35);
+ QOffsetRect(µOn, 64, 222);
+ QSetRect(µOff, 0, 0, 16, 35);
+ QOffsetRect(µOff, 64, 187);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitEnemies
+// Structures and graphics relating to enemies are loaded up.
+// Enemies includes darts, balloons, fish, etc.
+
+void InitEnemies (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ short i;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&balloonSrcRect, 0, 0, 24, 30 * kNumBalloonFrames);
+ theErr = CreateOffScreenGWorld(&balloonSrcMap, &balloonSrcRect, kPreferredDepth);
+ SetGWorld(balloonSrcMap, nil);
+ LoadGraphic(kBalloonPictID);
+
+ theErr = CreateOffScreenGWorld(&balloonMaskMap, &balloonSrcRect, 1);
+ SetGWorld(balloonMaskMap, nil);
+ LoadGraphic(kBalloonPictID + 1000);
+
+ QSetRect(&copterSrcRect, 0, 0, 32, 30 * kNumCopterFrames);
+ theErr = CreateOffScreenGWorld(&copterSrcMap, &copterSrcRect, kPreferredDepth);
+ SetGWorld(copterSrcMap, nil);
+ LoadGraphic(kCopterPictID);
+
+ theErr = CreateOffScreenGWorld(&copterMaskMap, &copterSrcRect, 1);
+ SetGWorld(copterMaskMap, nil);
+ LoadGraphic(kCopterPictID + 1000);
+
+ QSetRect(&dartSrcRect, 0, 0, 64, 19 * kNumDartFrames);
+ theErr = CreateOffScreenGWorld(&dartSrcMap, &dartSrcRect, kPreferredDepth);
+ SetGWorld(dartSrcMap, nil);
+ LoadGraphic(kDartPictID);
+
+ theErr = CreateOffScreenGWorld(&dartMaskMap, &dartSrcRect, 1);
+ SetGWorld(dartMaskMap, nil);
+ LoadGraphic(kDartPictID + 1000);
+
+ QSetRect(&ballSrcRect, 0, 0, 32, 32 * kNumBallFrames);
+ theErr = CreateOffScreenGWorld(&ballSrcMap, &ballSrcRect, kPreferredDepth);
+ SetGWorld(ballSrcMap, nil);
+ LoadGraphic(kBallPictID);
+
+ theErr = CreateOffScreenGWorld(&ballMaskMap, &ballSrcRect, 1);
+ SetGWorld(ballMaskMap, nil);
+ LoadGraphic(kBallPictID + 1000);
+
+ QSetRect(&dripSrcRect, 0, 0, 16, 12 * kNumDripFrames);
+ theErr = CreateOffScreenGWorld(&dripSrcMap, &dripSrcRect, kPreferredDepth);
+ SetGWorld(dripSrcMap, nil);
+ LoadGraphic(kDripPictID);
+
+ theErr = CreateOffScreenGWorld(&dripMaskMap, &dripSrcRect, 1);
+ SetGWorld(dripMaskMap, nil);
+ LoadGraphic(kDripPictID + 1000);
+
+ QSetRect(&enemySrcRect, 0, 0, 36, 33);
+ theErr = CreateOffScreenGWorld(&enemySrcMap, &enemySrcRect, kPreferredDepth);
+ SetGWorld(enemySrcMap, nil);
+ LoadGraphic(kEnemyPictID);
+
+ theErr = CreateOffScreenGWorld(&enemyMaskMap, &enemySrcRect, 1);
+ SetGWorld(enemyMaskMap, nil);
+ LoadGraphic(kEnemyPictID + 1000);
+
+ QSetRect(&fishSrcRect, 0, 0, 16, 16 * kNumFishFrames);
+ theErr = CreateOffScreenGWorld(&fishSrcMap, &fishSrcRect, kPreferredDepth);
+ SetGWorld(fishSrcMap, nil);
+ LoadGraphic(kFishPictID);
+
+ theErr = CreateOffScreenGWorld(&fishMaskMap, &fishSrcRect, 1);
+ SetGWorld(fishMaskMap, nil);
+ LoadGraphic(kFishPictID + 1000);
+
+ for (i = 0; i < kNumBalloonFrames; i++)
+ {
+ QSetRect(&balloonSrc[i], 0, 0, 24, 30);
+ QOffsetRect(&balloonSrc[i], 0, 30 * i);
+ }
+
+ for (i = 0; i < kNumCopterFrames; i++)
+ {
+ QSetRect(&copterSrc[i], 0, 0, 32, 30);
+ QOffsetRect(&copterSrc[i], 0, 30 * i);
+ }
+
+ for (i = 0; i < kNumDartFrames; i++)
+ {
+ QSetRect(&dartSrc[i], 0, 0, 64, 19);
+ QOffsetRect(&dartSrc[i], 0, 19 * i);
+ }
+
+ for (i = 0; i < kNumBallFrames; i++)
+ {
+ QSetRect(&ballSrc[i], 0, 0, 32, 32);
+ QOffsetRect(&ballSrc[i], 0, 32 * i);
+ }
+
+ for (i = 0; i < kNumDripFrames; i++)
+ {
+ QSetRect(&dripSrc[i], 0, 0, 16, 12);
+ QOffsetRect(&dripSrc[i], 0, 12 * i);
+ }
+
+ for (i = 0; i < kNumFishFrames; i++)
+ {
+ QSetRect(&fishSrc[i], 0, 0, 16, 16);
+ QOffsetRect(&fishSrc[i], 0, 16 * i);
+ }
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
diff --git a/GpApp/StructuresInit2.cpp b/GpApp/StructuresInit2.cpp
new file mode 100644
index 0000000..81e9f39
--- /dev/null
+++ b/GpApp/StructuresInit2.cpp
@@ -0,0 +1,477 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// StructuresInit2.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLResources.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "GameOver.h"
+#include "MainWindow.h"
+#include "Objects.h"
+#include "RectUtils.h"
+#include "Room.h"
+#include "RoomGraphics.h"
+#include "Utilities.h"
+
+
+#define kAngelPictID 1019
+#define kSupportPictID 1999
+#define kClutterPictID 4018
+
+
+void InitClutter (void);
+void InitSupport (void);
+void InitAngel (void);
+
+
+extern Rect suppSrcRect, justRoomsRect;
+extern Rect tileSrcRect, angelSrcRect;
+extern GDHandle thisGDevice;
+extern CGrafPtr tileSrcMap;
+extern FSSpecPtr theHousesSpecs;
+extern hotPtr hotSpots;
+extern sparklePtr sparkles;
+extern flyingPtPtr flyingPoints;
+extern flamePtr flames, tikiFlames, bbqCoals;
+extern pendulumPtr pendulums;
+extern bandPtr bands;
+extern greasePtr grease;
+extern starPtr theStars;
+extern shredPtr shreds;
+extern dynaPtr dinahs;
+extern demoPtr demoData;
+extern short maxFiles;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- InitClutter
+// Structures and graphics relating to clutter are loaded up.
+// Clutter includes mirrors, teddy bears, fireplaces, calendars, etc.
+
+void InitClutter (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&clutterSrcRect, 0, 0, 128, 69);
+ theErr = CreateOffScreenGWorld(&clutterSrcMap, &clutterSrcRect, kPreferredDepth);
+ SetGWorld(clutterSrcMap, nil);
+ LoadGraphic(kClutterPictID);
+
+ theErr = CreateOffScreenGWorld(&clutterMaskMap, &clutterSrcRect, 1);
+ SetGWorld(clutterMaskMap, nil);
+ LoadGraphic(kClutterPictID + 1000);
+
+ QSetRect(&flowerSrc[0], 0, 0, 10, 28);
+ QOffsetRect(&flowerSrc[0], 0, 23);
+
+ QSetRect(&flowerSrc[1], 0, 0, 24, 35);
+ QOffsetRect(&flowerSrc[1], 10, 16);
+
+ QSetRect(&flowerSrc[2], 0, 0, 34, 35);
+ QOffsetRect(&flowerSrc[2], 34, 16);
+
+ QSetRect(&flowerSrc[3], 0, 0, 27, 23);
+ QOffsetRect(&flowerSrc[3], 68, 14);
+
+ QSetRect(&flowerSrc[4], 0, 0, 27, 14);
+ QOffsetRect(&flowerSrc[4], 68, 37);
+
+ QSetRect(&flowerSrc[5], 0, 0, 32, 51);
+ QOffsetRect(&flowerSrc[5], 95, 0);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitSupport
+// The floor support grphic is loaded up. It is only visible whenÉ
+// playing in 9-room mode. It is the horizontal wooden beam thatÉ
+// seperates floors from one another.
+
+void InitSupport (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&suppSrcRect, 0, 0, kRoomWide, kFloorSupportTall); // 44
+ theErr = CreateOffScreenGWorld(&suppSrcMap, &suppSrcRect, kPreferredDepth);
+ SetGWorld(suppSrcMap, nil);
+ LoadGraphic(kSupportPictID);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- InitAngel
+// This loads the graphic of the girl riding the glider. It is seenÉ
+// only upon completing a house. She flies across the screen droppingÉ
+// stars below.
+
+void InitAngel (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&angelSrcRect, 0, 0, 96, 44);
+ theErr = CreateOffScreenGWorld(&angelSrcMap, &angelSrcRect, kPreferredDepth);
+ SetGWorld(angelSrcMap, nil);
+ LoadGraphic(kAngelPictID);
+
+ theErr = CreateOffScreenGWorld(&angelMaskMap, &angelSrcRect, 1);
+ SetGWorld(angelMaskMap, nil);
+ LoadGraphic(kAngelPictID + 1);
+
+ SetGWorld(wasCPort, wasWorld);
+}
+
+//-------------------------------------------------------------- CreateOffscreens
+// All "utility" or "work" offscreen pix/bit maps are created here.
+// These would be offscreens that are reused throughout a game - theyÉ
+// are not static (mere repositories for graphics). Most are usedÉ
+// to facilitate the animation when a game is in progress.
+
+void CreateOffscreens (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ GetGWorld(&wasCPort, &wasWorld);
+
+ justRoomsRect = houseRect;
+ ZeroRectCorner(&justRoomsRect);
+
+ workSrcRect = houseRect; // Set up work map
+ ZeroRectCorner(&workSrcRect);
+ theErr = CreateOffScreenGWorld(&workSrcMap, &workSrcRect, kPreferredDepth);
+
+ backSrcRect = houseRect; // Set up background map
+ ZeroRectCorner(&backSrcRect);
+ theErr = CreateOffScreenGWorld(&backSrcMap, &backSrcRect, kPreferredDepth);
+
+ InitScoreboardMap(); SpinCursor(1);
+ InitGliderMap(); SpinCursor(1);
+ InitBlowers(); SpinCursor(1);
+ InitFurniture(); SpinCursor(1);
+ InitPrizes(); SpinCursor(1);
+ InitTransports(); SpinCursor(1);
+ InitSwitches(); SpinCursor(1);
+ InitLights(); SpinCursor(1);
+ InitAppliances(); SpinCursor(1);
+ InitEnemies(); SpinCursor(1);
+ InitClutter(); SpinCursor(1);
+ InitSupport(); SpinCursor(1);
+ InitAngel(); SpinCursor(1);
+
+ QSetRect(&tileSrcRect, 0, 0, 128, 80);
+ tileSrcMap = nil;
+// ????
+}
+
+//-------------------------------------------------------------- CreatePointers
+// This function allocates other large structures. Pointers to holdÉ
+// large arrays, etc.
+
+void CreatePointers (void)
+{
+ Handle tempHandle;
+
+ thisRoom = nil;
+ thisRoom = (roomPtr)NewPtr(sizeof(roomType));
+ if (thisRoom == nil)
+ RedAlert(kErrNoMemory);
+
+ hotSpots = nil;
+ hotSpots = (hotPtr)NewPtr(sizeof(hotObject) * kMaxHotSpots);
+ if (hotSpots == nil)
+ RedAlert(kErrNoMemory);
+
+ sparkles = nil;
+ sparkles = (sparklePtr)NewPtr(sizeof(sparkleType) * kMaxSparkles);
+ if (sparkles == nil)
+ RedAlert(kErrNoMemory);
+
+ flyingPoints = nil;
+ flyingPoints = (flyingPtPtr)NewPtr(sizeof(flyingPtType) * kMaxFlyingPts);
+ if (flyingPoints == nil)
+ RedAlert(kErrNoMemory);
+
+ flames = nil;
+ flames = (flamePtr)NewPtr(sizeof(flameType) * kMaxCandles);
+ if (flames == nil)
+ RedAlert(kErrNoMemory);
+
+ tikiFlames = nil;
+ tikiFlames = (flamePtr)NewPtr(sizeof(flameType) * kMaxTikis);
+ if (tikiFlames == nil)
+ RedAlert(kErrNoMemory);
+
+ bbqCoals = nil;
+ bbqCoals = (flamePtr)NewPtr(sizeof(flameType) * kMaxCoals);
+ if (bbqCoals == nil)
+ RedAlert(kErrNoMemory);
+
+ pendulums = nil;
+ pendulums = (pendulumPtr)NewPtr(sizeof(pendulumType) * kMaxPendulums);
+ if (pendulums == nil)
+ RedAlert(kErrNoMemory);
+
+ // GlidePort: This is broken code, savedMaps is a flat buffer
+ /*
+ savedMaps = nil;
+ savedMaps = (savedPtr)NewPtr(sizeof(savedType) * kMaxSavedMaps);
+ if (savedMaps == nil)
+ RedAlert(kErrNoMemory);
+
+ for (i = 0; i < kMaxSavedMaps; i++)
+ savedMaps[i].map = nil;
+ */
+
+ bands = nil;
+ bands = (bandPtr)NewPtr(sizeof(bandType) * kMaxRubberBands);
+ if (bands == nil)
+ RedAlert(kErrNoMemory);
+
+ grease = nil;
+ grease = (greasePtr)NewPtr(sizeof(greaseType) * kMaxGrease);
+ if (grease == nil)
+ RedAlert(kErrNoMemory);
+
+ theStars = nil;
+ theStars = (starPtr)NewPtr(sizeof(starType) * kMaxStars);
+ if (theStars == nil)
+ RedAlert(kErrNoMemory);
+
+ shreds = nil;
+ shreds = (shredPtr)NewPtr(sizeof(shredType) * kMaxShredded);
+ if (shreds == nil)
+ RedAlert(kErrNoMemory);
+
+ dinahs = nil;
+ dinahs = (dynaPtr)NewPtr(sizeof(dynaType) * kMaxDynamicObs);
+ if (dinahs == nil)
+ RedAlert(kErrNoMemory);
+
+ masterObjects = nil;
+ masterObjects = (objDataPtr)NewPtr(sizeof(objDataType) * kMaxMasterObjects);
+ if (masterObjects == nil)
+ RedAlert(kErrNoMemory);
+
+ srcRects = nil;
+ srcRects = (Rect *)NewPtr(sizeof(Rect) * kNumSrcRects);
+ if (srcRects == nil)
+ RedAlert(kErrNoMemory);
+
+ theHousesSpecs = nil;
+ theHousesSpecs = (FSSpecPtr)NewPtr(sizeof(FSSpec) * maxFiles);
+ if (theHousesSpecs == nil)
+ RedAlert(kErrNoMemory);
+
+#ifdef CREATEDEMODATA
+ demoData = nil;
+ demoData = (demoPtr)NewPtr(sizeof(demoType) * 2000);
+ if (demoData == nil)
+ RedAlert(kErrNoMemory);
+#else
+ demoData = nil;
+ demoData = (demoPtr)NewPtr(kDemoLength);
+ if (demoData == nil)
+ RedAlert(kErrNoMemory);
+ tempHandle = GetResource('demo', 128);
+ if (tempHandle == nil)
+ RedAlert(kErrNoMemory);
+ else
+ {
+ BlockMove(*tempHandle, demoData, kDemoLength);
+ ReleaseResource(tempHandle);
+ }
+#endif
+}
+
+//-------------------------------------------------------------- InitSrcRects
+
+// This is a nasty, ugly function that initializes all global rectanglesÉ
+// used in Glider PRO.
+
+void InitSrcRects (void)
+{
+ QSetRect(&srcRects[kFloorVent], 0, 0, 48, 11); // Blowers
+ QOffsetRect(&srcRects[kFloorVent], 0, 0);
+ QSetRect(&srcRects[kCeilingVent], 0, 0, 48, 11);
+ QOffsetRect(&srcRects[kCeilingVent], 0, 11);
+ QSetRect(&srcRects[kFloorBlower], 0, 0, 48, 15);
+ QOffsetRect(&srcRects[kFloorBlower], 0, 22);
+ QSetRect(&srcRects[kCeilingBlower], 0, 0, 48, 15);
+ QOffsetRect(&srcRects[kCeilingBlower], 0, 37);
+ QSetRect(&srcRects[kSewerGrate], 0, 0, 48, 17);
+ QOffsetRect(&srcRects[kSewerGrate], 0, 52);
+ QSetRect(&srcRects[kLeftFan], 0, 0, 40, 55);
+ QOffsetRect(&srcRects[kLeftFan], 0, 69);
+ QSetRect(&srcRects[kRightFan], 0, 0, 40, 55);
+ QOffsetRect(&srcRects[kRightFan], 0, 124);
+ QSetRect(&srcRects[kTaper], 0, 0, 20, 59);
+ QOffsetRect(&srcRects[kTaper], 0, 209);
+ QSetRect(&srcRects[kCandle], 0, 0, 32, 30);
+ QOffsetRect(&srcRects[kCandle], 0, 179);
+ QSetRect(&srcRects[kStubby], 0, 0, 20, 36);
+ QOffsetRect(&srcRects[kStubby], 0, 268);
+ QSetRect(&srcRects[kTiki], 0, 0, 27, 28);
+ QOffsetRect(&srcRects[kTiki], 21, 268);
+ QSetRect(&srcRects[kBBQ], 0, 0, 64, 33);
+ QSetRect(&srcRects[kInvisBlower], 0, 0, 24, 24);
+ QSetRect(&srcRects[kGrecoVent], 0, 0, 48, 18);
+ QOffsetRect(&srcRects[kGrecoVent], 0, 340);
+ QSetRect(&srcRects[kSewerBlower], 0, 0, 32, 12);
+ QOffsetRect(&srcRects[kSewerBlower], 0, 390);
+ QSetRect(&srcRects[kLiftArea], 0, 0, 64, 32);
+
+ QSetRect(&srcRects[kTable], 0, 0, 64, kTableThick); // Furniture
+ QSetRect(&srcRects[kShelf], 0, 0, 64, kShelfThick);
+ QSetRect(&srcRects[kCabinet], 0, 0, 64, 64);
+ QSetRect(&srcRects[kFilingCabinet], 0, 0, 74, 107);
+ QSetRect(&srcRects[kWasteBasket], 0, 0, 64, 61);
+ QOffsetRect(&srcRects[kWasteBasket], 0, 43);
+ QSetRect(&srcRects[kMilkCrate], 0, 0, 64, 58);
+ QOffsetRect(&srcRects[kMilkCrate], 0, 104);
+ QSetRect(&srcRects[kCounter], 0, 0, 128, 64);
+ QSetRect(&srcRects[kDresser], 0, 0, 128, 64);
+ QSetRect(&srcRects[kDeckTable], 0, 0, 64, kTableThick);
+ QSetRect(&srcRects[kStool], 0, 0, 48, 38);
+ QOffsetRect(&srcRects[kStool], 0, 183);
+ QSetRect(&srcRects[kTrunk], 0, 0, 144, 80);
+ QSetRect(&srcRects[kInvisObstacle], 0, 0, 64, 64);
+ QSetRect(&srcRects[kManhole], 0, 0, 123, 22);
+ QSetRect(&srcRects[kBooks], 0, 0, 64, 51);
+ QSetRect(&srcRects[kInvisBounce], 0, 0, 64, 64);
+
+ QSetRect(&srcRects[kRedClock], 0, 0, 28, 17); // Prizes
+ QSetRect(&srcRects[kBlueClock], 0, 0, 28, 25);
+ QOffsetRect(&srcRects[kBlueClock], 0, 17);
+ QSetRect(&srcRects[kYellowClock], 0, 0, 28, 28);
+ QOffsetRect(&srcRects[kYellowClock], 0, 42);
+ QSetRect(&srcRects[kCuckoo], 0, 0, 40, 80);
+ QOffsetRect(&srcRects[kCuckoo], 0, 148);
+ QSetRect(&srcRects[kPaper], 0, 0, 48, 21);
+ QOffsetRect(&srcRects[kPaper], 0, 127);
+ QSetRect(&srcRects[kBattery], 0, 0, 16, 25);
+ QOffsetRect(&srcRects[kBattery], 32, 0);
+ QSetRect(&srcRects[kBands], 0, 0, 28, 23);
+ QOffsetRect(&srcRects[kBands], 20, 70);
+ QSetRect(&srcRects[kGreaseRt], 0, 0, 32, 27);
+ QOffsetRect(&srcRects[kGreaseRt], 0, 243);
+ QSetRect(&srcRects[kGreaseLf], 0, 0, 32, 27);
+ QOffsetRect(&srcRects[kGreaseLf], 0, 324);
+ QSetRect(&srcRects[kFoil], 0, 0, 55, 15);
+ QOffsetRect(&srcRects[kFoil], 0, 228);
+ QSetRect(&srcRects[kInvisBonus], 0, 0, 24, 24);
+ QSetRect(&srcRects[kStar], 0, 0, 32, 31);
+ QOffsetRect(&srcRects[kStar], 48, 0);
+ QSetRect(&srcRects[kSparkle], 0, 0, 20, 19);
+ QOffsetRect(&srcRects[kSparkle], 0, 70);
+ QSetRect(&srcRects[kHelium], 0, 0, 56, 16);
+ QOffsetRect(&srcRects[kHelium], 32, 270);
+ QSetRect(&srcRects[kSlider], 0, 0, 64, 16);
+
+ QSetRect(&srcRects[kUpStairs], 0, 0, 160, 267); // Transport
+ QSetRect(&srcRects[kDownStairs], 0, 0, 160, 267);
+ QSetRect(&srcRects[kMailboxLf], 0, 0, 94, 80);
+ QSetRect(&srcRects[kMailboxRt], 0, 0, 94, 80);
+ QSetRect(&srcRects[kFloorTrans], 0, 0, 56, 15);
+ QOffsetRect(&srcRects[kFloorTrans], 0, 1);
+ QSetRect(&srcRects[kCeilingTrans], 0, 0, 56, 15);
+ QOffsetRect(&srcRects[kCeilingTrans], 0, 16);
+ QSetRect(&srcRects[kDoorInLf], 0, 0, 144, 322);
+ QSetRect(&srcRects[kDoorInRt], 0, 0, 144, 322);
+ QSetRect(&srcRects[kDoorExRt], 0, 0, 16, 322);
+ QSetRect(&srcRects[kDoorExLf], 0, 0, 16, 322);
+ QSetRect(&srcRects[kWindowInLf], 0, 0, 20, 170);
+ QSetRect(&srcRects[kWindowInRt], 0, 0, 20, 170);
+ QSetRect(&srcRects[kWindowExRt], 0, 0, 16, 170);
+ QSetRect(&srcRects[kWindowExLf], 0, 0, 16, 170);
+ QSetRect(&srcRects[kInvisTrans], 0, 0, 64, 32);
+ QSetRect(&srcRects[kDeluxeTrans], 0, 0, 64, 64);
+
+ QSetRect(&srcRects[kLightSwitch], 0, 0, 15, 24); // Switch
+ QSetRect(&srcRects[kMachineSwitch], 0, 0, 16, 24);
+ QOffsetRect(&srcRects[kMachineSwitch], 0, 48);
+ QSetRect(&srcRects[kThermostat], 0, 0, 15, 24);
+ QOffsetRect(&srcRects[kThermostat], 0, 48);
+ QSetRect(&srcRects[kPowerSwitch], 0, 0, 8, 8);
+ QOffsetRect(&srcRects[kPowerSwitch], 0, 72);
+ QSetRect(&srcRects[kKnifeSwitch], 0, 0, 16, 24);
+ QOffsetRect(&srcRects[kKnifeSwitch], 0, 80);
+ QSetRect(&srcRects[kInvisSwitch], 0, 0, 12, 12);
+ QSetRect(&srcRects[kTrigger], 0, 0, 12, 12);
+ QSetRect(&srcRects[kLgTrigger], 0, 0, 48, 48);
+ QSetRect(&srcRects[kSoundTrigger], 0, 0, 32, 32);
+
+ QSetRect(&srcRects[kCeilingLight], 0, 0, 64, 20); // Lights
+ QOffsetRect(&srcRects[kCeilingLight], 0, 0);
+ QSetRect(&srcRects[kLightBulb], 0, 0, 16, 28);
+ QOffsetRect(&srcRects[kLightBulb], 0, 20);
+ QSetRect(&srcRects[kTableLamp], 0, 0, 48, 70);
+ QOffsetRect(&srcRects[kTableLamp], 16, 20);
+ QSetRect(&srcRects[kHipLamp], 0, 0, 72, 276);
+ QSetRect(&srcRects[kDecoLamp], 0, 0, 64, 212);
+ QSetRect(&srcRects[kFlourescent], 0, 0, 64, 12);
+ QSetRect(&srcRects[kTrackLight], 0, 0, 64, 24);
+ QSetRect(&srcRects[kInvisLight], 0, 0, 16, 16);
+
+ QSetRect(&srcRects[kShredder], 0, 0, 73, 22); // Appliances
+ QSetRect(&srcRects[kToaster], 0, 0, 48, 27);
+ QOffsetRect(&srcRects[kToaster], 0, 22);
+ QSetRect(&srcRects[kMacPlus], 0, 0, 48, 58);
+ QOffsetRect(&srcRects[kMacPlus], 0, 49);
+ QSetRect(&srcRects[kGuitar], 0, 0, 64, 172);
+ QSetRect(&srcRects[kTV], 0, 0, 92, 77);
+ QSetRect(&srcRects[kCoffee], 0, 0, 43, 64);
+ QOffsetRect(&srcRects[kCoffee], 0, 107);
+ QSetRect(&srcRects[kOutlet], 0, 0, 16, 24);
+ QOffsetRect(&srcRects[kOutlet], 64, 22);
+ QSetRect(&srcRects[kVCR], 0, 0, 96, 22);
+ QSetRect(&srcRects[kStereo], 0, 0, 128, 53);
+ QSetRect(&srcRects[kMicrowave], 0, 0, 92, 59);
+ QSetRect(&srcRects[kCinderBlock], 0, 0, 40, 62);
+ QSetRect(&srcRects[kFlowerBox], 0, 0, 80, 32);
+ QSetRect(&srcRects[kCDs], 0, 0, 16, 30);
+ QOffsetRect(&srcRects[kCDs], 48, 22);
+ QSetRect(&srcRects[kCustomPict], 0, 0, 72, 34);
+
+ QSetRect(&srcRects[kBalloon], 0, 0, 24, 30); // Enemies
+ QSetRect(&srcRects[kCopterLf], 0, 0, 32, 30);
+ QSetRect(&srcRects[kCopterRt], 0, 0, 32, 30);
+ QSetRect(&srcRects[kDartLf], 0, 0, 64, 19);
+ QSetRect(&srcRects[kDartRt], 0, 0, 64, 19);
+ QSetRect(&srcRects[kBall], 0, 0, 32, 32);
+ QSetRect(&srcRects[kDrip], 0, 0, 16, 12);
+ QSetRect(&srcRects[kFish], 0, 0, 36, 33);
+ QSetRect(&srcRects[kCobweb], 0, 0, 54, 45);
+
+ QSetRect(&srcRects[kOzma], 0, 0, 102, 92); // Clutter
+ QSetRect(&srcRects[kMirror], 0, 0, 64, 64);
+ QSetRect(&srcRects[kMousehole], 0, 0, 10, 11);
+ QSetRect(&srcRects[kFireplace], 0, 0, 180, 142);
+ QSetRect(&srcRects[kWallWindow], 0, 0, 64, 80);
+ QSetRect(&srcRects[kBear], 0, 0, 56, 58);
+ QSetRect(&srcRects[kCalendar], 0, 0, 63, 92);
+ QSetRect(&srcRects[kVase1], 0, 0, 36, 45);
+ QSetRect(&srcRects[kVase2], 0, 0, 35, 57);
+ QSetRect(&srcRects[kBulletin], 0, 0, 80, 58);
+ QSetRect(&srcRects[kCloud], 0, 0, 128, 30);
+ QSetRect(&srcRects[kFaucet], 0, 0, 56, 18);
+ QOffsetRect(&srcRects[kFaucet], 0, 51);
+ QSetRect(&srcRects[kRug], 0, 0, 144, 18);
+ QSetRect(&srcRects[kChimes], 0, 0, 28, 74);
+}
+
diff --git a/GpApp/Tools.cpp b/GpApp/Tools.cpp
new file mode 100644
index 0000000..9a55cae
--- /dev/null
+++ b/GpApp/Tools.cpp
@@ -0,0 +1,546 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Tools.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLTextUtils.h"
+#include "PLControlDefinitions.h"
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "RectUtils.h"
+#include "Utilities.h"
+
+
+#define kToolsHigh 4
+#define kToolsWide 4
+#define kTotalTools 16 // kToolsHigh * kToolsWide
+#define kPopUpControl 129
+#define kFirstBlower 1
+#define kLastBlower 15
+#define kBlowerBase 1
+#define kFirstFurniture 1
+#define kLastFurniture 15
+#define kFurnitureBase 21
+#define kFirstBonus 1
+#define kLastBonus 15
+#define kBonusBase 41
+#define kFirstTransport 1
+#define kLastTransport 12
+#define kTransportBase 61
+#define kFirstSwitch 1
+#define kLastSwitch 9
+#define kSwitchBase 81
+#define kFirstLight 1
+#define kLastLight 8
+#define kLightBase 101
+#define kFirstAppliance 1
+#define kLastAppliance 14
+#define kApplianceBase 121
+#define kFirstEnemy 1
+#define kLastEnemy 9
+#define kEnemyBase 141
+#define kFirstClutter 1
+#define kLastClutter 15
+#define kClutterBase 161
+#define kToolsPictID 1011
+
+
+void CreateToolsOffscreen (void);
+void KillToolsOffscreen (void);
+void FrameSelectedTool (void);
+void DrawToolName (void);
+void DrawToolTiles (void);
+void SwitchToolModes (short);
+
+
+Rect toolsWindowRect, toolSrcRect, toolTextRect;
+Rect toolRects[kTotalTools];
+ControlHandle classPopUp;
+GWorldPtr toolSrcMap;
+WindowPtr toolsWindow;
+short isToolsH, isToolsV;
+short toolSelected, toolMode;
+short firstTool, lastTool, objectBase;
+Boolean isToolsOpen;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- CreateToolsOffscreen
+
+#ifndef COMPILEDEMO
+void CreateToolsOffscreen (void)
+{
+ CGrafPtr wasCPort;
+ GDHandle wasWorld;
+ OSErr theErr;
+
+ if (toolSrcMap == nil)
+ {
+ GetGWorld(&wasCPort, &wasWorld);
+
+ QSetRect(&toolSrcRect, 0, 0, 360, 216);
+ theErr = CreateOffScreenGWorld(&toolSrcMap, &toolSrcRect, kPreferredDepth);
+ SetGWorld(toolSrcMap, nil);
+ LoadGraphic(kToolsPictID);
+
+ SetGWorld(wasCPort, wasWorld);
+ }
+}
+#endif
+
+//-------------------------------------------------------------- KillToolsOffscreen
+
+#ifndef COMPILEDEMO
+void KillToolsOffscreen (void)
+{
+ if (toolSrcMap != nil)
+ {
+ DisposeGWorld(toolSrcMap);
+// KillOffScreenPixMap(toolSrcMap);
+ toolSrcMap = nil;
+ }
+}
+#endif
+
+//-------------------------------------------------------------- FrameSelectedTool
+
+#ifndef COMPILEDEMO
+void FrameSelectedTool (void)
+{
+ Rect theRect;
+ short toolIcon;
+
+ toolIcon = toolSelected;
+ if ((toolMode == kBlowerMode) && (toolIcon >= 7))
+ {
+ toolIcon--;
+ }
+ else if ((toolMode == kTransportMode) && (toolIcon >= 7))
+ {
+ if (toolIcon >= 15)
+ toolIcon -= 4;
+ else
+ toolIcon = ((toolIcon - 7) / 2) + 7;
+ }
+
+ theRect = toolRects[toolIcon];
+ PenSize(2, 2);
+ ForeColor(redColor);
+ FrameRect(&theRect);
+ PenNormal();
+ ForeColor(blackColor);
+}
+#endif
+
+//-------------------------------------------------------------- DrawToolName
+
+#ifndef COMPILEDEMO
+void DrawToolName (void)
+{
+ Str255 theString;
+
+ if (toolSelected == 0)
+ PasStringCopy(PSTR("Selection Tool"), theString);
+ else
+ GetIndString(theString, kObjectNameStrings,
+ toolSelected + ((toolMode - 1) * 0x0010));
+
+ EraseRect(&toolTextRect);
+ MoveTo(toolTextRect.left + 3, toolTextRect.bottom - 6);
+ TextFont(applFont);
+ TextSize(9);
+ TextFace(bold);
+ ColorText(theString, 171L);
+}
+#endif
+
+//-------------------------------------------------------------- DrawToolTiles
+
+#ifndef COMPILEDEMO
+void DrawToolTiles (void)
+{
+ Rect srcRect, destRect;
+ short i;
+
+ DrawCIcon(2000, toolRects[0].left, toolRects[0].top); // Selection Tool
+
+ for (i = 0; i < 15; i++) // Other tools
+ {
+ QSetRect(&srcRect, 0, 0, 24, 24);
+ QSetRect(&destRect, 0, 0, 24, 24);
+
+ QOffsetRect(&srcRect, i * 24, (toolMode - 1) * 24);
+ QOffsetRect(&destRect, toolRects[i + 1].left + 2, toolRects[i + 1].top + 2);
+
+ CopyBits((BitMap *)*GetGWorldPixMap(toolSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(toolsWindow)),
+ &srcRect, &destRect, srcCopy, nil);
+ }
+}
+#endif
+
+//-------------------------------------------------------------- EraseSelectedTool
+
+void EraseSelectedTool (void)
+{
+#ifndef COMPILEDEMO
+ Rect theRect;
+ short toolIcon;
+
+ if (toolsWindow == nil)
+ return;
+
+ SetPort((GrafPtr)toolsWindow);
+
+ toolIcon = toolSelected;
+ if ((toolMode == kBlowerMode) && (toolIcon >= 7))
+ {
+ toolIcon--;
+ }
+ else if ((toolMode == kTransportMode) && (toolIcon >= 7))
+ {
+ if (toolIcon >= 15)
+ toolIcon -= 4;
+ else
+ toolIcon = ((toolIcon - 7) / 2) + 7;
+ }
+
+ theRect = toolRects[toolIcon];
+ PenSize(2, 2);
+ ForeColor(whiteColor);
+ FrameRect(&theRect);
+#endif
+}
+
+//-------------------------------------------------------------- SelectTool
+
+void SelectTool (short which)
+{
+#ifndef COMPILEDEMO
+ Rect theRect;
+ short toolIcon;
+
+ if (toolsWindow == nil)
+ return;
+
+ SetPort((GrafPtr)toolsWindow);
+
+ toolIcon = which;
+ if ((toolMode == kBlowerMode) && (toolIcon >= 7))
+ {
+ toolIcon--;
+ }
+ else if ((toolMode == kTransportMode) && (toolIcon >= 7))
+ {
+ if (toolIcon >= 15)
+ toolIcon -= 4;
+ else
+ toolIcon = ((toolIcon - 7) / 2) + 7;
+ }
+
+ theRect = toolRects[toolIcon];
+ ForeColor(redColor);
+ FrameRect(&theRect);
+ PenNormal();
+ ForeColor(blackColor);
+
+ toolSelected = which;
+ DrawToolName();
+#endif
+}
+
+//-------------------------------------------------------------- UpdateToolsWindow
+
+void UpdateToolsWindow (void)
+{
+#ifndef COMPILEDEMO
+ if (toolsWindow == nil)
+ return;
+
+ SetPortWindowPort(toolsWindow);
+ DrawControls(toolsWindow);
+
+ DkGrayForeColor();
+ MoveTo(4, 25);
+ Line(108, 0);
+ ForeColor(blackColor);
+
+ DrawToolTiles();
+ FrameSelectedTool();
+ DrawToolName();
+#endif
+}
+
+//-------------------------------------------------------------- OpenToolsWindow
+
+void OpenToolsWindow (void)
+{
+#ifndef COMPILEDEMO
+ Rect src, dest;
+ Point globalMouse;
+ short h, v;
+
+ if (toolsWindow == nil)
+ {
+ QSetRect(&toolsWindowRect, 0, 0, 116, 152); // 143
+ QSetRect(&toolTextRect, 0, 0, 116, 12);
+ InsetRect(&toolTextRect, -1, -1);
+ QOffsetRect(&toolTextRect, 0, 157 - 15);
+ if (thisMac.hasColor)
+ toolsWindow = NewCWindow(nil, &toolsWindowRect,
+ PSTR("Tools"), false, kWindoidWDEF, kPutInFront, true, 0L);
+ else
+ toolsWindow = NewWindow(nil, &toolsWindowRect,
+ PSTR("Tools"), false, kWindoidWDEF, kPutInFront, true, 0L);
+
+ if (toolsWindow == nil)
+ RedAlert(kErrNoMemory);
+
+// if (OptionKeyDown())
+// {
+// isToolsH = qd.screenBits.bounds.right - 120;
+// isToolsV = 35;
+// }
+ MoveWindow(toolsWindow, isToolsH, isToolsV, true);
+ globalMouse = MyGetGlobalMouse();
+ QSetRect(&src, 0, 0, 1, 1);
+ QOffsetRect(&src, globalMouse.h, globalMouse.v);
+ GetWindowRect(toolsWindow, &dest);
+ BringToFront(toolsWindow);
+ ShowHide(toolsWindow, true);
+// FlagWindowFloating(toolsWindow); TEMP - use flaoting windows
+ HiliteAllWindows();
+
+ classPopUp = GetNewControl(kPopUpControl, toolsWindow);
+ if (classPopUp == nil)
+ RedAlert(kErrFailedResourceLoad);
+
+ SetControlValue(classPopUp, toolMode);
+
+ for (v = 0; v < kToolsHigh; v++)
+ for (h = 0; h < kToolsWide; h++)
+ {
+ QSetRect(&toolRects[(v * kToolsWide) + h], 2, 29, 30, 57);
+ QOffsetRect(&toolRects[(v * kToolsWide) + h], h * 28, v * 28);
+ }
+
+ CreateToolsOffscreen();
+
+ SwitchToolModes(toolMode);
+ toolSelected = kSelectTool;
+ }
+
+ UpdateToolsCheckmark(true);
+#endif
+}
+
+//-------------------------------------------------------------- CloseToolsWindow
+
+void CloseToolsWindow (void)
+{
+#ifndef COMPILEDEMO
+ CloseThisWindow(&toolsWindow);
+ KillToolsOffscreen();
+ UpdateToolsCheckmark(false);
+#endif
+}
+
+//-------------------------------------------------------------- ToggleToolsWindow
+
+void ToggleToolsWindow (void)
+{
+#ifndef COMPILEDEMO
+ if (toolsWindow == nil)
+ {
+ OpenToolsWindow();
+ isToolsOpen = true;
+ }
+ else
+ {
+ CloseToolsWindow();
+ isToolsOpen = true;
+ }
+#endif
+}
+
+//-------------------------------------------------------------- SwitchToolModes
+
+#ifndef COMPILEDEMO
+void SwitchToolModes (short newMode)
+{
+ if (toolsWindow == nil)
+ return;
+
+ SelectTool(kSelectTool);
+ switch (newMode)
+ {
+ case kBlowerMode:
+ firstTool = kFirstBlower;
+ lastTool = kLastBlower;
+ objectBase = kBlowerBase;
+ break;
+
+ case kFurnitureMode:
+ firstTool = kFirstFurniture;
+ lastTool = kLastFurniture;
+ objectBase = kFurnitureBase;
+ break;
+
+ case kBonusMode:
+ firstTool = kFirstBonus;
+ lastTool = kLastBonus;
+ objectBase = kBonusBase;
+ break;
+
+ case kTransportMode:
+ firstTool = kFirstTransport;
+ lastTool = kLastTransport;
+ objectBase = kTransportBase;
+ break;
+
+ case kSwitchMode:
+ firstTool = kFirstSwitch;
+ lastTool = kLastSwitch;
+ objectBase = kSwitchBase;
+ break;
+
+ case kLightMode:
+ firstTool = kFirstLight;
+ lastTool = kLastLight;
+ objectBase = kLightBase;
+ break;
+
+ case kApplianceMode:
+ firstTool = kFirstAppliance;
+ lastTool = kLastAppliance;
+ objectBase = kApplianceBase;
+ break;
+
+ case kEnemyMode:
+ firstTool = kFirstEnemy;
+ lastTool = kLastEnemy;
+ objectBase = kEnemyBase;
+ break;
+
+ case kClutterMode:
+ firstTool = kFirstClutter;
+ lastTool = kLastClutter;
+ objectBase = kClutterBase;
+ break;
+ }
+
+ toolMode = newMode;
+ InvalWindowRect(toolsWindow, &toolsWindowRect);
+}
+#endif
+
+//-------------------------------------------------------------- HandleToolsClick
+
+void HandleToolsClick (Point wherePt)
+{
+#ifndef COMPILEDEMO
+ ControlHandle theControl;
+ short i, part, newMode, toolIcon;
+
+ if (toolsWindow == nil)
+ return;
+
+ SetPortWindowPort(toolsWindow);
+ GlobalToLocal(&wherePt);
+
+ part = FindControl(wherePt, toolsWindow, &theControl);
+ if ((theControl != nil) && (part != 0))
+ {
+ part = TrackControl(theControl, wherePt, (ControlActionUPP)-1L);
+ if (part != 0)
+ {
+ newMode = GetControlValue(theControl);
+ if (newMode != toolMode)
+ {
+ EraseSelectedTool();
+ SwitchToolModes(newMode);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < kTotalTools; i++)
+ if ((PtInRect(wherePt, &toolRects[i])) && (i <= lastTool))
+ {
+ EraseSelectedTool();
+ toolIcon = i;
+ if ((toolMode == kBlowerMode) && (toolIcon >= 7))
+ {
+ toolIcon++;
+ }
+ if ((toolMode == kTransportMode) && (toolIcon >= 7))
+ {
+ if (toolIcon >= 11)
+ toolIcon += 4;
+ else
+ toolIcon = ((toolIcon - 7) * 2) + 7;
+ }
+ SelectTool(toolIcon);
+ break;
+ }
+ }
+#endif
+}
+
+//-------------------------------------------------------------- NextToolMode
+
+void NextToolMode (void)
+{
+#ifndef COMPILEDEMO
+ if (toolsWindow == nil)
+ return;
+
+ if ((theMode == kEditMode) && (toolMode < kClutterMode))
+ {
+ EraseSelectedTool();
+ toolMode++;
+ SetControlValue(classPopUp, toolMode);
+ SwitchToolModes(toolMode);
+ toolSelected = kSelectTool;
+ }
+#endif
+}
+
+//-------------------------------------------------------------- PrevToolMode
+
+void PrevToolMode (void)
+{
+#ifndef COMPILEDEMO
+ if (toolsWindow == nil)
+ return;
+
+ if ((theMode == kEditMode) && (toolMode > kBlowerMode))
+ {
+ EraseSelectedTool();
+ toolMode--;
+ SetControlValue(classPopUp, toolMode);
+ SwitchToolModes(toolMode);
+ toolSelected = kSelectTool;
+ }
+#endif
+}
+
+//-------------------------------------------------------------- SetSpecificToolMode
+
+void SetSpecificToolMode (short modeToSet)
+{
+#ifndef COMPILEDEMO
+ if ((toolsWindow == nil) || (theMode != kEditMode))
+ return;
+
+ EraseSelectedTool();
+ toolMode = modeToSet;
+ SetControlValue(classPopUp, toolMode);
+ SwitchToolModes(toolMode);
+ toolSelected = kSelectTool;
+#endif
+}
+
diff --git a/GpApp/Tools.h b/GpApp/Tools.h
new file mode 100644
index 0000000..184c6dc
--- /dev/null
+++ b/GpApp/Tools.h
@@ -0,0 +1,12 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Tools.h
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+extern GWorldPtr toolSrcMap;
+extern WindowPtr toolsWindow;
diff --git a/GpApp/Transit.cpp b/GpApp/Transit.cpp
new file mode 100644
index 0000000..9fd5186
--- /dev/null
+++ b/GpApp/Transit.cpp
@@ -0,0 +1,558 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Transit.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Environ.h"
+#include "RectUtils.h"
+
+
+void HandleRoomVisitation (void);
+
+
+short linkedToWhat;
+Boolean takingTheStairs, firstPlayer;
+
+
+extern Rect justRoomsRect, transRect;
+extern short transRoom, otherPlayerEscaped;
+extern short localNumbers[9];
+extern Boolean topOpen, twoPlayerGame, onePlayerLeft;
+extern Boolean playerDead, playerSuicide, tvOn;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- WhatAreWeLinkedTo
+
+short WhatAreWeLinkedTo (short where, Byte who)
+{
+ short what, whatType;
+ char wasState;
+
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ what = (*thisHouse)->rooms[where].objects[who].what;
+ HSetState((Handle)thisHouse, wasState);
+
+ switch (what)
+ {
+ case kMailboxLf:
+ whatType = kLinkedToLeftMailbox;
+ break;
+
+ case kMailboxRt:
+ whatType = kLinkedToRightMailbox;
+ break;
+
+ case kCeilingTrans:
+ whatType = kLinkedToCeilingDuct;
+ break;
+
+ default:
+ whatType = kLinkedToOther;
+ break;
+ }
+
+ return (whatType);
+}
+
+//-------------------------------------------------------------- ReadyGliderFromTransit
+
+void ReadyGliderFromTransit (gliderPtr thisGlider, short toWhat)
+{
+ Rect tempRect;
+
+ if ((twoPlayerGame) && (onePlayerLeft) && (thisGlider->which == playerDead))
+ return;
+
+ FlagGliderNormal(thisGlider);
+
+ switch (toWhat)
+ {
+ case kLinkedToOther:
+ StartGliderTransportingIn(thisGlider); // set glider's mode
+ tempRect = thisGlider->dest; // position glider
+ CenterRectInRect(&tempRect, &transRect);
+ thisGlider->dest.left = tempRect.left;
+ thisGlider->dest.right = tempRect.right;
+ thisGlider->dest.top = tempRect.top;
+ thisGlider->dest.bottom = tempRect.bottom;
+ thisGlider->destShadow.left = tempRect.left;
+ thisGlider->destShadow.right = tempRect.right;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->wholeShadow = thisGlider->destShadow;
+ thisGlider->enteredRect = thisGlider->dest;
+ break;
+
+ case kLinkedToLeftMailbox:
+ StartGliderMailingOut(thisGlider);
+ thisGlider->clip = transRect; // fix clip
+ thisGlider->clip.right -= 64;
+ thisGlider->clip.bottom -= 25;
+ tempRect = thisGlider->dest;
+ thisGlider->dest.left = thisGlider->clip.right;
+ thisGlider->dest.right = thisGlider->dest.left;
+ thisGlider->dest.bottom = thisGlider->clip.bottom - 4;
+ thisGlider->dest.top = thisGlider->dest.bottom - RectTall(&tempRect);
+ thisGlider->destShadow.left = thisGlider->dest.left;
+ thisGlider->destShadow.right = thisGlider->dest.right;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->wholeShadow = thisGlider->destShadow;
+ break;
+
+ case kLinkedToRightMailbox:
+ StartGliderMailingOut(thisGlider);
+ thisGlider->clip = transRect; // fix clip
+ thisGlider->clip.left += 79;
+ thisGlider->clip.bottom -= 25;
+ tempRect = thisGlider->dest;
+ thisGlider->dest.right = thisGlider->clip.left;
+ thisGlider->dest.left = thisGlider->dest.right;
+ thisGlider->dest.bottom = thisGlider->clip.bottom - 4;
+ thisGlider->dest.top = thisGlider->dest.bottom - RectTall(&tempRect);
+ thisGlider->destShadow.left = thisGlider->dest.left;
+ thisGlider->destShadow.right = thisGlider->dest.right;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->wholeShadow = thisGlider->destShadow;
+ break;
+
+ case kLinkedToCeilingDuct:
+ StartGliderDuctingIn(thisGlider);
+ tempRect = thisGlider->dest; // set glider's position
+ CenterRectInRect(&tempRect, &transRect);
+ thisGlider->dest.left = tempRect.left;
+ thisGlider->dest.right = tempRect.right;
+ thisGlider->dest.top = tempRect.top;
+ thisGlider->dest.bottom = thisGlider->dest.top;
+ QOffsetRect(&thisGlider->dest, 0, -RectTall(&tempRect));
+ thisGlider->destShadow.left = tempRect.left;
+ thisGlider->destShadow.right = tempRect.right;
+ thisGlider->whole = thisGlider->dest;
+ thisGlider->wholeShadow = thisGlider->destShadow;
+ break;
+
+ case kLinkedToFloorDuct:
+ break;
+
+ default:
+ break;
+ }
+
+ if ((twoPlayerGame) && (thisGlider->which != firstPlayer))
+ TagGliderIdle(thisGlider);
+}
+
+//-------------------------------------------------------------- MoveRoomToRoom
+
+void MoveRoomToRoom (gliderPtr thisGlider, short where)
+{
+ Rect enterRect;
+
+ HandleRoomVisitation();
+ switch (where)
+ {
+ case kToRight:
+ SetMusicalMode(kProdGameScoreMode);
+ if (twoPlayerGame)
+ {
+ UndoGliderLimbo(&theGlider);
+ UndoGliderLimbo(&theGlider2);
+ InsureGliderFacingRight(&theGlider);
+ InsureGliderFacingRight(&theGlider2);
+ }
+ else
+ InsureGliderFacingRight(thisGlider);
+ ForceThisRoom(localNumbers[kEastRoom]);
+ if (twoPlayerGame)
+ {
+ OffsetGlider(&theGlider, kToLeft);
+ OffsetGlider(&theGlider2, kToLeft);
+ QSetRect(&enterRect, 0, 0, 48, 20);
+ QOffsetRect(&enterRect, 0,
+ kGliderStartsDown + (short)thisRoom->leftStart - 2);
+ theGlider.enteredRect = enterRect;
+ theGlider2.enteredRect = enterRect;
+ }
+ else
+ {
+ OffsetGlider(thisGlider, kToLeft);
+ QSetRect(&enterRect, 0, 0, 48, 20);
+ QOffsetRect(&enterRect, 0,
+ kGliderStartsDown + (short)thisRoom->leftStart - 2);
+ thisGlider->enteredRect = enterRect;
+ }
+ break;
+
+ case kToLeft:
+ SetMusicalMode(kProdGameScoreMode);
+ if (twoPlayerGame)
+ {
+ UndoGliderLimbo(&theGlider);
+ UndoGliderLimbo(&theGlider2);
+ InsureGliderFacingLeft(&theGlider);
+ InsureGliderFacingLeft(&theGlider2);
+ }
+ else
+ InsureGliderFacingLeft(thisGlider);
+ ForceThisRoom(localNumbers[kWestRoom]);
+ if (twoPlayerGame)
+ {
+ OffsetGlider(&theGlider, kToRight);
+ OffsetGlider(&theGlider2, kToRight);
+ QSetRect(&enterRect, 0, 0, 48, 20);
+ QOffsetRect(&enterRect, kRoomWide - 48,
+ kGliderStartsDown + (short)thisRoom->rightStart - 2);
+ theGlider.enteredRect = enterRect;
+ theGlider2.enteredRect = enterRect;
+ }
+ else
+ {
+ OffsetGlider(thisGlider, kToRight);
+ QSetRect(&enterRect, 0, 0, 48, 20);
+ QOffsetRect(&enterRect, kRoomWide - 48,
+ kGliderStartsDown + (short)thisRoom->rightStart - 2);
+ thisGlider->enteredRect = enterRect;
+ }
+ break;
+
+ case kAbove:
+ SetMusicalMode(kKickGameScoreMode);
+ ForceThisRoom(localNumbers[kNorthRoom]);
+ if (!takingTheStairs)
+ {
+ if (twoPlayerGame)
+ {
+ UndoGliderLimbo(&theGlider);
+ UndoGliderLimbo(&theGlider2);
+ OffsetGlider(&theGlider, kBelow);
+ OffsetGlider(&theGlider2, kBelow);
+ theGlider.enteredRect = theGlider.dest;
+ theGlider2.enteredRect = theGlider2.dest;
+ }
+ else
+ {
+ OffsetGlider(thisGlider, kBelow);
+ thisGlider->enteredRect = thisGlider->dest;
+ }
+ }
+ else
+ {
+ if (twoPlayerGame)
+ {
+ ReadyGliderForTripUpStairs(&theGlider);
+ ReadyGliderForTripUpStairs(&theGlider2);
+ }
+ else
+ ReadyGliderForTripUpStairs(thisGlider);
+ }
+ break;
+
+ case kBelow:
+ SetMusicalMode(kKickGameScoreMode);
+ ForceThisRoom(localNumbers[kSouthRoom]);
+ if (!takingTheStairs)
+ {
+ if (twoPlayerGame)
+ {
+ UndoGliderLimbo(&theGlider);
+ UndoGliderLimbo(&theGlider2);
+ OffsetGlider(&theGlider, kAbove);
+ OffsetGlider(&theGlider2, kAbove);
+ theGlider.enteredRect = theGlider.dest;
+ theGlider2.enteredRect = theGlider2.dest;
+ }
+ else
+ {
+ OffsetGlider(thisGlider, kAbove);
+ thisGlider->enteredRect = thisGlider->dest;
+ }
+ }
+ else
+ {
+ if (twoPlayerGame)
+ {
+ ReadyGliderForTripDownStairs(&theGlider);
+ ReadyGliderForTripDownStairs(&theGlider2);
+ }
+ else
+ ReadyGliderForTripDownStairs(thisGlider);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ((twoPlayerGame) && (!onePlayerLeft))
+ {
+ if (firstPlayer == kPlayer1)
+ TagGliderIdle(&theGlider2);
+ else
+ TagGliderIdle(&theGlider);
+ }
+
+ ReadyLevel();
+ RefreshScoreboard(kNormalTitleMode);
+ WipeScreenOn(where, &justRoomsRect);
+
+#ifdef COMPILEQT
+ RenderFrame();
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom) && (tvOn))
+ {
+ GoToBeginningOfMovie(theMovie);
+ StartMovie(theMovie);
+ }
+#endif
+}
+
+//-------------------------------------------------------------- TransportRoomToRoom
+
+void TransportRoomToRoom (gliderPtr thisGlider)
+{
+ Boolean sameRoom;
+
+ SetMusicalMode(kKickGameScoreMode);
+ HandleRoomVisitation();
+
+ sameRoom = (transRoom == thisRoomNumber);
+ if (!sameRoom)
+ ForceThisRoom(transRoom);
+ if (twoPlayerGame)
+ {
+ UndoGliderLimbo(&theGlider); // turn off limbo if needed
+ UndoGliderLimbo(&theGlider2); // turn off limbo if needed
+ ReadyGliderFromTransit(&theGlider, linkedToWhat);
+ ReadyGliderFromTransit(&theGlider2, linkedToWhat);
+ }
+ else
+ ReadyGliderFromTransit(thisGlider, linkedToWhat);
+
+ if (!sameRoom)
+ ReadyLevel();
+ RefreshScoreboard(kNormalTitleMode);
+ if (!sameRoom)
+ WipeScreenOn(kAbove, &justRoomsRect);
+
+#ifdef COMPILEQT
+ RenderFrame();
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom) && (tvOn))
+ {
+ GoToBeginningOfMovie(theMovie);
+ StartMovie(theMovie);
+ }
+#endif
+}
+
+//-------------------------------------------------------------- MoveDuctToDuct
+
+void MoveDuctToDuct (gliderPtr thisGlider)
+{
+ Boolean sameRoom;
+
+ SetMusicalMode(kKickGameScoreMode);
+ HandleRoomVisitation();
+
+ sameRoom = (transRoom == thisRoomNumber);
+ if (!sameRoom)
+ ForceThisRoom(transRoom);
+
+ if (twoPlayerGame)
+ {
+ UndoGliderLimbo(&theGlider); // turn off limbo if needed
+ UndoGliderLimbo(&theGlider2); // turn off limbo if needed
+ ReadyGliderFromTransit(&theGlider, linkedToWhat);
+ ReadyGliderFromTransit(&theGlider2, linkedToWhat);
+ }
+ else
+ ReadyGliderFromTransit(thisGlider, linkedToWhat);
+
+ if (!sameRoom)
+ ReadyLevel();
+ RefreshScoreboard(kNormalTitleMode);
+ if (!sameRoom)
+ WipeScreenOn(kAbove, &justRoomsRect);
+
+#ifdef COMPILEQT
+ RenderFrame();
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom) && (tvOn))
+ {
+ GoToBeginningOfMovie(theMovie);
+ StartMovie(theMovie);
+ }
+#endif
+}
+
+//-------------------------------------------------------------- MoveMailToMail
+
+void MoveMailToMail (gliderPtr thisGlider)
+{
+ Boolean sameRoom;
+
+ SetMusicalMode(kKickGameScoreMode);
+ HandleRoomVisitation();
+
+ sameRoom = (transRoom == thisRoomNumber);
+ if (!sameRoom)
+ ForceThisRoom(transRoom);
+
+ if (twoPlayerGame)
+ {
+ UndoGliderLimbo(&theGlider); // turn off limbo if needed
+ UndoGliderLimbo(&theGlider2); // turn off limbo if needed
+ ReadyGliderFromTransit(&theGlider, linkedToWhat);
+ ReadyGliderFromTransit(&theGlider2, linkedToWhat);
+ }
+ else
+ ReadyGliderFromTransit(thisGlider, linkedToWhat);
+
+ if (!sameRoom)
+ ReadyLevel();
+ RefreshScoreboard(kNormalTitleMode);
+ if (!sameRoom)
+ WipeScreenOn(kAbove, &justRoomsRect);
+
+#ifdef COMPILEQT
+ RenderFrame();
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom) && (tvOn))
+ {
+ GoToBeginningOfMovie(theMovie);
+ StartMovie(theMovie);
+ }
+#endif
+}
+
+//-------------------------------------------------------------- HandleRoomVisitation
+
+void HandleRoomVisitation (void)
+{
+ houseType *thisHousePtr;
+ char wasState;
+
+ if (!thisRoom->visited)
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ thisHousePtr = *thisHouse;
+ thisHousePtr->rooms[localNumbers[kCentralRoom]].visited = true;
+ HSetState((Handle)thisHouse, wasState);
+ theScore += kRoomVisitScore;
+ thisRoom->visited = true;
+ }
+}
+
+//-------------------------------------------------------------- ForceKillGlider
+
+void ForceKillGlider (void)
+{
+ if (theGlider.mode == kGliderInLimbo)
+ {
+ if (theGlider2.mode != kGliderFadingOut)
+ {
+ StartGliderFadingOut(&theGlider2);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ playerSuicide = true;
+ }
+ }
+ else if (theGlider2.mode == kGliderInLimbo)
+ {
+ if (theGlider.mode != kGliderFadingOut)
+ {
+ StartGliderFadingOut(&theGlider);
+ PlayPrioritySound(kFadeOutSound, kFadeOutPriority);
+ playerSuicide = true;
+ }
+ }
+}
+
+//-------------------------------------------------------------- FollowTheLeader
+
+void FollowTheLeader (void)
+{
+ short wasEscaped;
+ Boolean oneOrTwo;
+
+ playerSuicide = false;
+ wasEscaped = otherPlayerEscaped;
+ otherPlayerEscaped = kNoOneEscaped;
+
+ if (theGlider.mode == kGliderInLimbo)
+ {
+ oneOrTwo = true;
+ theGlider2.dest = theGlider.dest;
+ theGlider2.destShadow = theGlider.destShadow;
+ theGlider2.whole = theGlider2.dest;
+ theGlider2.wholeShadow = theGlider2.destShadow;
+ }
+ else if (theGlider2.mode == kGliderInLimbo)
+ {
+ oneOrTwo = false;
+ theGlider.dest = theGlider2.dest;
+ theGlider.destShadow = theGlider2.destShadow;
+ theGlider.whole = theGlider.dest;
+ theGlider.wholeShadow = theGlider.destShadow;
+ }
+
+ switch (wasEscaped)
+ {
+ case kPlayerEscapedUp:
+ case kPlayerEscapingUpStairs:
+ case kPlayerEscapedUpStairs:
+ if (oneOrTwo)
+ MoveRoomToRoom(&theGlider2, kAbove);
+ else
+ MoveRoomToRoom(&theGlider, kAbove);
+ break;
+
+ case kPlayerEscapedDown:
+ case kPlayerEscapingDownStairs:
+ case kPlayerEscapedDownStairs:
+ if (oneOrTwo)
+ MoveRoomToRoom(&theGlider2, kBelow);
+ else
+ MoveRoomToRoom(&theGlider, kBelow);
+ break;
+
+ case kPlayerEscapedLeft:
+ if (oneOrTwo)
+ MoveRoomToRoom(&theGlider2, kToLeft);
+ else
+ MoveRoomToRoom(&theGlider, kToLeft);
+ break;
+
+ case kPlayerEscapedRight:
+ if (oneOrTwo)
+ MoveRoomToRoom(&theGlider2, kToRight);
+ else
+ MoveRoomToRoom(&theGlider, kToRight);
+ break;
+
+ case kPlayerTransportedOut:
+ if (oneOrTwo)
+ TransportRoomToRoom(&theGlider2);
+ else
+ TransportRoomToRoom(&theGlider);
+ break;
+
+ case kPlayerMailedOut:
+ if (oneOrTwo)
+ MoveMailToMail(&theGlider2);
+ else
+ MoveMailToMail(&theGlider);
+ break;
+
+ case kPlayerDuckedOut:
+ if (oneOrTwo)
+ MoveDuctToDuct(&theGlider2);
+ else
+ MoveDuctToDuct(&theGlider);
+ break;
+
+ default:
+ break;
+ }
+}
+
diff --git a/GpApp/Transitions.cpp b/GpApp/Transitions.cpp
new file mode 100644
index 0000000..927a7e4
--- /dev/null
+++ b/GpApp/Transitions.cpp
@@ -0,0 +1,145 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Transitions.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Environ.h"
+#include "MainWindow.h"
+#include "RectUtils.h"
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- PourScreenOn
+
+void PourScreenOn (Rect *theRect)
+{
+ #define kMaxColumnsWide 96
+ #define kChipHigh 20
+ #define kChipWide 16
+ Rect columnRects[kMaxColumnsWide];
+ short columnProgress[kMaxColumnsWide];
+ short i, colsComplete, colWide, rowTall;
+ Boolean working;
+
+ colWide = theRect->right / kChipWide; // determine # of cols
+ rowTall = (theRect->bottom / kChipHigh) + 1; // determine # of rows
+
+ working = true;
+ colsComplete = 0;
+ for (i = 0; i < colWide; i++)
+ {
+ columnProgress[i] = 0;
+ QSetRect(&columnRects[i], 0, 0, kChipWide, kChipHigh);
+ QOffsetRect(&columnRects[i], (i * kChipWide) + theRect->left, theRect->top);
+ }
+
+ while (working)
+ {
+ do
+ {
+ i = RandomInt(colWide);
+ }
+ while (columnProgress[i] >= rowTall);
+
+ if (columnRects[i].left < theRect->left)
+ columnRects[i].left = theRect->left;
+ if (columnRects[i].top < theRect->top)
+ columnRects[i].top = theRect->top;
+ if (columnRects[i].right > theRect->right)
+ columnRects[i].right = theRect->right;
+ if (columnRects[i].bottom > theRect->bottom)
+ columnRects[i].bottom = theRect->bottom;
+
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &columnRects[i], &columnRects[i], srcCopy, nil);
+
+ QOffsetRect(&columnRects[i], 0, kChipHigh);
+ columnProgress[i]++;
+ if (columnProgress[i] >= rowTall)
+ {
+ colsComplete++;
+ if (colsComplete >= colWide)
+ working = false;
+ }
+ }
+}
+
+//-------------------------------------------------------------- WipeScreenOn
+
+void WipeScreenOn (short direction, Rect *theRect)
+{
+ #define kWipeRectThick 4
+ Rect wipeRect;
+ RgnHandle dummyRgn;
+ short hOffset, vOffset;
+ short i, count;
+
+ wipeRect = *theRect;
+ switch (direction)
+ {
+ case kAbove:
+ wipeRect.bottom = wipeRect.top + kWipeRectThick;
+ hOffset = 0;
+ vOffset = kWipeRectThick;
+ count = ((theRect->bottom - theRect->top) / kWipeRectThick) + 1;
+ break;
+
+ case kToRight:
+ wipeRect.left = wipeRect.right - kWipeRectThick;
+ hOffset = -kWipeRectThick;
+ vOffset = 0;
+ count = workSrcRect.right / kWipeRectThick;
+ break;
+
+ case kBelow:
+ wipeRect.top = wipeRect.bottom - kWipeRectThick;
+ hOffset = 0;
+ vOffset = -kWipeRectThick;
+ count = ((theRect->bottom - theRect->top) / kWipeRectThick) + 1;
+ break;
+
+ case kToLeft:
+ wipeRect.right = wipeRect.left + kWipeRectThick;
+ hOffset = kWipeRectThick;
+ vOffset = 0;
+ count = workSrcRect.right / kWipeRectThick;
+ break;
+ }
+
+ dummyRgn = NewRgn();
+
+ for (i = 0; i < count; i++)
+ {
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ &wipeRect, &wipeRect, srcCopy, GetPortVisibleRegion(GetWindowPort(mainWindow), dummyRgn));
+
+ QOffsetRect(&wipeRect, hOffset, vOffset);
+
+ if (wipeRect.top < theRect->top)
+ wipeRect.top = theRect->top;
+ else if (wipeRect.top > theRect->bottom)
+ wipeRect.top = theRect->bottom;
+ if (wipeRect.bottom < theRect->top)
+ wipeRect.bottom = theRect->top;
+ else if (wipeRect.bottom > theRect->bottom)
+ wipeRect.bottom = theRect->bottom;
+ }
+
+ DisposeRgn(dummyRgn);
+}
+
+//-------------------------------------------------------------- DumpScreenOn
+
+void DumpScreenOn (Rect *theRect)
+{
+ CopyBits((BitMap *)*GetGWorldPixMap(workSrcMap),
+ GetPortBitMapForCopyBits(GetWindowPort(mainWindow)),
+ theRect, theRect, srcCopy, nil);
+}
+
diff --git a/GpApp/Triggers.cpp b/GpApp/Triggers.cpp
new file mode 100644
index 0000000..77238e2
--- /dev/null
+++ b/GpApp/Triggers.cpp
@@ -0,0 +1,205 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Triggers.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+
+
+#define kMaxTriggers 16
+
+
+typedef struct
+{
+ short object, room;
+ short index, timer;
+ short what;
+ Boolean armed;
+} trigType, *trigPtr;
+
+
+short FindEmptyTriggerSlot (void);
+void FireTrigger (short);
+
+
+trigType triggers[kMaxTriggers];
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- ArmTrigger
+
+void ArmTrigger (hotPtr who)
+{
+ short where, whoLinked;
+
+ if (who->stillOver)
+ return;
+
+ where = FindEmptyTriggerSlot();
+
+ if (where != -1)
+ {
+ whoLinked = who->who; // what is trigger's obj. #
+ triggers[where].room = masterObjects[whoLinked].roomLink;
+ triggers[where].object = masterObjects[whoLinked].objectLink;
+ triggers[where].index = whoLinked;
+ triggers[where].timer = masterObjects[whoLinked].theObject.data.e.delay * 3;
+ triggers[where].what = masterObjects[triggers[where].object].theObject.what;
+ triggers[where].armed = true;
+ }
+
+ who->stillOver = true;
+}
+
+//-------------------------------------------------------------- FindEmptyTriggerSlot
+
+short FindEmptyTriggerSlot (void)
+{
+ short where, i;
+
+ where = -1;
+
+ for (i = 0; i < kMaxTriggers; i++)
+ {
+ if (!triggers[i].armed)
+ {
+ where = i;
+ break;
+ }
+ }
+
+ return (where);
+}
+
+//-------------------------------------------------------------- HandleTriggers
+
+void HandleTriggers (void)
+{
+ short i;
+
+ for (i = 0; i < kMaxTriggers; i++)
+ {
+ if (triggers[i].armed)
+ {
+ triggers[i].timer--;
+ if (triggers[i].timer <= 0)
+ {
+ triggers[i].timer = 0;
+ triggers[i].armed = false;
+ FireTrigger(i);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------- FireTrigger
+
+void FireTrigger (short index)
+{
+ short triggerIs, triggeredIs;
+ char wasState;
+
+ triggerIs = triggers[index].index;
+
+ if (masterObjects[triggerIs].localLink != -1)
+ {
+ triggeredIs = masterObjects[triggerIs].localLink;
+ switch (masterObjects[triggeredIs].theObject.what)
+ {
+ case kGreaseRt:
+ case kGreaseLf:
+ if (SetObjectState(triggers[index].room, triggers[index].object,
+ kForceOn, triggeredIs))
+ {
+ SpillGrease(masterObjects[triggeredIs].dynaNum,
+ masterObjects[triggeredIs].hotNum);
+ }
+ break;
+
+ case kLightSwitch:
+ case kMachineSwitch:
+ case kThermostat:
+ case kPowerSwitch:
+ case kKnifeSwitch:
+ case kInvisSwitch:
+ TriggerSwitch(masterObjects[triggeredIs].dynaNum);
+ break;
+
+ case kSoundTrigger:
+ PlayPrioritySound(kChordSound, kChordPriority); // Change me
+ break;
+
+ case kToaster:
+ TriggerToast(masterObjects[triggeredIs].dynaNum);
+ break;
+
+ case kGuitar:
+ PlayPrioritySound(kChordSound, kChordPriority);
+ break;
+
+ case kCoffee:
+ PlayPrioritySound(kCoffeeSound, kCoffeePriority);
+ break;
+
+ case kOutlet:
+ TriggerOutlet(masterObjects[triggeredIs].dynaNum);
+ break;
+
+ case kBalloon:
+ TriggerBalloon(masterObjects[triggeredIs].dynaNum);
+ break;
+
+ case kCopterLf:
+ case kCopterRt:
+ TriggerCopter(masterObjects[triggeredIs].dynaNum);
+ break;
+
+ case kDartLf:
+ case kDartRt:
+ TriggerDart(masterObjects[triggeredIs].dynaNum);
+ break;
+
+ case kDrip:
+ TriggerDrip(masterObjects[triggeredIs].dynaNum);
+ break;
+
+ case kFish:
+ TriggerFish(masterObjects[triggeredIs].dynaNum);
+ break;
+ }
+ }
+ else
+ {
+ wasState = HGetState((Handle)thisHouse);
+ HLock((Handle)thisHouse);
+ triggeredIs = masterObjects[triggerIs].localLink;
+ switch ((*thisHouse)->rooms[triggers[index].room].
+ objects[triggers[index].object].what)
+ {
+ case kGreaseRt:
+ case kGreaseLf:
+ if (SetObjectState(triggers[index].room, triggers[index].object,
+ kForceOn, triggeredIs))
+ {
+ SpillGrease(masterObjects[triggeredIs].dynaNum,
+ masterObjects[triggeredIs].hotNum);
+ }
+ break;
+ }
+ HSetState((Handle)thisHouse, wasState);
+ }
+}
+
+//-------------------------------------------------------------- ZeroTriggers
+
+void ZeroTriggers (void)
+{
+ short i;
+
+ for (i = 0; i < kMaxTriggers; i++)
+ triggers[i].armed = false;
+}
+
diff --git a/GpApp/Trip.cpp b/GpApp/Trip.cpp
new file mode 100644
index 0000000..08134a2
--- /dev/null
+++ b/GpApp/Trip.cpp
@@ -0,0 +1,245 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// Trip.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "Externs.h"
+#include "Environ.h"
+
+
+extern dynaPtr dinahs;
+extern hotPtr hotSpots;
+extern short numDynamics, tvWithMovieNumber;
+extern Boolean tvOn;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- ToggleToaster
+
+void ToggleToaster (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+}
+
+//-------------------------------------------------------------- ToggleMacPlus
+
+void ToggleMacPlus (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+ if (dinahs[index].active)
+ dinahs[index].timer = 40;
+ else
+ dinahs[index].timer = 10;
+}
+
+//-------------------------------------------------------------- ToggleTV
+
+void ToggleTV (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+ if ((thisMac.hasQT) && (hasMovie) && (tvInRoom) && (tvWithMovieNumber == index))
+ {
+ if (dinahs[index].active)
+ {
+ GoToBeginningOfMovie(theMovie);
+ StartMovie(theMovie);
+ tvOn = true;
+ }
+ else
+ {
+ StopMovie(theMovie);
+ tvOn = false;
+ }
+ }
+ dinahs[index].timer = 4;
+}
+
+//-------------------------------------------------------------- ToggleCoffee
+
+void ToggleCoffee (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+ dinahs[index].timer = 4;
+}
+
+//-------------------------------------------------------------- ToggleOutlet
+
+void ToggleOutlet (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+}
+
+//-------------------------------------------------------------- ToggleVCR
+
+void ToggleVCR (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+ dinahs[index].timer = 4;
+}
+
+//-------------------------------------------------------------- ToggleStereo
+
+void ToggleStereos (short index)
+{
+ if (dinahs[index].timer == 0)
+ {
+ dinahs[index].active = !dinahs[index].active;
+ dinahs[index].timer = 4;
+ }
+}
+
+//-------------------------------------------------------------- ToggleMicrowave
+
+void ToggleMicrowave (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+ dinahs[index].timer = 4;
+}
+
+//-------------------------------------------------------------- ToggleBalloon
+
+void ToggleBalloon (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+}
+
+//-------------------------------------------------------------- ToggleCopter
+
+void ToggleCopter (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+}
+
+//-------------------------------------------------------------- ToggleDart
+
+void ToggleDart (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+}
+
+//-------------------------------------------------------------- ToggleBall
+
+void ToggleBall (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+}
+
+//-------------------------------------------------------------- ToggleDrip
+
+void ToggleDrip (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+}
+
+//-------------------------------------------------------------- ToggleFish
+
+void ToggleFish (short index)
+{
+ dinahs[index].active = !dinahs[index].active;
+}
+
+//-------------------------------------------------------------- TriggerSwitch
+
+void TriggerSwitch (short who)
+{
+ HandleSwitches(&hotSpots[who]);
+}
+
+//-------------------------------------------------------------- TriggerToast
+
+void TriggerToast (short who)
+{
+ if (!dinahs[who].moving)
+ {
+ if (dinahs[who].active)
+ {
+ dinahs[who].vVel = (short)-dinahs[who].count;
+ dinahs[who].frame = 0;
+ dinahs[who].moving = true;
+ PlayPrioritySound(kToastLaunchSound, kToastLaunchPriority);
+ }
+ else
+ dinahs[who].frame = dinahs[who].timer;
+ }
+}
+
+//-------------------------------------------------------------- TriggerOutlet
+
+void TriggerOutlet (short who)
+{
+ if (dinahs[who].position == 0)
+ {
+ if (dinahs[who].active)
+ {
+ dinahs[who].position = 1;
+ dinahs[who].timer = kLengthOfZap;
+ PlayPrioritySound(kZapSound, kZapPriority);
+ }
+ else
+ dinahs[who].timer = dinahs[who].count;
+ }
+}
+
+//-------------------------------------------------------------- TriggerDrip
+
+void TriggerDrip (short who)
+{
+ if ((!dinahs[who].moving) && (dinahs[who].timer > 7))
+ dinahs[who].timer = 7; // kick off drip
+}
+
+//-------------------------------------------------------------- TriggerFish
+
+void TriggerFish (short who)
+{
+ if ((dinahs[who].active) && (!dinahs[who].moving))
+ {
+ dinahs[who].whole = dinahs[who].dest;
+ dinahs[who].moving = true;
+ dinahs[who].frame = 4;
+ PlayPrioritySound(kFishOutSound, kFishOutPriority);
+ }
+}
+
+//-------------------------------------------------------------- TriggerBalloon
+
+void TriggerBalloon (short who)
+{
+ if (!dinahs[who].moving)
+ dinahs[who].timer = kStartSparkle + 1;
+}
+
+
+//-------------------------------------------------------------- TriggerCopter
+
+void TriggerCopter (short who)
+{
+ if (!dinahs[who].moving)
+ dinahs[who].timer = kStartSparkle + 1;
+}
+
+
+//-------------------------------------------------------------- TriggerDart
+
+void TriggerDart (short who)
+{
+ if (!dinahs[who].moving)
+ dinahs[who].timer = kStartSparkle + 1;
+}
+
+//-------------------------------------------------------------- UpdateOutletsLighting
+
+void UpdateOutletsLighting (short room, short nLights)
+{
+ short i;
+
+ for (i = 0; i < numDynamics; i++)
+ {
+ if ((dinahs[i].type == kOutlet) && (dinahs[i].room == room))
+ dinahs[i].hVel = nLights;
+ }
+}
+
diff --git a/GpApp/Utilities.cpp b/GpApp/Utilities.cpp
new file mode 100644
index 0000000..a05bf67
--- /dev/null
+++ b/GpApp/Utilities.cpp
@@ -0,0 +1,763 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Utilities.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+#include "PLQuickdraw.h"
+#include "PLPasStr.h"
+#include "PLResources.h"
+#include "PLSound.h"
+#include "Externs.h"
+#include "Utilities.h"
+
+
+GDHandle thisGDevice;
+UInt32 theSeed;
+
+
+extern Boolean switchedOut;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- MyGetGlobalMouse
+// Returns the position of the mouse in global coordinates.
+
+Point MyGetGlobalMouse (void)
+{
+ Point localWhere;
+
+ GetMouse(&localWhere);
+ LocalToGlobal(&localWhere);
+ return (localWhere);
+}
+
+//-------------------------------------------------------------- ToolBoxInit
+
+// The standard ToolBox intialization that must happen when any MacÉ
+// program first launches.
+
+void ToolBoxInit (void)
+{
+ InitCursor();
+ switchedOut = false;
+}
+
+//-------------------------------------------------------------- RandomInt
+// Returns a random integer (short) within "range".
+
+short RandomInt (short range)
+{
+ register long rawResult;
+
+ rawResult = Random();
+ if (rawResult < 0L)
+ rawResult *= -1L;
+ rawResult = (rawResult * (long)range) / 32768L;
+
+ return ((short)rawResult);
+}
+
+//-------------------------------------------------------------- RandomLong
+
+// Returns a random long interger within "range".
+
+long RandomLong (long range)
+{
+ register long highWord, lowWord;
+ register long rawResultHi, rawResultLo;
+
+ highWord = (range & 0xFFFF0000) >> 16;
+ lowWord = range & 0x0000FFFF;
+
+ rawResultHi = Random();
+ if (rawResultHi < 0L)
+ rawResultHi *= -1L;
+ rawResultHi = (rawResultHi * highWord) / 32768L;
+
+ rawResultLo = Random();
+ if (rawResultLo < 0L)
+ rawResultLo *= -1L;
+ rawResultLo = (rawResultLo * lowWord) / 32768L;
+
+ rawResultHi = (rawResultHi << 16) + rawResultLo;
+
+ return (rawResultHi);
+}
+
+//-------------------------------------------------------------- InitRandomLongQUS
+
+// Initializes random seed for quick & dirty long random number function (below).
+
+void InitRandomLongQUS (void)
+{
+ GetDateTime(&theSeed);
+}
+
+//-------------------------------------------------------------- RandomLongQUS
+
+// Very simple (but fast) pseudo-random number generator.
+
+UInt32 RandomLongQUS (void)
+{
+ theSeed = theSeed * 1103515245 + 12345;
+ return (theSeed);
+}
+
+//-------------------------------------------------------------- RedAlert
+
+// Called when we must quit app. Brings up a dialog informing userÉ
+// of the problem and the exits to shell.
+
+void RedAlert (short errorNumber)
+{
+ #define rDeathAlertID 170 // alert res. ID for death error
+ #define rErrTitleID 170 // string ID for death error title
+ #define rErrMssgID 171 // string ID for death error message
+ short dummyInt;
+ Str255 errTitle, errMessage, errNumberString;
+
+ InitCursor();
+
+ if (errorNumber > 1) // <= 0 is unaccounted for
+ {
+ GetIndString(errTitle, rErrTitleID, errorNumber);
+ GetIndString(errMessage, rErrMssgID, errorNumber);
+ }
+ else
+ {
+ GetIndString(errTitle, rErrTitleID, 1);
+ GetIndString(errMessage, rErrMssgID, 1);
+ }
+ NumToString((long)errorNumber, errNumberString);
+ ParamText(errTitle, errMessage, errNumberString, PSTR(""));
+// CenterAlert(rDeathAlertID);
+
+ dummyInt = Alert(rDeathAlertID, nil);
+ ExitToShell();
+}
+
+//-------------------------------------------------------------- FindOurDevice
+
+// Finds the main device (monitor with the menu bar on it).
+
+void FindOurDevice (void)
+{
+ thisGDevice = GetMainDevice();
+ if (thisGDevice == nil)
+ RedAlert(kErrFailedGetDevice);
+}
+
+//-------------------------------------------------------------- CreateOffScreenBitMap
+// Creates an offscreen bit map (b&w - 1 bit depth).
+
+/*
+void CreateOffScreenBitMap (Rect *theRect, GrafPtr *offScreen)
+{
+ GrafPtr theBWPort;
+ BitMap theBitMap;
+ long theRowBytes;
+
+ theBWPort = (GrafPtr)(NewPtr(sizeof(GrafPort)));
+ OpenPort(theBWPort);
+ theRowBytes = (long)((theRect->right - theRect->left + 15L) / 16L) * 2L;
+ theBitMap.rowBytes = (short)theRowBytes;
+ theBitMap.baseAddr = NewPtr((long)theBitMap.rowBytes *
+ (theRect->bottom - theRect->top));
+ if (theBitMap.baseAddr == nil)
+ RedAlert(kErrNoMemory);
+ theBitMap.bounds = *theRect;
+ if (MemError() != noErr)
+ RedAlert(kErrNoMemory);
+ SetPortBits(&theBitMap);
+ ClipRect(theRect);
+ RectRgn(theBWPort->visRgn, theRect);
+ EraseRect(theRect);
+ *offScreen = theBWPort;
+}
+*/
+//-------------------------------------------------------------- CreateOffScreenPixMap
+// Creates an offscreen pix map using the depth of the current device.
+/*
+void CreateOffScreenPixMap (Rect *theRect, CGrafPtr *offScreen)
+{
+ CTabHandle thisColorTable;
+ GDHandle oldDevice;
+ CGrafPtr newCGrafPtr;
+ Ptr theseBits;
+ long sizeOfOff, offRowBytes;
+ OSErr theErr;
+ short thisDepth;
+ char wasState;
+
+ oldDevice = GetGDevice();
+ SetGDevice(thisGDevice);
+ newCGrafPtr = nil;
+ newCGrafPtr = (CGrafPtr)NewPtr(sizeof(CGrafPort));
+ if (newCGrafPtr != nil)
+ {
+ OpenCPort(newCGrafPtr);
+ thisDepth = (**(*newCGrafPtr).portPixMap).pixelSize;
+ offRowBytes = ((((long)thisDepth *
+ (long)(theRect->right - theRect->left)) + 15L) >> 4L) << 1L;
+ sizeOfOff = (long)(theRect->bottom - theRect->top + 1) * offRowBytes;
+ // sizeOfOff = (long)(theRect->bottom - theRect->top) * offRowBytes;
+ OffsetRect(theRect, -theRect->left, -theRect->top);
+ theseBits = NewPtr(sizeOfOff);
+ if (theseBits != nil)
+ { // workaround
+ (**(*newCGrafPtr).portPixMap).baseAddr = theseBits + offRowBytes;
+ // (**(*newCGrafPtr).portPixMap).baseAddr = theseBits;
+ (**(*newCGrafPtr).portPixMap).rowBytes = (short)offRowBytes + 0x8000;
+ (**(*newCGrafPtr).portPixMap).bounds = *theRect;
+ wasState = HGetState((Handle)thisGDevice);
+ HLock((Handle)thisGDevice);
+ thisColorTable = (**(**thisGDevice).gdPMap).pmTable;
+ HSetState((Handle)thisGDevice, wasState);
+ theErr = HandToHand((Handle *)&thisColorTable);
+ (**(*newCGrafPtr).portPixMap).pmTable = thisColorTable;
+ ClipRect(theRect);
+ RectRgn(newCGrafPtr->visRgn, theRect);
+ ForeColor(blackColor);
+ BackColor(whiteColor);
+ EraseRect(theRect);
+ }
+ else
+ {
+ CloseCPort(newCGrafPtr);
+ DisposePtr((Ptr)newCGrafPtr);
+ newCGrafPtr = nil;
+ RedAlert(kErrNoMemory);
+ }
+ }
+ else
+ RedAlert(kErrNoMemory);
+
+ *offScreen = newCGrafPtr;
+ SetGDevice(oldDevice);
+}
+*/
+//-------------------------------------------------------------------- CreateOffScreenGWorld
+// Creates an offscreen GWorldÊusing the depth passed in.
+
+OSErr CreateOffScreenGWorld (GWorldPtr *theGWorld, Rect *bounds, short depth)
+{
+ OSErr theErr;
+
+ theErr = NewGWorld(theGWorld, depth, bounds, nil, nil, useTempMem);
+
+ if (theErr)
+ theErr = NewGWorld(theGWorld, depth, bounds, nil, nil, 0);
+
+ LockPixels(GetGWorldPixMap(*theGWorld));
+
+ return theErr;
+}
+
+
+//-------------------------------------------------------------- KillOffScreenPixMap
+// Destroys memory allocated by an offscreen pix map.
+/*
+void KillOffScreenPixMap (CGrafPtr offScreen)
+{
+ Ptr theseBits;
+
+ if (offScreen != nil)
+ {
+ theseBits = (**(*offScreen).portPixMap).baseAddr;
+ theseBits -= (**(*offScreen).portPixMap).rowBytes & 0x7FFF; // workaround
+ DisposePtr(theseBits);
+ DisposeHandle((Handle)(**(*offScreen).portPixMap).pmTable);
+ CloseCPort(offScreen);
+ DisposePtr((Ptr)offScreen);
+ }
+}
+*/
+//-------------------------------------------------------------- KillOffScreenBitMap
+// Destroys memory allocated by an offscreen bit map.
+/*
+void KillOffScreenBitMap (GrafPtr offScreen)
+{
+ if (offScreen != nil)
+ {
+ DisposePtr((Ptr)(offScreen->portBits.baseAddr));
+ ClosePort(offScreen);
+ DisposePtr((Ptr)offScreen);
+ }
+}
+*/
+//-------------------------------------------------------------- LoadGraphic
+// Function loads the specified 'PICT' from disk and draws it toÉ
+// the current port (no scaling, clipping, etc, are done). AlwaysÉ
+// draws in the upper left corner of current port.
+
+void LoadGraphic (short resID)
+{
+ Rect bounds;
+ PicHandle thePicture;
+
+ thePicture = GetPicture(resID);
+ if (thePicture == nil)
+ RedAlert(kErrFailedGraphicLoad);
+
+ HLock((Handle)thePicture);
+ bounds = (*thePicture)->picFrame;
+ HUnlock((Handle)thePicture);
+ OffsetRect(&bounds, -bounds.left, -bounds.top);
+ DrawPicture(thePicture, &bounds);
+
+ ReleaseResource((Handle)thePicture);
+}
+
+//-------------------------------------------------------------- LoadScaledGraphic
+// Loads the specified 'PICT' and draws it mapped to the rectangleÉ
+// specified. If this rect isn't the same size of the 'PICT', scalingÉ
+// will occur.
+
+void LoadScaledGraphic (short resID, Rect *theRect)
+{
+ PicHandle thePicture;
+
+ thePicture = GetPicture(resID);
+ if (thePicture == nil)
+ RedAlert(kErrFailedGraphicLoad);
+ DrawPicture(thePicture, theRect);
+ ReleaseResource((Handle)thePicture);
+}
+
+//-------------------------------------------------------------- PlotSICN
+// Draws a small icon (16 x 16 pixels).
+/*
+void PlotSICN (Rect *theRect, SICNHand theSICN, long theIndex)
+{
+ char state;
+ BitMap srcBits;
+
+ if ((theSICN != nil) &&
+ ((GetHandleSize((Handle)theSICN) / sizeof(SICN)) > theIndex))
+ {
+ state = HGetState((Handle)theSICN);
+ HLock((Handle)theSICN);
+
+ srcBits.baseAddr = (Ptr)(*theSICN)[theIndex];
+ srcBits.rowBytes = 2;
+ SetRect(&srcBits.bounds, 0, 0, 16, 16);
+
+ CopyBits(&srcBits,&(*qd.thePort).portBits,
+ &srcBits.bounds, theRect, srcCopy, nil);
+
+ HSetState((Handle) theSICN, state);
+ }
+}
+*/
+//-------------------------------------------------------------- LargeIconPlot
+// Draws a standard b&w icon (32 x 32) - resource is an 'ICON'.
+
+void LargeIconPlot (Rect *theRect, short theID)
+{
+ OSErr theErr;
+ Handle theSuite;
+
+ theErr = GetIconSuite(&theSuite, theID, svAllLargeData);
+ if (theErr == noErr)
+ theErr = PlotIconSuite(theRect, atNone, ttNone, theSuite);
+}
+
+//-------------------------------------------------------------- DrawCIcon
+
+// Draws a standard color icon (32 x 32) - resource is a 'CICN'.
+
+void DrawCIcon (short theID, short h, short v)
+{
+ CIconHandle theIcon;
+ Rect theRect;
+
+ theIcon = GetCIcon(theID);
+ if (theIcon != nil)
+ {
+ SetRect(&theRect, 0, 0, 32, 32);
+ OffsetRect(&theRect, h, v);
+ PlotCIcon(&theRect, theIcon);
+ DisposeCIcon(theIcon);
+ }
+}
+
+//-------------------------------------------------------------- LongSquareRoot
+
+// This is a quick and dirty square root function that returns prettyÉ
+// accurate long integer results. It uses no transcendental functions orÉ
+// floating point.
+
+long LongSquareRoot (long theNumber)
+{
+ long currentAnswer;
+ long nextTrial;
+
+ if (theNumber <= 1L)
+ return (theNumber);
+
+ nextTrial = theNumber / 2;
+
+ do
+ {
+ currentAnswer = nextTrial;
+ nextTrial = (nextTrial + theNumber / nextTrial) / 2;
+ }
+ while (nextTrial < currentAnswer);
+
+ return(currentAnswer);
+}
+
+//-------------------------------------------------------------- WaitForInputEvent
+
+// Wait for either a key to be hit or the mouse button to be clicked.
+// Also has a "timeout" parameter ("seconds").
+
+Boolean WaitForInputEvent (short seconds)
+{
+ EventRecord theEvent;
+ KeyMap theKeys;
+ long timeToBail;
+ Boolean waiting, didResume;
+
+ timeToBail = TickCount() + 60L * (long)seconds;
+ FlushEvents(everyEvent, 0);
+ waiting = true;
+ didResume = false;
+
+ while (waiting)
+ {
+ GetKeys(theKeys);
+ if ((BitTst(&theKeys, kCommandKeyMap)) || (BitTst(&theKeys, kOptionKeyMap)) ||
+ (BitTst(&theKeys, kShiftKeyMap)) || (BitTst(&theKeys, kControlKeyMap)))
+ waiting = false;
+ if (GetNextEvent(everyEvent, &theEvent))
+ {
+ if ((theEvent.what == mouseDown) || (theEvent.what == keyDown))
+ waiting = false;
+ else if ((theEvent.what == osEvt) && (theEvent.message & 0x01000000))
+ {
+ if (theEvent.message & 0x00000001) // resuming
+ {
+ didResume = true;
+ waiting = false;
+ }
+ else // suspending
+ {
+ InitCursor();
+ }
+ }
+ }
+ if ((seconds != -1) && (TickCount() >= timeToBail))
+ waiting = false;
+ }
+ FlushEvents(everyEvent, 0);
+ return (didResume);
+}
+
+//-------------------------------------------------------------- WaitCommandQReleased
+
+// Waits until the Command-Q key combination is released.
+
+void WaitCommandQReleased (void)
+{
+ KeyMap theKeys;
+ Boolean waiting;
+
+ waiting = true;
+
+ while (waiting)
+ {
+ GetKeys(theKeys);
+ if ((!BitTst(&theKeys, kCommandKeyMap)) || (!BitTst(&theKeys, kQKeyMap)))
+ waiting = false;
+ }
+ FlushEvents(everyEvent, 0);
+}
+
+//-------------------------------------------------------------- KeyMapOffsetFromRawKey
+// Converts a raw key code to keymap offset (ugly stuff).
+
+char KeyMapOffsetFromRawKey (char rawKeyCode)
+{
+ char hiByte, loByte, theOffset;
+
+ hiByte = rawKeyCode & 0xF0;
+ loByte = rawKeyCode & 0x0F;
+
+ if (loByte <= 0x07)
+ theOffset = hiByte + (0x07 - loByte);
+ else
+ theOffset = hiByte + (0x17 - loByte);
+
+ return (theOffset);
+}
+
+//-------------------------------------------------------------- GetKeyMapFromMessage
+// Gets the key map offset from a keyDown event's message field.
+
+char GetKeyMapFromMessage (intptr_t message)
+{
+ long theVirtual;
+ char offset;
+
+ theVirtual = (message & keyCodeMask) >> 8;
+ offset = KeyMapOffsetFromRawKey((char)theVirtual);
+ return (offset);
+}
+
+//-------------------------------------------------------------- GetKeyName
+// Given a keyDown event (it's message field), this function returnsÉ
+// a string with that key's name (so we get "Shift" and "Esc", etc.).
+
+void GetKeyName (intptr_t message, StringPtr theName)
+{
+ long theASCII, theVirtual;
+
+ theASCII = message & charCodeMask;
+ theVirtual = (message & keyCodeMask) >> 8;
+
+ if ((theASCII >= kExclamationASCII) && (theASCII <= kZKeyASCII))
+ {
+
+ if ((theVirtual >= 0x0041) && (theVirtual <= 0x005C))
+ {
+ PasStringCopy(PSTR("( )"), theName);
+ theName[2] = (char)theASCII;
+ }
+ else
+ {
+ PasStringCopy(PSTR(" key"), theName);
+ theName[1] = (char)theASCII;
+ }
+ }
+ else
+ {
+ switch (theASCII)
+ {
+ case kHomeKeyASCII:
+ PasStringCopy(PSTR("home"), theName);
+ break;
+
+ case kEnterKeyASCII:
+ PasStringCopy(PSTR("enter"), theName);
+ break;
+
+ case kEndKeyASCII:
+ PasStringCopy(PSTR("end"), theName);
+ break;
+
+ case kHelpKeyASCII:
+ PasStringCopy(PSTR("help"), theName);
+ break;
+
+ case kDeleteKeyASCII:
+ PasStringCopy(PSTR("delete"), theName);
+ break;
+
+ case kTabKeyASCII:
+ PasStringCopy(PSTR("tab"), theName);
+ break;
+
+ case kPageUpKeyASCII:
+ PasStringCopy(PSTR("pg up"), theName);
+ break;
+
+ case kPageDownKeyASCII:
+ PasStringCopy(PSTR("pg dn"), theName);
+ break;
+
+ case kReturnKeyASCII:
+ PasStringCopy(PSTR("return"), theName);
+ break;
+
+ case kFunctionKeyASCII:
+ switch (theVirtual)
+ {
+ case 0x0060:
+ PasStringCopy(PSTR("F5"), theName);
+ break;
+ case 0x0061:
+ PasStringCopy(PSTR("F6"), theName);
+ break;
+ case 0x0062:
+ PasStringCopy(PSTR("F7"), theName);
+ break;
+ case 0x0063:
+ PasStringCopy(PSTR("F3"), theName);
+ break;
+ case 0x0064:
+ PasStringCopy(PSTR("F8"), theName);
+ break;
+ case 0x0065:
+ PasStringCopy(PSTR("F9"), theName);
+ break;
+ case 0x0067:
+ PasStringCopy(PSTR("F11"), theName);
+ break;
+ case 0x0069:
+ PasStringCopy(PSTR("F13"), theName);
+ break;
+ case 0x006B:
+ PasStringCopy(PSTR("F14"), theName);
+ break;
+ case 0x006D:
+ PasStringCopy(PSTR("F10"), theName);
+ break;
+ case 0x006F:
+ PasStringCopy(PSTR("F12"), theName);
+ break;
+ case 0x0071:
+ PasStringCopy(PSTR("F15"), theName);
+ break;
+ case 0x0076:
+ PasStringCopy(PSTR("F4"), theName);
+ break;
+ case 0x0078:
+ PasStringCopy(PSTR("F2"), theName);
+ break;
+ case 0x007A:
+ PasStringCopy(PSTR("F1"), theName);
+ break;
+ default:
+ NumToString(theVirtual, theName);
+ break;
+ }
+ break;
+
+ case kClearKeyASCII:
+ PasStringCopy(PSTR("clear"), theName);
+ break;
+
+ case kEscapeKeyASCII:
+ if (theVirtual == 0x0047)
+ PasStringCopy(PSTR("clear"), theName);
+ else
+ PasStringCopy(PSTR("esc"), theName);
+ break;
+
+ case kLeftArrowKeyASCII:
+ PasStringCopy(PSTR("lf arrow"), theName);
+ break;
+
+ case kRightArrowKeyASCII:
+ PasStringCopy(PSTR("rt arrow"), theName);
+ break;
+
+ case kUpArrowKeyASCII:
+ PasStringCopy(PSTR("up arrow"), theName);
+ break;
+
+ case kDownArrowKeyASCII:
+ PasStringCopy(PSTR("dn arrow"), theName);
+ break;
+
+ case kSpaceBarASCII:
+ PasStringCopy(PSTR("space"), theName);
+ break;
+
+ case kForwardDeleteASCII:
+ PasStringCopy(PSTR("frwd del"), theName);
+ break;
+
+ default:
+ PasStringCopy(PSTR("????"), theName);
+ break;
+ }
+ }
+}
+
+//-------------------------------------------------------------- OptionKeyDown
+// Returns true is the Option key is being held down.
+
+Boolean OptionKeyDown (void)
+{
+ KeyMap theKeys;
+
+ GetKeys(theKeys);
+ if (BitTst(&theKeys, kOptionKeyMap))
+ return (true);
+ else
+ return (false);
+}
+
+//-------------------------------------------------------------- ExtractCTSeed
+// Very esoteric - gets the "color table seed" from a specified graf port.
+/*
+long ExtractCTSeed (CGrafPtr porter)
+{
+ long theSeed;
+
+ theSeed = (**((**(porter->portPixMap)).pmTable)).ctSeed;
+ return(theSeed);
+}
+*/
+//-------------------------------------------------------------- ForceCTSeed
+// Forces the "color table seed" from a specified graf port to aÉ
+// specified value.
+/*
+void ForceCTSeed (CGrafPtr porter, long newSeed)
+{
+ (**((**(porter->portPixMap)).pmTable)).ctSeed = newSeed;
+}
+*/
+//-------------------------------------------------------------- DelayTicks
+// Lil' function that just sits and waits a specified number ofÉ
+// Ticks (1/60 of a second).
+
+void DelayTicks (long howLong)
+{
+ UInt32 whoCares;
+
+ Delay(howLong, &whoCares);
+}
+
+//-------------------------------------------------------------- UnivGetSoundVolume
+// Returns the speaker volume (as set by the user) in the range ofÉ
+// zero to seven (handles Sound Manager 3 case as well).
+
+void UnivGetSoundVolume (short *volume, Boolean hasSM3)
+{
+ long longVol;
+ OSErr theErr;
+
+// if (hasSM3)
+// {
+ theErr = GetDefaultOutputVolume(&longVol);
+ *volume = LoWord(longVol) / 0x0024;
+// }
+// else
+// GetSoundVol(volume);
+
+ if (*volume > 7)
+ *volume = 7;
+ else if (*volume < 0)
+ *volume = 0;
+}
+
+//-------------------------------------------------------------- UnivSetSoundVolume
+// Sets the speaker volume to a specified value (in the range ofÉ
+// zero to seven (handles Sound Manager 3 case as well).
+
+void UnivSetSoundVolume (short volume, Boolean hasSM3)
+{
+ long longVol;
+ OSErr theErr;
+
+ if (volume > 7)
+ volume = 7;
+ else if (volume < 0)
+ volume = 0;
+
+// if (hasSM3)
+// {
+ longVol = (long)volume * 0x0025;
+ if (longVol > 0x00000100)
+ longVol = 0x00000100;
+ longVol = longVol + (longVol << 16);
+ theErr = SetDefaultOutputVolume(longVol);
+// }
+// else
+// SetSoundVol(volume);
+}
+
diff --git a/GpApp/Utilities.h b/GpApp/Utilities.h
new file mode 100644
index 0000000..d5fca68
--- /dev/null
+++ b/GpApp/Utilities.h
@@ -0,0 +1,11 @@
+//============================================================================
+//----------------------------------------------------------------------------
+// Utilities.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+
+#include "PLQDOffscreen.h"
+
+
+OSErr CreateOffScreenGWorld (GWorldPtr *theGWorld, Rect *bounds, short depth);
diff --git a/Sources/Validate.c b/GpApp/Validate.c
old mode 100755
new mode 100644
similarity index 100%
rename from Sources/Validate.c
rename to GpApp/Validate.c
diff --git a/GpApp/WindowUtils.cpp b/GpApp/WindowUtils.cpp
new file mode 100644
index 0000000..c9027bd
--- /dev/null
+++ b/GpApp/WindowUtils.cpp
@@ -0,0 +1,172 @@
+
+//============================================================================
+//----------------------------------------------------------------------------
+// WindowUtils.c
+//----------------------------------------------------------------------------
+//============================================================================
+
+#include "PLPasStr.h"
+#include "Externs.h"
+#include "Environ.h"
+#include "RectUtils.h"
+
+
+#define kFloatingKind 2048
+#define kMessageWindowTall 48
+
+
+WindowPtr mssgWindow;
+
+
+//============================================================== Functions
+//-------------------------------------------------------------- GetWindowTopLeft
+
+// Returns the top left coordinate of the specified window. CorrdinatesÉ
+// are (of course) global (local coordinates would always be (0, 0)).
+
+void GetWindowLeftTop (WindowPtr theWindow, short *left, short *top)
+{
+ Point thePoint;
+ Rect bounds;
+
+ *left = 0;
+ *top = 0;
+
+ if (theWindow != nil)
+ {
+ SetPortWindowPort(theWindow);
+ GetWindowBounds(theWindow, kWindowContentRgn, &bounds);
+ thePoint.h = bounds.left;
+ thePoint.v = bounds.top;
+ LocalToGlobal(&thePoint);
+ *left = thePoint.h;
+ *top = thePoint.v;
+ }
+}
+
+//-------------------------------------------------------------- GetWindowRect
+
+// Returns bounding rectangle of the specified window in global coords.
+
+void GetWindowRect (WindowPtr theWindow, Rect *bounds)
+{
+ if (theWindow != nil)
+ {
+ SetPortWindowPort(theWindow);
+ GetWindowBounds(theWindow, kWindowContentRgn, bounds);
+ LocalToGlobalRect(bounds);
+ }
+}
+
+//-------------------------------------------------------------- GetLocalWindowRect
+// Returns bounding rectangle of the specified window in local coords.
+// (When you just need its width and height.)
+
+void GetLocalWindowRect (WindowPtr theWindow, Rect *bounds)
+{
+ if (theWindow != nil)
+ {
+ SetPortWindowPort(theWindow);
+ GetWindowBounds(theWindow, kWindowContentRgn, bounds);
+ }
+}
+
+//-------------------------------------------------------------- FlagWindowFloating
+// Sets the specified window's windowKind field to my own kFloatingKindÉ
+// variable. This way I can examine a window later and determine ifÉ
+// it's supposed to "float" above all other windows.
+/*
+void FlagWindowFloating (WindowPtr theWindow)
+{
+ if (theWindow != nil)
+ {
+ ((WindowPeek)theWindow)->windowKind = kFloatingKind;
+ BringToFront(theWindow);
+ }
+}
+
+//-------------------------------------------------------------- IsWindowFloating
+
+// Tests a specific window to see if it is supposed to "float" above allÉ
+// other windows.
+
+Boolean IsWindowFloating (WindowPtr theWindow)
+{
+ if (theWindow != nil)
+ {
+ return (((WindowPeek)theWindow)->windowKind == kFloatingKind);
+ }
+ else
+ return (false);
+}
+*/
+//-------------------------------------------------------------- OpenMessageWindow
+// Brings up a simple message window. Nice sort of utility function.
+// Anytime you want a small, quick message to come up, call this.
+
+void OpenMessageWindow (const PLPasStr &title)
+{
+ Rect mssgWindowRect;
+
+ SetRect(&mssgWindowRect, 0, 0, 256, kMessageWindowTall);
+ if (thisMac.hasColor)
+ mssgWindow = NewCWindow(nil, &mssgWindowRect,
+ title, false, noGrowDocProc, kPutInFront, false, 0L);
+ else
+ mssgWindow = NewWindow(nil, &mssgWindowRect,
+ title, false, noGrowDocProc, kPutInFront, false, 0L);
+
+ if (mssgWindow != nil)
+ {
+ ShowWindow(mssgWindow);
+ SetPort((GrafPtr)mssgWindow);
+ ClipRect(&mssgWindowRect);
+ ForeColor(blackColor);
+ BackColor(whiteColor);
+ TextFont(systemFont);
+ }
+}
+
+//-------------------------------------------------------------- SetMessageWindowMessage
+
+// For the above message window, this function displays a string of textÉ
+// in the center of the window.
+
+void SetMessageWindowMessage (StringPtr message)
+{
+ Rect mssgWindowRect;
+
+ if (mssgWindow != nil)
+ {
+ SetPort((GrafPtr)mssgWindow);
+ SetRect(&mssgWindowRect, 0, 0, 256, kMessageWindowTall);
+ InsetRect(&mssgWindowRect, 16, 16);
+ EraseRect(&mssgWindowRect);
+ MoveTo(mssgWindowRect.left, mssgWindowRect.bottom - 6);
+ DrawString(message);
+ }
+}
+
+//-------------------------------------------------------------- CloseMessageWindow
+
+// Closes the previously referred to "message window".
+
+void CloseMessageWindow (void)
+{
+ if (mssgWindow != nil)
+ DisposeWindow(mssgWindow);
+ mssgWindow = nil;
+}
+
+//-------------------------------------------------------------- CloseThisWindow
+
+// Given a specific window, this function will close it and set the windowÉ
+// pointer to null.
+
+void CloseThisWindow (WindowPtr *theWindow)
+{
+ if (*theWindow != nil)
+ DisposeWindow(*theWindow);
+ *theWindow = nil;
+}
+
diff --git a/GpApp/x64/Debug/vc141.idb b/GpApp/x64/Debug/vc141.idb
new file mode 100644
index 0000000..31c6543
Binary files /dev/null and b/GpApp/x64/Debug/vc141.idb differ
diff --git a/GpApp2/ApplicationResources.bin b/GpApp2/ApplicationResources.bin
new file mode 100644
index 0000000..271d6a0
Binary files /dev/null and b/GpApp2/ApplicationResources.bin differ
diff --git a/CarbonLib b/GpApp2/CarbonLib
old mode 100755
new mode 100644
similarity index 100%
rename from CarbonLib
rename to GpApp2/CarbonLib
diff --git a/GPLv2-LICENSE.md b/GpApp2/GPLv2-LICENSE.md
similarity index 100%
rename from GPLv2-LICENSE.md
rename to GpApp2/GPLv2-LICENSE.md
diff --git a/GpApp2/Glider PRO.bin b/GpApp2/Glider PRO.bin
new file mode 100644
index 0000000..271d6a0
Binary files /dev/null and b/GpApp2/Glider PRO.bin differ
diff --git a/Glider PRO.r b/GpApp2/Glider PRO.r
similarity index 100%
rename from Glider PRO.r
rename to GpApp2/Glider PRO.r
diff --git a/Houses/Art Museum.binhex b/GpApp2/Houses/Art Museum.binhex
similarity index 100%
rename from Houses/Art Museum.binhex
rename to GpApp2/Houses/Art Museum.binhex
diff --git a/Houses/Art Museum.mov b/GpApp2/Houses/Art Museum.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Art Museum.mov
rename to GpApp2/Houses/Art Museum.mov
diff --git a/Houses/CD Demo House.binhex b/GpApp2/Houses/CD Demo House.binhex
similarity index 100%
rename from Houses/CD Demo House.binhex
rename to GpApp2/Houses/CD Demo House.binhex
diff --git a/Houses/CD Demo House.mov b/GpApp2/Houses/CD Demo House.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/CD Demo House.mov
rename to GpApp2/Houses/CD Demo House.mov
diff --git a/Houses/California or Bust!.binhex b/GpApp2/Houses/California or Bust!.binhex
similarity index 100%
rename from Houses/California or Bust!.binhex
rename to GpApp2/Houses/California or Bust!.binhex
diff --git a/Houses/Castle o' the Air.binhex b/GpApp2/Houses/Castle o' the Air.binhex
similarity index 100%
rename from Houses/Castle o' the Air.binhex
rename to GpApp2/Houses/Castle o' the Air.binhex
diff --git a/Houses/Castle o' the Air.mov b/GpApp2/Houses/Castle o' the Air.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Castle o' the Air.mov
rename to GpApp2/Houses/Castle o' the Air.mov
diff --git a/Houses/Davis Station.binhex b/GpApp2/Houses/Davis Station.binhex
similarity index 100%
rename from Houses/Davis Station.binhex
rename to GpApp2/Houses/Davis Station.binhex
diff --git a/Houses/Davis Station.mov b/GpApp2/Houses/Davis Station.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Davis Station.mov
rename to GpApp2/Houses/Davis Station.mov
diff --git a/Houses/Demo House.binhex b/GpApp2/Houses/Demo House.binhex
similarity index 100%
rename from Houses/Demo House.binhex
rename to GpApp2/Houses/Demo House.binhex
diff --git a/Houses/Demo House.mov b/GpApp2/Houses/Demo House.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Demo House.mov
rename to GpApp2/Houses/Demo House.mov
diff --git a/Houses/Empty House.binhex b/GpApp2/Houses/Empty House.binhex
similarity index 100%
rename from Houses/Empty House.binhex
rename to GpApp2/Houses/Empty House.binhex
diff --git a/Houses/Fun House.binhex b/GpApp2/Houses/Fun House.binhex
similarity index 100%
rename from Houses/Fun House.binhex
rename to GpApp2/Houses/Fun House.binhex
diff --git a/Houses/Grand Prix.binhex b/GpApp2/Houses/Grand Prix.binhex
similarity index 100%
rename from Houses/Grand Prix.binhex
rename to GpApp2/Houses/Grand Prix.binhex
diff --git a/Houses/Grand Prix.mov b/GpApp2/Houses/Grand Prix.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Grand Prix.mov
rename to GpApp2/Houses/Grand Prix.mov
diff --git a/Houses/ImagineHouse PRO II.binhex b/GpApp2/Houses/ImagineHouse PRO II.binhex
similarity index 100%
rename from Houses/ImagineHouse PRO II.binhex
rename to GpApp2/Houses/ImagineHouse PRO II.binhex
diff --git a/Houses/ImagineHouse PRO II.mov b/GpApp2/Houses/ImagineHouse PRO II.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/ImagineHouse PRO II.mov
rename to GpApp2/Houses/ImagineHouse PRO II.mov
diff --git a/Houses/In The Mirror.binhex b/GpApp2/Houses/In The Mirror.binhex
similarity index 100%
rename from Houses/In The Mirror.binhex
rename to GpApp2/Houses/In The Mirror.binhex
diff --git a/Houses/Land of Illusion.binhex b/GpApp2/Houses/Land of Illusion.binhex
similarity index 100%
rename from Houses/Land of Illusion.binhex
rename to GpApp2/Houses/Land of Illusion.binhex
diff --git a/Houses/Land of Illusion.mov b/GpApp2/Houses/Land of Illusion.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Land of Illusion.mov
rename to GpApp2/Houses/Land of Illusion.mov
diff --git a/Houses/Leviathan.binhex b/GpApp2/Houses/Leviathan.binhex
similarity index 100%
rename from Houses/Leviathan.binhex
rename to GpApp2/Houses/Leviathan.binhex
diff --git a/Houses/Leviathan.mov b/GpApp2/Houses/Leviathan.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Leviathan.mov
rename to GpApp2/Houses/Leviathan.mov
diff --git a/Houses/Metropolis.binhex b/GpApp2/Houses/Metropolis.binhex
similarity index 100%
rename from Houses/Metropolis.binhex
rename to GpApp2/Houses/Metropolis.binhex
diff --git a/Houses/Nemo's Market.binhex b/GpApp2/Houses/Nemo's Market.binhex
similarity index 100%
rename from Houses/Nemo's Market.binhex
rename to GpApp2/Houses/Nemo's Market.binhex
diff --git a/Houses/Nemo's Market.mov b/GpApp2/Houses/Nemo's Market.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Nemo's Market.mov
rename to GpApp2/Houses/Nemo's Market.mov
diff --git a/Houses/Rainbow's End.binhex b/GpApp2/Houses/Rainbow's End.binhex
similarity index 100%
rename from Houses/Rainbow's End.binhex
rename to GpApp2/Houses/Rainbow's End.binhex
diff --git a/Houses/Rainbow's End.mov b/GpApp2/Houses/Rainbow's End.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Rainbow's End.mov
rename to GpApp2/Houses/Rainbow's End.mov
diff --git a/Houses/Sampler.binhex b/GpApp2/Houses/Sampler.binhex
similarity index 100%
rename from Houses/Sampler.binhex
rename to GpApp2/Houses/Sampler.binhex
diff --git a/GpApp2/Houses/Slumberland.bin b/GpApp2/Houses/Slumberland.bin
new file mode 100644
index 0000000..0de5225
Binary files /dev/null and b/GpApp2/Houses/Slumberland.bin differ
diff --git a/Houses/Slumberland.binhex b/GpApp2/Houses/Slumberland.binhex
similarity index 100%
rename from Houses/Slumberland.binhex
rename to GpApp2/Houses/Slumberland.binhex
diff --git a/Houses/Slumberland.mov b/GpApp2/Houses/Slumberland.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Slumberland.mov
rename to GpApp2/Houses/Slumberland.mov
diff --git a/Houses/SpacePods.binhex b/GpApp2/Houses/SpacePods.binhex
similarity index 100%
rename from Houses/SpacePods.binhex
rename to GpApp2/Houses/SpacePods.binhex
diff --git a/Houses/SpacePods.mov b/GpApp2/Houses/SpacePods.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/SpacePods.mov
rename to GpApp2/Houses/SpacePods.mov
diff --git a/Houses/Teddy World.binhex b/GpApp2/Houses/Teddy World.binhex
similarity index 100%
rename from Houses/Teddy World.binhex
rename to GpApp2/Houses/Teddy World.binhex
diff --git a/Houses/Teddy World.mov b/GpApp2/Houses/Teddy World.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Teddy World.mov
rename to GpApp2/Houses/Teddy World.mov
diff --git a/Houses/The Asylum Pro.binhex b/GpApp2/Houses/The Asylum Pro.binhex
similarity index 100%
rename from Houses/The Asylum Pro.binhex
rename to GpApp2/Houses/The Asylum Pro.binhex
diff --git a/Houses/Titanic.binhex b/GpApp2/Houses/Titanic.binhex
similarity index 100%
rename from Houses/Titanic.binhex
rename to GpApp2/Houses/Titanic.binhex
diff --git a/Houses/Titanic.mov b/GpApp2/Houses/Titanic.mov
old mode 100755
new mode 100644
similarity index 100%
rename from Houses/Titanic.mov
rename to GpApp2/Houses/Titanic.mov
diff --git a/README.md b/GpApp2/README.md
similarity index 100%
rename from README.md
rename to GpApp2/README.md
diff --git a/GpD3D/EGpDisplayDriverType.h b/GpD3D/EGpDisplayDriverType.h
new file mode 100644
index 0000000..e020781
--- /dev/null
+++ b/GpD3D/EGpDisplayDriverType.h
@@ -0,0 +1,8 @@
+#pragma once
+
+enum EGpDisplayDriverType
+{
+ EGpDisplayDriverType_D3D11,
+
+ EGpDisplayDriverType_Count,
+};
diff --git a/GpD3D/GpAppEnvironment.cpp b/GpD3D/GpAppEnvironment.cpp
new file mode 100644
index 0000000..34310b8
--- /dev/null
+++ b/GpD3D/GpAppEnvironment.cpp
@@ -0,0 +1,130 @@
+#include "GpAppEnvironment.h"
+#include "GpFiberStarter.h"
+#include "GpAppInterface.h"
+#include "GpPLGlueDisplayDriver.h"
+#include "GpFiber.h"
+#include "HostSuspendCallArgument.h"
+
+#include
+
+GpAppEnvironment::GpAppEnvironment()
+ : m_applicationState(ApplicationState_NotStarted)
+ , m_displayDriver(nullptr)
+ , m_applicationFiber(nullptr)
+ , m_vosFiber(nullptr)
+ , m_suspendCallID(PortabilityLayer::HostSuspendCallID_Unknown)
+ , m_suspendArgs(nullptr)
+ , m_suspendReturnValue(nullptr)
+{
+}
+
+GpAppEnvironment::~GpAppEnvironment()
+{
+ assert(m_applicationFiber == nullptr);
+}
+
+void GpAppEnvironment::Init()
+{
+}
+
+void GpAppEnvironment::Tick(GpFiber *vosFiber)
+{
+ GpAppInterface_Get()->PL_IncrementTickCounter(1);
+
+ m_vosFiber = vosFiber;
+
+ if (m_applicationState == ApplicationState_WaitingForEvents)
+ m_applicationState = ApplicationState_Running;
+
+ for (;;)
+ {
+ switch (m_applicationState)
+ {
+ case ApplicationState_NotStarted:
+ InitializeApplicationState();
+ m_applicationFiber = GpFiberStarter::StartFiber(GpAppEnvironment::StaticAppThreadFunc, this, vosFiber);
+ m_applicationState = ApplicationState_Running;
+ break;
+ case ApplicationState_WaitingForEvents:
+ return;
+ case ApplicationState_Running:
+ m_applicationFiber->YieldTo();
+ break;
+ case ApplicationState_SystemCall:
+ {
+ PortabilityLayer::HostSuspendCallID callID = m_suspendCallID;
+ const PortabilityLayer::HostSuspendCallArgument *args = m_suspendArgs;
+ PortabilityLayer::HostSuspendCallArgument *returnValue = m_suspendReturnValue;
+
+ DispatchSystemCall(callID, args, returnValue);
+ assert(m_applicationState != ApplicationState_SystemCall);
+ }
+ break;
+ case ApplicationState_TimedSuspend:
+ if (m_delaySuspendTicks <= 1)
+ m_applicationState = ApplicationState_Running;
+ else
+ {
+ m_delaySuspendTicks--;
+ return;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ };
+ }
+}
+
+void GpAppEnvironment::SetDisplayDriver(IGpDisplayDriver *displayDriver)
+{
+ m_displayDriver = displayDriver;
+}
+
+void GpAppEnvironment::StaticAppThreadFunc(void *context)
+{
+ static_cast(context)->AppThreadFunc();
+}
+
+void GpAppEnvironment::AppThreadFunc()
+{
+ GpAppInterface_Get()->ApplicationMain();
+}
+
+void GpAppEnvironment::InitializeApplicationState()
+{
+ GpAppInterface_Get()->PL_HostDisplayDriver_SetInstance(GpPLGlueDisplayDriver::GetInstance());
+ GpAppInterface_Get()->PL_InstallHostSuspendHook(GpAppEnvironment::StaticSuspendHookFunc, this);
+
+ SynchronizeState();
+}
+
+void GpAppEnvironment::SynchronizeState()
+{
+ GpPLGlueDisplayDriver::GetInstance()->SetGpDisplayDriver(m_displayDriver);
+}
+
+void GpAppEnvironment::StaticSuspendHookFunc(void *context, PortabilityLayer::HostSuspendCallID callID, const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue)
+{
+ GpAppEnvironment *appEnv = static_cast(context);
+
+ appEnv->m_suspendCallID = callID;
+ appEnv->m_suspendArgs = args;
+ appEnv->m_suspendReturnValue = returnValue;
+ appEnv->m_applicationState = ApplicationState_SystemCall;
+
+ appEnv->m_vosFiber->YieldTo();
+}
+
+void GpAppEnvironment::DispatchSystemCall(PortabilityLayer::HostSuspendCallID callID, const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue)
+{
+ switch (callID)
+ {
+ case PortabilityLayer::HostSuspendCallID_Delay:
+ m_applicationState = ApplicationState_TimedSuspend;
+ m_delaySuspendTicks = args[0].m_uint;
+ break;
+ default:
+ assert(false);
+ }
+}
diff --git a/GpD3D/GpAppEnvironment.h b/GpD3D/GpAppEnvironment.h
new file mode 100644
index 0000000..443122a
--- /dev/null
+++ b/GpD3D/GpAppEnvironment.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "HostSuspendCallID.h"
+
+#include
+
+namespace PortabilityLayer
+{
+ union HostSuspendCallArgument;
+}
+
+class IGpDisplayDriver;
+class GpFiber;
+
+class GpAppEnvironment
+{
+public:
+ GpAppEnvironment();
+ ~GpAppEnvironment();
+
+ void Init();
+
+ void Tick(GpFiber *vosFiber);
+ void SetDisplayDriver(IGpDisplayDriver *displayDriver);
+
+private:
+ enum ApplicationState
+ {
+ ApplicationState_NotStarted,
+ ApplicationState_WaitingForEvents,
+ ApplicationState_Running,
+ ApplicationState_Terminated,
+ ApplicationState_SystemCall,
+ ApplicationState_TimedSuspend,
+ };
+
+ static void StaticAppThreadFunc(void *context);
+ void AppThreadFunc();
+ void InitializeApplicationState();
+ void SynchronizeState();
+
+ static void StaticSuspendHookFunc(void *context, PortabilityLayer::HostSuspendCallID callID, const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue);
+ void DispatchSystemCall(PortabilityLayer::HostSuspendCallID callID, const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue);
+
+ ApplicationState m_applicationState;
+ IGpDisplayDriver *m_displayDriver;
+ GpFiber *m_applicationFiber;
+ GpFiber *m_vosFiber;
+
+ uint32_t m_delaySuspendTicks;
+
+ PortabilityLayer::HostSuspendCallID m_suspendCallID;
+ const PortabilityLayer::HostSuspendCallArgument *m_suspendArgs;
+ PortabilityLayer::HostSuspendCallArgument *m_suspendReturnValue;
+};
diff --git a/GpD3D/GpCoreDefs.h b/GpD3D/GpCoreDefs.h
new file mode 100644
index 0000000..bfe42cb
--- /dev/null
+++ b/GpD3D/GpCoreDefs.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#if __cplusplus >= 199711L
+#define GP_IS_CPP11 1
+#else
+#define GP_IS_CPP11 0
+#endif
+
+#if GP_IS_CPP11
+#define GP_DELETED = delete
+#else
+#ifndef nullptr
+#define nullptr 0
+#endif
+
+#ifndef override
+#define override
+#endif
+
+#ifndef final
+#define final
+#endif
+
+#define GP_DELETED
+#endif
diff --git a/GpD3D/GpD3D.vcxproj b/GpD3D/GpD3D.vcxproj
new file mode 100644
index 0000000..24013d1
--- /dev/null
+++ b/GpD3D/GpD3D.vcxproj
@@ -0,0 +1,177 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}
+ GpD3D
+ 10.0.17763.0
+
+
+
+ Application
+ true
+ v141
+ MultiByte
+
+
+ Application
+ false
+ v141
+ true
+ MultiByte
+
+
+ Application
+ true
+ v141
+ MultiByte
+
+
+ Application
+ false
+ v141
+ true
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level4
+ Disabled
+ true
+ true
+
+
+ shlwapi.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ shlwapi.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {6233c3f2-5781-488e-b190-4fa8836f5a77}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GpD3D/GpD3D.vcxproj.filters b/GpD3D/GpD3D.vcxproj.filters
new file mode 100644
index 0000000..54e5914
--- /dev/null
+++ b/GpD3D/GpD3D.vcxproj.filters
@@ -0,0 +1,129 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/GpD3D/GpDisplayDriverD3D11.cpp b/GpD3D/GpDisplayDriverD3D11.cpp
new file mode 100644
index 0000000..53fb13d
--- /dev/null
+++ b/GpD3D/GpDisplayDriverD3D11.cpp
@@ -0,0 +1,290 @@
+#include "GpDisplayDriverD3D11.h"
+#include "GpWindows.h"
+#include "GpFiber_Win32.h"
+
+#include
+#include
+
+#include
+
+#pragma comment (lib, "d3d11.lib")
+
+void DebugPrintf(const char *fmt, ...)
+{
+ char buf[256];
+ va_list argp;
+ va_start(argp, fmt);
+ vsnprintf_s(buf, 255, fmt, argp);
+ OutputDebugString(buf);
+ va_end(argp);
+}
+
+LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_DESTROY:
+ {
+ PostQuitMessage(0);
+ return 0;
+ }
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void StartD3DForWindow(HWND hWnd, IDXGISwapChain1*& swapChain)
+{
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc;
+
+ ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
+
+ swapChainDesc.BufferCount = 2;
+ swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.SampleDesc.Count = 1;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+
+ DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapChainFullscreenDesc;
+
+ ZeroMemory(&swapChainFullscreenDesc, sizeof(swapChainFullscreenDesc));
+
+ swapChainFullscreenDesc.Windowed = TRUE;
+ swapChainFullscreenDesc.RefreshRate.Numerator = 60;
+ swapChainFullscreenDesc.RefreshRate.Denominator = 1;
+
+ UINT flags = 0;
+ const D3D_FEATURE_LEVEL featureLevels[] =
+ {
+ D3D_FEATURE_LEVEL_9_1
+ };
+
+ flags |= D3D11_CREATE_DEVICE_DEBUG;
+
+ ID3D11Device *device = NULL;
+ ID3D11DeviceContext *context = NULL;
+
+ D3D_FEATURE_LEVEL selectedFeatureLevel;
+
+ HRESULT result = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, featureLevels, sizeof(featureLevels) / sizeof(featureLevels[0]),
+ D3D11_SDK_VERSION, &device, &selectedFeatureLevel, &context);
+
+ IDXGIDevice2 *dxgiDevice = nullptr;
+ result = device->QueryInterface(__uuidof(IDXGIDevice2), reinterpret_cast(&dxgiDevice));
+
+ IDXGIAdapter *dxgiAdapter = nullptr;
+ result = dxgiDevice->GetAdapter(&dxgiAdapter);
+
+ IDXGIFactory2 *dxgiFactory = nullptr;
+ result = dxgiAdapter->GetParent(__uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory));
+
+ result = dxgiFactory->CreateSwapChainForHwnd(device, hWnd, &swapChainDesc, nullptr, nullptr, &swapChain);
+}
+
+bool GpDisplayDriverD3D11::PresentFrameAndSync()
+{
+ DXGI_PRESENT_PARAMETERS presentParams;
+
+ ZeroMemory(&presentParams, sizeof(presentParams));
+
+ UINT lastPresentCount = 0;
+
+ if (FAILED(m_SwapChain->GetLastPresentCount(&lastPresentCount)))
+ return false;
+
+ if (FAILED(m_SwapChain->Present1(1, 0, &presentParams)))
+ return false;
+
+ //DebugPrintf("r: %i\n", static_cast(r));
+
+ DXGI_FRAME_STATISTICS stats;
+ if (FAILED(m_SwapChain->GetFrameStatistics(&stats)))
+ return false;
+
+ if (stats.SyncQPCTime.QuadPart != 0)
+ {
+ if (m_SyncTimeBase.QuadPart == 0)
+ m_SyncTimeBase = stats.SyncQPCTime;
+
+ LARGE_INTEGER timestamp;
+ timestamp.QuadPart = stats.SyncQPCTime.QuadPart - m_SyncTimeBase.QuadPart;
+
+ bool compacted = false;
+ if (m_PresentHistory.Size() > 0)
+ {
+ CompactedPresentHistoryItem &lastItem = m_PresentHistory[m_PresentHistory.Size() - 1];
+ LONGLONG timeDelta = timestamp.QuadPart - lastItem.m_Timestamp.QuadPart;
+
+ if (timeDelta < 0)
+ timeDelta = 0; // This should never happen
+
+ if (timeDelta * static_cast(m_Properties.m_FrameTimeLockDenominator) < m_QPFrequency.QuadPart * static_cast(m_Properties.m_FrameTimeLockNumerator))
+ {
+ lastItem.m_NumFrames++;
+ compacted = true;
+ }
+ }
+
+ if (!compacted)
+ {
+ if (m_PresentHistory.Size() == m_PresentHistory.CAPACITY)
+ m_PresentHistory.RemoveFromStart();
+
+ CompactedPresentHistoryItem *newItem = m_PresentHistory.Append();
+ newItem->m_Timestamp = timestamp;
+ newItem->m_NumFrames = 1;
+ }
+ }
+
+ if (m_PresentHistory.Size() >= 2)
+ {
+ const size_t presentHistorySizeMinusOne = m_PresentHistory.Size() - 1;
+ unsigned int numFrames = 0;
+ for (size_t i = 0; i < presentHistorySizeMinusOne; i++)
+ numFrames += m_PresentHistory[i].m_NumFrames;
+
+ LONGLONG timeFrame = m_PresentHistory[presentHistorySizeMinusOne].m_Timestamp.QuadPart - m_PresentHistory[0].m_Timestamp.QuadPart;
+
+ unsigned int cancelledFrames = 0;
+ LONGLONG cancelledTime = 0;
+
+ const int overshootTolerance = 2;
+
+ for (size_t i = 0; i < presentHistorySizeMinusOne; i++)
+ {
+ LONGLONG blockTimeframe = m_PresentHistory[i + 1].m_Timestamp.QuadPart - m_PresentHistory[i].m_Timestamp.QuadPart;
+ unsigned int blockNumFrames = m_PresentHistory[i].m_NumFrames;
+
+ if (blockTimeframe * static_cast(numFrames) >= timeFrame * static_cast(blockNumFrames) * overshootTolerance)
+ {
+ cancelledTime += blockTimeframe;
+ cancelledFrames += blockNumFrames;
+ }
+ }
+
+ numFrames -= cancelledFrames;
+ timeFrame -= cancelledTime;
+
+ // timeFrame / numFrames = Frame timestep
+ // Unless Frame timestep is within the frame lock range, a.k.a.
+ // timeFrame / numFrames / qpFreq >= minFrameTimeNum / minFrameTimeDenom
+
+ bool isInFrameTimeLock = false;
+ if (timeFrame * static_cast(m_Properties.m_FrameTimeLockMinDenominator) >= static_cast(numFrames) * static_cast(m_Properties.m_FrameTimeLockMinNumerator) * m_QPFrequency.QuadPart
+ && timeFrame * static_cast(m_Properties.m_FrameTimeLockMaxDenominator) <= static_cast(numFrames) * static_cast(m_Properties.m_FrameTimeLockMaxNumerator) * m_QPFrequency.QuadPart)
+ {
+ isInFrameTimeLock = true;
+ }
+
+ LONGLONG frameTimeStep = m_FrameTimeSliceSize;
+ if (!isInFrameTimeLock)
+ {
+ const int MAX_FRAMES_PER_STEP = 4;
+
+ frameTimeStep = timeFrame / numFrames;
+ if (frameTimeStep > m_FrameTimeSliceSize * MAX_FRAMES_PER_STEP)
+ frameTimeStep = m_FrameTimeSliceSize * MAX_FRAMES_PER_STEP;
+ }
+
+ m_FrameTimeAccumulated += frameTimeStep;
+ while (m_FrameTimeAccumulated >= m_FrameTimeSliceSize)
+ {
+ m_Properties.m_TickFunc(m_Properties.m_TickFuncContext, m_vosFiber);
+ m_FrameTimeAccumulated -= m_FrameTimeSliceSize;
+ }
+ }
+
+ return true;
+}
+
+void GpDisplayDriverD3D11::Run()
+{
+ HWND hWnd;
+ WNDCLASSEX wc;
+
+ LPVOID fiber = ConvertThreadToFiberEx(this, 0);
+ if (!fiber)
+ return; // ???
+
+ m_vosFiber = new GpFiber_Win32(fiber);
+
+ ZeroMemory(&wc, sizeof(wc));
+
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = WinProc;
+ wc.hInstance = g_gpWindowsGlobals.m_hInstance;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
+ wc.lpszClassName = "GPD3D11WindowClass";
+
+ RegisterClassEx(&wc);
+
+ LONG windowStyle = WS_OVERLAPPEDWINDOW;
+ HMENU menus = NULL;
+
+ // TODO: Fix the resolution here
+ RECT wr = { 0, 0, m_windowWidth, m_windowHeight };
+ AdjustWindowRect(&wr, windowStyle, menus != NULL);
+
+ hWnd = CreateWindowExW(NULL, L"GPD3D11WindowClass", L"GlidePort", WS_OVERLAPPEDWINDOW, 300, 300, wr.right - wr.left, wr.bottom - wr.top, NULL, menus, g_gpWindowsGlobals.m_hInstance, NULL);
+
+ ShowWindow(hWnd, g_gpWindowsGlobals.m_nCmdShow);
+
+ StartD3DForWindow(hWnd, m_SwapChain);
+
+ LARGE_INTEGER lastTimestamp;
+ memset(&lastTimestamp, 0, sizeof(lastTimestamp));
+
+ MSG msg;
+ for (;;)
+ {
+ if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+
+ DispatchMessage(&msg);
+
+ if (msg.message == WM_QUIT)
+ break;
+ }
+ else
+ {
+ PresentFrameAndSync();
+ }
+ }
+
+ // Exit
+ ConvertFiberToThread();
+}
+
+void GpDisplayDriverD3D11::Shutdown()
+{
+ delete this;
+}
+
+void GpDisplayDriverD3D11::GetDisplayResolution(unsigned int &width, unsigned int &height)
+{
+ width = m_windowWidth;
+ height = m_windowHeight;
+}
+
+GpDisplayDriverD3D11 *GpDisplayDriverD3D11::Create(const GpDisplayDriverProperties &properties)
+{
+ return new GpDisplayDriverD3D11(properties);
+}
+
+GpDisplayDriverD3D11::GpDisplayDriverD3D11(const GpDisplayDriverProperties &properties)
+ : m_Properties(properties)
+ , m_FrameTimeAccumulated(0)
+ , m_windowWidth(640)
+ , m_windowHeight(480)
+ , m_vosFiber(nullptr)
+{
+ memset(&m_SyncTimeBase, 0, sizeof(m_SyncTimeBase));
+
+ QueryPerformanceFrequency(&m_QPFrequency);
+
+ m_FrameTimeSliceSize = m_QPFrequency.QuadPart * static_cast(properties.m_FrameTimeLockNumerator) / static_cast(properties.m_FrameTimeLockDenominator);
+}
diff --git a/GpD3D/GpDisplayDriverD3D11.h b/GpD3D/GpDisplayDriverD3D11.h
new file mode 100644
index 0000000..5e47bc8
--- /dev/null
+++ b/GpD3D/GpDisplayDriverD3D11.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "GpWindows.h"
+#include "GpRingBuffer.h"
+
+#include "IGpDisplayDriver.h"
+#include "GpCoreDefs.h"
+#include "GpDisplayDriverProperties.h"
+
+struct IDXGISwapChain1;
+
+class GpDisplayDriverD3D11 : public IGpDisplayDriver
+{
+public:
+ void Run() override;
+ void Shutdown() override;
+
+ void GetDisplayResolution(unsigned int &width, unsigned int &height) override;
+
+ static GpDisplayDriverD3D11 *Create(const GpDisplayDriverProperties &properties);
+
+private:
+ GpDisplayDriverD3D11(const GpDisplayDriverProperties &properties);
+
+ bool PresentFrameAndSync();
+
+ IDXGISwapChain1 *m_SwapChain;
+
+ struct CompactedPresentHistoryItem
+ {
+ LARGE_INTEGER m_Timestamp;
+ unsigned int m_NumFrames;
+ };
+
+ GpRingBuffer m_PresentHistory;
+ GpDisplayDriverProperties m_Properties;
+
+ LARGE_INTEGER m_SyncTimeBase;
+ LARGE_INTEGER m_QPFrequency;
+ UINT m_ExpectedSyncDelta;
+ bool m_IsResettingSwapChain;
+
+ LONGLONG m_FrameTimeAccumulated;
+ LONGLONG m_FrameTimeSliceSize;
+
+ DWORD m_windowWidth;
+ DWORD m_windowHeight;
+
+ GpFiber *m_vosFiber;
+};
diff --git a/GpD3D/GpDisplayDriverFactory.cpp b/GpD3D/GpDisplayDriverFactory.cpp
new file mode 100644
index 0000000..fc79bb1
--- /dev/null
+++ b/GpD3D/GpDisplayDriverFactory.cpp
@@ -0,0 +1,23 @@
+#include "GpDisplayDriverFactory.h"
+#include "GpDisplayDriverProperties.h"
+
+#include
+
+IGpDisplayDriver *GpDisplayDriverFactory::CreateDisplayDriver(const GpDisplayDriverProperties &properties)
+{
+ assert(properties.m_Type < EGpDisplayDriverType_Count);
+
+ if (ms_Registry[properties.m_Type])
+ return ms_Registry[properties.m_Type](properties);
+ else
+ return nullptr;
+}
+
+void GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType type, FactoryFunc_t func)
+{
+ assert(type < EGpDisplayDriverType_Count);
+
+ ms_Registry[type] = func;
+}
+
+GpDisplayDriverFactory::FactoryFunc_t GpDisplayDriverFactory::ms_Registry[EGpDisplayDriverType_Count];
diff --git a/GpD3D/GpDisplayDriverFactory.h b/GpD3D/GpDisplayDriverFactory.h
new file mode 100644
index 0000000..706375a
--- /dev/null
+++ b/GpD3D/GpDisplayDriverFactory.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "EGpDisplayDriverType.h"
+
+class IGpDisplayDriver;
+struct GpDisplayDriverProperties;
+
+class GpDisplayDriverFactory
+{
+public:
+ typedef IGpDisplayDriver *(*FactoryFunc_t)(const GpDisplayDriverProperties &properties);
+
+ static IGpDisplayDriver *CreateDisplayDriver(const GpDisplayDriverProperties &properties);
+ static void RegisterDisplayDriverFactory(EGpDisplayDriverType type, FactoryFunc_t func);
+
+private:
+ static FactoryFunc_t ms_Registry[EGpDisplayDriverType_Count];
+};
diff --git a/GpD3D/GpDisplayDriverFactoryD3D11.cpp b/GpD3D/GpDisplayDriverFactoryD3D11.cpp
new file mode 100644
index 0000000..33bfea2
--- /dev/null
+++ b/GpD3D/GpDisplayDriverFactoryD3D11.cpp
@@ -0,0 +1,7 @@
+#include "GpDisplayDriverFactoryD3D11.h"
+#include "GpDisplayDriverD3D11.h"
+
+IGpDisplayDriver *GpDisplayDriverFactoryD3D11::Create(const GpDisplayDriverProperties &properties)
+{
+ return GpDisplayDriverD3D11::Create(properties);
+}
diff --git a/GpD3D/GpDisplayDriverFactoryD3D11.h b/GpD3D/GpDisplayDriverFactoryD3D11.h
new file mode 100644
index 0000000..b540217
--- /dev/null
+++ b/GpD3D/GpDisplayDriverFactoryD3D11.h
@@ -0,0 +1,10 @@
+#pragma once
+
+class IGpDisplayDriver;
+struct GpDisplayDriverProperties;
+
+class GpDisplayDriverFactoryD3D11
+{
+public:
+ static IGpDisplayDriver *Create(const GpDisplayDriverProperties &properties);
+};
diff --git a/GpD3D/GpDisplayDriverProperties.h b/GpD3D/GpDisplayDriverProperties.h
new file mode 100644
index 0000000..79ae5bd
--- /dev/null
+++ b/GpD3D/GpDisplayDriverProperties.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "EGpDisplayDriverType.h"
+
+class IGpDisplayDriver;
+class GpFiber;
+
+struct GpDisplayDriverProperties
+{
+ typedef void(*TickFunc_t)(void *context, GpFiber *vosFiber);
+
+ EGpDisplayDriverType m_Type;
+
+ unsigned int m_FrameTimeLockNumerator;
+ unsigned int m_FrameTimeLockDenominator;
+
+ unsigned int m_FrameTimeLockMinNumerator;
+ unsigned int m_FrameTimeLockMinDenominator;
+
+ unsigned int m_FrameTimeLockMaxNumerator;
+ unsigned int m_FrameTimeLockMaxDenominator;
+
+ // Tick function and context to call when a frame needs to be served.
+ TickFunc_t m_TickFunc;
+ void *m_TickFuncContext;
+};
diff --git a/GpD3D/GpEvent.h b/GpD3D/GpEvent.h
new file mode 100644
index 0000000..7ccaac1
--- /dev/null
+++ b/GpD3D/GpEvent.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "GpCoreDefs.h"
+
+class GpEvent final
+{
+public:
+ void Wait();
+ void WaitMSec(unsigned int msec);
+ void Signal();
+ void Reset();
+ void Destroy();
+
+ static GpEvent *Create(bool autoReset, bool startSignalled);
+
+private:
+ explicit GpEvent(void *privateData);
+ ~GpEvent();
+
+ void *m_PrivateData;
+};
diff --git a/GpD3D/GpEvent_Win32.cpp b/GpD3D/GpEvent_Win32.cpp
new file mode 100644
index 0000000..6323697
--- /dev/null
+++ b/GpD3D/GpEvent_Win32.cpp
@@ -0,0 +1,49 @@
+#include "GpEvent.h"
+#include "GpWindows.h"
+
+#include
+
+GpEvent::~GpEvent()
+{
+ CloseHandle(static_cast(m_PrivateData));
+}
+
+void GpEvent::Wait()
+{
+ WaitForSingleObject(static_cast(m_PrivateData), INFINITE);
+}
+
+void GpEvent::WaitMSec(unsigned int msec)
+{
+ assert(msec < MAXDWORD);
+ WaitForSingleObject(static_cast(m_PrivateData), static_cast(msec));
+}
+
+void GpEvent::Signal()
+{
+ SetEvent(static_cast(m_PrivateData));
+}
+
+void GpEvent::Reset()
+{
+ ResetEvent(static_cast(m_PrivateData));
+}
+
+void GpEvent::Destroy()
+{
+ delete this;
+}
+
+GpEvent *GpEvent::Create(bool autoReset, bool startSignalled)
+{
+ HANDLE handle = CreateEventA(nullptr, autoReset ? FALSE : TRUE, startSignalled ? TRUE : FALSE, nullptr);
+ if (!handle)
+ return nullptr;
+
+ return new GpEvent(handle);
+}
+
+GpEvent::GpEvent(void *privateData)
+ : m_PrivateData(privateData)
+{
+}
diff --git a/GpD3D/GpFiber.h b/GpD3D/GpFiber.h
new file mode 100644
index 0000000..01fbd2c
--- /dev/null
+++ b/GpD3D/GpFiber.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "CoreDefs.h"
+
+class GpFiber
+{
+public:
+ virtual void YieldTo() = 0;
+ virtual void Destroy() = 0;
+};
diff --git a/GpD3D/GpFiberStarter.h b/GpD3D/GpFiberStarter.h
new file mode 100644
index 0000000..24d98a8
--- /dev/null
+++ b/GpD3D/GpFiberStarter.h
@@ -0,0 +1,11 @@
+#pragma once
+
+class GpFiber;
+
+class GpFiberStarter
+{
+public:
+ typedef void(*ThreadFunc_t)(void *context);
+
+ static GpFiber *StartFiber(ThreadFunc_t threadFunc, void *context, GpFiber *creatingFiber);
+};
diff --git a/GpD3D/GpFiberStarter_Win32.cpp b/GpD3D/GpFiberStarter_Win32.cpp
new file mode 100644
index 0000000..d3d2c78
--- /dev/null
+++ b/GpD3D/GpFiberStarter_Win32.cpp
@@ -0,0 +1,52 @@
+#include "GpFiberStarter.h"
+#include "GpFiber_Win32.h"
+#include "GpWindows.h"
+
+#include
+
+namespace GpFiberStarter_Win32
+{
+ struct FiberStartState
+ {
+ GpFiberStarter::ThreadFunc_t m_threadFunc;
+ GpFiber *m_creatingFiber;
+ void *m_context;
+ };
+
+ static VOID WINAPI FiberStartRoutine(LPVOID lpThreadParameter)
+ {
+ const FiberStartState *tss = static_cast(lpThreadParameter);
+
+ GpFiberStarter::ThreadFunc_t threadFunc = tss->m_threadFunc;
+ GpFiber *creatingFiber = tss->m_creatingFiber;
+ void *context = tss->m_context;
+ creatingFiber->YieldTo();
+
+ threadFunc(context);
+
+ assert(!"Fiber function exited");
+ }
+}
+
+GpFiber *GpFiberStarter::StartFiber(ThreadFunc_t threadFunc, void *context, GpFiber *creatingFiber)
+{
+ ULONG_PTR lowLimit;
+ ULONG_PTR highLimit;
+
+ GetCurrentThreadStackLimits(&lowLimit, &highLimit);
+
+ ULONG_PTR stackSize = highLimit - lowLimit;
+
+ GpFiberStarter_Win32::FiberStartState startState;
+ startState.m_context = context;
+ startState.m_creatingFiber = creatingFiber;
+ startState.m_threadFunc = threadFunc;
+
+ void *fiber = CreateFiber(static_cast(stackSize), GpFiberStarter_Win32::FiberStartRoutine, &startState);
+ if (!fiber)
+ return nullptr;
+
+ SwitchToFiber(fiber);
+
+ return new GpFiber_Win32(fiber);
+}
diff --git a/GpD3D/GpFiber_Win32.cpp b/GpD3D/GpFiber_Win32.cpp
new file mode 100644
index 0000000..ade6202
--- /dev/null
+++ b/GpD3D/GpFiber_Win32.cpp
@@ -0,0 +1,17 @@
+#include "GpFiber_Win32.h"
+
+GpFiber_Win32::GpFiber_Win32(LPVOID fiber)
+ : m_fiber(fiber)
+{
+}
+
+void GpFiber_Win32::YieldTo()
+{
+ SwitchToFiber(m_fiber);
+}
+
+void GpFiber_Win32::Destroy()
+{
+ DeleteFiber(m_fiber);
+ delete this;
+}
diff --git a/GpD3D/GpFiber_Win32.h b/GpD3D/GpFiber_Win32.h
new file mode 100644
index 0000000..9d0ea9b
--- /dev/null
+++ b/GpD3D/GpFiber_Win32.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "GpWindows.h"
+#include "GpFiber.h"
+
+class GpFiber_Win32 final : public GpFiber
+{
+public:
+ explicit GpFiber_Win32(LPVOID fiber);
+
+ void YieldTo() override;
+ void Destroy() override;
+
+private:
+ LPVOID m_fiber;
+};
diff --git a/GpD3D/GpFileStream_Win32.cpp b/GpD3D/GpFileStream_Win32.cpp
new file mode 100644
index 0000000..eeb3ca0
--- /dev/null
+++ b/GpD3D/GpFileStream_Win32.cpp
@@ -0,0 +1,141 @@
+#include "GpFileStream_Win32.h"
+
+GpFileStream_Win32::GpFileStream_Win32(HANDLE handle, bool readable, bool writeable, bool seekable)
+ : m_handle(handle)
+ , m_readable(readable)
+ , m_writeable(writeable)
+ , m_seekable(seekable)
+{
+}
+
+size_t GpFileStream_Win32::Read(void *bytesOut, size_t size)
+{
+ if (!m_readable)
+ return 0;
+
+ size_t totalRead = 0;
+ while (size)
+ {
+ const DWORD chunkSizeToRead = (size > MAXDWORD) ? MAXDWORD : size;
+ DWORD numRead = 0;
+
+ BOOL readSucceeded = ReadFile(m_handle, bytesOut, chunkSizeToRead, &numRead, nullptr);
+ if (!readSucceeded)
+ return totalRead;
+
+ totalRead += static_cast(numRead);
+ size -= static_cast(numRead);
+ bytesOut = static_cast(static_cast(bytesOut) + numRead);
+
+ if (numRead != chunkSizeToRead)
+ return totalRead;
+ }
+
+ return totalRead;
+}
+
+size_t GpFileStream_Win32::Write(const void *bytes, size_t size)
+{
+ if (!m_writeable)
+ return 0;
+
+ size_t totalWritten = 0;
+ while (size)
+ {
+ const DWORD chunkSizeToWrite = (size > MAXDWORD) ? MAXDWORD : size;
+ DWORD numWritten = 0;
+
+ BOOL writeSucceeded = WriteFile(m_handle, bytes, chunkSizeToWrite, &numWritten, nullptr);
+ if (!writeSucceeded)
+ return totalWritten;
+
+ totalWritten += static_cast(numWritten);
+ size -= static_cast(numWritten);
+ bytes = static_cast(static_cast(bytes) + numWritten);
+
+ if (numWritten != chunkSizeToWrite)
+ return totalWritten;
+ }
+
+ return totalWritten;
+}
+
+bool GpFileStream_Win32::IsSeekable() const
+{
+ return m_seekable;
+}
+
+bool GpFileStream_Win32::IsReadOnly() const
+{
+ return !m_writeable;
+}
+
+bool GpFileStream_Win32::IsWriteOnly() const
+{
+ return !m_readable;
+}
+
+bool GpFileStream_Win32::SeekStart(PortabilityLayer::UFilePos_t loc)
+{
+ LARGE_INTEGER li;
+ li.QuadPart = static_cast(loc);
+ return SetFilePointerEx(m_handle, li, nullptr, FILE_BEGIN) != 0;
+}
+
+bool GpFileStream_Win32::SeekCurrent(PortabilityLayer::FilePos_t loc)
+{
+ LARGE_INTEGER li;
+ li.QuadPart = static_cast(loc);
+ return SetFilePointerEx(m_handle, li, nullptr, FILE_CURRENT) != 0;
+}
+
+bool GpFileStream_Win32::SeekEnd(PortabilityLayer::UFilePos_t loc)
+{
+ LARGE_INTEGER li;
+ li.QuadPart = static_cast(loc);
+ return SetFilePointerEx(m_handle, li, nullptr, FILE_END) != 0;
+}
+
+bool GpFileStream_Win32::Truncate(PortabilityLayer::UFilePos_t loc)
+{
+ if (!m_writeable)
+ return false;
+
+ PortabilityLayer::UFilePos_t oldPos = Tell();
+ if (!SeekStart(loc))
+ return false;
+
+ if (!SetEndOfFile(m_handle))
+ return false;
+
+ if (!SeekStart(oldPos))
+ return false;
+
+ return true;
+}
+
+PortabilityLayer::UFilePos_t GpFileStream_Win32::Size() const
+{
+ LARGE_INTEGER fsize;
+ if (!GetFileSizeEx(m_handle, &fsize))
+ return 0;
+
+ return static_cast(fsize.QuadPart);
+}
+
+PortabilityLayer::UFilePos_t GpFileStream_Win32::Tell() const
+{
+ LARGE_INTEGER zero;
+ zero.QuadPart = 0;
+
+ LARGE_INTEGER fpos;
+ if (!SetFilePointerEx(m_handle, zero, &fpos, FILE_CURRENT))
+ return 0;
+
+ return static_cast(fpos.QuadPart);
+}
+
+void GpFileStream_Win32::Close()
+{
+ CloseHandle(m_handle);
+}
diff --git a/GpD3D/GpFileStream_Win32.h b/GpD3D/GpFileStream_Win32.h
new file mode 100644
index 0000000..95130b5
--- /dev/null
+++ b/GpD3D/GpFileStream_Win32.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "GpCoreDefs.h"
+#include "GpWindows.h"
+#include "IOStream.h"
+
+class GpFileStream_Win32 final : public PortabilityLayer::IOStream
+{
+public:
+ explicit GpFileStream_Win32(HANDLE handle, bool readable, bool writeable, bool seekable);
+
+ size_t Read(void *bytesOut, size_t size) override;
+ size_t Write(const void *bytes, size_t size) override;
+ bool IsSeekable() const override;
+ bool IsReadOnly() const override;
+ bool IsWriteOnly() const override;
+ bool SeekStart(PortabilityLayer::UFilePos_t loc) override;
+ bool SeekCurrent(PortabilityLayer::FilePos_t loc) override;
+ bool SeekEnd(PortabilityLayer::UFilePos_t loc) override;
+ bool Truncate(PortabilityLayer::UFilePos_t loc) override;
+ PortabilityLayer::UFilePos_t Size() const override;
+ PortabilityLayer::UFilePos_t Tell() const override;
+ void Close() override;
+
+private:
+ HANDLE m_handle;
+ bool m_readable;
+ bool m_writeable;
+ bool m_seekable;
+};
diff --git a/GpD3D/GpFileSystem_Win32.cpp b/GpD3D/GpFileSystem_Win32.cpp
new file mode 100644
index 0000000..6959281
--- /dev/null
+++ b/GpD3D/GpFileSystem_Win32.cpp
@@ -0,0 +1,96 @@
+#include "GpFileSystem_Win32.h"
+#include "GpFileStream_Win32.h"
+#include "GpWindows.h"
+#include "GpMemoryBuffer.h"
+
+#include
+#include
+#include
+
+GpFileSystem_Win32::GpFileSystem_Win32()
+{
+ PWSTR docsPath;
+ if (!FAILED(SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &docsPath)))
+ {
+ try
+ {
+ m_prefsDir = docsPath;
+ }
+ catch(...)
+ {
+ CoTaskMemFree(docsPath);
+ throw;
+ }
+
+ m_prefsDir.append(L"\\GlidePort");
+
+ CreateDirectoryW(m_prefsDir.c_str(), nullptr);
+ m_prefsDir.append(L"\\");
+ }
+}
+
+bool GpFileSystem_Win32::FileExists(PortabilityLayer::EVirtualDirectory virtualDirectory, const char *path)
+{
+ wchar_t winPath[MAX_PATH + 1];
+
+ if (!ResolvePath(virtualDirectory, path, winPath))
+ return false;
+
+ return PathFileExistsW(winPath) != 0;
+}
+
+PortabilityLayer::IOStream *GpFileSystem_Win32::OpenFile(PortabilityLayer::EVirtualDirectory virtualDirectory, const char *path, bool writeAccess, bool create)
+{
+ wchar_t winPath[MAX_PATH + 1];
+
+ if (!ResolvePath(virtualDirectory, path, winPath))
+ return false;
+
+ const DWORD desiredAccess = writeAccess ? (GENERIC_WRITE | GENERIC_READ) : GENERIC_READ;
+ const DWORD creationDisposition = create ? OPEN_ALWAYS : OPEN_EXISTING;
+
+ HANDLE h = CreateFileW(winPath, desiredAccess, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+
+ return new GpFileStream_Win32(h, true, writeAccess, true);
+}
+
+GpFileSystem_Win32 *GpFileSystem_Win32::GetInstance()
+{
+ return &ms_instance;
+}
+
+bool GpFileSystem_Win32::ResolvePath(PortabilityLayer::EVirtualDirectory virtualDirectory, const char *path, wchar_t *outPath)
+{
+ const wchar_t *baseDir = nullptr;
+
+ switch (virtualDirectory)
+ {
+ case PortabilityLayer::EVirtualDirectory_ApplicationData:
+ baseDir = L"D:\\Source Code\\GlidePort\\Packaged\\";
+ break;
+ case PortabilityLayer::EVirtualDirectory_Prefs:
+ baseDir = m_prefsDir.c_str();
+ break;
+ default:
+ return false;
+ }
+
+ if (baseDir == nullptr)
+ return false;
+
+ const size_t baseDirLen = wcslen(baseDir);
+ const size_t pathLen = strlen(path);
+
+ if (baseDirLen >= MAX_PATH || MAX_PATH - baseDirLen < pathLen)
+ return false;
+
+ memcpy(outPath, baseDir, sizeof(wchar_t) * baseDirLen);
+ for (size_t i = 0; i < pathLen; i++)
+ outPath[baseDirLen + i] = static_cast(path[i]);
+
+ outPath[baseDirLen + pathLen] = static_cast(0);
+
+ return true;
+}
+
+GpFileSystem_Win32 GpFileSystem_Win32::ms_instance;
diff --git a/GpD3D/GpFileSystem_Win32.h b/GpD3D/GpFileSystem_Win32.h
new file mode 100644
index 0000000..1a91e16
--- /dev/null
+++ b/GpD3D/GpFileSystem_Win32.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "HostFileSystem.h"
+
+#include "GpCoreDefs.h"
+
+#include
+
+class GpFileSystem_Win32 final : public PortabilityLayer::HostFileSystem
+{
+public:
+ GpFileSystem_Win32();
+
+ bool FileExists(PortabilityLayer::EVirtualDirectory virtualDirectory, const char *path) override;
+ PortabilityLayer::IOStream *OpenFile(PortabilityLayer::EVirtualDirectory virtualDirectory, const char *path, bool writeAccess, bool create) override;
+
+ static GpFileSystem_Win32 *GetInstance();
+
+private:
+ bool ResolvePath(PortabilityLayer::EVirtualDirectory virtualDirectory, const char *path, wchar_t *outPath);
+
+ std::wstring m_prefsDir;
+
+ static GpFileSystem_Win32 ms_instance;
+};
diff --git a/GpD3D/GpGlobalConfig.cpp b/GpD3D/GpGlobalConfig.cpp
new file mode 100644
index 0000000..95b909c
--- /dev/null
+++ b/GpD3D/GpGlobalConfig.cpp
@@ -0,0 +1,3 @@
+#include "GpGlobalConfig.h"
+
+GpGlobalConfig g_gpGlobalConfig;
diff --git a/GpD3D/GpGlobalConfig.h b/GpD3D/GpGlobalConfig.h
new file mode 100644
index 0000000..54e8bcb
--- /dev/null
+++ b/GpD3D/GpGlobalConfig.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "EGpDisplayDriverType.h"
+
+struct GpGlobalConfig
+{
+ EGpDisplayDriverType m_displayDriverType;
+};
+
+extern GpGlobalConfig g_gpGlobalConfig;
diff --git a/GpD3D/GpMain.cpp b/GpD3D/GpMain.cpp
new file mode 100644
index 0000000..25ee433
--- /dev/null
+++ b/GpD3D/GpMain.cpp
@@ -0,0 +1,48 @@
+#include "GpMain.h"
+#include "GpDisplayDriverFactory.h"
+#include "GpDisplayDriverProperties.h"
+#include "GpGlobalConfig.h"
+#include "GpAppEnvironment.h"
+#include "IGpDisplayDriver.h"
+
+#include
+
+namespace
+{
+ void TickAppEnvironment(void *context, GpFiber *vosFiber)
+ {
+ static_cast(context)->Tick(vosFiber);
+ }
+}
+
+int GpMain::Run()
+{
+ GpAppEnvironment *appEnvironment = new GpAppEnvironment();
+
+ GpDisplayDriverProperties ddProps;
+ memset(&ddProps, 0, sizeof(ddProps));
+
+ ddProps.m_FrameTimeLockNumerator = 1;
+ ddProps.m_FrameTimeLockDenominator = 60;
+
+ // +/- 1% tolerance for frame time variance
+ ddProps.m_FrameTimeLockMinNumerator = 99;
+ ddProps.m_FrameTimeLockMinDenominator = 6000;
+ ddProps.m_FrameTimeLockMaxNumerator = 101;
+ ddProps.m_FrameTimeLockMaxDenominator = 6000;
+
+ ddProps.m_TickFunc = TickAppEnvironment;
+ ddProps.m_TickFuncContext = appEnvironment;
+ ddProps.m_Type = g_gpGlobalConfig.m_displayDriverType;
+
+ IGpDisplayDriver *displayDriver = GpDisplayDriverFactory::CreateDisplayDriver(ddProps);
+
+ appEnvironment->Init();
+
+ appEnvironment->SetDisplayDriver(displayDriver);
+
+ // Start the display loop
+ displayDriver->Run();
+
+ return 0;
+}
diff --git a/GpD3D/GpMain.h b/GpD3D/GpMain.h
new file mode 100644
index 0000000..7d15e06
--- /dev/null
+++ b/GpD3D/GpMain.h
@@ -0,0 +1,6 @@
+#pragma once
+
+namespace GpMain
+{
+ int Run();
+}
diff --git a/GpD3D/GpMain_Win32.cpp b/GpD3D/GpMain_Win32.cpp
new file mode 100644
index 0000000..f55a8bd
--- /dev/null
+++ b/GpD3D/GpMain_Win32.cpp
@@ -0,0 +1,33 @@
+#include "GpWindows.h"
+#include "GpMain.h"
+#include "GpDisplayDriverFactory.h"
+#include "GpDisplayDriverFactoryD3D11.h"
+#include "GpGlobalConfig.h"
+#include "GpFileSystem_Win32.h"
+#include "GpAppInterface.h"
+#include "GpSystemServices_Win32.h"
+
+#include "HostFileSystem.h"
+
+#include
+
+#include
+
+GPWindowsGlobals g_gpWindowsGlobals;
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+ GpAppInterface_Get()->PL_HostFileSystem_SetInstance(GpFileSystem_Win32::GetInstance());
+ GpAppInterface_Get()->PL_HostSystemServices_SetInstance(GpSystemServices_Win32::GetInstance());
+
+ g_gpWindowsGlobals.m_hInstance = hInstance;
+ g_gpWindowsGlobals.m_hPrevInstance = hPrevInstance;
+ g_gpWindowsGlobals.m_cmdLine = lpCmdLine;
+ g_gpWindowsGlobals.m_nCmdShow = nCmdShow;
+
+ g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_D3D11;
+
+ GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_D3D11, GpDisplayDriverFactoryD3D11::Create);
+
+ return GpMain::Run();
+}
diff --git a/GpD3D/GpMemoryBuffer.cpp b/GpD3D/GpMemoryBuffer.cpp
new file mode 100644
index 0000000..74930f7
--- /dev/null
+++ b/GpD3D/GpMemoryBuffer.cpp
@@ -0,0 +1,49 @@
+#include "GpMemoryBuffer.h"
+
+#include
+
+void *GpMemoryBuffer::Contents()
+{
+ return reinterpret_cast(this) + AlignedSize();
+}
+
+size_t GpMemoryBuffer::Size()
+{
+ return m_size;
+}
+
+void GpMemoryBuffer::Destroy()
+{
+ delete[] reinterpret_cast(this);
+}
+
+GpMemoryBuffer *GpMemoryBuffer::Create(size_t sz)
+{
+ const size_t allowedSize = SIZE_MAX - AlignedSize();
+ if (sz > allowedSize)
+ return nullptr;
+
+ const size_t bufferSize = GpMemoryBuffer::AlignedSize() + sz;
+
+ uint8_t *buffer = new uint8_t[bufferSize];
+ new (buffer) GpMemoryBuffer(sz);
+
+ return reinterpret_cast(buffer);
+}
+
+GpMemoryBuffer::GpMemoryBuffer(size_t sz)
+ : m_size(sz)
+{
+}
+
+GpMemoryBuffer::~GpMemoryBuffer()
+{
+}
+
+size_t GpMemoryBuffer::AlignedSize()
+{
+ const size_t paddedSize = (sizeof(GpMemoryBuffer) + PL_SYSTEM_MEMORY_ALIGNMENT - 1);
+ const size_t sz = paddedSize - paddedSize % PL_SYSTEM_MEMORY_ALIGNMENT;
+
+ return sz;
+}
diff --git a/GpD3D/GpMemoryBuffer.h b/GpD3D/GpMemoryBuffer.h
new file mode 100644
index 0000000..d5ea10d
--- /dev/null
+++ b/GpD3D/GpMemoryBuffer.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "HostMemoryBuffer.h"
+
+class GpMemoryBuffer final : public PortabilityLayer::HostMemoryBuffer
+{
+public:
+ void *Contents() override;
+ size_t Size() override;
+ void Destroy() override;
+
+ static GpMemoryBuffer *Create(size_t sz);
+
+private:
+ explicit GpMemoryBuffer(size_t sz);
+ ~GpMemoryBuffer();
+
+ static size_t AlignedSize();
+
+ size_t m_size;
+};
diff --git a/GpD3D/GpPLGlueDisplayDriver.cpp b/GpD3D/GpPLGlueDisplayDriver.cpp
new file mode 100644
index 0000000..c7ab62d
--- /dev/null
+++ b/GpD3D/GpPLGlueDisplayDriver.cpp
@@ -0,0 +1,28 @@
+#include "GpPLGlueDisplayDriver.h"
+#include "IGpDisplayDriver.h"
+
+GpPLGlueDisplayDriver::GpPLGlueDisplayDriver()
+ : m_displayDriver(nullptr)
+{
+}
+
+void GpPLGlueDisplayDriver::GetDisplayResolution(unsigned int &width, unsigned int &height)
+{
+ m_displayDriver->GetDisplayResolution(width, height);
+}
+
+void GpPLGlueDisplayDriver::HideCursor()
+{
+}
+
+GpPLGlueDisplayDriver *GpPLGlueDisplayDriver::GetInstance()
+{
+ return &ms_instance;
+}
+
+void GpPLGlueDisplayDriver::SetGpDisplayDriver(IGpDisplayDriver *displayDriver)
+{
+ m_displayDriver = displayDriver;
+}
+
+GpPLGlueDisplayDriver GpPLGlueDisplayDriver::ms_instance;
diff --git a/GpD3D/GpPLGlueDisplayDriver.h b/GpD3D/GpPLGlueDisplayDriver.h
new file mode 100644
index 0000000..6ded7c4
--- /dev/null
+++ b/GpD3D/GpPLGlueDisplayDriver.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "HostDisplayDriver.h"
+
+class IGpDisplayDriver;
+
+class GpPLGlueDisplayDriver final : public PortabilityLayer::HostDisplayDriver
+{
+public:
+ GpPLGlueDisplayDriver();
+
+ void GetDisplayResolution(unsigned int &width, unsigned int &height) override;
+ void HideCursor() override;
+
+ void SetGpDisplayDriver(IGpDisplayDriver *displayDriver);
+
+ static GpPLGlueDisplayDriver *GetInstance();
+
+private:
+ IGpDisplayDriver *m_displayDriver;
+
+ static GpPLGlueDisplayDriver ms_instance;
+};
diff --git a/GpD3D/GpRingBuffer.h b/GpD3D/GpRingBuffer.h
new file mode 100644
index 0000000..2e8eb4b
--- /dev/null
+++ b/GpD3D/GpRingBuffer.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include
+#include
+
+#include "GpCoreDefs.h"
+
+template
+class GpRingBuffer
+{
+public:
+ GpRingBuffer()
+ : m_Size(0)
+ , m_Start(0)
+ {
+ }
+
+ TItem &operator[](size_t index)
+ {
+ assert(index < m_Size);
+ return m_Items[(m_Start + index) % TCapacity];
+ }
+
+ void RemoveFromStart()
+ {
+ assert(m_Size >= 1);
+ m_Start = (m_Start + 1) % TCapacity;
+ m_Size--;
+ }
+
+ void RemoveFromEnd()
+ {
+ assert(m_Size >= 1);
+ m_Size--;
+ }
+
+ void Clear()
+ {
+ m_Size = 0;
+ m_Start = 0;
+ }
+
+ size_t Size() const
+ {
+ return m_Size;
+ }
+
+ TItem *Append()
+ {
+ if (m_Size == TCapacity)
+ return nullptr;
+
+ m_Size++;
+ return &m_Items[(m_Start + (m_Size - 1)) % TCapacity];
+ }
+
+ static const size_t CAPACITY = TCapacity;
+
+private:
+ TItem m_Items[TCapacity];
+ size_t m_Size;
+ size_t m_Start;
+};
\ No newline at end of file
diff --git a/GpD3D/GpSystemServices_Win32.cpp b/GpD3D/GpSystemServices_Win32.cpp
new file mode 100644
index 0000000..42c6328
--- /dev/null
+++ b/GpD3D/GpSystemServices_Win32.cpp
@@ -0,0 +1,19 @@
+#include "GpSystemServices_Win32.h"
+
+#include
+
+GpSystemServices_Win32::GpSystemServices_Win32()
+{
+}
+
+uint32_t GpSystemServices_Win32::GetTime() const
+{
+ return 0;
+}
+
+GpSystemServices_Win32 *GpSystemServices_Win32::GetInstance()
+{
+ return &ms_instance;
+}
+
+GpSystemServices_Win32 GpSystemServices_Win32::ms_instance;
diff --git a/GpD3D/GpSystemServices_Win32.h b/GpD3D/GpSystemServices_Win32.h
new file mode 100644
index 0000000..89b089e
--- /dev/null
+++ b/GpD3D/GpSystemServices_Win32.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "HostSystemServices.h"
+#include "GpCoreDefs.h"
+#include "GpWindows.h"
+
+
+class GpSystemServices_Win32 final : public PortabilityLayer::HostSystemServices
+{
+public:
+ GpSystemServices_Win32();
+
+ uint32_t GetTime() const override;
+
+ static GpSystemServices_Win32 *GetInstance();
+
+private:
+ static GpSystemServices_Win32 ms_instance;
+};
diff --git a/GpD3D/GpWindows.h b/GpD3D/GpWindows.h
new file mode 100644
index 0000000..b1441e7
--- /dev/null
+++ b/GpD3D/GpWindows.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+
+#include
+
+struct GPWindowsGlobals
+{
+ HINSTANCE m_hInstance;
+ HINSTANCE m_hPrevInstance;
+ LPSTR m_cmdLine;
+ int m_nCmdShow;
+};
+
+extern GPWindowsGlobals g_gpWindowsGlobals;
diff --git a/GpD3D/IGpDisplayDriver.h b/GpD3D/IGpDisplayDriver.h
new file mode 100644
index 0000000..a2231d7
--- /dev/null
+++ b/GpD3D/IGpDisplayDriver.h
@@ -0,0 +1,13 @@
+#pragma once
+
+// Display drivers are responsible for timing and calling the game tick function.
+class IGpDisplayDriver
+{
+public:
+ virtual ~IGpDisplayDriver() {}
+
+ virtual void Run() = 0;
+ virtual void Shutdown() = 0;
+
+ virtual void GetDisplayResolution(unsigned int &width, unsigned int &height) = 0;
+};
diff --git a/GpD3D/x64/Debug/vc141.idb b/GpD3D/x64/Debug/vc141.idb
new file mode 100644
index 0000000..8c4b4fa
Binary files /dev/null and b/GpD3D/x64/Debug/vc141.idb differ
diff --git a/Headers/About.h b/Headers/About.h
deleted file mode 100755
index 1f8c23d..0000000
--- a/Headers/About.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// About.h
//----------------------------------------------------------------------------
//============================================================================
void DoAbout (void);
\ No newline at end of file
diff --git a/Headers/DialogUtils.h b/Headers/DialogUtils.h
deleted file mode 100755
index 1a81109..0000000
--- a/Headers/DialogUtils.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// DialogUtils.h
//----------------------------------------------------------------------------
//============================================================================
#include
void BringUpDialog (DialogPtr *theDialog, short dialogID);
//void GetPutDialogCorner (Point *);
//void GetGetDialogCorner (Point *);
//void CenterDialog (short);
void GetDialogRect (Rect *, short);
//void TrueCenterDialog (short);
//void CenterAlert (short);
//void ZoomOutDialogRect (short);
//void ZoomOutAlertRect (short);
void FlashDialogButton (DialogPtr, short);
void DrawDefaultButton (DialogPtr);
void GetDialogString (DialogPtr, short, StringPtr);
void SetDialogString (DialogPtr, short, StringPtr);
short GetDialogStringLen (DialogPtr, short);
void GetDialogItemValue (DialogPtr, short, short *);
void SetDialogItemValue (DialogPtr, short, short);
void ToggleDialogItemValue (DialogPtr, short);
void SetDialogNumToStr (DialogPtr, short, long);
void GetDialogNumFromStr (DialogPtr, short, long *);
void GetDialogItemRect (DialogPtr, short, Rect *);
void SetDialogItemRect (DialogPtr, short, Rect *);
void OffsetDialogItemRect (DialogPtr, short, short, short);
void SelectFromRadioGroup (DialogPtr, short, short, short);
//void AddMenuToPopUp (DialogPtr, short, MenuHandle);
void GetPopUpMenuValue (DialogPtr, short, short *);
void SetPopUpMenuValue (DialogPtr, short, short);
void MyEnableControl(DialogPtr, short);
void MyDisableControl(DialogPtr, short);
void DrawDialogUserText (DialogPtr, short, StringPtr, Boolean);
void DrawDialogUserText2 (DialogPtr, short, StringPtr);
void LoadDialogPICT (DialogPtr, short, short);
void FrameDialogItem (DialogPtr, short);
void FrameDialogItemC (DialogPtr, short, long);
void FrameOvalDialogItem (DialogPtr, short);
void BorderDialogItem (DialogPtr, short, short);
void ShadowDialogItem (DialogPtr, short, short);
void EraseDialogItem (DialogPtr, short);
\ No newline at end of file
diff --git a/Headers/Environ.h b/Headers/Environ.h
deleted file mode 100755
index 1c972bc..0000000
--- a/Headers/Environ.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// Environ.h
//----------------------------------------------------------------------------
//============================================================================
#include
typedef struct
{
Rect screen, gray;
long dirID;
short wasDepth, isDepth;
short thisResFile;
short numScreens;
short vRefNum;
Boolean can1Bit;
Boolean can4Bit;
Boolean can8Bit;
Boolean wasColorOrGray;
Boolean hasWNE;
Boolean hasSystem7;
Boolean hasColor;
Boolean hasGestalt;
Boolean canSwitch;
Boolean canColor;
Boolean hasSM3;
Boolean hasQT;
Boolean hasDrag;
} macEnviron;
extern macEnviron thisMac;
\ No newline at end of file
diff --git a/Headers/Externs.h b/Headers/Externs.h
deleted file mode 100755
index 39b299f..0000000
--- a/Headers/Externs.h
+++ /dev/null
@@ -1 +0,0 @@
-
//============================================================================
//----------------------------------------------------------------------------
// Externs.h
//----------------------------------------------------------------------------
//============================================================================
#pragma once
#include
#define kPreferredDepth 8
#define kNilPointer 0L
#define kPutInFront (WindowPtr)-1L
#define kNormalUpdates TRUE
#define kOneKilobyte 1024
#define kOkayButton 1
#define kCancelButton 2
#define kControlActive 0
#define kControlInactive 255
#define kAsynch TRUE
#define kSynch FALSE
#define kHomeKeyASCII 0x01
#define kEnterKeyASCII 0x03
#define kEndKeyASCII 0x04
#define kHelpKeyASCII 0x05
#define kDeleteKeyASCII 0x08
#define kTabKeyASCII 0x09
#define kPageUpKeyASCII 0x0B
#define kPageDownKeyASCII 0x0C
#define kReturnKeyASCII 0x0D
#define kFunctionKeyASCII 0x10
#define kClearKeyASCII 0x1A
#define kEscapeKeyASCII 0x1B
#define kLeftArrowKeyASCII 0x1C
#define kRightArrowKeyASCII 0x1D
#define kUpArrowKeyASCII 0x1E
#define kDownArrowKeyASCII 0x1F
#define kSpaceBarASCII 0x20
#define kExclamationASCII 0x21
#define kPlusKeyASCII 0x2B
#define kMinusKeyASCII 0x2D
#define k0KeyASCII 0x30
#define k1KeyASCII 0x31
#define k2KeyASCII 0x32
#define k3KeyASCII 0x33
#define k4KeyASCII 0x34
#define k5KeyASCII 0x35
#define k6KeyASCII 0x36
#define k7KeyASCII 0x37
#define k8KeyASCII 0x38
#define k9KeyASCII 0x39
#define kCapAKeyASCII 0x41
#define kCapBKeyASCII 0x42
#define kCapCKeyASCII 0x43
#define kCapDKeyASCII 0x44
#define kCapEKeyASCII 0x45
#define kCapFKeyASCII 0x46
#define kCapGKeyASCII 0x47
#define kCapHKeyASCII 0x48
#define kCapIKeyASCII 0x49
#define kCapJKeyASCII 0x4A
#define kCapKKeyASCII 0x4B
#define kCapLKeyASCII 0x4C
#define kCapMKeyASCII 0x4D
#define kCapNKeyASCII 0x4E
#define kCapOKeyASCII 0x4F
#define kCapPKeyASCII 0x50
#define kCapQKeyASCII 0x51
#define kCapRKeyASCII 0x52
#define kCapSKeyASCII 0x53
#define kCapTKeyASCII 0x54
#define kCapUKeyASCII 0x55
#define kCapVKeyASCII 0x56
#define kCapWKeyASCII 0x57
#define kCapXKeyASCII 0x58
#define kCapYKeyASCII 0x59
#define kCapZKeyASCII 0x5A
#define kAKeyASCII 0x61
#define kBKeyASCII 0x62
#define kCKeyASCII 0x63
#define kDKeyASCII 0x64
#define kEKeyASCII 0x65
#define kFKeyASCII 0x66
#define kGKeyASCII 0x67
#define kHKeyASCII 0x68
#define kIKeyASCII 0x69
#define kJKeyASCII 0x6A
#define kKKeyASCII 0x6B
#define kLKeyASCII 0x6C
#define kMKeyASCII 0x6D
#define kNKeyASCII 0x6E
#define kOKeyASCII 0x6F
#define kPKeyASCII 0x70
#define kQKeyASCII 0x71
#define kRKeyASCII 0x72
#define kSKeyASCII 0x73
#define kTKeyASCII 0x74
#define kUKeyASCII 0x75
#define kVKeyASCII 0x76
#define kWKeyASCII 0x77
#define kXKeyASCII 0x78
#define kYKeyASCII 0x79
#define kZKeyASCII 0x7A
#define kForwardDeleteASCII 0x7F
#define kPlusKeypadMap 66 // key map offset for + on keypad
#define kMinusKeypadMap 73 // key map offset for - on keypad
#define kTimesKeypadMap 68 // key map offset for * on keypad
#define k0KeypadMap 85 // key map offset for 0 on keypad
#define k1KeypadMap 84 // key map offset for 1 on keypad
#define k2KeypadMap 83 // key map offset for 2 on keypad
#define k3KeypadMap 82 // key map offset for 3 on keypad
#define k4KeypadMap 81 // key map offset for 4 on keypad
#define k5KeypadMap 80 // key map offset for 5 on keypad
#define k6KeypadMap 95 // key map offset for 6 on keypad
#define k7KeypadMap 94 // key map offset for 7 on keypad
#define k8KeypadMap 92 // key map offset for 8 on keypad
#define k9KeypadMap 91 // key map offset for 9 on keypad
#define kUpArrowKeyMap 121 // key map offset for up arrow
#define kDownArrowKeyMap 122 // key map offset for down arrow
#define kRightArrowKeyMap 123 // key map offset for right arrow
#define kLeftArrowKeyMap 124 // key map offset for left arrow
#define kAKeyMap 7
#define kBKeyMap 12
#define kCKeyMap 15
#define kDKeyMap 5
#define kEKeyMap 9
#define kFKeyMap 4
#define kGKeyMap 2
#define kHKeyMap 3
#define kMKeyMap 41
#define kNKeyMap 42
#define kOKeyMap 24
#define kPKeyMap 36
#define kQKeyMap 11
#define kRKeyMap 8
#define kSKeyMap 6
#define kTKeyMap 22
#define kVKeyMap 14
#define kWKeyMap 10
#define kXKeyMap 0
#define kZKeyMap 1
#define kPeriodKeyMap 40
#define kCommandKeyMap 48
#define kEscKeyMap 50
#define kDeleteKeyMap 52
#define kSpaceBarMap 54
#define kTabKeyMap 55
#define kControlKeyMap 60
#define kOptionKeyMap 61
#define kCapsLockKeyMap 62
#define kShiftKeyMap 63
#define kTabRawKey 0x30 // key map offset for Tab key
#define kClearRawKey 0x47 // key map offset for Clear key
#define kF5RawKey 0x60 // key map offset for F5
#define kF6RawKey 0x61 // key map offset for F6
#define kF7RawKey 0x62 // key map offset for F7
#define kF3RawKey 0x63 // key map offset for F3
#define kF8RawKey 0x64 // key map offset for F8
#define kF9RawKey 0x65 // key map offset for F9
#define kF11RawKey 0x67 // key map offset for F11
#define kF13RawKey 0x69 // key map offset for F13
#define kF14RawKey 0x6B // key map offset for F14
#define kF10RawKey 0x6D // key map offset for F10
#define kF12RawKey 0x6F // key map offset for F12
#define kF15RawKey 0x71 // key map offset for F15
#define kF4RawKey 0x76 // key map offset for F4
#define kF2RawKey 0x78 // key map offset for F2
#define kF1RawKey 0x7A // key map offset for F1
#define kErrUnnaccounted 1
#define kErrNoMemory 2
#define kErrDialogDidntLoad 3
#define kErrFailedResourceLoad 4
#define kErrFailedGraphicLoad 5
#define kErrFailedOurDirect 6
#define kErrFailedValidation 7
#define kErrNeedSystem7 8
#define kErrFailedGetDevice 9
#define kErrFailedMemoryOperation 10
#define kErrFailedCatSearch 11
#define kErrNeedColorQD 12
#define kErrNeed16Or256Colors 13
#define iAbout 1
#define iNewGame 1
#define iTwoPlayer 2
#define iOpenSavedGame 3
#define iLoadHouse 5
#define iQuit 7
#define iEditor 1
#define iHighScores 3
#define iPrefs 4
#define iHelp 5
#define iNewHouse 1
#define iSave 2
#define iHouse 4
#define iRoom 5
#define iObject 6
#define iCut 8
#define iCopy 9
#define iPaste 10
#define iClear 11
#define iDuplicate 12
#define iBringForward 14
#define iSendBack 15
#define iGoToRoom 17
#define iMapWindow 19
#define iObjectWindow 20
#define iCoordinateWindow 21
//-------------------------------------------------------------- Structs
/*
typedef short SICN[16];
typedef SICN *SICNList;
typedef SICNList *SICNHand;
*/
#pragma options align=mac68k
typedef struct
{
Str32 wasDefaultName;
Str15 wasLeftName, wasRightName;
Str15 wasBattName, wasBandName;
Str15 wasHighName;
Str31 wasHighBanner;
// long encrypted, fakeLong;
long wasLeftMap, wasRightMap;
long wasBattMap, wasBandMap;
short wasVolume;
short prefVersion;
short wasMaxFiles;
short wasEditH, wasEditV;
short wasMapH, wasMapV;
short wasMapWide, wasMapHigh;
short wasToolsH, wasToolsV;
short wasLinkH, wasLinkV;
short wasCoordH, wasCoordV;
short isMapLeft, isMapTop;
short wasNumNeighbors;
short wasDepthPref;
short wasToolGroup;
short smWarnings;
short wasFloor, wasSuite;
Boolean wasZooms, wasMusicOn;
Boolean wasAutoEdit, wasDoColorFade;
Boolean wasMapOpen, wasToolsOpen;
Boolean wasCoordOpen, wasQuickTrans;
Boolean wasIdleMusic, wasGameMusic;
Boolean wasEscPauseKey;
Boolean wasDoAutoDemo, wasScreen2;
Boolean wasDoBackground, wasHouseChecks;
Boolean wasPrettyMap, wasBitchDialogs;
} prefsInfo;
#pragma options align=reset
//-------------------------------------------------------------- Prototypes
void DoAbout (void); // --- About.c
void LoadCursors (void); // --- AnimCursor.c
void DisposCursors (void);
void IncrementCursor (void);
void DecrementCursor (void);
void SpinCursor (short);
void BackSpinCursor (short);
void ColorText (StringPtr, long); // --- ColorUtils.c
void ColorRect (Rect *, long);
void ColorOval (Rect *, long);
void ColorRegion (RgnHandle, long);
void ColorLine (short, short, short, short, long);
void HiliteRect (Rect *, short, short);
void ColorFrameRect (Rect *, long);
void ColorFrameWHRect (short, short, short, short, long);
void ColorFrameOval (Rect *, long);
void LtGrayForeColor (void);
void GrayForeColor (void);
void DkGrayForeColor (void);
void RestoreColorsSlam (void);
void MonitorWait (void); // --- DebugUtils.c
void DisplayRect (Rect *);
void FlashRect (Rect *);
void CheckLegitRect(Rect *, Rect *);
void DisplayLong (long);
void DisplayShort (short);
void FlashLong (long);
void FlashShort (short);
void DoBarGraph (short, short, short, short);
short BetaOkay (void);
void DebugNum (long);
void DisplayCTSeed (CGrafPtr);
void FillScreenRed (void);
void DumpToResEditFile (Ptr, long);
void HandleEvent (void); // --- Event.c
void HiliteAllWindows (void);
void IgnoreThisClick (void);
short WhatsOurDepth (void); // --- Environs.c
void SwitchToDepth (short, Boolean);
void CheckOurEnvirons (void);
//void ReflectSecondMonitorEnvirons (Boolean, Boolean, Boolean);
void HandleDepthSwitching (void);
void RestoreColorDepth (void);
void CheckMemorySize (void);
void SetAppMemorySize (long);
Boolean CheckFileError (short, StringPtr); // --- File Error.c
Boolean SavePrefs (prefsInfo *, short); // --- Prefs.c
Boolean LoadPrefs (prefsInfo *, short);
void PasStringCopy (StringPtr, StringPtr); // --- StringUtils.c
short WhichStringFirst (StringPtr, StringPtr);
void PasStringCopyNum (StringPtr, StringPtr, short);
void PasStringConcat (StringPtr, StringPtr);
void GetLineOfText (StringPtr, short, StringPtr);
void WrapText (StringPtr, short);
void GetFirstWordOfString (StringPtr, StringPtr);
void CollapseStringToWidth (StringPtr, short);
void GetChooserName (StringPtr);
StringPtr GetLocalizedString (short, StringPtr);
Point MyGetGlobalMouse (void); // --- Utilities.c
void ToolBoxInit (void);
void FindOurDevice (void);
short RandomInt (short);
long RandomLong (long);
void InitRandomLongQUS (void);
unsigned long RandomLongQUS (void);
//void CenterAlert (short);
void RedAlert (short);
//void CreateOffScreenBitMap (Rect *, GrafPtr *);
//void CreateOffScreenPixMap (Rect *, CGrafPtr *);
//void KillOffScreenPixMap (CGrafPtr);
//void KillOffScreenBitMap (GrafPtr);
void LoadGraphic (short);
void LoadScaledGraphic (short, Rect *);
//void PlotSICN (Rect *, SICNHand, long);
void LargeIconPlot (Rect *, short);
void DrawCIcon (short, short, short);
char KeyMapOffsetFromRawKey (char);
long LongSquareRoot (long);
//void HideMenuBarOld (void);
//void ShowMenuBarOld (void);
Boolean WaitForInputEvent (short);
void WaitCommandQReleased (void);
char GetKeyMapFromMessage (long);
void GetKeyName (long, StringPtr);
Boolean OptionKeyDown (void);
long ExtractCTSeed (CGrafPtr);
//void ForceCTSeed (CGrafPtr, long);
void DelayTicks (long);
void UnivGetSoundVolume (short *, Boolean);
void UnivSetSoundVolume (short, Boolean);
Boolean ValidInstallation (Boolean); // --- Validate.c
void GetWindowLeftTop (WindowPtr, short *, short *); // --- WindowUtils.c
void GetWindowRect (WindowPtr, Rect *);
void GetLocalWindowRect (WindowPtr, Rect *);
//void FlagWindowFloating (WindowPtr);
//Boolean IsWindowFloating (WindowPtr);
void OpenMessageWindow (StringPtr);
void SetMessageWindowMessage (StringPtr);
void CloseMessageWindow (void);
void CloseThisWindow (WindowPtr *);
#ifdef powerc
// extern pascal void SetSoundVol(short level); // for old Sound Manager
// extern pascal void GetSoundVol(short *level)
// THREEWORDINLINE(0x4218, 0x10B8, 0x0260);
#endif
#include "GliderDefines.h"
#include "GliderStructs.h"
#include "GliderVars.h"
#include "GliderProtos.h"
\ No newline at end of file
diff --git a/Headers/GameOver.h b/Headers/GameOver.h
deleted file mode 100755
index d90c6f9..0000000
--- a/Headers/GameOver.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// GameOver.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern GWorldPtr angelSrcMap;
extern GWorldPtr angelMaskMap;
\ No newline at end of file
diff --git a/Headers/GliderDefines.h b/Headers/GliderDefines.h
deleted file mode 100755
index 015e91d..0000000
--- a/Headers/GliderDefines.h
+++ /dev/null
@@ -1 +0,0 @@
-
//============================================================================
//----------------------------------------------------------------------------
// GliderDefines.h
//----------------------------------------------------------------------------
//============================================================================
//============================================================== Defines
//#define CREATEDEMODATA
//#define COMPILEDEMO
//#define CAREFULDEBUG
#define COMPILENOCP
#define COMPILEQT
#define BUILD_ARCADE_VERSION 1
#define kYellowUnaccounted 1
#define kYellowFailedResOpen 2
#define kYellowFailedResAdd 3
#define kYellowFailedResCreate 4
#define kYellowNoHouses 5
#define kYellowNewerVersion 6
#define kYellowNoBackground 7
#define kYellowIllegalRoomNum 8
#define kYellowNoBoundsRes 9
#define kYellowScrapError 10
#define kYellowNoMemory 11
#define kYellowFailedWrite 12
#define kYellowNoMusic 13
#define kYellowFailedSound 14
#define kYellowAppleEventErr 15
#define kYellowOpenedOldHouse 16
#define kYellowLostAllHouses 17
#define kYellowFailedSaveGame 18
#define kYellowSavedTimeWrong 19
#define kYellowSavedVersWrong 20
#define kYellowSavedRoomsWrong 21
#define kYellowQTMovieNotLoaded 22
#define kYellowNoRooms 23
#define kYellowCantOrderLinks 24
#define kSwitchIfNeeded 0
#define kSwitchTo256Colors 1
#define kSwitchTo16Grays 2
#define kProdGameScoreMode -4
#define kKickGameScoreMode -3
#define kPlayGameScoreMode -2
#define kPlayWholeScoreMode -1
#define kPlayChorus 4
#define kPlayRefrainSparse1 5
#define kPlayRefrainSparse2 6
#define kHitWallSound 0 // ¥¥¥¥¥¥
#define kFadeInSound 1 // ¥¥
#define kFadeOutSound 2 // ¥¥¥¥¥¥
#define kBeepsSound 3 // ¥¥
#define kBuzzerSound 4 // ¥¥¥¥¥¥
#define kDingSound 5 //
#define kEnergizeSound 6 // ¥¥¥¥¥¥
#define kFollowSound 7 // ¥¥ ¥¥
#define kMicrowavedSound 8 // ¥¥ ¥¥
#define kSwitchSound 9 // ¥¥ ¥¥
#define kBirdSound 10 // ¥¥¥¥¥¥
#define kCuckooSound 11 //
#define kTikSound 12 // ¥¥ ¥¥
#define kTokSound 13 // ¥¥ ¥¥
#define kBlowerOn 14 // ¥¥ ¥¥
#define kBlowerOff 15 // ¥¥ ¥¥
#define kCaughtFireSound 16 // ¥¥¥¥¥¥
#define kScoreTikSound 17 //
#define kThrustSound 18 // ¥¥¥ ¥¥
#define kFizzleSound 19 // ¥¥¥¥ ¥¥
#define kFireBandSound 20 // ¥¥ ¥¥ ¥¥
#define kBandReboundSound 21 // ¥¥ ¥¥¥¥
#define kGreaseSpillSound 22 // ¥¥ ¥¥¥
#define kChordSound 23 //
#define kVCRSound 24 // ¥¥¥¥¥¥¥
#define kFoilHitSound 25 // ¥¥ ¥¥
#define kShredSound 26 // ¥¥ ¥¥
#define kToastLaunchSound 27 // ¥¥ ¥¥
#define kToastLandSound 28 // ¥¥¥¥¥¥¥
#define kMacOnSound 29 //
#define kMacBeepSound 30 //
#define kMacOffSound 31 //
#define kTVOnSound 32 //
#define kTVOffSound 33 // ¥¥¥¥¥¥
#define kCoffeeSound 34 // ¥¥
#define kMysticSound 35 // ¥¥¥¥¥¥
#define kZapSound 36 // ¥¥
#define kPopSound 37 // ¥¥¥¥¥¥
#define kEnemyInSound 38 //
#define kEnemyOutSound 39 // ¥¥¥¥¥¥
#define kPaperCrunchSound 40 // ¥¥ ¥¥
#define kBounceSound 41 // ¥¥ ¥¥
#define kDripSound 42 // ¥¥ ¥¥
#define kDropSound 43 // ¥¥¥¥¥¥
#define kFishOutSound 44 //
#define kFishInSound 45 // ¥¥ ¥¥
#define kDontExitSound 46 // ¥¥ ¥¥
#define kSizzleSound 47 // ¥¥ ¥¥
#define kPaper1Sound 48 // ¥¥ ¥¥
#define kPaper2Sound 49 // ¥¥¥¥¥¥
#define kPaper3Sound 50 //
#define kPaper4Sound 51 // ¥¥¥ ¥¥
#define kTypingSound 52 // ¥¥¥¥ ¥¥
#define kCarriageSound 53 // ¥¥ ¥¥ ¥¥
#define kChord2Sound 54 // ¥¥ ¥¥¥¥
#define kPhoneRingSound 55 // ¥¥ ¥¥¥
#define kChime1Sound 56 //
#define kChime2Sound 57 // ¥¥¥¥¥¥¥
#define kWebTwangSound 58 // ¥¥ ¥¥
#define kTransOutSound 59 // ¥¥ ¥¥
#define kTransInSound 60 // ¥¥ ¥¥
#define kBonusSound 61 // ¥¥¥¥¥¥¥
#define kHissSound 62 //
#define kTriggerSound 63
#define kHitWallPriority 100 // ¥¥¥¥¥¥
#define kScoreTikPriority 101 // ¥¥
#define kBandReboundPriority 102 // ¥¥¥¥¥¥
#define kDontExitPriority 103 // ¥¥
#define kTikPriority 200 // ¥¥¥¥¥¥
#define kTokPriority 201 //
#define kMysticPriority 202 // ¥¥¥¥¥¥
#define kChime1Priority 203 // ¥¥ ¥¥
#define kChime2Priority 204 // ¥¥ ¥¥
#define kThrustPriority 300 // ¥¥ ¥¥
#define kFireBandPriority 301 // ¥¥¥¥¥¥
#define kChordPriority 302 //
#define kVCRPriority 303 // ¥¥ ¥¥
#define kToastLaunchPriority 304 // ¥¥ ¥¥
#define kToastLandPriority 305 // ¥¥ ¥¥
#define kCoffeePriority 306 // ¥¥ ¥¥
#define kBouncePriority 307 // ¥¥¥¥¥¥
#define kDripPriority 308 //
#define kDropPriority 309 // ¥¥¥ ¥¥
#define kWebTwangPriority 310 // ¥¥¥¥ ¥¥
#define kHissPriority 311 // ¥¥ ¥¥ ¥¥
#define kFoilHitPriority 400 // ¥¥ ¥¥¥¥
#define kMacOnPriority 401 // ¥¥ ¥¥¥
#define kMacOffPriority 402 //
#define kMacBeepPriority 403 // ¥¥¥¥¥¥¥
#define kTVOnPriority 404 // ¥¥ ¥¥
#define kTVOffPriority 405 // ¥¥ ¥¥
#define kZapPriority 406 // ¥¥ ¥¥
#define kPopPriority 407 // ¥¥¥¥¥¥¥
#define kEnemyInPriority 408 //
#define kEnemyOutPriority 409 //
#define kPaperCrunchPriority 410 //
#define kFishOutPriority 411 //
#define kFishInPriority 412 //
#define kSizzlePriority 413
#define kPhoneRingPriority 500
#define kSwitchPriority 700
#define kBlowerOnPriority 701
#define kBlowerOffPriority 702
#define kFizzlePriority 703
#define kBeepsPriority 800
#define kBuzzerPriority 801
#define kDingPriority 802
#define kEnergizePriority 803
#define kBirdPriority 804
#define kCuckooPriority 805
#define kGreaseSpillPriority 806
#define kPapersPriority 807
#define kTypingPriority 808
#define kCarriagePriority 809
#define kChord2Priority 810
#define kMicrowavedPriority 811
#define kBonusPriority 812
#define kFadeInPriority 900
#define kFadeOutPriority 901
#define kCaughtFirePriority 902
#define kShredPriority 903
#define kFollowPriority 904
#define kTransInPriority 905
#define kTransOutPriority 906
#define kTriggerPriority 999
#define kArrowCursor 0
#define kBeamCursor 1
#define kHandCursor 2
#define kAppleMenuID 128
#define kGameMenuID 129
#define kOptionsMenuID 130
#define kHouseMenuID 131
#define kSplashMode 0
#define kEditMode 1
#define kPlayMode 2
#define kIdleSplashMode 0
#define kIdleDemoMode 1
#define kIdleSplashTicks 7200L // 2 minutes
#define kIdleLastMode 1
#define kRoomAbove 1
#define kRoomBelow 2
#define kRoomToRight 3
#define kRoomToLeft 4
#define kBumpUp 1
#define kBumpDown 2
#define kBumpRight 3
#define kBumpLeft 4
#define kAbove 1
#define kToRight 2
#define kBelow 3
#define kToLeft 4
#define kBottomCorner 5
#define kTopCorner 6
#define kCentralRoom 0
#define kNorthRoom 1
#define kNorthEastRoom 2
#define kEastRoom 3
#define kSouthEastRoom 4
#define kSouthRoom 5
#define kSouthWestRoom 6
#define kWestRoom 7
#define kNorthWestRoom 8
#define kSimpleRoom 2000
#define kPaneledRoom 2001
#define kBasement 2002
#define kChildsRoom 2003
#define kAsianRoom 2004
#define kUnfinishedRoom 2005
#define kSwingersRoom 2006
#define kBathroom 2007
#define kLibrary 2008
#define kGarden 2009
#define kSkywalk 2010
#define kDirt 2011
#define kMeadow 2012
#define kField 2013
#define kRoof 2014
#define kSky 2015
#define kStratosphere 2016
#define kStars 2017
#define kMapRoomHeight 20
#define kMapRoomWidth 32
#define kMaxScores 10
#define kMaxRoomObs 24
#define kMaxSparkles 3
#define kNumSparkleModes 5
#define kMaxFlyingPts 3
#define kMaxFlyingPointsLoop 24
#define kMaxCandles 20
#define kMaxTikis 8
#define kMaxCoals 8
#define kMaxPendulums 8
#define kMaxHotSpots 56
#define kMaxSavedMaps 24
#define kMaxRubberBands 2
#define kMaxGrease 16
#define kMaxStars 4
#define kMaxShredded 4
#define kMaxDynamicObs 18
#define kMaxMasterObjects 216 // kMaxRoomObs * 9
#define kMaxViewWidth 1536
#define kMaxViewHeight 1026
#define kSelectTool 0
#define kBlowerMode 1
#define kFurnitureMode 2
#define kBonusMode 3
#define kTransportMode 4
#define kSwitchMode 5
#define kLightMode 6
#define kApplianceMode 7
#define kEnemyMode 8
#define kClutterMode 9
#define kIgnoreIt 0 // ¥¥¥¥¥¥
#define kLiftIt 1 // ¥¥ ¥¥
#define kDropIt 2 // ¥¥¥¥¥¥¥¥
#define kPushItLeft 3 // ¥¥ ¥¥
#define kPushItRight 4 // ¥¥ ¥¥
#define kDissolveIt 5 //
#define kRewardIt 6 // ¥¥¥¥¥¥
#define kMoveItUp 7 // ¥¥ ¥¥
#define kMoveItDown 8 // ¥¥
#define kSwitchIt 9 // ¥¥ ¥¥
#define kShredIt 10 // ¥¥¥¥¥¥
#define kStrumIt 11 //
#define kTriggerIt 12 // ¥¥¥¥¥¥¥¥
#define kBurnIt 13 // ¥¥
#define kSlideIt 14 // ¥¥
#define kTransportIt 15 // ¥¥
#define kIgnoreLeftWall 16 // ¥¥
#define kIgnoreRightWall 17 //
#define kMailItLeft 18 // ¥¥¥¥¥¥
#define kMailItRight 19 // ¥¥
#define kDuctItDown 20 // ¥¥
#define kDuctItUp 21 // ¥¥
#define kMicrowaveIt 22 // ¥¥¥¥¥¥
#define kIgnoreGround 23 //
#define kBounceIt 24 //
#define kChimeIt 25 // ¥¥
#define kWebIt 26 // ¥¥
#define kSoundIt 27
#define kFloorVent 0x01 // Blowers
#define kCeilingVent 0x02
#define kFloorBlower 0x03
#define kCeilingBlower 0x04
#define kSewerGrate 0x05
#define kLeftFan 0x06
#define kRightFan 0x07
#define kTaper 0x08
#define kCandle 0x09
#define kStubby 0x0A
#define kTiki 0x0B
#define kBBQ 0x0C
#define kInvisBlower 0x0D
#define kGrecoVent 0x0E
#define kSewerBlower 0x0F
#define kLiftArea 0x10
#define kTable 0x11 // Furniture
#define kShelf 0x12
#define kCabinet 0x13
#define kFilingCabinet 0x14
#define kWasteBasket 0x15
#define kMilkCrate 0x16
#define kCounter 0x17
#define kDresser 0x18
#define kDeckTable 0x19
#define kStool 0x1A
#define kTrunk 0x1B
#define kInvisObstacle 0x1C
#define kManhole 0x1D
#define kBooks 0x1E
#define kInvisBounce 0x1F
#define kRedClock 0x21 // Prizes
#define kBlueClock 0x22
#define kYellowClock 0x23
#define kCuckoo 0x24
#define kPaper 0x25
#define kBattery 0x26
#define kBands 0x27
#define kGreaseRt 0x28
#define kGreaseLf 0x29
#define kFoil 0x2A
#define kInvisBonus 0x2B
#define kStar 0x2C
#define kSparkle 0x2D
#define kHelium 0x2E
#define kSlider 0x2F
#define kUpStairs 0x31 // Transport
#define kDownStairs 0x32
#define kMailboxLf 0x33
#define kMailboxRt 0x34
#define kFloorTrans 0x35
#define kCeilingTrans 0x36
#define kDoorInLf 0x37
#define kDoorInRt 0x38
#define kDoorExRt 0x39
#define kDoorExLf 0x3A
#define kWindowInLf 0x3B
#define kWindowInRt 0x3C
#define kWindowExRt 0x3D
#define kWindowExLf 0x3E
#define kInvisTrans 0x3F
#define kDeluxeTrans 0x40
#define kLightSwitch 0x41 // Switches
#define kMachineSwitch 0x42
#define kThermostat 0x43
#define kPowerSwitch 0x44
#define kKnifeSwitch 0x45
#define kInvisSwitch 0x46
#define kTrigger 0x47
#define kLgTrigger 0x48
#define kSoundTrigger 0x49
#define kCeilingLight 0x51 // Lights
#define kLightBulb 0x52
#define kTableLamp 0x53
#define kHipLamp 0x54
#define kDecoLamp 0x55
#define kFlourescent 0x56
#define kTrackLight 0x57
#define kInvisLight 0x58
#define kShredder 0x61 // Appliances
#define kToaster 0x62
#define kMacPlus 0x63
#define kGuitar 0x64
#define kTV 0x65
#define kCoffee 0x66
#define kOutlet 0x67
#define kVCR 0x68
#define kStereo 0x69
#define kMicrowave 0x6A
#define kCinderBlock 0x6B
#define kFlowerBox 0x6C
#define kCDs 0x6D
#define kCustomPict 0x6E
#define kBalloon 0x71 // Enemies
#define kCopterLf 0x72
#define kCopterRt 0x73
#define kDartLf 0x74
#define kDartRt 0x75
#define kBall 0x76
#define kDrip 0x77
#define kFish 0x78
#define kCobweb 0x79
#define kOzma 0x81 // Clutter
#define kMirror 0x82
#define kMousehole 0x83
#define kFireplace 0x84
#define kFlower 0x85
#define kWallWindow 0x86
#define kBear 0x87
#define kCalendar 0x88
#define kVase1 0x89
#define kVase2 0x8A
#define kBulletin 0x8B
#define kCloud 0x8C
#define kFaucet 0x8D
#define kRug 0x8E
#define kChimes 0x8F
#define kNumSrcRects 0x90
#define kTableThick 8
#define kShelfThick 6
#define kToggle 0
#define kForceOn 1
#define kForceOff 2
#define kOneShot 3
#define kNumTrackLights 3
#define kNumOutletPicts 4
#define kNumCandleFlames 5
#define kNumTikiFlames 5
#define kNumBBQCoals 4
#define kNumPendulums 3
#define kNumBreadPicts 6
#define kNumBalloonFrames 8
#define kNumCopterFrames 10
#define kNumDartFrames 4
#define kNumBallFrames 2
#define kNumDripFrames 6
#define kNumFishFrames 8
#define kNumFlowers 6
#define kNumMarqueePats 7
#define kObjectNameStrings 1007
#define kSwitchLinkOnly 3
#define kTriggerLinkOnly 4
#define kTransportLinkOnly 5
#define kFloorVentTop 305
#define kCeilingVentTop 8
#define kFloorBlowerTop 304
#define kCeilingBlowerTop 5
#define kSewerGrateTop 303
#define kCeilingTransTop 6
#define kFloorTransTop 302
#define kStairsTop 28
#define kCounterBottom 304
#define kDresserBottom 293
#define kCeilingLightTop 4
#define kHipLampTop 23
#define kDecoLampTop 91
#define kFlourescentTop 12
#define kTrackLightTop 5
#define kDoorInTop 0
#define kDoorInLfLeft 0
#define kDoorInRtLeft 368
#define kDoorExTop 0
#define kDoorExLfLeft 0
#define kDoorExRtLeft 496
#define kWindowInTop 64
#define kWindowInLfLeft 0
#define kWindowInRtLeft 492
#define kWindowExTop 64
#define kWindowExLfLeft 0
#define kWindowExRtLeft 496
#define kNumTiles 8
#define kTileWide 64
#define kTileHigh 322
#define kRoomWide 512 // kNumTiles * kTileWide
#define kFloorSupportTall 44
#define kVertLocalOffset 322 // kTileHigh - 39 (was 283, then 295)
#define kCeilingLimit 8
#define kFloorLimit 312
#define kRoofLimit 122
#define kLeftWallLimit 12
#define kNoLeftWallLimit -24 // 0 - (kGliderWide / 2)
#define kRightWallLimit 500
#define kNoRightWallLimit 536 // kRoomWide + (kGliderWide / 2)
#define kNoCeilingLimit -10
#define kNoFloorLimit 332
#define kScoreboardHigh 0
#define kScoreboardLow 1
#define kScoreboardTall 20
#define kHouseVersion 0x0200
#define kNewHouseVersion 0x0300
#define kBaseBackgroundID 2000
#define kFirstOutdoorBack 2009
#define kNumBackgrounds 18
#define kUserBackground 3000
#define kUserStructureRange 3300
#define kSplash8BitPICT 1000
#define kRoomIsEmpty -1
#define kObjectIsEmpty -1
#define kNoObjectSelected -1
#define kInitialGliderSelected -2
#define kLeftGliderSelected -3
#define kRightGliderSelected -4
#define kWindoidWDEF 2048
#define kWindoidGrowWDEF 2064
#define kTicksPerFrame 2
#define kStarPictID 1995
#define kNumUndergroundFloors 8
#define kRoomVisitScore 100
#define kRedClockPoints 100
#define kBlueClockPoints 300
#define kYellowClockPoints 500
#define kCuckooClockPoints 1000
#define kStarPoints 5000
#define kRedOrangeColor8 23 // actually, 18
#define kMaxNumRoomsH 128
#define kMaxNumRoomsV 64
#define kStartSparkle 4
#define kLengthOfZap 30
#define kGliderWide 48
#define kGliderHigh 20
#define kHalfGliderWide 24
#define kGliderBurningHigh 26
#define kShadowHigh 9
#define kShadowTop 306
#define kFaceRight TRUE
#define kFaceLeft FALSE
#define kPlayer1 TRUE
#define kPlayer2 FALSE
#define kNumGliderSrcRects 31
#define kNumShadowSrcRects 2
#define kFirstAboutFaceFrame 18
#define kLastAboutFaceFrame 20
#define kWasBurning 2
#define kLeftFadeOffset 7
#define kLastFadeSequence 16
#define kGliderFoil2PictID 3963
#define kGlider2PictID 3974
#define kGliderFoilPictID 3976
#define kGliderPictID 3999
#define kGliderStartsDown 32
#define kGliderNormal 0 // ¥¥ ¥¥
#define kGliderFadingIn 1 // ¥¥¥ ¥¥¥
#define kGliderFadingOut 2 // ¥¥ ¥¥ ¥¥
#define kGliderGoingUp 3 // ¥¥ ¥¥
#define kGliderComingUp 4 // ¥¥ ¥¥
#define kGliderGoingDown 5 //
#define kGliderComingDown 6 // ¥¥¥¥¥¥
#define kGliderFaceLeft 7 // ¥¥ ¥¥
#define kGliderFaceRight 8 // ¥¥ ¥¥
#define kGliderBurning 9 // ¥¥ ¥¥
#define kGliderTransporting 10 // ¥¥¥¥¥¥
#define kGliderDuctingDown 11 //
#define kGliderDuctingUp 12 // ¥¥¥¥¥¥¥
#define kGliderDuctingIn 13 // ¥¥ ¥¥
#define kGliderMailInLeft 14 // ¥¥ ¥¥
#define kGliderMailOutLeft 15 // ¥¥ ¥¥
#define kGliderMailInRight 16 // ¥¥¥¥¥¥¥
#define kGliderMailOutRight 17 //
#define kGliderGoingFoil 18 // ¥¥¥¥¥¥¥¥
#define kGliderLosingFoil 19 // ¥¥
#define kGliderShredding 20 // ¥¥¥¥
#define kGliderInLimbo 21 // ¥¥
#define kGliderIdle 22 // ¥¥¥¥¥¥¥¥
#define kGliderTransportingIn 23
#define kPlayerIsDeadForever -69
#define kPlayerMailedOut -12
#define kPlayerDuckedOut -11
#define kPlayerTransportedOut -10
#define kPlayerEscapingDownStairs -9
#define kPlayerEscapingUpStairs -8
#define kPlayerEscapedDownStairs -7
#define kPlayerEscapedUpStairs -6
#define kPlayerEscapedDown -5
#define kPlayerEscapedUp -4
#define kPlayerEscapedLeft -3
#define kPlayerEscapedRight -2
#define kNoOneEscaped -1
#define kLinkedToOther 0
#define kLinkedToLeftMailbox 1
#define kLinkedToRightMailbox 2
#define kLinkedToCeilingDuct 3
#define kLinkedToFloorDuct 4
#define kResumeGameMode 0
#define kNewGameMode 1
#define kNormalTitleMode 0
#define kEscapedTitleMode 1
#define kSavingTitleMode 2
#define kScoreboardPictID 1997
#define kDemoLength 6702
\ No newline at end of file
diff --git a/Headers/GliderProtos.h b/Headers/GliderProtos.h
deleted file mode 100755
index af611a5..0000000
--- a/Headers/GliderProtos.h
+++ /dev/null
@@ -1 +0,0 @@
-
//============================================================================
//----------------------------------------------------------------------------
// GliderProtos.h
//----------------------------------------------------------------------------
//============================================================================
//-------------------------------------------------------------- Prototypes
void SetUpAppleEvents (void); // --- AppleEvents.c
void BringUpBanner (void); // --- Banner.c
SInt16 CountStarsInHouse (void);
void DisplayStarsRemaining (void);
void SetCoordinateHVD (SInt16, SInt16, SInt16); // --- Coordinate.c
void DeltaCoordinateD (SInt16);
void UpdateCoordWindow (void);
void OpenCoordWindow (void);
void CloseCoordWindow (void);
void ToggleCoordinateWindow (void);
void NilSavedMaps (void); // --- DynamicMaps.c
SInt16 BackUpToSavedMap (Rect *, SInt16, SInt16);
SInt16 ReBackUpSavedMap (Rect *, SInt16, SInt16);
void RestoreFromSavedMap (SInt16, SInt16, Boolean);
void AddSparkle (Rect *);
void AddFlyingPoint (Rect *, SInt16, SInt16, SInt16);
void ReBackUpFlames (SInt16, SInt16);
void AddCandleFlame (SInt16, SInt16, SInt16, SInt16);
void ReBackUpTikiFlames (SInt16, SInt16);
void AddTikiFlame (SInt16, SInt16, SInt16, SInt16);
void ReBackUpBBQCoals (SInt16, SInt16);
void AddBBQCoals (SInt16, SInt16, SInt16, SInt16);
void ReBackUpPendulum (SInt16, SInt16);
void AddPendulum (SInt16, SInt16, SInt16, SInt16);
void ReBackUpStar (SInt16, SInt16);
void AddStar (SInt16, SInt16, SInt16, SInt16);
void StopPendulum (SInt16, SInt16);
void StopStar (SInt16, SInt16);
void AddAShreddedGlider (Rect *);
void RemoveShreds (void);
void ZeroFlamesAndTheLike (void);
void CheckDynamicCollision (SInt16, gliderPtr, Boolean); // --- Dynamics.c
Boolean DidBandHitDynamic (SInt16);
void RenderToast (SInt16);
void RenderBalloon (SInt16);
void RenderCopter (SInt16);
void RenderDart (SInt16);
void RenderBall (SInt16);
void RenderDrip (SInt16);
void RenderFish (SInt16);
void HandleSparkleObject (SInt16);
void HandleToast (SInt16);
void HandleMacPlus (SInt16);
void HandleTV (SInt16);
void HandleCoffee (SInt16);
void HandleOutlet (SInt16);
void HandleVCR (SInt16);
void HandleStereo (SInt16);
void HandleMicrowave (SInt16);
void HandleBalloon (SInt16); // --- Dynamics2.c
void HandleCopter (SInt16);
void HandleDart (SInt16);
void HandleBall (SInt16);
void HandleDrip (SInt16);
void HandleFish (SInt16);
void HandleDynamics (void); // --- Dynamics3.c
void RenderDynamics (void);
void ZeroDinahs (void);
SInt16 AddDynamicObject (SInt16, Rect *, objectType *, SInt16, SInt16, Boolean);
void DoGameOver (void); // --- GameOver.c
void FlagGameOver (void);
void DoDiedGameOver (void);
void HandleGrease (void); // --- Grease.c
SInt16 ReBackUpGrease (SInt16, SInt16);
SInt16 AddGrease (SInt16, SInt16, SInt16, SInt16, SInt16, Boolean);
void SpillGrease (SInt16, SInt16);
void RedrawAllGrease (void);
void DoHighScores (void); // --- HighScores.c
void SortHighScores (void);
void ZeroHighScores (void);
void ZeroAllButHighestScore (void);
Boolean TestHighScore (void);
Boolean WriteScoresToDisk (void);
Boolean ReadScoresFromDisk (void);
Boolean CreateNewHouse (void); // --- House.c
Boolean InitializeEmptyHouse (void);
SInt16 RealRoomNumberCount (void);
SInt16 GetFirstRoomNumber (void);
void WhereDoesGliderBegin (Rect *, SInt16);
Boolean HouseHasOriginalPicts (void);
SInt16 CountHouseLinks (void);
void GenerateLinksList (void);
void SortRoomsObjects (SInt16);
void SortHouseObjects (void);
SInt16 CountRoomsVisited (void);
void GenerateRetroLinks (void);
void DoGoToDialog (void);
void ConvertHouseVer1To2 (void);
void ShiftWholeHouse (SInt16);
void DoHouseInfo (void); // --- HouseInfo.c
Boolean OpenHouse (void); // --- HouseIO.c
Boolean OpenSpecificHouse (FSSpec *);
Boolean SaveHouseAs (void);
Boolean ReadHouse (void);
Boolean WriteHouse (Boolean);
Boolean CloseHouse (void);
void OpenHouseResFork (void);
void CloseHouseResFork (void);
Boolean QuerySaveChanges (void);
void YellowAlert (SInt16, SInt16);
Boolean KeepObjectLegal (void); // --- HouseLegal.c
void CheckHouseForProblems (void);
Boolean SectGlider (gliderPtr, Rect *, Boolean); // --- Interactions.c
void HandleSwitches (hotPtr);
void HandleInteraction (void);
void FlagStillOvers (gliderPtr);
void InitializeMenus (void); // --- InterfaceInit.c
void GetExtraCursors (void);
void VariableInit (void);
void GetDemoInput (gliderPtr); // --- Input.c
void GetInput (gliderPtr);
SInt16 MergeFloorSuite (SInt16, SInt16); // --- Link.c
void ExtractFloorSuite (SInt16, SInt16 *, SInt16 *);
void UpdateLinkControl (void);
void UpdateLinkWindow (void);
void OpenLinkWindow (void);
void CloseLinkWindow (void);
void HandleLinkClick (Point);
void RedrawSplashScreen (void); // --- MainWindow.c
void UpdateMainWindow (void);
void UpdateMenuBarWindow (void);
void OpenMainWindow (void);
void CloseMainWindow (void);
void ZoomBetweenWindows (void);
void UpdateEditWindowTitle (void);
void HandleMainClick (Point, Boolean);
//void WashColorIn (void);
void CenterMapOnRoom (SInt16, SInt16); // --- Map.c
Boolean ThisRoomVisibleOnMap (void);
void FindNewActiveRoomRect (void);
void FlagMapRoomsForUpdate (void);
void UpdateMapWindow (void);
void ResizeMapWindow (SInt16, SInt16);
void OpenMapWindow (void);
void CloseMapWindow (void);
void ToggleMapWindow (void);
void HandleMapClick (EventRecord *);
void MoveRoom (Point);
void DoMarquee (void); // --- Marquee.c
void StartMarquee (Rect *);
void StartMarqueeHandled (Rect *, SInt16, SInt16);
void StopMarquee (void);
void PauseMarquee (void);
void ResumeMarquee (void);
void DragOutMarqueeRect (Point, Rect *);
void DragMarqueeRect (Point, Rect *, Boolean, Boolean);
void DragMarqueeHandle (Point, SInt16 *);
void DragMarqueeCorner (Point, SInt16 *, SInt16 *, Boolean);
Boolean MarqueeHasHandles (SInt16 *, SInt16 *);
Boolean PtInMarqueeHandle (Point);
void SetMarqueeGliderRect (SInt16, SInt16);
void InitMarquee (void);
void UpdateClipboardMenus (void); // --- Menu.c
void DoAppleMenu (SInt16);
void DoGameMenu (SInt16);
void DoOptionsMenu (SInt16);
void DoHouseMenu (SInt16);
void DoMenuChoice (long);
void UpdateMenus (Boolean);
void UpdateMapCheckmark (Boolean);
void UpdateToolsCheckmark (Boolean);
void UpdateCoordinateCheckmark (Boolean);
#ifdef COMPILEDEMO
void DoNotInDemo (void);
#endif
void OpenCloseEditWindows (void);
void StartGliderFadingIn (gliderPtr); // --- Modes.c
void StartGliderTransportingIn (gliderPtr);
void StartGliderFadingOut (gliderPtr);
void StartGliderGoingUpStairs (gliderPtr);
void StartGliderGoingDownStairs (gliderPtr);
void StartGliderMailingIn (gliderPtr, Rect *, hotPtr);
void StartGliderMailingOut (gliderPtr);
void StartGliderDuctingDown (gliderPtr, Rect *, hotPtr);
void StartGliderDuctingUp (gliderPtr, Rect *, hotPtr);
void StartGliderDuctingIn (gliderPtr);
void StartGliderTransporting (gliderPtr, hotPtr);
void FlagGliderNormal (gliderPtr);
void FlagGliderShredding (gliderPtr, Rect *);
void FlagGliderBurning (gliderPtr);
void FlagGliderFaceLeft (gliderPtr);
void FlagGliderFaceRight (gliderPtr);
void FlagGliderInLimbo (gliderPtr, Boolean);
void UndoGliderLimbo (gliderPtr);
void ToggleGliderFacing (gliderPtr);
void InsureGliderFacingRight (gliderPtr);
void InsureGliderFacingLeft (gliderPtr);
void ReadyGliderForTripUpStairs (gliderPtr);
void ReadyGliderForTripDownStairs (gliderPtr);
void StartGliderFoilGoing (gliderPtr);
void StartGliderFoilLosing (gliderPtr);
void TagGliderIdle (gliderPtr);
OSErr StartMusic (void); // --- Music.c
void StopTheMusic (void);
void ToggleMusicWhilePlaying (void);
void SetMusicalMode (SInt16);
void InitMusic (void);
void KillMusic (void);
long MusicBytesNeeded (void);
void TellHerNoMusic (void);
Boolean AddNewObject (Point, SInt16, Boolean); // --- ObjectAdd.c
SInt16 FindObjectSlotInRoom (SInt16);
Boolean DoesRoomNumHaveObject (SInt16, SInt16);
void ShoutNoMoreObjects (void);
void DrawSimpleBlowers (SInt16, Rect *); // --- ObjectDraw.c
void DrawTiki (Rect *, SInt16);
void DrawInvisibleBlower (Rect *);
void DrawLiftArea (Rect *);
void DrawTable (Rect *, SInt16);
void DrawShelf (Rect *);
void DrawCabinet (Rect *);
void DrawSimpleFurniture (SInt16, Rect *);
void DrawCounter (Rect *);
void DrawDresser (Rect *);
void DrawDeckTable (Rect *, SInt16);
void DrawStool (Rect *, SInt16);
void DrawInvisObstacle (Rect *);
void DrawInvisBounce (Rect *);
void DrawRedClock (Rect *);
void DrawBlueClock (Rect *);
void DrawYellowClock (Rect *);
void DrawCuckoo (Rect *);
void DrawSimplePrizes (SInt16, Rect *);
void DrawGreaseRt (Rect *, SInt16, Boolean);
void DrawGreaseLf (Rect *, SInt16, Boolean);
void DrawFoil (Rect *);
void DrawInvisBonus (Rect *);
void DrawSlider (Rect *);
void DrawMailboxLeft (Rect *, SInt16); // --- ObjectDraw2.c
void DrawMailboxRight (Rect *, SInt16);
void DrawSimpleTransport (SInt16, Rect *);
void DrawInvisTransport (Rect *);
void DrawLightSwitch (Rect *, Boolean);
void DrawMachineSwitch (Rect *, Boolean);
void DrawThermostat (Rect *, Boolean);
void DrawPowerSwitch (Rect *, Boolean);
void DrawKnifeSwitch (Rect *, Boolean);
void DrawInvisibleSwitch (Rect *);
void DrawTrigger (Rect *);
void DrawSoundTrigger (Rect *);
void DrawSimpleLight (SInt16, Rect *);
void DrawFlourescent (Rect *);
void DrawSimpleAppliance (SInt16, Rect *);
void DrawMacPlus (Rect *, Boolean, Boolean);
void DrawTrackLight (Rect *);
void DrawInvisLight (Rect *);
void DrawTV (Rect *, Boolean, Boolean);
void DrawCoffee (Rect *, Boolean, Boolean);
void DrawOutlet (Rect *);
void DrawVCR (Rect *, Boolean, Boolean);
void DrawStereo (Rect *, Boolean, Boolean);
void DrawMicrowave (Rect *, Boolean, Boolean);
void DrawBalloon (Rect *);
void DrawCopter (Rect *);
void DrawDart (Rect *, SInt16);
void DrawBall (SInt16, Rect *);
void DrawFish (SInt16, Rect *);
void DrawDrip (Rect *);
void DrawMirror (Rect *);
void DrawSimpleClutter (SInt16, Rect *);
void DrawFlower (Rect *, SInt16);
void DrawWallWindow (Rect *);
void DrawCalendar (Rect *);
void DrawBulletin (Rect *);
void DrawPictObject (SInt16, Rect *);
void DrawPictWithMaskObject (SInt16, Rect *);
void DrawPictSansWhiteObject (SInt16, Rect *);
void DrawCustPictSansWhite (SInt16, Rect *);
void DrawARoomsObjects (SInt16, Boolean); // --- ObjectDrawAll.c
void DoSelectionClick (Point, Boolean); // --- ObjectEdit.c
void DoNewObjectClick (Point);
void DeleteObject (void);
void DuplicateObject (void);
void MoveObject (SInt16, Boolean);
void DeselectObject (void);
Boolean ObjectHasHandle (SInt16 *, SInt16 *);
void HandleBlowerGlider (void);
void SelectNextObject (void);
void SelectPrevObject (void);
void GetThisRoomsObjRects (void);
void DrawThisRoomsObjects (void);
void HiliteAllObjects (void);
void GoToObjectInRoom (SInt16, SInt16, SInt16);
void GoToObjectInRoomNum (SInt16, SInt16);
void DoObjectInfo (void); // --- ObjectInfo.c
void GetObjectRect (objectPtr, Rect *); // --- ObjectRects.c
SInt16 CreateActiveRects (SInt16);
SInt16 VerticalRoomOffset (SInt16);
void OffsetRectRoomRelative (Rect *, SInt16);
SInt16 GetUpStairsRightEdge (void);
SInt16 GetDownStairsLeftEdge (void);
SInt16 GetRoomLinked (objectType *); // --- Objects.c
Boolean ObjectIsLinkTransport (objectType *);
Boolean ObjectIsLinkSwitch (objectType *);
void ListAllLocalObjects (void);
Boolean SetObjectState (SInt16, SInt16, SInt16, SInt16);
Boolean GetObjectState (SInt16, SInt16);
void BringSendFrontBack (Boolean);
Boolean IsThisValid (SInt16, SInt16);
void AddTempManholeRect (Rect *);
void NewGame (SInt16); // --- Play.c
void DoDemoGame (void);
void HideGlider (gliderPtr);
void StrikeChime (void);
void RestoreEntireGameScreen (void);
void HandleGlider (gliderPtr); // --- Player.c
void FinishGliderUpStairs (gliderPtr);
void FinishGliderDownStairs (gliderPtr);
void FinishGliderDuctingIn (gliderPtr);
void DeckGliderInFoil (gliderPtr);
void RemoveFoilFromGlider (gliderPtr);
void OffsetGlider (gliderPtr, SInt16);
void OffAMortal (gliderPtr);
void AddRectToWorkRects (Rect *); // --- Render.c
void AddRectToBackRects (Rect *);
void AddRectToWorkRectsWhole (Rect *);
void RenderGlider (gliderPtr, Boolean);
void CopyRectsQD (void);
void DirectWork2Main8 (Rect *);
void DirectBack2Work8 (Rect *);
void DirectGeneric2Work8 (long, long, Rect *, Rect *);
void DirectWork2Main4 (Rect *);
void DirectBack2Work4 (Rect *);
void DirectGeneric2Work4 (long, long, Rect *, Rect *);
void CopyRectsAssm (void);
void DirectFillBack8 (Rect *, Byte);
void DirectFillWork8 (Rect *, Byte);
void DirectFillBack4 (Rect *, Byte);
void DirectFillWork4 (Rect *, Byte);
void RenderFrame (void);
void InitGarbageRects (void);
void CopyRectBackToWork (Rect *);
void CopyRectWorkToBack (Rect *);
void CopyRectWorkToMain (Rect *);
void CopyRectMainToWork (Rect *);
void CopyRectMainToBack (Rect *);
void AddToMirrorRegion (Rect *);
void ZeroMirrorRegion (void);
void SetInitialTiles (SInt16, Boolean); // --- Room.c
Boolean CreateNewRoom (SInt16, SInt16);
void DoRoomInfo (void);
void ReadyBackground (SInt16, SInt16 *);
void ReflectCurrentRoom (Boolean);
void CopyRoomToThisRoom (SInt16);
void CopyThisRoomToRoom (void);
void ForceThisRoom (SInt16);
Boolean RoomExists (SInt16, SInt16, SInt16 *);
Boolean RoomNumExists (SInt16);
void DeleteRoom (Boolean);
SInt16 DoesNeighborRoomExist (SInt16);
void SelectNeighborRoom (SInt16);
SInt16 GetNeighborRoomNumber (SInt16);
Boolean GetRoomFloorSuite (SInt16, SInt16 *, SInt16 *);
SInt16 GetRoomNumber (SInt16, SInt16);
Boolean IsRoomAStructure (SInt16);
void DetermineRoomOpenings (void);
SInt16 GetOriginalBounding (SInt16);
SInt16 GetNumberOfLights (SInt16);
Boolean IsShadowVisible (void);
Boolean DoesRoomHaveFloor (void);
Boolean DoesRoomHaveCeiling (void);
void ReadyLevel (void); // --- RoomGraphics.c
void DrawLocale (void);
void RedrawRoomLighting (void);
Boolean PictIDExists (SInt16); // --- RoomInfo.c
void HandleBands (void); // --- RubberBands.c
Boolean AddBand (gliderPtr, SInt16, SInt16, Boolean);
void KillAllBands (void);
void SaveGame2 (void); // --- SavedGames.c
Boolean OpenSavedGame (void);
void SaveGame (Boolean);
void RefreshScoreboard (SInt16); // --- Scoreboard.c
void HandleDynamicScoreboard (void);
void QuickGlidersRefresh (void);
void QuickScoreRefresh (void);
void QuickBatteryRefresh (Boolean);
void QuickBandsRefresh (Boolean);
void QuickFoilRefresh (Boolean);
void HandleScore (void);
void AdjustScoreboardHeight (void);
void BlackenScoreboard (void);
//void PutRoomScrap (void); // --- Scrap.c
//void PutObjectScrap (void);
void GetRoomScrap (void);
void GetObjectScrap (void);
//void SeeIfValidScrapAvailable (Boolean);
Boolean HasDragManager (void);
//Boolean DragRoom (EventRecord *, Rect *, SInt16);
void DoLoadHouse (void); // --- SelectHouse.c
void BuildHouseList (void);
void AddExtraHouse (FSSpec *);
void DoSettingsMain (void); // --- Settings.c
void PlayPrioritySound (SInt16, SInt16); // --- Sound.c
void FlushAnyTriggerPlaying (void);
void PlaySound0 (SInt16, SInt16);
void PlaySound1 (SInt16, SInt16);
void PlaySound2 (SInt16, SInt16);
OSErr LoadTriggerSound (SInt16);
void DumpTriggerSound (void);
void InitSound (void);
void KillSound (void);
long SoundBytesNeeded (void);
void TellHerNoSounds (void);
void BitchAboutSM3 (void);
void InitScoreboardMap (void); // --- StructuresInit.c
void InitGliderMap (void);
void InitBlowers (void);
void InitFurniture (void);
void InitPrizes (void);
void InitTransports (void);
void InitSwitches (void);
void InitLights (void);
void InitAppliances (void);
void InitEnemies (void);
void CreateOffscreens (void); // --- StructuresInit2.c
void CreatePointers (void);
void InitSrcRects (void);
void UpdateToolsWindow (void); // --- Tools.c
void EraseSelectedTool (void);
void SelectTool (SInt16);
void OpenToolsWindow (void);
void CloseToolsWindow (void);
void ToggleToolsWindow (void);
void HandleToolsClick (Point);
void NextToolMode (void);
void PrevToolMode (void);
void SetSpecificToolMode (SInt16);
SInt16 WhatAreWeLinkedTo (SInt16, Byte); // --- Transit.c
void ReadyGliderFromTransit (gliderPtr, SInt16);
void MoveRoomToRoom (gliderPtr, SInt16);
void TransportRoomToRoom (gliderPtr);
void MoveDuctToDuct (gliderPtr);
void MoveMailToMail (gliderPtr);
void ForceKillGlider (void);
void FollowTheLeader (void);
void PourScreenOn (Rect *); // --- Transitions.c
void WipeScreenOn (SInt16, Rect *);
void DumpScreenOn (Rect *);
//void DissBits (Rect *);
//void DissBitsChunky (Rect *);
//void FillColorNoise (Rect *);
//void FillSnow (Rect *);
void ToggleToaster (SInt16); // --- Trip.c
void ToggleMacPlus (SInt16);
void ToggleTV (SInt16);
void ToggleCoffee (SInt16);
void ToggleOutlet (SInt16);
void ToggleVCR (SInt16);
void ToggleStereos (SInt16);
void ToggleMicrowave (SInt16);
void ToggleBalloon (SInt16);
void ToggleCopter (SInt16);
void ToggleDart (SInt16);
void ToggleBall (SInt16);
void ToggleDrip (SInt16);
void ToggleFish (SInt16);
void TriggerSwitch (SInt16);
void TriggerToast (SInt16);
void TriggerOutlet (SInt16);
void TriggerDrip (SInt16);
void TriggerFish (SInt16);
void TriggerBalloon (SInt16);
void TriggerCopter (SInt16);
void TriggerDart (SInt16);
void UpdateOutletsLighting (SInt16, SInt16);
void ArmTrigger (hotPtr); // --- Triggers.c
void HandleTriggers (void);
void ZeroTriggers (void);
\ No newline at end of file
diff --git a/Headers/GliderStructs.h b/Headers/GliderStructs.h
deleted file mode 100755
index 1744a30..0000000
--- a/Headers/GliderStructs.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// GliderStructs.h
//----------------------------------------------------------------------------
//============================================================================
#include
typedef struct
{
Point topLeft; // 4
short distance; // 2
Boolean initial; // 1
Boolean state; // 1 F. lf. dn. rt. up
Byte vector; // 1 | x | x | x | x | 8 | 4 | 2 | 1 |
Byte tall; // 1
} blowerType; // total = 10
typedef struct
{
Rect bounds; // 8
short pict; // 2
} furnitureType; // total = 10
typedef struct
{
Point topLeft; // 4
short length; // 2 grease spill
short points; // 2 invis bonus
Boolean state; // 1
Boolean initial; // 1
} bonusType; // total = 10
typedef struct
{
Point topLeft; // 4
short tall; // 2 invis transport
short where; // 2
Byte who; // 1
Byte wide; // 1
} transportType; // total = 10
typedef struct
{
Point topLeft; // 4
short delay; // 2
short where; // 2
Byte who; // 1
Byte type; // 1
} switchType; // total = 10
typedef struct
{
Point topLeft; // 4
short length; // 2
Byte byte0; // 1
Byte byte1; // 1
Boolean initial; // 1
Boolean state; // 1
} lightType; // total = 10
typedef struct
{
Point topLeft; // 4
short height; // 2 toaster, pict ID
Byte byte0; // 1
Byte delay; // 1
Boolean initial; // 1
Boolean state; // 1
} applianceType; // total = 10
typedef struct
{
Point topLeft; // 4
short length; // 2
Byte delay; // 1
Byte byte0; // 1
Boolean initial; // 1
Boolean state; // 1
} enemyType; // total = 10
typedef struct
{
Rect bounds; // 8
short pict; // 2
} clutterType; // total = 10
typedef struct
{
short what; // 2
union
{
blowerType a;
furnitureType b;
bonusType c;
transportType d;
switchType e;
lightType f;
applianceType g;
enemyType h;
clutterType i;
} data; // 10
} objectType, *objectPtr; // total = 12
typedef struct
{
Str31 banner; // 32 = 32
Str15 names[kMaxScores]; // 16 * 10 = 160
long scores[kMaxScores]; // 4 * 10 = 40
unsigned long timeStamps[kMaxScores]; // 4 * 10 = 40
short levels[kMaxScores]; // 2 * 10 = 20
} scoresType; // total = 292
typedef struct
{
short version; // 2
short wasStarsLeft; // 2
long timeStamp; // 4
Point where; // 4
long score; // 4
long unusedLong; // 4
long unusedLong2; // 4
short energy; // 2
short bands; // 2
short roomNumber; // 2
short gliderState; // 2
short numGliders; // 2
short foil; // 2
short unusedShort; // 2
Boolean facing; // 1
Boolean showFoil; // 1
} gameType; // total = 40
typedef struct
{
short unusedShort; // 2
Byte unusedByte; // 1
Boolean visited; // 1
objectType objects[kMaxRoomObs]; // 24 * 12
} savedRoom, *saveRoomPtr; // total = 292
typedef struct
{
FSSpec house; // 70
short version; // 2
short wasStarsLeft; // 2
long timeStamp; // 4
Point where; // 4
long score; // 4
long unusedLong; // 4
long unusedLong2; // 4
short energy; // 2
short bands; // 2
short roomNumber; // 2
short gliderState; // 2
short numGliders; // 2
short foil; // 2
short nRooms; // 2
Boolean facing; // 1
Boolean showFoil; // 1
savedRoom savedData[]; // 4
} game2Type, *gamePtr; // total = 114
typedef struct
{
Str27 name; // 28
short bounds; // 2
Byte leftStart; // 1
Byte rightStart; // 1
Byte unusedByte; // 1
Boolean visited; // 1
short background; // 2
short tiles[kNumTiles]; // 2 * 8
short floor, suite; // 2 + 2
short openings; // 2
short numObjects; // 2
objectType objects[kMaxRoomObs]; // 24 * 12
} roomType, *roomPtr; // total = 348
typedef struct
{
short version; // 2
short unusedShort; // 2
long timeStamp; // 4
long flags; // 4 (bit 0 = wardBit)
Point initial; // 4
Str255 banner; // 256
Str255 trailer; // 256
scoresType highScores; // 292
gameType savedGame; // 40
Boolean hasGame; // 1
Boolean unusedBoolean; // 1
short firstRoom; // 2
short nRooms; // 2
roomType rooms[]; // 348 * nRooms
} houseType, *housePtr, **houseHand; // total = 866 +
typedef struct
{
Rect src, mask, dest, whole;
Rect destShadow, wholeShadow;
Rect clip, enteredRect;
long leftKey, rightKey;
long battKey, bandKey;
short hVel, vVel;
short wasHVel, wasVVel;
short vDesiredVel, hDesiredVel;
short mode, frame, wasMode;
Boolean facing, tipped;
Boolean sliding, ignoreLeft, ignoreRight;
Boolean fireHeld, which;
Boolean heldLeft, heldRight;
Boolean dontDraw, ignoreGround;
} gliderType, *gliderPtr;
typedef struct
{
Rect bounds;
short action;
short who;
Boolean isOn, stillOver;
Boolean doScrutinize;
} hotObject, *hotPtr;
typedef struct
{
Rect dest;
GWorldPtr map;
short where;
short who;
} savedType, *savedPtr;
typedef struct
{
Rect bounds;
short mode;
} sparkleType, *sparklePtr;
typedef struct
{
Rect dest, whole;
short start;
short stop;
short mode;
short loops;
short hVel, vVel;
} flyingPtType, *flyingPtPtr;
typedef struct
{
Rect dest, src;
short mode;
short who;
} flameType, *flamePtr;
typedef struct
{
Rect dest, src;
short mode, where;
short who, link;
Boolean toOrFro, active;
} pendulumType, *pendulumPtr;
typedef struct
{
Boolean left;
Boolean top;
Boolean right;
Boolean bottom;
} boundsType, *boundsPtr, **boundsHand;
typedef struct
{
Rect dest;
short mode, count;
short hVel, vVel;
} bandType, *bandPtr;
typedef struct
{
short srcRoom, srcObj;
short destRoom, destObj;
} linksType, *linksPtr;
typedef struct
{
Rect dest;
short mapNum, mode;
short who, where;
short start, stop;
short frame, hotNum;
Boolean isRight;
} greaseType, *greasePtr;
typedef struct
{
Rect dest, src;
short mode, who;
short link, where;
} starType, *starPtr;
typedef struct
{
Rect bounds;
short frame;
} shredType, *shredPtr;
typedef struct
{
Rect dest;
Rect whole;
short hVel, vVel;
short type, count;
short frame, timer;
short position, room;
Byte byte0, byte1;
Boolean moving, active;
} dynaType, *dynaPtr;
typedef struct
{
short roomNum; // room # object in (real number)
short objectNum; // obj. # in house (real number)
short roomLink; // room # object linked to (if any)
short objectLink; // obj. # object linked to (if any)
short localLink; // index in master list if exists
short hotNum; // index into active rects (if any)
short dynaNum; // index into dinahs (if any)
objectType theObject; // actual object data
} objDataType, *objDataPtr;
typedef struct
{
long frame;
char key;
char padding;
} demoType, *demoPtr;
typedef struct
{
short room;
short object;
} retroLink, *retroLinkPtr;
\ No newline at end of file
diff --git a/Headers/GliderVars.h b/Headers/GliderVars.h
deleted file mode 100755
index 4d4e19a..0000000
--- a/Headers/GliderVars.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// GliderVars.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern Rect blowerSrcRect;
extern Rect flame[], tikiFlame[];
extern Rect coals[];
extern Rect furnitureSrcRect;
extern Rect tableSrc, shelfSrc, hingeSrc, handleSrc, knobSrc;
extern Rect leftFootSrc, rightFootSrc, deckSrc;
extern Rect bonusSrcRect;
extern Rect pointsSrcRect;
extern Rect starSrc[], sparkleSrc[];
extern Rect digits[], pendulumSrc[], greaseSrcRt[], greaseSrcLf[];
extern Rect transSrcRect;
extern Rect switchSrcRect;
extern Rect lightSwitchSrc[], machineSwitchSrc[], thermostatSrc[];
extern Rect powerSrc[], knifeSwitchSrc[];
extern Rect lightSrcRect;
extern Rect flourescentSrc1, flourescentSrc2;
extern Rect trackLightSrc[];
extern Rect applianceSrcRect, toastSrcRect, shredSrcRect; // Appliances
extern Rect plusScreen1, plusScreen2, tvScreen1, tvScreen2;
extern Rect coffeeLight1, coffeeLight2, vcrTime1, vcrTime2;
extern Rect stereoLight1, stereoLight2, microOn, microOff;
extern Rect outletSrc[];
extern Rect balloonSrcRect, copterSrcRect, dartSrcRect; // Enemies
extern Rect ballSrcRect, dripSrcRect, enemySrcRect;
extern Rect fishSrcRect;
extern Rect balloonSrc[], copterSrc[], dartSrc[];
extern Rect ballSrc[], dripSrc[], fishSrc[];
extern Rect clutterSrcRect;
extern Rect flowerSrc[];
extern Rect *srcRects;
extern Movie theMovie;
extern Rect movieRect;
extern Boolean hasMovie, tvInRoom;
extern gliderType theGlider, theGlider2;
extern objDataPtr masterObjects;
extern Rect workSrcRect;
extern Rect backSrcRect;
extern Rect mainWindowRect, houseRect;
extern houseHand thisHouse;
extern roomPtr thisRoom;
extern WindowPtr mainWindow, coordWindow;
extern long theScore;
extern short playOriginH, playOriginV;
extern short thisRoomNumber, theMode, batteryTotal, bandsTotal;
extern short foilTotal, mortals, numMasterObjects, previousRoom;
extern Boolean fileDirty, gameDirty, showFoil, doZooms, isPlayMusicGame;
\ No newline at end of file
diff --git a/Headers/House.h b/Headers/House.h
deleted file mode 100755
index fd64fed..0000000
--- a/Headers/House.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// House.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern Str32 thisHouseName;
extern Boolean houseUnlocked;
\ No newline at end of file
diff --git a/Headers/MainWindow.h b/Headers/MainWindow.h
deleted file mode 100755
index f932866..0000000
--- a/Headers/MainWindow.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// MainWindow.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern GWorldPtr workSrcMap;
\ No newline at end of file
diff --git a/Headers/Map.h b/Headers/Map.h
deleted file mode 100755
index 8e4e8bd..0000000
--- a/Headers/Map.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// Map.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern GWorldPtr nailSrcMap;
extern WindowPtr mapWindow;
\ No newline at end of file
diff --git a/Headers/Marquee.h b/Headers/Marquee.h
deleted file mode 100755
index fb21eb2..0000000
--- a/Headers/Marquee.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// Marquee.h
//----------------------------------------------------------------------------
//============================================================================
#pragma once
#include
typedef struct
{
Pattern pats[kNumMarqueePats];
Rect bounds, handle;
short index, direction, dist;
Boolean active, paused, handled;
} marquee;
extern marquee theMarquee;
\ No newline at end of file
diff --git a/Headers/ObjectEdit.h b/Headers/ObjectEdit.h
deleted file mode 100755
index dfebe55..0000000
--- a/Headers/ObjectEdit.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// ObjectEdit.h
//----------------------------------------------------------------------------
//============================================================================
#pragma once
#include
extern Rect roomObjectRects[];
extern short objActive;
\ No newline at end of file
diff --git a/Headers/Objects.h b/Headers/Objects.h
deleted file mode 100755
index 083b420..0000000
--- a/Headers/Objects.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// Objects.h
//----------------------------------------------------------------------------
//============================================================================
extern GWorldPtr blowerSrcMap;
extern GWorldPtr blowerMaskMap;
extern GWorldPtr furnitureSrcMap;
extern GWorldPtr furnitureMaskMap;
extern GWorldPtr bonusSrcMap;
extern GWorldPtr bonusMaskMap;
extern GWorldPtr pointsSrcMap;
extern GWorldPtr pointsMaskMap;
extern GWorldPtr transSrcMap;
extern GWorldPtr transMaskMap;
extern GWorldPtr switchSrcMap;
extern GWorldPtr lightSrcMap;
extern GWorldPtr lightMaskMap;
extern GWorldPtr applianceSrcMap;
extern GWorldPtr applianceMaskMap;
extern GWorldPtr toastSrcMap;
extern GWorldPtr toastMaskMap;
extern GWorldPtr shredSrcMap;
extern GWorldPtr shredMaskMap;
extern GWorldPtr balloonSrcMap;
extern GWorldPtr balloonMaskMap;
extern GWorldPtr copterSrcMap;
extern GWorldPtr copterMaskMap;
extern GWorldPtr dartSrcMap;
extern GWorldPtr dartMaskMap;
extern GWorldPtr ballSrcMap;
extern GWorldPtr ballMaskMap;
extern GWorldPtr dripSrcMap;
extern GWorldPtr dripMaskMap;
extern GWorldPtr enemySrcMap;
extern GWorldPtr enemyMaskMap;
extern GWorldPtr fishSrcMap;
extern GWorldPtr fishMaskMap;
extern GWorldPtr clutterSrcMap;
extern GWorldPtr clutterMaskMap;
\ No newline at end of file
diff --git a/Headers/Play.h b/Headers/Play.h
deleted file mode 100755
index b863d2f..0000000
--- a/Headers/Play.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// Play.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern GWorldPtr glidSrcMap;
extern GWorldPtr glid2SrcMap;
extern GWorldPtr glidMaskMap;
\ No newline at end of file
diff --git a/Headers/Player.h b/Headers/Player.h
deleted file mode 100755
index a78a38e..0000000
--- a/Headers/Player.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// Player.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern GWorldPtr shadowSrcMap;
extern GWorldPtr shadowMaskMap;
\ No newline at end of file
diff --git a/Headers/RectUtils.h b/Headers/RectUtils.h
deleted file mode 100755
index 7ff4de5..0000000
--- a/Headers/RectUtils.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// RectUtils.h
//----------------------------------------------------------------------------
//============================================================================
#pragma once
#include
void FrameWHRect (short, short, short, short);
void NormalizeRect (Rect *);
void ZeroRectCorner (Rect *);
void CenterRectOnPoint (Rect *, Point);
short HalfRectWide (Rect *);
short HalfRectTall (Rect *);
short RectWide (Rect *);
short RectTall (Rect *);
void GlobalToLocalRect (Rect *);
void LocalToGlobalRect (Rect *);
void CenterRectInRect (Rect *, Rect *);
void HOffsetRect (Rect *, short);
void VOffsetRect (Rect *, short);
Boolean IsRectLeftOfRect (Rect *, Rect *);
void QOffsetRect (Rect *, short, short);
void QSetRect (Rect *, short, short, short, short);
Boolean ForceRectInRect (Rect *, Rect *);
void QUnionSimilarRect (Rect *, Rect *, Rect *);
void FrameRectSansCorners (Rect *);
void SetEraseRect (short, short, short, short);
\ No newline at end of file
diff --git a/Headers/Room.h b/Headers/Room.h
deleted file mode 100755
index 434913e..0000000
--- a/Headers/Room.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// Room.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern GWorldPtr backSrcMap;
\ No newline at end of file
diff --git a/Headers/RoomGraphics.h b/Headers/RoomGraphics.h
deleted file mode 100755
index 5538be1..0000000
--- a/Headers/RoomGraphics.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// RoomGraphics.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern GWorldPtr suppSrcMap;
\ No newline at end of file
diff --git a/Headers/RubberBands.h b/Headers/RubberBands.h
deleted file mode 100755
index 566ab20..0000000
--- a/Headers/RubberBands.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// RubberBands.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern GWorldPtr bandsSrcMap;
extern GWorldPtr bandsMaskMap;
\ No newline at end of file
diff --git a/Headers/Scoreboard.h b/Headers/Scoreboard.h
deleted file mode 100755
index 9d989ea..0000000
--- a/Headers/Scoreboard.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// Scoreboard.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern GWorldPtr boardSrcMap;
extern GWorldPtr badgeSrcMap;
extern GWorldPtr boardTSrcMap;
extern GWorldPtr boardGSrcMap;
extern GWorldPtr boardPSrcMap;
\ No newline at end of file
diff --git a/Headers/Tools.h b/Headers/Tools.h
deleted file mode 100755
index ff80070..0000000
--- a/Headers/Tools.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// Tools.h
//----------------------------------------------------------------------------
//============================================================================
#include
extern GWorldPtr toolSrcMap;
extern WindowPtr toolsWindow;
\ No newline at end of file
diff --git a/Headers/Utilities.h b/Headers/Utilities.h
deleted file mode 100755
index 3f57af2..0000000
--- a/Headers/Utilities.h
+++ /dev/null
@@ -1 +0,0 @@
-//============================================================================
//----------------------------------------------------------------------------
// Utilities.c
//----------------------------------------------------------------------------
//============================================================================
#include
OSErr CreateOffScreenGWorld (GWorldPtr *theGWorld, Rect *bounds, short depth);
\ No newline at end of file
diff --git a/MiniRez/MiniRez.cpp b/MiniRez/MiniRez.cpp
new file mode 100644
index 0000000..2e4cb85
--- /dev/null
+++ b/MiniRez/MiniRez.cpp
@@ -0,0 +1,528 @@
+#include
+#include
+#include
+#include
+
+#include "BytePack.h"
+#include "CFileStream.h"
+#include "IOStream.h"
+
+#include "MacBinary2.h"
+#include "MacFileMem.h"
+
+// Very simplified resource compiler
+
+using namespace PortabilityLayer;
+
+struct SimpleResource
+{
+ char m_type[4];
+ int m_resourceID;
+ std::string m_name;
+ std::vector m_resourceData;
+ size_t m_offsetInResData;
+ uint8_t m_attributes;
+};
+
+struct ResCatalogData
+{
+};
+
+bool IsWhitespace(char c)
+{
+ return c <= ' ';
+}
+
+void AppendUInt16(std::vector &vec, uint16_t value)
+{
+ uint8_t encoded[2];
+ BytePack::BigUInt16(encoded, value);
+ vec.push_back(encoded[0]);
+ vec.push_back(encoded[1]);
+}
+
+void AppendInt16(std::vector &vec, int16_t value)
+{
+ AppendUInt16(vec, static_cast(value));
+}
+
+void AppendUInt32(std::vector &vec, uint32_t value)
+{
+ uint8_t encoded[4];
+ BytePack::BigUInt32(encoded, value);
+ vec.push_back(encoded[0]);
+ vec.push_back(encoded[1]);
+ vec.push_back(encoded[2]);
+ vec.push_back(encoded[3]);
+}
+
+uint32_t TypeToU32(const char *resType)
+{
+ uint32_t v = 0;
+ for (int i = 0; i < 4; i++)
+ v |= static_cast(resType[i]) << (24 - i * 8);
+
+ return v;
+}
+
+bool FindNextNonWhitespace(CFileStream &fs, char &nextChar)
+{
+ for (;;)
+ {
+ char c;
+ if (!fs.Read(&c, 1))
+ return false;
+
+ if (!IsWhitespace(c))
+ {
+ nextChar = c;
+ return true;
+ }
+ }
+}
+
+std::string HandleEscapes(const std::string &str)
+{
+ const size_t len = str.size();
+
+ std::string processed;
+
+ for (size_t i = 0; i < len; i++)
+ {
+ const char c = str[i];
+
+ if (c == '\\' && len - i >= 5 && str[i + 1] == '0' && str[i + 2] == 'x')
+ {
+ const char highNibbleChar = str[i + 3];
+ const char lowNibbleChar = str[i + 4];
+
+ int highNibble = highNibbleChar - '0';
+ int lowNibble = lowNibbleChar - '0';
+
+ const char reconstructed = (highNibble << 4) | lowNibble;
+ processed.append(&reconstructed, 1);
+
+ i += 4;
+ }
+ else
+ processed.append(&c, 1);
+ }
+
+ return processed;
+}
+
+void DefError()
+{
+ fprintf(stderr, "Malformed def");
+ exit(-1);
+}
+
+int main(int argc, const char **argv)
+{
+ if (argc != 3)
+ {
+ fprintf(stderr, "Usage: MiniRez ");
+ return -1;
+ }
+
+ FILE *f = nullptr;
+ if (fopen_s(&f, argv[1], "rb"))
+ {
+ fprintf(stderr, "Failed to open input file");
+ return -1;
+ }
+
+ CFileStream fs(f, true, false, true);
+
+ int defsParsed = 0;
+
+ std::vector resources;
+
+ for (;;)
+ {
+ printf("%i defs parsed...\n", defsParsed);
+ defsParsed++;
+ UFilePos_t defStartOffset = fs.Tell();
+
+ char nextChar = 0;
+ if (!FindNextNonWhitespace(fs, nextChar))
+ break;
+
+ if (IsWhitespace(nextChar))
+ continue;
+
+ if (nextChar == 'd')
+ {
+ char nextChars[3];
+ if (fs.Read(nextChars, 3) != 3 || nextChars[0] != 'a' || nextChars[1] != 't' || nextChars[2] != 'a')
+ {
+ fprintf(stderr, "Unknown token");
+ return -1;
+ }
+
+ if (!FindNextNonWhitespace(fs, nextChar) || nextChar != '\'')
+ DefError();
+
+ char resType[5];
+ if (!fs.Read(resType, 5) || resType[4] != '\'')
+ DefError();
+
+ if (!FindNextNonWhitespace(fs, nextChar) || nextChar != '(')
+ DefError();
+
+ int resID = 0;
+ bool hasProperty = false;
+ bool isNegative = false;
+ for (;;)
+ {
+ if (!fs.Read(&nextChar, 1))
+ DefError();
+
+ if (nextChar == ')')
+ break;
+ else if (nextChar == ',')
+ {
+ hasProperty = true;
+ break;
+ }
+ else if (nextChar == '-')
+ isNegative = true;
+ else if (nextChar >= '0' && nextChar <= '9')
+ resID = resID * 10 + (nextChar - '0');
+ else
+ DefError();
+ }
+
+ std::string resName;
+ std::string propName;
+ std::vector resData;
+
+ if (hasProperty)
+ {
+ char singleCharStr[2];
+ singleCharStr[1] = '\0';
+
+ if (!FindNextNonWhitespace(fs, singleCharStr[0]))
+ DefError();
+
+
+ if (singleCharStr[0] == '\"')
+ {
+ hasProperty = false;
+
+ for (;;)
+ {
+ if (!fs.Read(singleCharStr, 1))
+ DefError();
+
+ if (singleCharStr[0] == '"')
+ break;
+
+ resName += singleCharStr;
+ }
+
+ if (!FindNextNonWhitespace(fs, nextChar))
+ DefError();
+
+ if (nextChar == ')')
+ {
+ }
+ else if (nextChar == ',')
+ {
+ hasProperty = true;
+ if (!FindNextNonWhitespace(fs, singleCharStr[0]))
+ DefError();
+ }
+ else
+ DefError();
+ }
+
+ if (hasProperty)
+ {
+ propName = singleCharStr;
+
+ for (;;)
+ {
+ if (!fs.Read(singleCharStr, 1))
+ DefError();
+
+ if (singleCharStr[0] == ')')
+ break;
+
+ propName += singleCharStr;
+ }
+ }
+ }
+
+ if (!FindNextNonWhitespace(fs, nextChar) || nextChar != '{')
+ DefError();
+
+ // Data item parse loop
+ for (;;)
+ {
+ if (!FindNextNonWhitespace(fs, nextChar))
+ DefError();
+
+ if (nextChar == '$')
+ {
+ // Res data bytes
+ uint8_t b = 0;
+ bool highNibble = true;
+
+ if (!fs.Read(&nextChar, 1) || nextChar != '\"')
+ DefError();
+
+ for (;;)
+ {
+ if (!fs.Read(&nextChar, 1))
+ DefError();
+
+ uint8_t fragment = 0;
+
+ if (nextChar == '\"')
+ break;
+ else if (nextChar >= '0' && nextChar <= '9')
+ fragment = nextChar - '0';
+ else if (nextChar >= 'a' && nextChar <= 'f')
+ fragment = nextChar - 'a' + 0xa;
+ else if (nextChar >= 'A' && nextChar <= 'F')
+ fragment = nextChar - 'A' + 0xa;
+ else if (nextChar == ' ')
+ {
+ continue;
+ }
+ else
+ DefError();
+
+ if (highNibble)
+ {
+ b = fragment << 4;
+ highNibble = false;
+ }
+ else
+ {
+ resData.push_back(b | fragment);
+ highNibble = true;
+ }
+ }
+
+ continue;
+ }
+ else if (nextChar == '}')
+ break;
+ else if (nextChar == '/')
+ {
+ if (!fs.Read(&nextChar, 1))
+ DefError();
+
+ if (nextChar == '/')
+ {
+ for (;;)
+ {
+ if (!fs.Read(&nextChar, 1))
+ DefError();
+
+ if (nextChar == '\r' || nextChar == '\n')
+ break;
+ }
+ }
+ else if (nextChar == '*')
+ {
+ char prevChar = nextChar;
+
+ for (;;)
+ {
+ if (!fs.Read(&nextChar, 1))
+ DefError();
+
+ if (nextChar == '/' && prevChar == '*')
+ break;
+
+ prevChar = nextChar;
+ }
+ }
+ else
+ DefError();
+ }
+ else
+ DefError();
+ }
+
+ if (!FindNextNonWhitespace(fs, nextChar) || nextChar != ';')
+ DefError();
+
+ SimpleResource *res = new SimpleResource();
+ res->m_name = HandleEscapes(resName);
+ res->m_resourceID = resID;
+ memcpy(res->m_type, resType, 4);
+ res->m_resourceData.swap(resData);
+ res->m_attributes = 0;
+
+ if (propName == "purgeable")
+ res->m_attributes |= (1 << 5);
+
+
+ resources.push_back(res);
+ }
+ else
+ {
+ fprintf(stderr, "Unknown token");
+ return -1;
+ }
+ }
+
+ std::vector resourceForkData;
+
+ for (size_t i = 0; i < 16; i++)
+ resourceForkData.push_back(0);
+
+ size_t resForkDataStart = resourceForkData.size();
+
+ std::vector uniqueResTypes;
+ std::vector resTypeCounts;
+ std::vector uniqueResNames;
+
+ printf("Re-emitting defs...\n");
+ for (size_t i = 0; i < resources.size(); i++)
+ {
+ SimpleResource *res = resources[i];
+
+ res->m_offsetInResData = resourceForkData.size() - resForkDataStart;
+
+ uint8_t packedLen[4];
+ BytePack::BigUInt32(packedLen, static_cast(res->m_resourceData.size()));
+
+ for (int j = 0; j < 4; j++)
+ resourceForkData.push_back(packedLen[j]);
+
+ for (size_t j = 0; j < res->m_resourceData.size(); j++)
+ resourceForkData.push_back(res->m_resourceData[j]);
+
+ uint32_t resTypeCode = TypeToU32(res->m_type);
+ std::vector::iterator uniqueResTypeIndex = std::find(uniqueResTypes.begin(), uniqueResTypes.end(), resTypeCode);
+
+ if (uniqueResTypeIndex == uniqueResTypes.end())
+ {
+ uniqueResTypes.push_back(resTypeCode);
+ resTypeCounts.push_back(1);
+ }
+ else
+ resTypeCounts[uniqueResTypeIndex - uniqueResTypes.begin()]++;
+
+ if (!res->m_name.empty())
+ {
+ if (std::find(uniqueResNames.begin(), uniqueResNames.end(), res->m_name) == uniqueResNames.end())
+ uniqueResNames.push_back(res->m_name);
+ }
+ }
+
+ const size_t resDataSize = resourceForkData.size() - resForkDataStart;
+ const size_t resMapPos = resourceForkData.size();
+
+ // Reserved space for resource header copy (16), handle to next res map (4), file ref number (2)
+ for (size_t j = 0; j < 22; j++)
+ resourceForkData.push_back(0);
+
+ uint16_t resForkAttributes = 0; // We don't use any of these
+
+ const size_t typeListEntrySize = 8;
+ const size_t refListEntrySize = 12;
+
+ const size_t resourceTypeListStartLoc = 28;
+ const size_t resourceTypeListSize = 2 + uniqueResTypes.size() * typeListEntrySize;
+ const size_t resourceRefListStartLoc = resourceTypeListStartLoc + resourceTypeListSize;
+ const size_t resourceNameListStartLoc = resourceRefListStartLoc + resources.size() * refListEntrySize;
+
+ AppendUInt16(resourceForkData, resForkAttributes);
+ AppendUInt16(resourceForkData, static_cast(resourceTypeListStartLoc));
+ AppendUInt16(resourceForkData, static_cast(resourceNameListStartLoc));
+ AppendUInt16(resourceForkData, static_cast(uniqueResTypes.size() - 1));
+
+ std::vector refListStartForType;
+ refListStartForType.resize(resTypeCounts.size());
+
+ refListStartForType[0] = 0;
+ for (size_t i = 1; i < refListStartForType.size(); i++)
+ refListStartForType[i] = refListStartForType[i - 1] + resTypeCounts[i - 1];
+
+ std::vector nameListStarts;
+ nameListStarts.resize(uniqueResNames.size());
+
+ nameListStarts[0] = 0;
+ for (size_t i = 1; i < nameListStarts.size(); i++)
+ nameListStarts[i] = nameListStarts[i - 1] + uniqueResNames[i - 1].size() + 1;
+
+ // Write resource type list
+ for (size_t i = 0; i < uniqueResTypes.size(); i++)
+ {
+ AppendUInt32(resourceForkData, uniqueResTypes[i]);
+ AppendUInt16(resourceForkData, resTypeCounts[i] - 1);
+ AppendUInt16(resourceForkData, static_cast(refListStartForType[i] * refListEntrySize + resourceTypeListSize));
+ }
+
+ // Write reference lists
+ for (size_t ti = 0; ti < uniqueResTypes.size(); ti++)
+ {
+ uint32_t resType = uniqueResTypes[ti];
+
+ for (size_t i = 0; i < resources.size(); i++)
+ {
+ const SimpleResource *res = resources[i];
+ if (TypeToU32(res->m_type) != resType)
+ continue;
+
+ AppendInt16(resourceForkData, res->m_resourceID);
+ if (res->m_name.empty())
+ AppendInt16(resourceForkData, -1);
+ else
+ {
+ const std::vector::iterator nameIt = std::find(uniqueResNames.begin(), uniqueResNames.end(), res->m_name);
+ const size_t nameIndex = nameIt - uniqueResNames.begin();
+
+ AppendUInt16(resourceForkData, static_cast(nameListStarts[nameIndex]));
+ }
+
+ resourceForkData.push_back(res->m_attributes);
+
+ const size_t resDataStart = res->m_offsetInResData;
+
+ resourceForkData.push_back((resDataStart >> 16) & 0xff);
+ resourceForkData.push_back((resDataStart >> 8) & 0xff);
+ resourceForkData.push_back((resDataStart >> 0) & 0xff);
+
+ for (int j = 0; j < 4; j++)
+ resourceForkData.push_back(0); // Reserved
+ }
+ }
+
+ // Write name lists
+ for (size_t ni = 0; ni < uniqueResNames.size(); ni++)
+ {
+ const std::string &name = uniqueResNames[ni];
+ const size_t nameLen = name.size();
+
+ resourceForkData.push_back(static_cast(nameLen));
+
+ for (size_t i = 0; i < nameLen; i++)
+ resourceForkData.push_back(name[i]);
+ }
+
+ const size_t resMapSize = resourceForkData.size() - resMapPos;
+
+ BytePack::BigUInt32(&resourceForkData[0], static_cast(resForkDataStart));
+ BytePack::BigUInt32(&resourceForkData[4], static_cast(resMapPos));
+ BytePack::BigUInt32(&resourceForkData[8], static_cast(resDataSize));
+ BytePack::BigUInt32(&resourceForkData[12], static_cast(resMapSize));
+
+ FILE *outF = nullptr;
+ if (fopen_s(&outF, argv[2], "wb"))
+ {
+ fprintf(stderr, "Failed to open output file");
+ return -1;
+ }
+
+ fwrite(&resourceForkData[0], 1, resourceForkData.size(), outF);
+ fclose(outF);
+
+ return 0;
+}
diff --git a/MiniRez/MiniRez.vcxproj b/MiniRez/MiniRez.vcxproj
new file mode 100644
index 0000000..e835547
--- /dev/null
+++ b/MiniRez/MiniRez.vcxproj
@@ -0,0 +1,136 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {2FF15659-5C72-48B8-B55B-3C658E4125B5}
+ MiniRez
+ 10.0.16299.0
+
+
+
+ Application
+ true
+ v141
+ MultiByte
+
+
+ Application
+ false
+ v141
+ true
+ MultiByte
+
+
+ Application
+ true
+ v141
+ MultiByte
+
+
+ Application
+ false
+ v141
+ true
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+
+
+
+
+
+
+
+ {6ec62b0f-9353-40a4-a510-3788f1368b33}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MiniRez/MiniRez.vcxproj.filters b/MiniRez/MiniRez.vcxproj.filters
new file mode 100644
index 0000000..2476dcf
--- /dev/null
+++ b/MiniRez/MiniRez.vcxproj.filters
@@ -0,0 +1,22 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/MiniRez/x64/Debug/vc141.idb b/MiniRez/x64/Debug/vc141.idb
new file mode 100644
index 0000000..bdae131
Binary files /dev/null and b/MiniRez/x64/Debug/vc141.idb differ
diff --git a/PortabilityLayer.props b/PortabilityLayer.props
new file mode 100644
index 0000000..1f3de77
--- /dev/null
+++ b/PortabilityLayer.props
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+ $(SolutionDir)\PortabilityLayer;%(AdditionalIncludeDirectories)
+
+
+
+
\ No newline at end of file
diff --git a/PortabilityLayer/AEHandlerDesc.h b/PortabilityLayer/AEHandlerDesc.h
new file mode 100644
index 0000000..d4639fe
--- /dev/null
+++ b/PortabilityLayer/AEHandlerDesc.h
@@ -0,0 +1,20 @@
+#pragma once
+#ifndef __PL_AE_HANDLER_DESC_H__
+#define __PL_AE_HANDLER_DESC_H__
+
+#include "PLAppleEventsCommonTypes.h"
+
+#include
+
+namespace PortabilityLayer
+{
+ struct AEHandlerDesc
+ {
+ AEEventClass m_eventClass;
+ AEEventID m_eventID;
+ AEEventHandler m_handler;
+ uint32_t m_ref;
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/AEManager.cpp b/PortabilityLayer/AEManager.cpp
new file mode 100644
index 0000000..1193083
--- /dev/null
+++ b/PortabilityLayer/AEManager.cpp
@@ -0,0 +1,73 @@
+#include "AEManager.h"
+#include "AEHandlerDesc.h"
+
+#include
+
+namespace PortabilityLayer
+{
+ class AEManagerImpl final : public AEManager
+ {
+ public:
+ AEManagerImpl();
+
+ void Init() override;
+ void Shutdown() override;
+
+ void InstallEventHandler(AEEventClass eventClass, AEEventID eventID, AEEventHandler handler, uint32_t ref, bool isSysHandler) override;
+ void SetInteractAllowed(AEInteractAllowed interactAllowed) override;
+
+ static AEManagerImpl *GetInstance();
+
+ private:
+ std::vector m_handlers;
+ AEInteractAllowed m_interactAllowed;
+
+ static AEManagerImpl ms_instance;
+ };
+
+ AEManagerImpl::AEManagerImpl()
+ : m_interactAllowed(kAEInteractUnknown)
+ {
+ }
+
+ void AEManagerImpl::Init()
+ {
+ m_interactAllowed = kAEInteractUnknown;
+ }
+
+ void AEManagerImpl::Shutdown()
+ {
+ m_handlers.clear();
+ }
+
+ void AEManagerImpl::InstallEventHandler(AEEventClass eventClass, AEEventID eventID, AEEventHandler handler, uint32_t ref, bool isSysHandler)
+ {
+ AEHandlerDesc desc;
+ desc.m_eventClass = eventClass;
+ desc.m_eventID = eventID;
+ desc.m_handler = handler;
+ desc.m_ref = ref;
+
+ m_handlers.push_back(desc);
+ }
+
+ void AEManagerImpl::SetInteractAllowed(AEInteractAllowed interactAllowed)
+ {
+ m_interactAllowed = interactAllowed;
+ }
+
+ AEManagerImpl *AEManagerImpl::GetInstance()
+ {
+ return &ms_instance;
+ }
+
+ AEManagerImpl AEManagerImpl::ms_instance;
+
+
+ AEManager *AEManager::GetInstance()
+ {
+ return AEManagerImpl::GetInstance();
+ }
+}
+
+
diff --git a/PortabilityLayer/AEManager.h b/PortabilityLayer/AEManager.h
new file mode 100644
index 0000000..572b75e
--- /dev/null
+++ b/PortabilityLayer/AEManager.h
@@ -0,0 +1,24 @@
+#pragma once
+#ifndef __PL_AE_MANAGER_H__
+#define __PL_AE_MANAGER_H__
+
+#include "PLAppleEventsCommonTypes.h"
+
+#include
+
+namespace PortabilityLayer
+{
+ class AEManager
+ {
+ public:
+ virtual void Init() = 0;
+ virtual void Shutdown() = 0;
+
+ virtual void InstallEventHandler(AEEventClass eventClass, AEEventID eventID, AEEventHandler handler, uint32_t ref, bool isSysHandler) = 0;
+ virtual void SetInteractAllowed(AEInteractAllowed interactAllowed) = 0;
+
+ static AEManager *GetInstance();
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/BinHex4.cpp b/PortabilityLayer/BinHex4.cpp
new file mode 100644
index 0000000..d07139e
--- /dev/null
+++ b/PortabilityLayer/BinHex4.cpp
@@ -0,0 +1,302 @@
+#include "BinHex4.h"
+#include "IOStream.h"
+
+#include
+#include
+#include
+
+// See: https://files.stairways.com/other/binhex-40-specs-info.txt
+// Unfortunately, while the spec specifies that decoding is to be done high-to-low,
+// it doesn't specify how the encoded 6-bit value is split.
+
+#include "MacFileInfo.h"
+#include "ByteUnpack.h"
+#include "XModemCRC.h"
+#include "MacFileMem.h"
+
+namespace
+{
+ static bool IsEOL(char c)
+ {
+ return c == '\r' || c == '\n';
+ }
+
+ static bool IsWhitespaceChar(char c)
+ {
+ return c == '\r' || c == '\n' || c == ' ' || c == '\t';
+ }
+
+ uint16_t BinHexCRCNoPadding(const uint8_t *bytes, size_t size, int initialValue)
+ {
+ uint16_t crc = initialValue;
+ for (size_t b = 0; b < size; b++)
+ {
+ uint8_t v = bytes[b];
+
+ for (int i = 0; i < 8; i++)
+ {
+ int temp = (crc & 0x8000);
+ crc = (crc << 1) | (v >> 7);
+
+ if (temp)
+ crc = crc ^ 0x1021;
+
+ v = (v << 1) & 0xff;
+ }
+ }
+
+ return static_cast(crc);
+ }
+
+ uint16_t BinHexCRC(const uint8_t *bytes, size_t size)
+ {
+ const uint8_t zeroBytes[] = { 0, 0 };
+
+ uint16_t crc = BinHexCRCNoPadding(bytes, size, 0);
+ return BinHexCRCNoPadding(zeroBytes, 2, crc);
+ }
+}
+
+namespace PortabilityLayer
+{
+ MacFileMem *BinHex4::LoadHQX(IOStream *stream)
+ {
+ const uint8_t errCodeChar = 64;
+
+ uint8_t charMap[128];
+ for (int i = 0; i < 128; i++)
+ charMap[i] = errCodeChar;
+
+ const char binHexCharacters[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
+
+ for (int i = 0; i < 64; i++)
+ charMap[binHexCharacters[i]] = static_cast(i);
+
+ const char expectedPrefix[] = "(This file must be converted with BinHex";
+ const size_t prefixSizeChars = sizeof(expectedPrefix) - 1;
+ char prefix[prefixSizeChars];
+
+ if (stream->Read(prefix, prefixSizeChars) != prefixSizeChars)
+ return nullptr;
+
+ if (memcmp(prefix, expectedPrefix, prefixSizeChars))
+ return nullptr;
+
+ // Find end char
+ for (;;)
+ {
+ char nextChar;
+ if (!stream->Read(&nextChar, 1))
+ return nullptr;
+
+ if (IsEOL(nextChar))
+ break;
+ }
+
+ // Find start colon
+ for (;;)
+ {
+ char nextChar;
+ if (!stream->Read(&nextChar, 1))
+ return nullptr;
+
+ if (IsWhitespaceChar(nextChar))
+ continue;
+ else if (nextChar == ':')
+ break;
+ else
+ return nullptr;
+ }
+
+ std::vector bytesAfter6To8;
+
+ if (stream->IsSeekable())
+ {
+ UFilePos_t filePos = stream->Tell();
+ if (stream->SeekEnd(0))
+ {
+ UFilePos_t endPos = stream->Tell();
+ if (!stream->SeekStart(filePos))
+ return nullptr;
+
+ if (endPos > filePos && (endPos - filePos) < SIZE_MAX / 6)
+ bytesAfter6To8.reserve(static_cast(endPos - filePos) * 6 / 8);
+ }
+ }
+
+ // Undo 8-to-6 coding
+ const size_t bufferCapacity = 128;
+ size_t bufferReadPos = 0;
+ size_t bufferSize = 0;
+ char buffer[bufferCapacity];
+
+ bool isEOF = false;
+
+ int decodedByte = 0;
+ int decodedByteBitPos = 8;
+
+ for (;;)
+ {
+ if (bufferReadPos == bufferSize)
+ {
+ const size_t numRead = stream->Read(buffer, bufferCapacity);
+ if (numRead == 0)
+ return nullptr; // Missing terminator
+
+ bufferSize = numRead;
+ bufferReadPos = 0;
+ }
+
+ char nextChar = buffer[bufferReadPos++];
+
+ if (nextChar == ':')
+ break;
+
+ if (IsWhitespaceChar(nextChar))
+ continue;
+
+ if (nextChar < 0 || nextChar > 127)
+ return nullptr;
+
+ uint8_t value6Bit = charMap[nextChar];
+ if (value6Bit == errCodeChar)
+ return nullptr;
+
+ switch (decodedByteBitPos)
+ {
+ case 8:
+ decodedByte = value6Bit << 2;
+ decodedByteBitPos = 2;
+ break;
+ case 6:
+ decodedByte |= value6Bit;
+ bytesAfter6To8.push_back(decodedByte);
+ decodedByte = 0;
+ decodedByteBitPos = 8;
+ break;
+ case 4:
+ decodedByte |= (value6Bit >> 2);
+ bytesAfter6To8.push_back(decodedByte);
+ decodedByte = (value6Bit << 6) & 0xff;
+ decodedByteBitPos = 6;
+ break;
+ case 2:
+ decodedByte |= (value6Bit >> 4);
+ bytesAfter6To8.push_back(decodedByte);
+ decodedByte = (value6Bit << 4) & 0xff;
+ decodedByteBitPos = 4;
+ break;
+ default:
+ return nullptr;
+ }
+ }
+
+ const size_t bytesBeforeRLEDec = bytesAfter6To8.size();
+ size_t decodedDataSize = 0;
+ for (size_t i = 0; i < bytesBeforeRLEDec; i++)
+ {
+ const uint8_t b = bytesAfter6To8[i];
+ if (b == 0x90)
+ {
+ if (i == bytesBeforeRLEDec - 1)
+ return nullptr;
+
+ const uint8_t runLength = bytesAfter6To8[++i];
+
+ if (runLength == 0)
+ decodedDataSize++; // 0x90 literal
+ else
+ decodedDataSize += runLength - 1; // RLE, runs of length 1 are permitted
+ }
+ else
+ decodedDataSize++;
+ }
+
+ std::vector decodedBytes;
+ decodedBytes.reserve(decodedDataSize);
+
+ for (size_t i = 0; i < bytesBeforeRLEDec; i++)
+ {
+ const uint8_t b = bytesAfter6To8[i];
+
+ if (b == 0x90)
+ {
+ const uint8_t runLength = bytesAfter6To8[++i];
+
+ if (runLength == 0)
+ decodedBytes.push_back(0x90);
+ else
+ {
+ if (decodedBytes.size() == 0)
+ return nullptr;
+
+ const uint8_t lastByte = *(decodedBytes.end() - 1);
+ for (size_t r = 1; r < runLength; r++)
+ decodedBytes.push_back(lastByte);
+ }
+ }
+ else
+ decodedBytes.push_back(b);
+ }
+
+ assert(decodedBytes.size() == decodedDataSize);
+
+ if (decodedBytes.size() == 0)
+ return nullptr;
+
+ const uint8_t nameLength = decodedBytes[0];
+ if (decodedBytes.size() < 22 + nameLength || nameLength > 63)
+ return nullptr;
+
+ // Header format:
+ // uint8_t nameLength
+ // char name[nameLength]
+ // char
+ // char fileType[4]
+ // char fileCreator[4]
+ // word flags
+ // dword dataLength
+ // dword resourceLength
+ // word headerCRC
+
+ const size_t headerStartLoc = 2 + nameLength;
+
+ if (decodedBytes[nameLength + 1] != 0)
+ return nullptr;
+
+ MacFileInfo mfi;
+ mfi.m_fileName.Set(nameLength, reinterpret_cast(&decodedBytes[1]));
+ memcpy(mfi.m_properties.m_fileType, &decodedBytes[headerStartLoc + 0], 4);
+ memcpy(mfi.m_properties.m_fileCreator, &decodedBytes[headerStartLoc + 4], 4);
+ mfi.m_properties.m_finderFlags = ByteUnpack::BigUInt16(&decodedBytes[headerStartLoc + 8]);
+ mfi.m_dataForkSize = ByteUnpack::BigUInt32(&decodedBytes[headerStartLoc + 10]);
+ mfi.m_resourceForkSize = ByteUnpack::BigUInt32(&decodedBytes[headerStartLoc + 14]);
+
+ const size_t availableDataSize = decodedBytes.size() - 26 - nameLength; // +4 bytes for CRCs
+
+ if (mfi.m_dataForkSize > availableDataSize || availableDataSize - mfi.m_dataForkSize < mfi.m_resourceForkSize)
+ return nullptr;
+
+ const uint16_t expectedHeaderCRC = ByteUnpack::BigUInt16(&decodedBytes[headerStartLoc + 18]);
+ const uint16_t actualHeaderCRC = BinHexCRC(&decodedBytes[0], headerStartLoc + 18);
+
+ if (expectedHeaderCRC != actualHeaderCRC)
+ return nullptr;
+
+ const size_t dataForkStart = headerStartLoc + 20;
+ const size_t dataForkCRCLoc = dataForkStart + mfi.m_dataForkSize;
+ const size_t resourceForkStart = dataForkCRCLoc + 2;
+ const size_t resourceForkCRCLoc = resourceForkStart + mfi.m_resourceForkSize;
+
+ const uint16_t expectedDataCRC = ByteUnpack::BigUInt16(&decodedBytes[dataForkCRCLoc]);
+ const uint16_t expectedResCRC = ByteUnpack::BigUInt16(&decodedBytes[resourceForkCRCLoc]);
+
+ if (expectedDataCRC != BinHexCRC(&decodedBytes[dataForkStart], mfi.m_dataForkSize))
+ return false;
+
+ if (expectedResCRC != BinHexCRC(&decodedBytes[resourceForkStart], mfi.m_resourceForkSize))
+ return false;
+
+ return new MacFileMem(&decodedBytes[dataForkStart], &decodedBytes[resourceForkStart], nullptr, mfi);
+ }
+}
diff --git a/PortabilityLayer/BinHex4.h b/PortabilityLayer/BinHex4.h
new file mode 100644
index 0000000..be30643
--- /dev/null
+++ b/PortabilityLayer/BinHex4.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#ifndef __PL_BINHEX4_H__
+#define __PL_BINHEX4_H__
+
+namespace PortabilityLayer
+{
+ class IOStream;
+ class MacFileMem;
+
+ namespace BinHex4
+ {
+ MacFileMem *LoadHQX(IOStream *stream);
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/BinarySearch.h b/PortabilityLayer/BinarySearch.h
new file mode 100644
index 0000000..ca52557
--- /dev/null
+++ b/PortabilityLayer/BinarySearch.h
@@ -0,0 +1,36 @@
+#pragma once
+#ifndef __PL_BINARY_SEARCH_H__
+#define __PL_BINARY_SEARCH_H__
+
+#include
+
+namespace PortabilityLayer
+{
+ template
+ TIterator BinarySearch(const TIterator &startInclusive, const TIterator &endExclusive, const TItem &item, const TPredicate &pred)
+ {
+ TIterator searchStartInclusive = startInclusive;
+ TIterator searchEndExclusive = endExclusive;
+
+ while (searchStartInclusive != searchEndExclusive)
+ {
+ const ptrdiff_t delta = searchEndExclusive - searchStartInclusive;
+ const ptrdiff_t halfDelta = delta / 2;
+
+ const TIterator midPoint = searchStartInclusive + halfDelta;
+
+ const int comparison = pred(item, *midPoint);
+
+ if (comparison < 0)
+ searchEndExclusive = midPoint;
+ else if (comparison > 0)
+ searchStartInclusive = midPoint + 1;
+ else
+ return midPoint;
+ }
+
+ return endExclusive;
+ }
+}
+
+#endif
diff --git a/PortabilityLayer/BytePack.h b/PortabilityLayer/BytePack.h
new file mode 100644
index 0000000..ccb1f55
--- /dev/null
+++ b/PortabilityLayer/BytePack.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#ifndef __PL_BYTEPACK_H__
+#define __PL_BYTEPACK_H__
+
+#include "DataTypes.h"
+
+namespace PortabilityLayer
+{
+ namespace BytePack
+ {
+ void BigUInt64(uint8_t *bytes, uint64_t value);
+ void BigUInt32(uint8_t *bytes, uint32_t value);
+ void BigUInt16(uint8_t *bytes, uint16_t value);
+ }
+}
+
+namespace PortabilityLayer
+{
+ namespace BytePack
+ {
+ inline void BigUInt64(uint8_t *bytes, uint64_t value)
+ {
+ bytes[0] = static_cast((value >> 56) & 0xff);
+ bytes[1] = static_cast((value >> 48) & 0xff);
+ bytes[2] = static_cast((value >> 40) & 0xff);
+ bytes[3] = static_cast((value >> 32) & 0xff);
+ bytes[4] = static_cast((value >> 24) & 0xff);
+ bytes[5] = static_cast((value >> 16) & 0xff);
+ bytes[6] = static_cast((value >> 8) & 0xff);
+ bytes[7] = static_cast(value & 0xff);
+ }
+
+ inline void BigUInt32(uint8_t *bytes, uint32_t value)
+ {
+ bytes[0] = static_cast((value >> 24) & 0xff);
+ bytes[1] = static_cast((value >> 16) & 0xff);
+ bytes[2] = static_cast((value >> 8) & 0xff);
+ bytes[3] = static_cast(value & 0xff);
+ }
+
+ inline void BigUInt16(uint8_t *bytes, uint16_t value)
+ {
+ bytes[0] = static_cast((value >> 8) & 0xff);
+ bytes[1] = static_cast(value & 0xff);
+ }
+
+ inline void BigInt64(uint8_t *bytes, int64_t value)
+ {
+ bytes[0] = static_cast((value >> 56) & 0xff);
+ bytes[1] = static_cast((value >> 48) & 0xff);
+ bytes[2] = static_cast((value >> 40) & 0xff);
+ bytes[3] = static_cast((value >> 32) & 0xff);
+ bytes[4] = static_cast((value >> 24) & 0xff);
+ bytes[5] = static_cast((value >> 16) & 0xff);
+ bytes[6] = static_cast((value >> 8) & 0xff);
+ bytes[7] = static_cast(value & 0xff);
+ }
+
+ inline void BigInt32(uint8_t *bytes, uint32_t value)
+ {
+ bytes[0] = static_cast((value >> 24) & 0xff);
+ bytes[1] = static_cast((value >> 16) & 0xff);
+ bytes[2] = static_cast((value >> 8) & 0xff);
+ bytes[3] = static_cast(value & 0xff);
+ }
+
+ inline void BigInt16(uint8_t *bytes, uint16_t value)
+ {
+ bytes[0] = static_cast((value >> 8) & 0xff);
+ bytes[1] = static_cast(value & 0xff);
+ }
+ }
+}
+
+#endif
diff --git a/PortabilityLayer/ByteSwap.cpp b/PortabilityLayer/ByteSwap.cpp
new file mode 100644
index 0000000..92836e8
--- /dev/null
+++ b/PortabilityLayer/ByteSwap.cpp
@@ -0,0 +1,37 @@
+#include "ByteSwap.h"
+
+namespace PortabilityLayer
+{
+ namespace ByteSwap
+ {
+ void BigInt16(int16_t &v)
+ {
+ const uint8_t *asU8 = reinterpret_cast(&v);
+ const int8_t *asS8 = reinterpret_cast(&v);
+
+ v = static_cast((asS8[0] << 8) | asU8[1]);
+ }
+
+ void BigInt32(int32_t &v)
+ {
+ const uint8_t *asU8 = reinterpret_cast(&v);
+ const int8_t *asS8 = reinterpret_cast(&v);
+
+ v = static_cast((asS8[0] << 24) | (asU8[1] << 16) | (asU8[2] << 8) | asU8[3]);
+ }
+
+ void BigUInt16(uint16_t &v)
+ {
+ const uint8_t *asU8 = reinterpret_cast(&v);
+
+ v = static_cast((asU8[0] << 8) | asU8[1]);
+ }
+
+ void BigUInt32(uint32_t &v)
+ {
+ const uint8_t *asU8 = reinterpret_cast(&v);
+
+ v = static_cast((asU8[0] << 24) | (asU8[1] << 16) | (asU8[2] << 8) | asU8[3]);
+ }
+ }
+}
diff --git a/PortabilityLayer/ByteSwap.h b/PortabilityLayer/ByteSwap.h
new file mode 100644
index 0000000..ca132db
--- /dev/null
+++ b/PortabilityLayer/ByteSwap.h
@@ -0,0 +1,18 @@
+#pragma once
+#ifndef __PL_BYTESWAP_H__
+#define __PL_BYTESWAP_H__
+
+#include
+
+namespace PortabilityLayer
+{
+ namespace ByteSwap
+ {
+ void BigInt16(int16_t &v);
+ void BigInt32(int32_t &v);
+ void BigUInt16(uint16_t &v);
+ void BigUInt32(uint32_t &v);
+ }
+}
+
+#endif
diff --git a/PortabilityLayer/ByteUnpack.h b/PortabilityLayer/ByteUnpack.h
new file mode 100644
index 0000000..240fa1b
--- /dev/null
+++ b/PortabilityLayer/ByteUnpack.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#ifndef __PL_BYTEUNPACK_H__
+#define __PL_BYTEUNPACK_H__
+
+#include "DataTypes.h"
+
+namespace PortabilityLayer
+{
+ namespace ByteUnpack
+ {
+ uint64_t BigUInt64(const uint8_t *bytes);
+ uint32_t BigUInt32(const uint8_t *bytes);
+ uint16_t BigUInt16(const uint8_t *bytes);
+
+ int64_t BigInt64(const uint8_t *bytes);
+ int32_t BigInt32(const uint8_t *bytes);
+ int16_t BigInt16(const uint8_t *bytes);
+ }
+}
+
+namespace PortabilityLayer
+{
+ namespace ByteUnpack
+ {
+ inline uint64_t BigUInt64(const uint8_t *bytes)
+ {
+ return (static_cast(bytes[0]) << 56)
+ | (static_cast(bytes[1]) << 48)
+ | (static_cast(bytes[2]) << 32)
+ | (static_cast(bytes[3]) << 24)
+ | (static_cast(bytes[4]) << 16)
+ | (static_cast(bytes[5]) << 8)
+ | (static_cast(bytes[6]));
+ }
+
+ inline uint32_t BigUInt32(const uint8_t *bytes)
+ {
+ return (static_cast(bytes[0]) << 24)
+ | (static_cast(bytes[1]) << 16)
+ | (static_cast(bytes[2]) << 8)
+ | (static_cast(bytes[3]));
+ }
+
+ inline uint16_t BigUInt16(const uint8_t *bytes)
+ {
+ return (static_cast(bytes[0]) << 8)
+ | (static_cast(bytes[1]));
+ }
+
+ inline int64_t BigInt64(const uint8_t *bytes)
+ {
+ return (static_cast(bytes[0]) << 56)
+ | (static_cast(bytes[1]) << 48)
+ | (static_cast(bytes[2]) << 32)
+ | (static_cast(bytes[3]) << 24)
+ | (static_cast(bytes[4]) << 16)
+ | (static_cast(bytes[5]) << 8)
+ | (static_cast(bytes[6]));
+ }
+
+ inline int32_t BigInt32(const uint8_t *bytes)
+ {
+ return (static_cast(bytes[0]) << 24)
+ | (static_cast(bytes[1]) << 16)
+ | (static_cast(bytes[2]) << 8)
+ | (static_cast(bytes[3]));
+ }
+
+ inline int16_t BigInt16(const uint8_t *bytes)
+ {
+ return (static_cast(bytes[0]) << 8)
+ | (static_cast(bytes[1]));
+ }
+ }
+}
+
+#endif
diff --git a/PortabilityLayer/CFileStream.cpp b/PortabilityLayer/CFileStream.cpp
new file mode 100644
index 0000000..700a041
--- /dev/null
+++ b/PortabilityLayer/CFileStream.cpp
@@ -0,0 +1,110 @@
+#include "CFileStream.h"
+
+namespace PortabilityLayer
+{
+ CFileStream::CFileStream(FILE *f)
+ : m_file(f)
+ , m_readOnly(false)
+ , m_writeOnly(false)
+ , m_seekable(true)
+ {
+ }
+
+ CFileStream::CFileStream(FILE *f, bool isReadOnly, bool isWriteOnly, bool isSeekable)
+ : m_file(f)
+ , m_readOnly(isReadOnly)
+ , m_writeOnly(isWriteOnly)
+ , m_seekable(isSeekable)
+ {
+ }
+
+ size_t CFileStream::Read(void *bytesOut, size_t size)
+ {
+ if (!m_file || m_writeOnly)
+ return 0;
+
+ return fread(bytesOut, 1, size, m_file);
+ }
+
+ size_t CFileStream::Write(const void *bytes, size_t size)
+ {
+ if (!m_file || m_readOnly)
+ return 0;
+
+ return fwrite(bytes, 1, size, m_file);
+ }
+
+ bool CFileStream::IsSeekable() const
+ {
+ return m_seekable;
+ }
+
+ bool CFileStream::IsReadOnly() const
+ {
+ return m_readOnly;
+ }
+
+ bool CFileStream::IsWriteOnly() const
+ {
+ return m_writeOnly;
+ }
+
+ bool CFileStream::SeekStart(UFilePos_t loc)
+ {
+ if (!m_file)
+ return false;
+
+ return fseek(m_file, static_cast(loc), SEEK_SET) == 0;
+ }
+
+ bool CFileStream::SeekCurrent(FilePos_t loc)
+ {
+ if (!m_file)
+ return false;
+
+ return fseek(m_file, static_cast(loc), SEEK_CUR) == 0;;
+ }
+
+ bool CFileStream::SeekEnd(UFilePos_t loc)
+ {
+ if (!m_file)
+ return false;
+
+ return fseek(m_file, static_cast(loc), SEEK_END) == 0;
+ }
+
+ bool CFileStream::Truncate(UFilePos_t loc)
+ {
+ return false;
+ }
+
+ UFilePos_t CFileStream::Tell() const
+ {
+ if (!m_file)
+ return 0;
+
+ return static_cast(ftell(m_file));
+ }
+
+ void CFileStream::Close()
+ {
+ if (m_file)
+ {
+ fclose(m_file);
+ m_file = nullptr;
+ }
+ }
+
+ UFilePos_t CFileStream::Size() const
+ {
+ if (!m_file || !m_seekable)
+ return 0;
+
+ long oldPos = ftell(m_file);
+ fseek(m_file, SEEK_END, 0);
+ const UFilePos_t endPos = static_cast(ftell(m_file));
+ fseek(m_file, oldPos, SEEK_SET);
+
+ return endPos;
+ }
+}
diff --git a/PortabilityLayer/CFileStream.h b/PortabilityLayer/CFileStream.h
new file mode 100644
index 0000000..c411515
--- /dev/null
+++ b/PortabilityLayer/CFileStream.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#ifndef __PL_CFILESTREAM_H__
+#define __PL_CFILESTREAM_H__
+
+#include
+
+#include "CoreDefs.h"
+#include "IOStream.h"
+
+namespace PortabilityLayer
+{
+ class CFileStream final : public IOStream
+ {
+ public:
+ explicit CFileStream(FILE *f);
+ CFileStream(FILE *f, bool isReadOnly, bool isWriteOnly, bool isSeekable);
+
+ size_t Read(void *bytesOut, size_t size) override;
+ size_t Write(const void *bytes, size_t size) override;
+ bool IsSeekable() const override;
+ bool IsReadOnly() const override;
+ bool IsWriteOnly() const override;
+ bool SeekStart(UFilePos_t loc) override;
+ bool SeekCurrent(FilePos_t loc) override;
+ bool SeekEnd(UFilePos_t loc) override;
+ bool Truncate(UFilePos_t loc) override;
+ UFilePos_t Size() const override;
+ UFilePos_t Tell() const override;
+ void Close() override;
+
+ private:
+ CFileStream(const CFileStream &other) PL_DELETED;
+
+ FILE *m_file;
+ bool m_readOnly;
+ bool m_writeOnly;
+ bool m_seekable;
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/DataTypes.h b/PortabilityLayer/DataTypes.h
new file mode 100644
index 0000000..b5c11fe
--- /dev/null
+++ b/PortabilityLayer/DataTypes.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#ifndef __PL_DATATYPES_H__
+#define __PL_DATATYPES_H__
+
+#include
+
+namespace PortabilityLayer
+{
+ typedef int64_t LargestInt_t;
+ typedef uint64_t LargestUInt_t;
+}
+
+#endif
diff --git a/PortabilityLayer/DisplayDeviceManager.cpp b/PortabilityLayer/DisplayDeviceManager.cpp
new file mode 100644
index 0000000..a0e0dd5
--- /dev/null
+++ b/PortabilityLayer/DisplayDeviceManager.cpp
@@ -0,0 +1,75 @@
+#include "DisplayDeviceManager.h"
+
+#include "PLQuickdraw.h"
+
+#include "MemoryManager.h"
+
+namespace PortabilityLayer
+{
+ class DisplayDeviceManagerImpl final : public DisplayDeviceManager
+ {
+ public:
+ DisplayDeviceManagerImpl();
+
+ void Init() override;
+ void Shutdown() override;
+
+ GDevice **GetMainDevice() override;
+
+
+ void IncrementTickCount(uint32_t count) override;
+ uint32_t GetTickCount() override;
+
+ static DisplayDeviceManagerImpl *GetInstance();
+
+ private:
+ GDHandle m_mainDevice;
+ uint32_t m_tickCount;
+
+ static DisplayDeviceManagerImpl ms_instance;
+ };
+
+ DisplayDeviceManagerImpl::DisplayDeviceManagerImpl()
+ : m_mainDevice(nullptr)
+ , m_tickCount(1)
+ {
+ }
+
+ void DisplayDeviceManagerImpl::Init()
+ {
+ m_mainDevice = MemoryManager::GetInstance()->NewHandle();
+ }
+
+ void DisplayDeviceManagerImpl::Shutdown()
+ {
+ MemoryManager::GetInstance()->ReleaseHandle(reinterpret_cast(m_mainDevice));
+ }
+
+ GDevice **DisplayDeviceManagerImpl::GetMainDevice()
+ {
+ return m_mainDevice;
+ }
+
+ void DisplayDeviceManagerImpl::IncrementTickCount(uint32_t count)
+ {
+ m_tickCount += count;
+ }
+
+ uint32_t DisplayDeviceManagerImpl::GetTickCount()
+ {
+ return m_tickCount;
+ }
+
+
+ DisplayDeviceManagerImpl *DisplayDeviceManagerImpl::GetInstance()
+ {
+ return &ms_instance;
+ }
+
+ DisplayDeviceManagerImpl DisplayDeviceManagerImpl::ms_instance;
+
+ DisplayDeviceManager *DisplayDeviceManager::GetInstance()
+ {
+ return DisplayDeviceManagerImpl::GetInstance();
+ }
+}
diff --git a/PortabilityLayer/DisplayDeviceManager.h b/PortabilityLayer/DisplayDeviceManager.h
new file mode 100644
index 0000000..6cc5f5a
--- /dev/null
+++ b/PortabilityLayer/DisplayDeviceManager.h
@@ -0,0 +1,25 @@
+#pragma once
+#ifndef __PL_DEVICE_MANAGER_H__
+#define __PL_DEVICE_MANAGER_H__
+
+#include
+
+struct GDevice;
+
+namespace PortabilityLayer
+{
+ class DisplayDeviceManager
+ {
+ public:
+ virtual void Init() = 0;
+ virtual void Shutdown() = 0;
+
+ virtual GDevice **GetMainDevice() = 0;
+ virtual void IncrementTickCount(uint32_t count) = 0;
+ virtual uint32_t GetTickCount() = 0;
+
+ static DisplayDeviceManager *GetInstance();
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/FileManager.cpp b/PortabilityLayer/FileManager.cpp
new file mode 100644
index 0000000..bafc946
--- /dev/null
+++ b/PortabilityLayer/FileManager.cpp
@@ -0,0 +1,207 @@
+#include "FileManager.h"
+#include "HostFileSystem.h"
+#include "HostMemoryBuffer.h"
+#include "MemReaderStream.h"
+#include "MacBinary2.h"
+#include "MacFileMem.h"
+#include "PLPasStr.h"
+#include "PLErrorCodes.h"
+
+#include
+
+namespace PortabilityLayer
+{
+ class VirtualFile;
+
+ class FileManagerImpl final : public FileManager
+ {
+ public:
+ bool FileExists(uint32_t dirID, const PLPasStr &filename) override;
+
+ int OpenFileDF(uint32_t dirID, const PLPasStr &filename, EFilePermission filePermission, short *outRefNum) override;
+ int OpenFileRF(uint32_t dirID, const PLPasStr &filename, EFilePermission filePermission, short *outRefNum) override;
+
+ int RawOpenFileDF(uint32_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, IOStream **outStream) override;
+ int RawOpenFileRF(uint32_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, IOStream **outStream) override;
+
+ static FileManagerImpl *GetInstance();
+
+ private:
+ typedef char ExtendedFileName_t[64 + 4];
+
+ struct OpenedFile
+ {
+ EVirtualDirectory m_dirID;
+ PascalStr<64> m_fileName;
+
+ IOStream *m_stream;
+ };
+
+ int OpenFileFork(uint32_t dirID, const PLPasStr &filename, const char *ext, EFilePermission permission, short *outRefNum);
+ int RawOpenFileFork(uint32_t dirID, const PLPasStr &filename, const char *ext, EFilePermission permission, bool ignoreMeta, IOStream **outStream);
+
+ static bool ConstructFilename(ExtendedFileName_t& extFN, const PLPasStr &fn, const char *extension);
+
+ std::vector m_refs;
+
+ static FileManagerImpl ms_instance;
+ };
+
+ bool FileManagerImpl::FileExists(uint32_t dirID, const PLPasStr &filename)
+ {
+ ExtendedFileName_t extFN;
+ if (!ConstructFilename(extFN, filename, ".gpf"))
+ return false;
+
+ return HostFileSystem::GetInstance()->FileExists(static_cast(dirID), extFN);
+ }
+
+ int FileManagerImpl::OpenFileDF(uint32_t dirID, const PLPasStr &filename, EFilePermission permission, short *outRefNum)
+ {
+ return OpenFileFork(dirID, filename, ".gpd", permission, outRefNum);
+ }
+
+ int FileManagerImpl::OpenFileRF(uint32_t dirID, const PLPasStr &filename, EFilePermission permission, short *outRefNum)
+ {
+ return OpenFileFork(dirID, filename, ".gpr", permission, outRefNum);
+ }
+
+ int FileManagerImpl::RawOpenFileDF(uint32_t dirID, const PLPasStr &filename, EFilePermission permission, bool ignoreMeta, IOStream **outStream)
+ {
+ return RawOpenFileFork(dirID, filename, ".gpd", permission, ignoreMeta, outStream);
+ }
+
+ int FileManagerImpl::RawOpenFileRF(uint32_t dirID, const PLPasStr &filename, EFilePermission permission, bool ignoreMeta, IOStream **outStream)
+ {
+ return RawOpenFileFork(dirID, filename, ".gpr", permission, ignoreMeta, outStream);
+ }
+
+ FileManagerImpl *FileManagerImpl::GetInstance()
+ {
+ return &ms_instance;
+ }
+
+ int FileManagerImpl::OpenFileFork(uint32_t dirID, const PLPasStr &filename, const char *extension, EFilePermission permission, short *outRefNum)
+ {
+ const size_t numRefs = m_refs.size();
+ size_t refIndex = m_refs.size();
+ for (size_t i = 0; i < numRefs; i++)
+ {
+ if (m_refs[i].m_stream == nullptr)
+ {
+ refIndex = i;
+ break;
+ }
+ }
+
+ if (refIndex == 0x7fff)
+ return tmfoErr;
+
+ IOStream *stream = nullptr;
+ int openError = RawOpenFileFork(dirID, filename, extension, permission, false, &stream);
+ if (openError != 0)
+ return openError;
+
+ if (refIndex == numRefs)
+ m_refs.push_back(OpenedFile());
+
+ OpenedFile &of = m_refs[refIndex];
+ of.m_stream = stream;
+ of.m_dirID = static_cast(dirID);
+ of.m_fileName.Set(filename.Length(), filename.Chars());
+
+ *outRefNum = static_cast(refIndex + 1);
+
+ return noErr;
+ }
+
+ int FileManagerImpl::RawOpenFileFork(uint32_t dirID, const PLPasStr &filename, const char *ext, EFilePermission permission, bool ignoreMeta, IOStream **outStream)
+ {
+ ExtendedFileName_t gpfExtFN;
+ ExtendedFileName_t extFN;
+
+ if (filename.Length() > 63)
+ return bdNamErr;
+
+ if (!ignoreMeta)
+ {
+ if (!ConstructFilename(gpfExtFN, filename, ".gpf"))
+ return bdNamErr;
+
+ if (!HostFileSystem::GetInstance()->FileExists(static_cast(dirID), gpfExtFN))
+ return fnfErr;
+ }
+
+ const bool needToCreate = !(ignoreMeta || HostFileSystem::GetInstance()->FileExists(static_cast(dirID), extFN));
+
+ if (!ConstructFilename(extFN, filename, ext))
+ return bdNamErr;
+
+ IOStream *fstream = nullptr;
+ switch (permission)
+ {
+ case EFilePermission_Any:
+ fstream = HostFileSystem::GetInstance()->OpenFile(static_cast(dirID), extFN, true, needToCreate);
+ if (fstream)
+ permission = EFilePermission_ReadWrite;
+ else
+ {
+ permission = EFilePermission_Read;
+ fstream = HostFileSystem::GetInstance()->OpenFile(static_cast(dirID), extFN, false, needToCreate);
+ }
+ break;
+ case EFilePermission_Read:
+ fstream = HostFileSystem::GetInstance()->OpenFile(static_cast(dirID), extFN, false, needToCreate);
+ break;
+ case EFilePermission_ReadWrite:
+ fstream = HostFileSystem::GetInstance()->OpenFile(static_cast(dirID), extFN, true, needToCreate);
+ break;
+ }
+
+ if (!fstream)
+ return permErr;
+
+ *outStream = fstream;
+ return noErr;
+ }
+
+ bool FileManagerImpl::ConstructFilename(ExtendedFileName_t& extFN, const PLPasStr &fn, const char *extension)
+ {
+ const size_t fnameSize = fn.Length();
+ if (fnameSize >= 64)
+ return false;
+
+ memcpy(extFN, fn.Chars(), fnameSize);
+ memcpy(extFN + fnameSize, extension, strlen(extension) + 1);
+
+ for (size_t i = 0; i < fnameSize; i++)
+ {
+ const char c = extFN[i];
+ if (c >= '0' && c <= '9')
+ continue;
+
+ if (c == '_')
+ continue;
+
+ if (c == ' ' && i != 0 && i != fnameSize - 1)
+ continue;
+
+ if (c >= 'a' && c <= 'z')
+ continue;
+
+ if (c >= 'A' && c <= 'Z')
+ continue;
+
+ return false;
+ }
+
+ return true;
+ }
+
+ FileManagerImpl FileManagerImpl::ms_instance;
+
+ FileManager *FileManager::GetInstance()
+ {
+ return FileManagerImpl::GetInstance();
+ }
+}
diff --git a/PortabilityLayer/FileManager.h b/PortabilityLayer/FileManager.h
new file mode 100644
index 0000000..7e628f5
--- /dev/null
+++ b/PortabilityLayer/FileManager.h
@@ -0,0 +1,31 @@
+#pragma once
+#ifndef __PL_FILE_MANAGER_H__
+#define __PL_FILE_MANAGER_H__
+
+#include "FilePermission.h"
+#include "CoreDefs.h"
+
+#include
+
+class PLPasStr;
+
+namespace PortabilityLayer
+{
+ class IOStream;
+
+ class FileManager
+ {
+ public:
+ virtual bool FileExists(uint32_t dirID, const PLPasStr &filename) = 0;
+
+ virtual int OpenFileDF(uint32_t dirID, const PLPasStr &filename, EFilePermission filePermission, short *outRefNum) = 0;
+ virtual int OpenFileRF(uint32_t dirID, const PLPasStr &filename, EFilePermission filePermission, short *outRefNum) = 0;
+
+ virtual int RawOpenFileDF(uint32_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, IOStream **outStream) = 0;
+ virtual int RawOpenFileRF(uint32_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, IOStream **outStream) = 0;
+
+ static FileManager *GetInstance();
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/FilePermission.h b/PortabilityLayer/FilePermission.h
new file mode 100644
index 0000000..f3926f5
--- /dev/null
+++ b/PortabilityLayer/FilePermission.h
@@ -0,0 +1,15 @@
+#pragma once
+#ifndef __PL_FILE_PERMISSION_H__
+#define __PL_FILE_PERMISSION_H__
+
+namespace PortabilityLayer
+{
+ enum EFilePermission
+ {
+ EFilePermission_Any,
+ EFilePermission_Read,
+ EFilePermission_ReadWrite,
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/GpAppInterface.h b/PortabilityLayer/GpAppInterface.h
new file mode 100644
index 0000000..0d1f844
--- /dev/null
+++ b/PortabilityLayer/GpAppInterface.h
@@ -0,0 +1,42 @@
+#pragma once
+#ifndef __GPAPP_INTERFACE_H__
+#define __GPAPP_INTERFACE_H__
+
+#include "HostSuspendHook.h"
+#include
+
+#ifdef GP_APP_DLL
+
+#ifdef GP_APP_DLL_EXPORT
+#define GP_APP_DLL_EXPORT_API extern "C" __declspec(dllexport)
+#else
+#define GP_APP_DLL_EXPORT_API extern "C" __declspec(dllimport)
+#endif
+
+#else
+
+#define GP_APP_DLL_EXPORT_API extern "C"
+
+#endif
+
+namespace PortabilityLayer
+{
+ class HostFileSystem;
+ class HostDisplayDriver;
+ class HostSystemServices;
+}
+
+class GpAppInterface
+{
+public:
+ virtual int ApplicationMain() = 0;
+ virtual void PL_IncrementTickCounter(uint32_t count) = 0;
+ virtual void PL_HostFileSystem_SetInstance(PortabilityLayer::HostFileSystem *instance) = 0;
+ virtual void PL_HostDisplayDriver_SetInstance(PortabilityLayer::HostDisplayDriver *instance) = 0;
+ virtual void PL_HostSystemServices_SetInstance(PortabilityLayer::HostSystemServices *instance) = 0;
+ virtual void PL_InstallHostSuspendHook(PortabilityLayer::HostSuspendHook_t hook, void *context) = 0;
+};
+
+GP_APP_DLL_EXPORT_API GpAppInterface *GpAppInterface_Get();
+
+#endif
diff --git a/PortabilityLayer/HostDisplayDriver.cpp b/PortabilityLayer/HostDisplayDriver.cpp
new file mode 100644
index 0000000..4dab6c2
--- /dev/null
+++ b/PortabilityLayer/HostDisplayDriver.cpp
@@ -0,0 +1,16 @@
+#include "HostDisplayDriver.h"
+
+namespace PortabilityLayer
+{
+ HostDisplayDriver *HostDisplayDriver::GetInstance()
+ {
+ return ms_instance;
+ }
+
+ void HostDisplayDriver::SetInstance(HostDisplayDriver *instance)
+ {
+ ms_instance = instance;
+ }
+
+ HostDisplayDriver *HostDisplayDriver::ms_instance;
+}
diff --git a/PortabilityLayer/HostDisplayDriver.h b/PortabilityLayer/HostDisplayDriver.h
new file mode 100644
index 0000000..35e1931
--- /dev/null
+++ b/PortabilityLayer/HostDisplayDriver.h
@@ -0,0 +1,21 @@
+#pragma once
+#ifndef __PL_HOST_DISPLAY_DRIVER_H__
+#define __PL_HOST_DISPLAY_DRIVER_H__
+
+namespace PortabilityLayer
+{
+ class HostDisplayDriver
+ {
+ public:
+ virtual void GetDisplayResolution(unsigned int &width, unsigned int &height) = 0;
+ virtual void HideCursor() = 0;
+
+ static void SetInstance(HostDisplayDriver *instance);
+ static HostDisplayDriver *GetInstance();
+
+ private:
+ static HostDisplayDriver *ms_instance;
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/HostFileSystem.cpp b/PortabilityLayer/HostFileSystem.cpp
new file mode 100644
index 0000000..56832c5
--- /dev/null
+++ b/PortabilityLayer/HostFileSystem.cpp
@@ -0,0 +1,16 @@
+#include "HostFileSystem.h"
+
+namespace PortabilityLayer
+{
+ HostFileSystem *HostFileSystem::GetInstance()
+ {
+ return ms_instance;
+ }
+
+ void HostFileSystem::SetInstance(HostFileSystem *instance)
+ {
+ ms_instance = instance;
+ }
+
+ HostFileSystem *HostFileSystem::ms_instance;
+}
diff --git a/PortabilityLayer/HostFileSystem.h b/PortabilityLayer/HostFileSystem.h
new file mode 100644
index 0000000..443822b
--- /dev/null
+++ b/PortabilityLayer/HostFileSystem.h
@@ -0,0 +1,25 @@
+#pragma once
+#ifndef __PL_HOST_FILESYSTEM_H__
+#define __PL_HOST_FILESYSTEM_H__
+
+#include "VirtualDirectory.h"
+
+namespace PortabilityLayer
+{
+ class IOStream;
+
+ class HostFileSystem
+ {
+ public:
+ virtual bool FileExists(EVirtualDirectory virtualDirectory, const char *path) = 0;
+ virtual IOStream *OpenFile(EVirtualDirectory virtualDirectory, const char *path, bool writeAccess, bool create) = 0;
+
+ static HostFileSystem *GetInstance();
+ static void SetInstance(HostFileSystem *instance);
+
+ private:
+ static HostFileSystem *ms_instance;
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/HostMemoryBuffer.h b/PortabilityLayer/HostMemoryBuffer.h
new file mode 100644
index 0000000..ca255e8
--- /dev/null
+++ b/PortabilityLayer/HostMemoryBuffer.h
@@ -0,0 +1,20 @@
+#pragma once
+#ifndef __PL_HOST_MEMORYBUFFER_H__
+#define __PL_HOST_MEMORYBUFFER_H__
+
+#include
+
+#include "CoreDefs.h"
+
+namespace PortabilityLayer
+{
+ class HostMemoryBuffer
+ {
+ public:
+ virtual void *Contents() = 0;
+ virtual size_t Size() = 0;
+ virtual void Destroy() = 0;
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/HostSuspendCallArgument.h b/PortabilityLayer/HostSuspendCallArgument.h
new file mode 100644
index 0000000..5d3b334
--- /dev/null
+++ b/PortabilityLayer/HostSuspendCallArgument.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+
+#include "HostSuspendCallID.h"
+
+namespace PortabilityLayer
+{
+ union HostSuspendCallArgument
+ {
+ uint32_t m_uint;
+ int32_t m_int;
+ size_t m_size;
+ void *m_pointer;
+ const void *m_constPointer;
+ };
+}
diff --git a/PortabilityLayer/HostSuspendCallID.h b/PortabilityLayer/HostSuspendCallID.h
new file mode 100644
index 0000000..4b3e0d5
--- /dev/null
+++ b/PortabilityLayer/HostSuspendCallID.h
@@ -0,0 +1,15 @@
+#pragma once
+#ifndef __PL_HOST_API_CALL_ID_H__
+#define __PL_HOST_API_CALL_ID_H__
+
+namespace PortabilityLayer
+{
+ enum HostSuspendCallID
+ {
+ HostSuspendCallID_Unknown,
+
+ HostSuspendCallID_Delay,
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/HostSuspendHook.cpp b/PortabilityLayer/HostSuspendHook.cpp
new file mode 100644
index 0000000..564cf28
--- /dev/null
+++ b/PortabilityLayer/HostSuspendHook.cpp
@@ -0,0 +1,22 @@
+#include "HostSuspendHook.h"
+#include "HostSuspendCallArgument.h"
+
+namespace
+{
+ static PortabilityLayer::HostSuspendHook_t gs_suspendHook;
+ static void *gs_suspendContext;
+}
+
+namespace PortabilityLayer
+{
+ void InstallHostSuspendHook(HostSuspendHook_t hook, void *context)
+ {
+ gs_suspendHook = hook;
+ gs_suspendContext = context;
+ }
+
+ void SuspendApplication(HostSuspendCallID callID, const HostSuspendCallArgument *args, HostSuspendCallArgument *returnValue)
+ {
+ gs_suspendHook(gs_suspendContext, callID, args, returnValue);
+ }
+}
diff --git a/PortabilityLayer/HostSuspendHook.h b/PortabilityLayer/HostSuspendHook.h
new file mode 100644
index 0000000..103e437
--- /dev/null
+++ b/PortabilityLayer/HostSuspendHook.h
@@ -0,0 +1,17 @@
+#pragma once
+#ifndef __PL_HOST_API_HOOK_H__
+#define __PL_HOST_API_HOOK_H__
+
+#include "HostSuspendCallID.h"
+
+namespace PortabilityLayer
+{
+ union HostSuspendCallArgument;
+
+ typedef void(*HostSuspendHook_t)(void *context, HostSuspendCallID callID, const HostSuspendCallArgument *args, HostSuspendCallArgument *returnValue);
+
+ void InstallHostSuspendHook(HostSuspendHook_t hook, void *context);
+ void SuspendApplication(HostSuspendCallID callID, const HostSuspendCallArgument *args, HostSuspendCallArgument *returnValue);
+}
+
+#endif
diff --git a/PortabilityLayer/HostSystemServices.cpp b/PortabilityLayer/HostSystemServices.cpp
new file mode 100644
index 0000000..3d3f72f
--- /dev/null
+++ b/PortabilityLayer/HostSystemServices.cpp
@@ -0,0 +1,16 @@
+#include "HostSystemServices.h"
+
+namespace PortabilityLayer
+{
+ void HostSystemServices::SetInstance(HostSystemServices *instance)
+ {
+ ms_instance = instance;
+ }
+
+ HostSystemServices *HostSystemServices::GetInstance()
+ {
+ return ms_instance;
+ }
+
+ HostSystemServices *HostSystemServices::ms_instance;
+}
diff --git a/PortabilityLayer/HostSystemServices.h b/PortabilityLayer/HostSystemServices.h
new file mode 100644
index 0000000..a1287a1
--- /dev/null
+++ b/PortabilityLayer/HostSystemServices.h
@@ -0,0 +1,22 @@
+#pragma once
+#ifndef __PL_HOST_SYSTEM_SERVICES_H__
+#define __PL_HOST_SYSTEM_SERVICES_H__
+
+#include
+
+namespace PortabilityLayer
+{
+ class HostSystemServices
+ {
+ public:
+ virtual uint32_t GetTime() const = 0;
+
+ static void SetInstance(HostSystemServices *instance);
+ static HostSystemServices *GetInstance();
+
+ private:
+ static HostSystemServices *ms_instance;
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/IOStream.h b/PortabilityLayer/IOStream.h
new file mode 100644
index 0000000..7167373
--- /dev/null
+++ b/PortabilityLayer/IOStream.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#ifndef __PL_IOTREAM_H__
+#define __PL_IOTREAM_H__
+
+#include "DataTypes.h"
+
+namespace PortabilityLayer
+{
+ typedef int64_t FilePos_t;
+ typedef uint64_t UFilePos_t;
+
+ class IOStream
+ {
+ public:
+ virtual size_t Read(void *bytesOut, size_t size) = 0;
+ virtual size_t Write(const void *bytes, size_t size) = 0;
+ virtual bool IsSeekable() const = 0;
+ virtual bool IsReadOnly() const = 0;
+ virtual bool IsWriteOnly() const = 0;
+ virtual bool SeekStart(UFilePos_t loc) = 0;
+ virtual bool SeekCurrent(FilePos_t loc) = 0;
+ virtual bool SeekEnd(UFilePos_t loc) = 0;
+ virtual bool Truncate(UFilePos_t loc) = 0;
+ virtual UFilePos_t Size() const = 0;
+ virtual UFilePos_t Tell() const = 0;
+ virtual void Close() = 0;
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/MMBlock.cpp b/PortabilityLayer/MMBlock.cpp
new file mode 100644
index 0000000..7c34c43
--- /dev/null
+++ b/PortabilityLayer/MMBlock.cpp
@@ -0,0 +1,12 @@
+#include "MMBlock.h"
+
+namespace PortabilityLayer
+{
+ size_t MMBlock::AlignedSize()
+ {
+ const size_t paddedSize = sizeof(MMBlock) + PL_SYSTEM_MEMORY_ALIGNMENT - 1;
+ const size_t paddedSizeTruncated = paddedSize - (paddedSize % PL_SYSTEM_MEMORY_ALIGNMENT);
+
+ return paddedSizeTruncated;
+ }
+}
diff --git a/PortabilityLayer/MMBlock.h b/PortabilityLayer/MMBlock.h
new file mode 100644
index 0000000..844094a
--- /dev/null
+++ b/PortabilityLayer/MMBlock.h
@@ -0,0 +1,20 @@
+#pragma once
+#ifndef __PL_MM_BLOCK_H__
+#define __PL_MM_BLOCK_H__
+
+#include
+
+#include "CoreDefs.h"
+#include "SmallestInt.h"
+
+namespace PortabilityLayer
+{
+ struct MMBlock
+ {
+ SmallestUInt::ValueType_t m_offsetFromAllocLocation;
+
+ static size_t AlignedSize();
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/MMHandleBlock.cpp b/PortabilityLayer/MMHandleBlock.cpp
new file mode 100644
index 0000000..651ec99
--- /dev/null
+++ b/PortabilityLayer/MMHandleBlock.cpp
@@ -0,0 +1,17 @@
+#include "MMHandleBlock.h"
+
+namespace PortabilityLayer
+{
+ MMHandleBlock::MMHandleBlock(void *contents, size_t size)
+ : m_contents(contents)
+ , m_rmSelfRef(nullptr)
+ , m_size(size)
+ {
+ }
+
+ void **MMHandleBlock::AsHandle()
+ {
+ return &m_contents;
+ }
+
+}
diff --git a/PortabilityLayer/MMHandleBlock.h b/PortabilityLayer/MMHandleBlock.h
new file mode 100644
index 0000000..bff3801
--- /dev/null
+++ b/PortabilityLayer/MMHandleBlock.h
@@ -0,0 +1,29 @@
+#pragma once
+#ifndef __PL_MM_HANDLE_BLOCK_H__
+#define __PL_MM_HANDLE_BLOCK_H__
+
+#include
+
+#include "CoreDefs.h"
+
+namespace PortabilityLayer
+{
+ struct ResourceCompiledRef;
+
+ struct MMHandleBlock
+ {
+ explicit MMHandleBlock(void *contents, size_t size);
+
+ void **AsHandle();
+
+ void *m_contents; // This must be the first field
+ ResourceCompiledRef *m_rmSelfRef;
+
+ size_t m_size;
+
+ private:
+ MMHandleBlock() PL_DELETED;
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/MacBinary2.cpp b/PortabilityLayer/MacBinary2.cpp
new file mode 100644
index 0000000..15efa66
--- /dev/null
+++ b/PortabilityLayer/MacBinary2.cpp
@@ -0,0 +1,185 @@
+#include "MacBinary2.h"
+
+#include "BytePack.h"
+#include "ByteUnpack.h"
+#include "DataTypes.h"
+#include "IOStream.h"
+#include "MacFileMem.h"
+#include "XModemCRC.h"
+
+// See: https://files.stairways.com/other/macbinaryii-standard-info.txt
+
+namespace
+{
+ namespace MB2FileOffsets
+ {
+ const unsigned int Version = 0;
+ const unsigned int FileNameLength = 1;
+ const unsigned int FileName = 2;
+ const unsigned int FileType = 65;
+ const unsigned int FileCreator = 69;
+ const unsigned int FinderFlagsHigh = 73;
+ const unsigned int YPos = 75;
+ const unsigned int XPos = 77;
+ const unsigned int Protected = 81;
+ const unsigned int DataForkSize = 83;
+ const unsigned int ResourceForkSize = 87;
+ const unsigned int CreationDate = 91;
+ const unsigned int ModifiedDate = 95;
+ const unsigned int CommentLength = 99;
+ const unsigned int FinderFlagsLow = 101;
+ const unsigned int DecompressedSize = 116;
+ const unsigned int SecondaryHeaderLength = 120;
+
+ const unsigned int WriterVersion = 122;
+ const unsigned int MinVersion = 123;
+ const unsigned int Checksum = 124;
+ const unsigned int ContentStart = 128;
+ };
+}
+
+namespace PortabilityLayer
+{
+ void MacBinary2::WriteBin(const MacFileMem *file, IOStream *stream)
+ {
+ const MacFileInfo &fileInfo = file->FileInfo();
+
+ uint8_t mb2Header[128];
+
+ memset(mb2Header, 0, sizeof(mb2Header));
+
+ mb2Header[MB2FileOffsets::Version] = 0;
+
+ size_t fileNameLength = fileInfo.m_fileName.Length();
+ if (fileNameLength == 0)
+ {
+ mb2Header[MB2FileOffsets::FileNameLength] = 1;
+ mb2Header[MB2FileOffsets::FileName] = '?';
+ }
+ else
+ {
+ if (fileNameLength > 63)
+ fileNameLength = 63;
+
+ mb2Header[MB2FileOffsets::FileNameLength] = static_cast(fileNameLength);
+ memcpy(mb2Header + MB2FileOffsets::FileName, &fileInfo.m_fileName[0], fileNameLength);
+ }
+
+ memcpy(mb2Header + MB2FileOffsets::FileType, fileInfo.m_properties.m_fileType, 4);
+ memcpy(mb2Header + MB2FileOffsets::FileCreator, fileInfo.m_properties.m_fileCreator, 4);
+
+ mb2Header[MB2FileOffsets::FinderFlagsHigh] = static_cast((fileInfo.m_properties.m_finderFlags >> 8) & 0xff);
+
+ BytePack::BigInt16(mb2Header + MB2FileOffsets::YPos, fileInfo.m_properties.m_yPos);
+ BytePack::BigInt16(mb2Header + MB2FileOffsets::XPos, fileInfo.m_properties.m_xPos);
+ mb2Header[MB2FileOffsets::Protected] = fileInfo.m_properties.m_protected;
+ BytePack::BigUInt32(mb2Header + MB2FileOffsets::DataForkSize, fileInfo.m_dataForkSize);
+ BytePack::BigUInt32(mb2Header + MB2FileOffsets::ResourceForkSize, fileInfo.m_resourceForkSize);
+ BytePack::BigUInt32(mb2Header + MB2FileOffsets::CreationDate, fileInfo.m_properties.m_creationDate);
+ BytePack::BigUInt32(mb2Header + MB2FileOffsets::ModifiedDate, fileInfo.m_properties.m_modifiedDate);
+
+ BytePack::BigUInt16(mb2Header + MB2FileOffsets::CommentLength, fileInfo.m_commentSize);
+ mb2Header[MB2FileOffsets::FinderFlagsLow] = static_cast(fileInfo.m_properties.m_finderFlags & 0xff);
+ // DecompressedSize is unused
+ // SecondaryHeaderLength is zero
+
+ mb2Header[MB2FileOffsets::WriterVersion] = 129;
+ mb2Header[MB2FileOffsets::MinVersion] = 129;
+
+ BytePack::BigUInt16(mb2Header + MB2FileOffsets::Checksum, XModemCRC(mb2Header, 124, 0));
+
+ stream->Write(mb2Header, 128);
+
+ uint8_t *padding = mb2Header;
+ memset(padding, 0, 128);
+
+ const size_t dataForkPadding = 127 - ((fileInfo.m_dataForkSize + 127) % 128);
+ const size_t resourceForkPadding = 127 - ((fileInfo.m_resourceForkSize + 127) % 128);
+
+ stream->Write(file->DataFork(), fileInfo.m_dataForkSize);
+ stream->Write(padding, dataForkPadding);
+ stream->Write(file->ResourceFork(), fileInfo.m_resourceForkSize);
+ stream->Write(padding, resourceForkPadding);
+ }
+
+ MacFileMem *MacBinary2::ReadBin(IOStream *stream)
+ {
+ MacFileInfo fileInfo;
+
+ uint8_t mb2Header[128];
+
+ if (stream->Read(mb2Header, 128) != 128)
+ return nullptr;
+
+ if (mb2Header[MB2FileOffsets::Version] != 0)
+ return nullptr;
+
+ const uint8_t fileNameLength = mb2Header[MB2FileOffsets::FileNameLength];
+ if (fileNameLength < 1 || fileNameLength > 63)
+ return nullptr;
+
+ fileInfo.m_fileName.Set(fileNameLength, reinterpret_cast(mb2Header + MB2FileOffsets::FileName));
+
+ memcpy(fileInfo.m_properties.m_fileType, mb2Header + MB2FileOffsets::FileType, 4);
+ memcpy(fileInfo.m_properties.m_fileCreator, mb2Header + MB2FileOffsets::FileCreator, 4);
+
+ fileInfo.m_properties.m_finderFlags = mb2Header[MB2FileOffsets::FinderFlagsHigh] << 8;
+
+ fileInfo.m_properties.m_yPos = ByteUnpack::BigInt16(mb2Header + MB2FileOffsets::YPos);
+ fileInfo.m_properties.m_xPos = ByteUnpack::BigInt16(mb2Header + MB2FileOffsets::XPos);
+ fileInfo.m_properties.m_protected = mb2Header[MB2FileOffsets::Protected];
+ fileInfo.m_dataForkSize = ByteUnpack::BigUInt32(mb2Header + MB2FileOffsets::DataForkSize);
+ fileInfo.m_resourceForkSize = ByteUnpack::BigUInt32(mb2Header + MB2FileOffsets::ResourceForkSize);
+ fileInfo.m_properties.m_creationDate = ByteUnpack::BigUInt32(mb2Header + MB2FileOffsets::CreationDate);
+ fileInfo.m_properties.m_modifiedDate = ByteUnpack::BigUInt32(mb2Header + MB2FileOffsets::ModifiedDate);
+
+ fileInfo.m_commentSize = ByteUnpack::BigUInt16(mb2Header + MB2FileOffsets::CommentLength);
+ fileInfo.m_properties.m_finderFlags |= mb2Header[MB2FileOffsets::FinderFlagsLow];
+
+ if (ByteUnpack::BigInt16(mb2Header + MB2FileOffsets::SecondaryHeaderLength) != 0)
+ return nullptr;
+
+ uint16_t crc = ByteUnpack::BigUInt16(mb2Header + MB2FileOffsets::Checksum);
+
+ uint16_t expectedCRC = XModemCRC(mb2Header, 124, 0);
+
+ if (fileInfo.m_dataForkSize > SIZE_MAX)
+ return nullptr;
+
+ if (fileInfo.m_resourceForkSize > SIZE_MAX)
+ return nullptr;
+
+ uint8_t *dataBuffer = nullptr;
+ uint8_t *rsrcBuffer = nullptr;
+
+ if (fileInfo.m_dataForkSize != 0)
+ dataBuffer = new uint8_t[fileInfo.m_dataForkSize];
+
+ if (fileInfo.m_resourceForkSize != 0)
+ rsrcBuffer = new uint8_t[fileInfo.m_resourceForkSize];
+
+ ScopedArray dataContents = dataBuffer;
+ ScopedArray rsrcContents = rsrcBuffer;
+
+ uint8_t *padding = mb2Header;
+
+ const size_t dataForkPadding = 127 - ((fileInfo.m_dataForkSize + 127) % 128);
+ const size_t resourceForkPadding = 127 - ((fileInfo.m_resourceForkSize + 127) % 128);
+
+ if (stream->Read(dataBuffer, fileInfo.m_dataForkSize) != fileInfo.m_dataForkSize)
+ return nullptr;
+
+ if (stream->Read(padding, dataForkPadding) != dataForkPadding)
+ return nullptr;
+
+ if (stream->Read(rsrcBuffer, fileInfo.m_resourceForkSize) != fileInfo.m_resourceForkSize)
+ return nullptr;
+
+ if (stream->Read(padding, resourceForkPadding) != resourceForkPadding)
+ return nullptr;
+
+ // Ignore comment for now
+ return new MacFileMem(dataBuffer, rsrcBuffer, nullptr, fileInfo);
+ }
+}
+
diff --git a/PortabilityLayer/MacBinary2.h b/PortabilityLayer/MacBinary2.h
new file mode 100644
index 0000000..0f6b198
--- /dev/null
+++ b/PortabilityLayer/MacBinary2.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#ifndef __PL_MACBINARY2_H__
+#define __PL_MACBINARY2_H__
+
+namespace PortabilityLayer
+{
+ class IOStream;
+ class MacFileMem;
+
+ namespace MacBinary2
+ {
+ void WriteBin(const MacFileMem *file, IOStream *stream);
+ MacFileMem *ReadBin(IOStream *stream);
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/MacFileInfo.cpp b/PortabilityLayer/MacFileInfo.cpp
new file mode 100644
index 0000000..0fc700a
--- /dev/null
+++ b/PortabilityLayer/MacFileInfo.cpp
@@ -0,0 +1,63 @@
+#include "MacFileInfo.h"
+#include "PLBigEndian.h"
+
+#include
+
+namespace PortabilityLayer
+{
+
+ static const unsigned int kOffsetFileType = 0;
+ static const unsigned int kOffsetFileCreator = 4;
+ static const unsigned int kOffsetXPos = 8;
+ static const unsigned int kOffsetYPos = 10;
+ static const unsigned int kOffsetFinderFlags = 12;
+ static const unsigned int kProtected = 14;
+ static const unsigned int kCreationDate = 15;
+ static const unsigned int kModifiedDate = 19;
+
+ static const unsigned int kSize = 23;
+
+ uint8_t m_data[kSize];
+
+ void MacFilePropertiesSerialized::Deserialize(MacFileProperties &props) const
+ {
+ memcpy(props.m_fileType, m_data + kOffsetFileType, 4);
+ memcpy(props.m_fileCreator, m_data + kOffsetFileCreator, 4);
+ memcpy(&props.m_xPos, m_data + kOffsetXPos, 2);
+ memcpy(&props.m_yPos, m_data + kOffsetYPos, 2);
+ memcpy(&props.m_finderFlags, m_data + kOffsetFinderFlags, 2);
+ memcpy(&props.m_protected, m_data + kProtected, 1);
+ memcpy(&props.m_creationDate, m_data + kCreationDate, 4);
+ memcpy(&props.m_modifiedDate, m_data + kModifiedDate, 4);
+
+ PortabilityLayer::ByteSwap::BigInt16(props.m_xPos);
+ PortabilityLayer::ByteSwap::BigInt16(props.m_yPos);
+ PortabilityLayer::ByteSwap::BigUInt16(props.m_finderFlags);
+ PortabilityLayer::ByteSwap::BigUInt32(props.m_creationDate);
+ PortabilityLayer::ByteSwap::BigUInt32(props.m_modifiedDate);
+ }
+
+ void MacFilePropertiesSerialized::Serialize(const MacFileProperties &props)
+ {
+ int16_t xPos = props.m_xPos;
+ int16_t yPos = props.m_yPos;
+ uint16_t finderFlags = props.m_finderFlags;
+ uint32_t creationDate = props.m_creationDate;
+ uint32_t modifiedDate = props.m_modifiedDate;
+
+ PortabilityLayer::ByteSwap::BigInt16(xPos);
+ PortabilityLayer::ByteSwap::BigInt16(yPos);
+ PortabilityLayer::ByteSwap::BigUInt16(finderFlags);
+ PortabilityLayer::ByteSwap::BigUInt32(creationDate);
+ PortabilityLayer::ByteSwap::BigUInt32(modifiedDate);
+
+ memcpy(m_data + kOffsetFileType, props.m_fileType, 4);
+ memcpy(m_data + kOffsetFileCreator, props.m_fileCreator, 4);
+ memcpy(m_data + kOffsetXPos, &xPos, 2);
+ memcpy(m_data + kOffsetYPos, &yPos, 2);
+ memcpy(m_data + kOffsetFinderFlags, &finderFlags, 2);
+ memcpy(m_data + kProtected, &props.m_protected, 1);
+ memcpy(m_data + kCreationDate, &creationDate, 4);
+ memcpy(m_data + kModifiedDate, &modifiedDate, 4);
+ }
+}
diff --git a/PortabilityLayer/MacFileInfo.h b/PortabilityLayer/MacFileInfo.h
new file mode 100644
index 0000000..a4d7557
--- /dev/null
+++ b/PortabilityLayer/MacFileInfo.h
@@ -0,0 +1,89 @@
+#pragma once
+
+#include "DataTypes.h"
+#include "PascalStr.h"
+
+namespace PortabilityLayer
+{
+ enum FinderFileFlags
+ {
+ FINDER_FILE_FLAG_LOCKED = (1 << 15),
+ FINDER_FILE_FLAG_INVISIBLE = (1 << 14),
+ FINDER_FILE_FLAG_BUNDLE = (1 << 13),
+ FINDER_FILE_FLAG_SYSTEM = (1 << 12),
+ FINDER_FILE_FLAG_COPY_PROTECTED = (1 << 11),
+ FINDER_FILE_FLAG_BUSY = (1 << 10),
+ FINDER_FILE_FLAG_CHANGED = (1 << 9),
+ FINDER_FILE_FLAG_INITED = (1 << 8),
+ };
+
+ struct MacFileProperties
+ {
+ MacFileProperties();
+
+ char m_fileType[4];
+ char m_fileCreator[4];
+ int16_t m_xPos;
+ int16_t m_yPos;
+ uint16_t m_finderFlags;
+ uint8_t m_protected;
+ uint32_t m_creationDate;
+ uint32_t m_modifiedDate;
+
+ void Serialize(void *buffer);
+ void Deserialize(const void *buffer);
+ };
+
+ struct MacFilePropertiesSerialized
+ {
+ static const unsigned int kOffsetFileType = 0;
+ static const unsigned int kOffsetFileCreator = 4;
+ static const unsigned int kOffsetXPos = 8;
+ static const unsigned int kOffsetYPos = 10;
+ static const unsigned int kOffsetFinderFlags = 12;
+ static const unsigned int kProtected = 14;
+ static const unsigned int kCreationDate = 15;
+ static const unsigned int kModifiedDate = 19;
+
+ static const unsigned int kSize = 23;
+
+ uint8_t m_data[kSize];
+
+ void Deserialize(MacFileProperties &props) const;
+ void Serialize(const MacFileProperties &props);
+ };
+
+ struct MacFileInfo
+ {
+ MacFileInfo();
+
+ PascalStr<64> m_fileName;
+ uint16_t m_commentSize;
+ uint32_t m_dataForkSize;
+ uint32_t m_resourceForkSize;
+
+ MacFileProperties m_properties;
+ };
+}
+
+namespace PortabilityLayer
+{
+ inline MacFileProperties::MacFileProperties()
+ : m_xPos(0)
+ , m_yPos(0)
+ , m_finderFlags(0)
+ , m_protected(0)
+ , m_creationDate(0)
+ , m_modifiedDate(0)
+ {
+ m_fileType[0] = m_fileType[1] = m_fileType[2] = m_fileType[3] = '\0';
+ m_fileCreator[0] = m_fileCreator[1] = m_fileCreator[2] = m_fileCreator[3] = '\0';
+ }
+
+ inline MacFileInfo::MacFileInfo()
+ : m_dataForkSize(0)
+ , m_resourceForkSize(0)
+ , m_commentSize(0)
+ {
+ }
+}
diff --git a/PortabilityLayer/MacFileMem.cpp b/PortabilityLayer/MacFileMem.cpp
new file mode 100644
index 0000000..7784ac6
--- /dev/null
+++ b/PortabilityLayer/MacFileMem.cpp
@@ -0,0 +1,26 @@
+#include "MacFileMem.h"
+
+namespace PortabilityLayer
+{
+ MacFileMem::MacFileMem(const uint8_t *dataFork, const uint8_t *resourceFork, const char* comment, const MacFileInfo &fileInfo)
+ : m_info(fileInfo)
+ {
+ uint8_t *buffer = new uint8_t[fileInfo.m_dataForkSize + fileInfo.m_resourceForkSize + fileInfo.m_commentSize + 1];
+ m_data.Set(buffer);
+
+ memcpy(buffer, dataFork, fileInfo.m_dataForkSize);
+ buffer += fileInfo.m_dataForkSize;
+
+ memcpy(buffer, resourceFork, fileInfo.m_resourceForkSize);
+ buffer += fileInfo.m_resourceForkSize;
+
+ memcpy(buffer, comment, fileInfo.m_commentSize);
+ buffer += fileInfo.m_commentSize;
+
+ *buffer = 0;
+ }
+
+ MacFileMem::~MacFileMem()
+ {
+ }
+}
diff --git a/PortabilityLayer/MacFileMem.h b/PortabilityLayer/MacFileMem.h
new file mode 100644
index 0000000..d7f2f3d
--- /dev/null
+++ b/PortabilityLayer/MacFileMem.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#ifndef __PL_MACFILEMEM_H__
+#define __PL_MACFILEMEM_H__
+
+#include "DataTypes.h"
+#include "MacFileInfo.h"
+#include "ScopedArray.h"
+
+namespace PortabilityLayer
+{
+ class MacFileMem
+ {
+ public:
+ MacFileMem(const uint8_t *dataFork, const uint8_t *resourceFork, const char* comment, const MacFileInfo &fileInfo);
+ ~MacFileMem();
+
+ const MacFileInfo &FileInfo() const;
+ const uint8_t *DataFork() const;
+ const uint8_t *ResourceFork() const;
+ const char *Comment() const;
+
+ private:
+ ScopedArray m_data;
+ MacFileInfo m_info;
+ };
+}
+
+namespace PortabilityLayer
+{
+ inline const MacFileInfo &MacFileMem::FileInfo() const
+ {
+ return m_info;
+ }
+
+ inline const uint8_t *MacFileMem::DataFork() const
+ {
+ return m_data;
+ }
+
+ inline const uint8_t *MacFileMem::ResourceFork() const
+ {
+ return m_data + m_info.m_dataForkSize;
+ }
+
+ inline const char *MacFileMem::Comment() const
+ {
+ return reinterpret_cast(m_data + m_info.m_dataForkSize + m_info.m_resourceForkSize);
+ }
+}
+
+#endif
diff --git a/PortabilityLayer/MacFileWriteableMem.h b/PortabilityLayer/MacFileWriteableMem.h
new file mode 100644
index 0000000..c5a93e3
--- /dev/null
+++ b/PortabilityLayer/MacFileWriteableMem.h
@@ -0,0 +1,14 @@
+#pragma once
+#ifndef __PL_MAC_FILE_WRITEABLE_MEM_H__
+#define __PL_MAC_FILE_WRITEABLE_MEM_H__
+
+namespace PortabilityLayer
+{
+ class MacFileWriteableMem
+ {
+ public:
+ private:
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/MacRsrcHeader.h b/PortabilityLayer/MacRsrcHeader.h
new file mode 100644
index 0000000..9958721
--- /dev/null
+++ b/PortabilityLayer/MacRsrcHeader.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#ifndef __PL_MACRSRCHEADER_H__
+#define __PL_MACRSRCHEADER_H__
+
+#include "DataTypes.h"
+
+namespace PortabilityLayer
+{
+ struct MacRsrcHeader
+ {
+ uint32_t m_resDataOffset;
+ uint32_t m_resMapOffset;
+ uint32_t m_resDataSize;
+ uint32_t m_resMapSize;
+
+ void Load(const void *data);
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/MacRsrcMap.h b/PortabilityLayer/MacRsrcMap.h
new file mode 100644
index 0000000..e7d4eb8
--- /dev/null
+++ b/PortabilityLayer/MacRsrcMap.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#ifndef __PL_MACRSRCMAP_H__
+#define __PL_MACRSRCMAP_H__
+
+#include "DataTypes.h"
+
+namespace PortabilityLayer
+{
+ struct MacRsrcMap
+ {
+ uint16_t m_resTypeListOffset;
+ uint16_t m_resNameListOffset;
+ uint16_t m_numTypesMinusOne;
+
+ void Load(const void *data);
+ };
+}
+
+#endif
diff --git a/PortabilityLayer/MemReaderStream.cpp b/PortabilityLayer/MemReaderStream.cpp
new file mode 100644
index 0000000..651fb71
--- /dev/null
+++ b/PortabilityLayer/MemReaderStream.cpp
@@ -0,0 +1,110 @@
+#include "MemReaderStream.h"
+
+#include
+
+namespace PortabilityLayer
+{
+ MemReaderStream::MemReaderStream(const void *memStream, size_t size)
+ : m_bytes(static_cast(memStream))
+ , m_size(size)
+ , m_loc(0)
+ {
+ }
+
+ size_t MemReaderStream::Read(void *bytesOut, size_t size)
+ {
+ size_t available = m_size - m_loc;
+ if (size > available)
+ size = available;
+
+ memcpy(bytesOut, m_bytes + m_loc, size);
+ m_loc += size;
+
+ return size;
+ }
+
+ size_t MemReaderStream::Write(const void *bytes, size_t size)
+ {
+ return 0;
+ }
+
+ bool IsSeekable()
+ {
+ return true;
+ }
+
+ bool MemReaderStream::IsSeekable() const
+ {
+ return true;
+ }
+
+ bool MemReaderStream::IsReadOnly() const
+ {
+ return true;
+ }
+
+ bool MemReaderStream::IsWriteOnly() const
+ {
+ return false;
+ }
+
+ bool MemReaderStream::SeekStart(UFilePos_t loc)
+ {
+ if (loc > m_size)
+ m_loc = m_size;
+ else
+ m_loc = static_cast(loc);
+
+ return true;
+ }
+
+ bool MemReaderStream::SeekCurrent(FilePos_t loc)
+ {
+ if (loc < 0)
+ {
+ if (static_cast(m_loc) + loc < 0)
+ m_loc = 0;
+ else
+ m_loc = static_cast(static_cast(m_loc) + loc);
+ }
+ else
+ {
+ const size_t available = m_size - m_loc;
+ if (static_cast