//============================================================================ //---------------------------------------------------------------------------- // Events.c //---------------------------------------------------------------------------- //============================================================================ #include "PLAppleEvents.h" #include "PLKeyEncoding.h" #include "PLTimeTaggedVOSEvent.h" #include "PLToolUtils.h" #include "PLQDraw.h" #include "DialogManager.h" #include "Externs.h" #include "Environ.h" #include "House.h" #include "InputManager.h" #include "ObjectEdit.h" #include "WindowManager.h" short BitchAboutColorDepth (void); void HandleMouseEvent (const GpMouseInputEvent &, uint32_t); void HandleKeyEvent (const KeyDownStates &keyStates, const GpKeyboardInputEvent &); 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 = PortabilityLayer::DialogManager::GetInstance()->DisplayAlert(kColorSwitchedAlert, nullptr); return (sheSaid); } //-------------------------------------------------------------- HandleMouseEvent // Handle a mouse click event. void HandleMouseEvent (const GpMouseInputEvent &theEvent, uint32_t tick) { WindowPtr whichWindow; long menuChoice, newSize; short thePart, hDelta, vDelta; Boolean isDoubleClick; Point evtPoint = Point::Create(theEvent.m_x, theEvent.m_y); thePart = FindWindow(evtPoint, &whichWindow); switch (thePart) { case RegionIDs::kMenuBar: menuChoice = MenuSelect(evtPoint); DoMenuChoice(menuChoice); break; case RegionIDs::kTitleBar: PortabilityLayer::WindowManager::GetInstance()->DragWindow(whichWindow, evtPoint, thisMac.screen); if (whichWindow == mainWindow) 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); break; case RegionIDs::kClose: if (TrackGoAway(whichWindow, evtPoint)) { if (whichWindow == mapWindow) ToggleMapWindow(); else if (whichWindow == toolsWindow) ToggleToolsWindow(); else if (whichWindow == linkWindow) CloseLinkWindow(); else if (whichWindow == coordWindow) ToggleCoordinateWindow(); } break; case RegionIDs::kExpand: if (whichWindow == mapWindow) { newSize = GrowWindow(mapWindow, evtPoint, &thisMac.gray); ResizeMapWindow(LoWord(newSize), HiWord(newSize)); } break; case RegionIDs::kContent: if (whichWindow == mainWindow) { hDelta = evtPoint.h - lastWhere.h; if (hDelta < 0) hDelta = -hDelta; vDelta = evtPoint.v - lastWhere.v; if (vDelta < 0) vDelta = -vDelta; if (((tick - lastUp) < doubleTime) && (hDelta < 5) && (vDelta < 5)) isDoubleClick = true; else { isDoubleClick = false; lastUp = tick; lastWhere = evtPoint; } HandleMainClick(evtPoint, isDoubleClick); } else if (whichWindow == mapWindow) HandleMapClick(theEvent); else if (whichWindow == toolsWindow) HandleToolsClick(evtPoint); else if (whichWindow == linkWindow) HandleLinkClick(evtPoint); break; default: break; } } //-------------------------------------------------------------- HandleKeyEvent // Handle a key-down event. void HandleKeyEvent (const KeyDownStates &keyStates, const GpKeyboardInputEvent &theEvent) { const intptr_t theChar = PackVOSKeyCode(theEvent); const bool shiftDown = keyStates.IsSet(PL_KEY_EITHER_SPECIAL(kShift)); const bool commandDown = keyStates.IsSet(PL_KEY_EITHER_SPECIAL(kControl)); const bool optionDown = keyStates.IsSet(PL_KEY_EITHER_SPECIAL(kAlt)); if ((commandDown) && (!optionDown)) DoMenuChoice(MenuKey(theChar)); else { switch (theChar) { case PL_KEY_SPECIAL(kPageUp): if (houseUnlocked) PrevToolMode(); break; case PL_KEY_SPECIAL(kPageDown): if (houseUnlocked) NextToolMode(); break; #if BUILD_ARCADE_VERSION case PL_KEY_SPECIAL(kLeftArrow): DoOptionsMenu(iHighScores); break; case PL_KEY_SPECIAL(kRightArrow): DoOptionsMenu(iHelp); break; case PL_KEY_SPECIAL(kUpArrow): DoGameMenu(iNewGame); break; case PL_KEY_SPECIAL(kDownArrow): DoGameMenu(iNewGame); break; #else case PL_KEY_SPECIAL(kLeftArrow): if (houseUnlocked) { if (objActive == kNoObjectSelected) SelectNeighborRoom(kRoomToLeft); else MoveObject(kBumpLeft, shiftDown); } break; case PL_KEY_SPECIAL(kRightArrow): if (houseUnlocked) { if (objActive == kNoObjectSelected) SelectNeighborRoom(kRoomToRight); else MoveObject(kBumpRight, shiftDown); } break; case PL_KEY_SPECIAL(kUpArrow): if (houseUnlocked) { if (objActive == kNoObjectSelected) SelectNeighborRoom(kRoomAbove); else MoveObject(kBumpUp, shiftDown); } break; case PL_KEY_SPECIAL(kDownArrow): if (houseUnlocked) { if (objActive == kNoObjectSelected) SelectNeighborRoom(kRoomBelow); else MoveObject(kBumpDown, shiftDown); } break; #endif case PL_KEY_SPECIAL(kDelete): if (houseUnlocked) { if (objActive == kNoObjectSelected) DeleteRoom(true); else DeleteObject(); } break; case PL_KEY_SPECIAL(kTab): if ((theMode == kEditMode) && (houseUnlocked)) { if (shiftDown) SelectPrevObject(); else SelectNextObject(); } break; case PL_KEY_SPECIAL(kEscape): if ((theMode == kEditMode) && (houseUnlocked)) DeselectObject(); break; case PL_KEY_ASCII('A'): if ((theMode == kEditMode) && (houseUnlocked)) SetSpecificToolMode(kApplianceMode); break; case PL_KEY_ASCII('B'): if ((theMode == kEditMode) && (houseUnlocked)) SetSpecificToolMode(kBlowerMode); break; case PL_KEY_ASCII('C'): if ((theMode == kEditMode) && (houseUnlocked)) SetSpecificToolMode(kClutterMode); break; case PL_KEY_ASCII('E'): if ((theMode == kEditMode) && (houseUnlocked)) SetSpecificToolMode(kEnemyMode); break; case PL_KEY_ASCII('F'): if ((theMode == kEditMode) && (houseUnlocked)) SetSpecificToolMode(kFurnitureMode); break; case PL_KEY_ASCII('L'): if ((theMode == kEditMode) && (houseUnlocked)) SetSpecificToolMode(kLightMode); break; case PL_KEY_ASCII('P'): if ((theMode == kEditMode) && (houseUnlocked)) SetSpecificToolMode(kBonusMode); break; case PL_KEY_ASCII('S'): if ((theMode == kEditMode) && (houseUnlocked)) SetSpecificToolMode(kSwitchMode); break; case PL_KEY_ASCII('T'): if ((theMode == kEditMode) && (houseUnlocked)) SetSpecificToolMode(kTransportMode); break; default: break; } } } //-------------------------------------------------------------- HandleUpdateEvent // Handle an update event. #if 0 void HandleUpdateEvent (EventRecord *theEvent) { if ((WindowPtr)theEvent->message == mainWindow) { SetPort((GrafPtr)mainWindow); UpdateMainWindow(); EndUpdate(mainWindow); } else if ((WindowPtr)theEvent->message == mapWindow) { SetPort((GrafPtr)mapWindow); UpdateMapWindow(); EndUpdate(mapWindow); } else if ((WindowPtr)theEvent->message == toolsWindow) { SetPort((GrafPtr)toolsWindow); UpdateToolsWindow(); EndUpdate(toolsWindow); } else if ((WindowPtr)theEvent->message == linkWindow) { SetPort((GrafPtr)linkWindow); UpdateLinkWindow(); EndUpdate(linkWindow); } else if ((WindowPtr)theEvent->message == coordWindow) { SetPort((GrafPtr)coordWindow); UpdateCoordWindow(); EndUpdate(coordWindow); } else if ((WindowPtr)theEvent->message == menuWindow) { UpdateMenuBarWindow(menuWindow->GetDrawSurface()); EndUpdate(menuWindow); } } //-------------------------------------------------------------- HandleOSEvent // Handle an OS Event (MultiFinder - user has switched in or out of app). void HandleOSEvent (EventRecord *theEvent) { PLError_t 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 != PLErrors::kNone) { 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) { PLError_t theErr; theErr = AEProcessAppleEvent(theEvent); if ((theErr != PLErrors::kNone) && (theErr != errAEEventNotHandled)) YellowAlert(kYellowAppleEventErr, theErr); } #endif //-------------------------------------------------------------- HandleIdleTask // Handle some processing during event lulls. void HandleIdleTask (void) { if (theMode == kEditMode) { SetPort(&mainWindow->GetDrawSurface()->m_port); 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) { TimeTaggedVOSEvent theEvent; uint32_t sleep = 2; bool itHappened = true; const KeyDownStates *eventKeys = PortabilityLayer::InputManager::GetInstance()->GetKeys(); if ((eventKeys->IsSet(PL_KEY_EITHER_SPECIAL(kControl))) && (eventKeys->IsSet(PL_KEY_EITHER_SPECIAL(kAlt)))) { HiliteAllObjects(); } else if ((eventKeys->IsSet(PL_KEY_EITHER_SPECIAL(kAlt))) && (theMode == kEditMode) && (houseUnlocked)) { EraseSelectedTool(); SelectTool(kSelectTool); } itHappened = WaitForEvent(&theEvent, sleep); if (itHappened) { if (theEvent.m_vosEvent.m_eventType == GpVOSEventTypes::kMouseInput) { switch (theEvent.m_vosEvent.m_event.m_mouseInputEvent.m_eventType) { case GpMouseEventTypes::kDown: HandleMouseEvent(theEvent.m_vosEvent.m_event.m_mouseInputEvent, theEvent.m_timestamp); break; default: break; } } else if (theEvent.m_vosEvent.m_eventType == GpVOSEventTypes::kKeyboardInput) { switch (theEvent.m_vosEvent.m_event.m_keyboardInputEvent.m_eventType) { case GpKeyboardInputEventTypes::kDown: case GpKeyboardInputEventTypes::kAuto: HandleKeyEvent(*eventKeys, theEvent.m_vosEvent.m_event.m_keyboardInputEvent); break; default: break; } } } else HandleIdleTask(); if ((theMode == kSplashMode) && doAutoDemo && !switchedOut) { if (TickCount() >= incrementModeTime) DoDemoGame(); } } //-------------------------------------------------------------- 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; }