Files
Aerofoil/GpApp/GameOver.cpp

524 lines
13 KiB
C++
Raw Normal View History

2019-11-11 00:11:59 -05:00
//============================================================================
//----------------------------------------------------------------------------
// GameOver.c
//----------------------------------------------------------------------------
//============================================================================
#include "PLToolUtils.h"
#include "PLPasStr.h"
2019-12-31 03:55:17 -05:00
#include "PLEventQueue.h"
2019-12-25 22:20:10 -05:00
#include "PLKeyEncoding.h"
2019-12-31 03:55:17 -05:00
#include "PLTimeTaggedVOSEvent.h"
2019-11-11 00:11:59 -05:00
#include "Externs.h"
#include "Environ.h"
2019-12-30 20:53:11 -05:00
#include "FontManager.h"
#include "FontFamily.h"
2020-01-05 16:41:04 -05:00
#include "InputManager.h"
2019-11-11 00:11:59 -05:00
#include "MainWindow.h"
#include "Objects.h"
2020-05-21 03:30:11 -04:00
#include "PLStandardColors.h"
2019-11-11 00:11:59 -05:00
#include "RectUtils.h"
2020-05-21 05:01:16 -04:00
#include "RenderedFont.h"
2020-05-21 03:30:11 -04:00
#include "ResolveCachingColor.h"
2019-11-11 00:11:59 -05:00
#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;
2019-12-30 20:53:11 -05:00
DrawSurface *pageSrcMap, *gameOverSrcMap, *angelSrcMap;
DrawSurface *pageMaskMap, *angelMaskMap;
2019-11-11 00:11:59 -05:00
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<61>
// completed the house.
void DoGameOver (void)
2019-12-30 20:53:11 -05:00
{
DrawSurface *surface = mainWindow->GetDrawSurface();
2019-11-11 00:11:59 -05:00
playing = false;
SetUpFinalScreen();
SetPort(mainWindow->GetDrawSurface());
2019-12-30 20:53:11 -05:00
ColorRect(surface, mainWindowRect, 244);
2019-11-11 00:11:59 -05:00
DoGameOverStarAnimation();
if (!TestHighScore())
RedrawSplashScreen();
}
//-------------------------------------------------------------- SetUpFinalScreen
// This sets up the game over screen (again, this function is for when<65>
// the player completes the house).
void SetUpFinalScreen (void)
{
Rect tempRect;
Str255 tempStr, subStr;
short count, offset, i, textDown;
char wasState;
2019-12-30 20:53:11 -05:00
DrawSurface *surface = workSrcMap;
2020-05-21 03:30:11 -04:00
PortabilityLayer::ResolveCachingColor blackColor = StdColors::Black();
PortabilityLayer::ResolveCachingColor whiteColor = StdColors::White();
2019-11-11 00:11:59 -05:00
2019-12-30 20:53:11 -05:00
ColorRect(surface, workSrcRect, 244);
2019-11-11 00:11:59 -05:00
QSetRect(&tempRect, 0, 0, 640, 460);
CenterRectInRect(&tempRect, &workSrcRect);
2019-12-30 20:53:11 -05:00
LoadScaledGraphic(surface, kMilkywayPictID, &tempRect);
2019-11-11 00:11:59 -05:00
textDown = tempRect.top;
if (textDown < 0)
textDown = 0;
PasStringCopy((*thisHouse)->trailer, tempStr);
count = 0;
do
{
GetLineOfText(tempStr, count, subStr);
2019-12-30 20:53:11 -05:00
2020-05-21 05:01:16 -04:00
PortabilityLayer::RenderedFont *appFont = GetApplicationFont(12, PortabilityLayer::FontFamilyFlag_Bold, true);
offset = ((thisMac.constrainedScreen.right - thisMac.constrainedScreen.left) -
2020-05-21 05:01:16 -04:00
appFont->MeasurePStr(subStr)) / 2;
2019-12-30 20:53:11 -05:00
const Point textShadowPos = Point::Create(offset + 1, textDown + 33 + (count * 20));
2020-05-21 05:01:16 -04:00
surface->DrawString(textShadowPos, subStr, blackColor, appFont);
2019-12-30 20:53:11 -05:00
const Point textPos = Point::Create(offset, textDown + 32 + (count * 20));
2020-05-21 05:01:16 -04:00
surface->DrawString(textPos, subStr, whiteColor, appFont);
2019-11-11 00:11:59 -05:00
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<65>
// completes a house.
void DoGameOverStarAnimation (void)
{
#define kStarFalls 8
2019-12-31 03:55:17 -05:00
TimeTaggedVOSEvent theEvent;
2019-11-11 00:11:59 -05:00
Rect angelDest;
long nextLoop;
short which, i, count, pass;
Boolean noInteruption;
short starFallSpeed = kStarFalls;
const int kStarSpacing = 32;
const int kAngelSpeed = 2;
const int kStarsReserved = 5;
const int kMaxFramesAlive = (kStarSpacing * kStarsReserved + kAngelSpeed - 1) / kAngelSpeed;
2019-11-11 00:11:59 -05:00
angelDest = angelSrcRect;
QOffsetRect(&angelDest, -96, 0);
noInteruption = true;
nextLoop = TickCount() + 2;
count = 0;
pass = 0;
FlushEvents(everyEvent, 0);
if (workSrcRect.bottom - angelDest.bottom > kMaxFramesAlive * starFallSpeed)
starFallSpeed = (workSrcRect.bottom - angelDest.bottom + kMaxFramesAlive - 1) / kMaxFramesAlive;
2019-11-11 00:11:59 -05:00
while (noInteruption)
{
if ((angelDest.left % kStarSpacing) == 0) // add a star
2019-11-11 00:11:59 -05:00
{
PlayPrioritySound(kMysticSound, kMysticPriority);
which = angelDest.left / kStarSpacing;
which = which % kStarsReserved;
2020-04-01 23:29:48 -04:00
if (which < 0)
which += kStarsReserved;
2019-11-11 00:11:59 -05:00
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 -= starFallSpeed;
2019-11-11 00:11:59 -05:00
AddRectToWorkRectsWhole(&pages[i].was);
AddRectToBackRects(&pages[i].dest);
if (pages[i].dest.top < workSrcRect.bottom)
QOffsetRect(&pages[i].dest, 0, starFallSpeed);
2019-11-11 00:11:59 -05:00
}
if (angelDest.left <= (workSrcRect.right + 2))
{
CopyMask((BitMap *)*GetGWorldPixMap(angelSrcMap),
(BitMap *)*GetGWorldPixMap(angelMaskMap),
(BitMap *)*GetGWorldPixMap(workSrcMap),
&angelSrcRect, &angelSrcRect, &angelDest);
angelDest.left -= kAngelSpeed;
2019-11-11 00:11:59 -05:00
AddRectToWorkRectsWhole(&angelDest);
angelDest.left += kAngelSpeed;
2019-11-11 00:11:59 -05:00
AddRectToBackRects(&angelDest);
QOffsetRect(&angelDest, kAngelSpeed, 0);
2019-11-11 00:11:59 -05:00
pass = 0;
}
CopyRectsQD();
numWork2Main = 0;
numBack2Work = 0;
do
{
2020-01-05 16:41:04 -05:00
const KeyDownStates *theKeys = PortabilityLayer::InputManager::GetInstance()->GetKeys();
if ((theKeys->IsSet(PL_KEY_EITHER_SPECIAL(kControl))) || (theKeys->IsSet(PL_KEY_EITHER_SPECIAL(kAlt))) || (theKeys->IsSet(PL_KEY_EITHER_SPECIAL(kShift))))
2019-11-11 00:11:59 -05:00
noInteruption = false;
2019-12-31 03:55:17 -05:00
if (PortabilityLayer::EventQueue::GetInstance()->Dequeue(&theEvent))
{
if (theEvent.IsLMouseDownEvent() || theEvent.IsKeyDownEvent())
2019-11-11 00:11:59 -05:00
noInteruption = false;
2019-12-31 03:55:17 -05:00
}
2019-12-25 22:20:10 -05:00
Delay(1, nullptr);
2019-11-11 00:11:59 -05:00
}
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<65>
// 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<65>
// lost their last glider (died), not due to getting through the entire<72>
// house. This function initializes the strucures/variables.
void InitDiedGameOver (void)
{
#define kPageSpacing 40
#define kPageRightOffset 128
#define kPageBackUp 128
short i;
2019-12-29 06:38:18 -05:00
PLError_t theErr;
2019-11-11 00:11:59 -05:00
QSetRect(&pageSrcRect, 0, 0, 25, 32 * 8);
2019-12-29 06:38:18 -05:00
theErr = CreateOffScreenGWorld(&gameOverSrcMap, &pageSrcRect, kPreferredPixelFormat);
2019-12-30 20:53:11 -05:00
LoadGraphic(gameOverSrcMap, kLettersPictID);
2019-11-11 00:11:59 -05:00
QSetRect(&pageSrcRect, 0, 0, 32, 32 * kPageFrames);
2019-12-29 06:38:18 -05:00
theErr = CreateOffScreenGWorld(&pageSrcMap, &pageSrcRect, kPreferredPixelFormat);
2019-12-30 20:53:11 -05:00
LoadGraphic(pageSrcMap, kPagesPictID);
2019-11-11 00:11:59 -05:00
2019-12-29 06:38:18 -05:00
theErr = CreateOffScreenGWorld(&pageMaskMap, &pageSrcRect, GpPixelFormats::kBW1);
2019-12-30 20:53:11 -05:00
LoadGraphic(pageMaskMap, kPagesMaskID);
2019-11-11 00:11:59 -05:00
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.constrainedScreen);
QOffsetRect(&pages[i].dest, -thisMac.constrainedScreen.left, -thisMac.constrainedScreen.top);
2019-11-11 00:11:59 -05:00
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.constrainedScreen.right - thisMac.constrainedScreen.left) / -2,
(thisMac.constrainedScreen.right - thisMac.constrainedScreen.left) / -2);
2019-11-11 00:11:59 -05:00
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);
}
2019-11-11 00:11:59 -05:00
pagesStuck = 0;
stopPages = ((thisMac.constrainedScreen.bottom - thisMac.constrainedScreen.top) / 2) - 16;
2019-11-11 00:11:59 -05:00
}
//-------------------------------------------------------------- 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<6F>
// across the screen.
void DrawPages (void)
{
short i;
for (i = 0; i < 8; i++)
{
if (pages[i].stuck)
{
CopyBitsConstrained((BitMap *)*GetGWorldPixMap(gameOverSrcMap),
2019-11-11 00:11:59 -05:00
(BitMap *)*GetGWorldPixMap(workSrcMap),
&lettersSrc[i], &pages[i].dest,
srcCopy, &justRoomsRect);
2019-11-11 00:11:59 -05:00
}
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<65>
// lost their last glider (died), not due to getting through the entire<72>
// house.
void DoDiedGameOver (void)
{
2019-12-31 03:55:17 -05:00
TimeTaggedVOSEvent theEvent;
long nextLoop;
Boolean userAborted;
2019-11-11 00:11:59 -05:00
userAborted = false;
InitDiedGameOver();
CopyRectMainToWork(&workSrcRect);
CopyRectMainToBack(&workSrcRect);
FlushEvents(everyEvent, 0);
nextLoop = TickCount() + 2;
while (pagesStuck < 8)
{
HandlePages();
DrawPages();
do
{
2020-01-05 16:41:04 -05:00
const KeyDownStates *theKeys = PortabilityLayer::InputManager::GetInstance()->GetKeys();
if ((theKeys->IsSet(PL_KEY_EITHER_SPECIAL(kAlt))) || (theKeys->IsSet(PL_KEY_EITHER_SPECIAL(kControl))) || (theKeys->IsSet(PL_KEY_EITHER_SPECIAL(kShift))))
2019-11-11 00:11:59 -05:00
{
pagesStuck = 8;
userAborted = true;
}
2019-12-31 03:55:17 -05:00
if (PortabilityLayer::EventQueue::GetInstance()->Dequeue(&theEvent))
{
if (theEvent.IsLMouseDownEvent() || theEvent.IsKeyDownEvent())
2019-11-11 00:11:59 -05:00
{
pagesStuck = 8;
userAborted = true;
}
2019-12-31 03:55:17 -05:00
}
Delay(1, nullptr);
2019-11-11 00:11:59 -05:00
}
while (TickCount() < nextLoop);
nextLoop = TickCount() + 2;
}
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();
}