Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MoofWars/MoofWars.cp
/* |
File: MoofWars.cp |
Contains: All of the main game functions are defined in here, including initialization, |
tear-down and the actual game loop. |
Written by: Timothy Carroll |
Copyright: Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
7/2/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
4/2/97 Timothy Carroll Now dispose of the color table when we exit |
the game. Technically, we still end up leaking |
the appPalette, so this should be corrected if |
InitGame is called more than once. |
4/2/97 Timothy Carroll Now check DSpStartup error code. |
2/24/97 Timothy Carroll Now conditionally allocate QD globals if we aren't |
using Metrowerks |
1/23/97 Timothy Carroll allocate QuickDraw globals so that MrC will |
compile. |
1/23/97 Timothy Carroll Added include for Moofwars.h so that MrC will |
compile |
1/23/97 Timothy Carroll Now include other system headers so that MrC |
will compile. |
8/15/96 Timothy Carroll Initial Release |
*/ |
#if __profile__ |
#include <profiler.h> |
#endif |
#include <fp.h> |
#include <QuickDraw.h> |
#include <Fonts.h> |
#include <Sound.h> |
#include "Moofwars.h" |
#include "TTileGrid.h" |
#include "TSpriteCollection.h" |
#include "TShipSprite.h" |
#include "TEnemySprite.h" |
#include "TShotSprite.h" |
#if qShowTiming |
#include <Timer.h> |
#include <FixMath.h> |
#include <TextUtils.h> |
#endif |
/******************************************************************************** |
GLOBALS |
********************************************************************************/ |
// Quickdraw Globals |
#if TARGET_RT_MAC_CFM |
#ifndef __MWERKS__ |
QDGlobals qd; |
#endif |
#endif |
CTabHandle gAppColorTable = NULL; |
DSpContextReference gDrawContext = NULL; |
// We define a few static variables to hold all the game information. Only in a few cases |
// do we actually need to export this information to other functions. In general, if a |
// particular object needs a piece of information, it should be sent directly to that object, |
// rather than be imported as a global. |
// The playing field |
static TTileGrid *theGrid = NULL; |
WorldRect32 gWorldBounds; |
// All of the sprite groups |
static TSpriteCollection *gFriendlyShipGroup = NULL; |
static TSpriteCollection *gEnemyShipGroup = NULL; |
static TSpriteCollection *gFriendlyShotGroup = NULL; |
static TSpriteCollection *gEnemyShotGroup = NULL; |
// We keep track of the two ships separately as well, |
// as we can use them as the camera location |
static TShipSprite *gFriendlyShip = NULL; |
static TEnemySprite *gEnemyShip = NULL; |
// Although the sprites would load their own graphics (because of the magic of our TGraphic |
// collection, we can preload the graphics and pass them to the TSprite constructors for |
// speed. These variables will manage the loading and unloading of the sprites. |
TGraphicCollection *gShipGraphics = NULL; |
TGraphicCollection *gEnemyGraphics = NULL; |
TGraphicCollection *gShotGraphics = NULL; |
#if qUsingSound |
// Sounds |
SndReference gSounds[10]; |
Boolean gPlayingSound = true; // If false, no sounds will play |
#endif |
#if qShowTiming |
// Miscellaneous |
long gShotsOnBoard = 0; // Holds the total number of shots in game |
#endif |
// Holds the current state of the keyboard and other input devices when processing |
// the list of sprites. |
TInputState gCommandKeys; |
TCommandTimer theTimer; |
// A standard set of lookup tables in 16.16 fixed notation, so that we can quickly |
// do sin and cos. We currently use 48 frames because thats easy to do from |
// Specular Infini-D. 360/48 = 7.5¡ per angle. |
SInt32 gSinLookup[48]; |
SInt32 gCosLookup[48]; |
/******************************************************************************** |
GLOBALS |
********************************************************************************/ |
void main (void); |
// Initialize everything for the game |
static OSStatus InitGame (void); |
// Fills in the initial values in the lookup tables. |
static OSStatus InitAngleLookups (void); |
#if qUsingSound |
// Initializes Sound API and loads all the sound resources |
static OSStatus LoadSounds (void); |
#endif |
// This creates a draw sprocket context |
static OSStatus InitDrawSprocket (void); |
// This loads all of our graphics and tile resources |
static OSStatus LoadGameGraphics (void); |
// This creates the grid, the initial sprites and sprite groups. |
static OSStatus CreateGame (void); |
// The actual event loop |
static OSStatus RunGame (void); |
// The cleanup code for InitGame |
static OSStatus CloseGame (void); |
/******************************************************************************** |
main |
All main does is the standard mac init, followed by initializing the game |
and running it once. In a real game it would probably put up a splash screen |
with some widgets on it. |
********************************************************************************/ |
void main (void) |
{ |
int loop; |
OSStatus theErr = noErr; |
InitGraf(&qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(nil); |
InitCursor(); |
MaxApplZone(); |
for (loop = 0; loop < 30; loop++) |
MoreMasters(); |
theErr = InitGame(); |
FAIL_OSERR (theErr, "\pCouldn't initialize new game") |
theErr = RunGame(); |
FAIL_OSERR (theErr, "\pFailure in game running code") |
error: |
cleanup: |
theErr= CloseGame(); |
} |
/************************************************************************************ |
InitGame |
Init Game loads all the sprites and sets up all the variables for running a game. |
Eventually, we can split out a large number of these routines so that they only |
need to be called when the application actually initializes, rather than once per game. |
Of course, our loading routines are way cool, so we may not care. :) |
************************************************************************************/ |
OSStatus InitGame (void) |
{ |
OSStatus theErr = noErr; |
PaletteHandle appPalette; |
// Load our initial color table and make it the default palette for the entire application. |
// (We'll also send this color table to DrawSprocket) |
gAppColorTable = GetCTable (kAppColorTableResID); |
FAIL_NIL (gAppColorTable, "\pFailed to load the color table") |
appPalette = NewPalette (256, gAppColorTable, pmExplicit + pmTolerant, 0); |
FAIL_NIL (appPalette, "\pFailed to convert the color table into a palette") |
SetPalette ( (WindowRef) -1L, appPalette, false); |
// Initialize the sound effects |
#if qUsingSound |
theErr = LoadSounds(); |
FAIL_OSERR (theErr, "\pFailed to load the sounds") |
#endif |
// Initialize our predefined arrays of the move angles. |
theErr = InitAngleLookups(); |
FAIL_OSERR (theErr, "\pFailed to initialize the lookup tables") |
// Initialize the keyboard command routines. |
#if qSyncTiming |
theTimer.Initialize(30); // 30 frames per second |
#else |
theTimer.Initialize (0); // one command per frame, fast as possible. |
#endif |
// Create a draw sprocket context |
theErr = InitDrawSprocket (); |
FAIL_OSERR (theErr, "\pFailed to initialize draw sprocket") |
// Load the game graphics |
theErr = LoadGameGraphics(); |
FAIL_OSERR (theErr, "\pFailed to preload the game graphics") |
// Create all of the game objects -- note that the stuff in here is probably the only thing that |
// would be run more than once every time the application runs -- the rest of the initialization code |
// will all run once. |
theErr = CreateGame(); |
FAIL_OSERR (theErr, "\pFailed to create the game objects") |
return noErr; |
error: |
if (theErr == noErr) |
theErr = paramErr; |
return theErr; |
} |
/************************************************************************************ |
InitAngleLookups |
************************************************************************************/ |
OSStatus InitAngleLookups(void) |
{ |
int loop; |
for (loop = 0; loop < 48; loop++) |
{ |
double angle = (90 - loop * 7.5)/57.296; |
gSinLookup[loop] = (1<<14) * sin (angle); |
gCosLookup[loop] = (1<<14) * -cos (angle); |
} |
return noErr; |
} |
/************************************************************************************ |
LoadSounds |
This initializes whatever sound API we're using and loads all of the sound resources. |
************************************************************************************/ |
#if qUsingSound |
OSStatus LoadSounds (void) |
{ |
OSStatus theErr; |
// Initialize and load all of the game sounds. |
theErr = HY_Setup (kNormal, 5); |
FAIL_OSERR (theErr, "\p Failed to set up hollywood API") |
gSounds[0] = HY_GetSoundResource(6000); |
FAIL_NIL(gSounds[0], "\p Failed to allocate the sound resource") |
gSounds[1] = HY_GetSoundResource(6001); |
FAIL_NIL(gSounds[1], "\p Failed to allocate the sound resource") |
gSounds[2] = HY_GetSoundResource(6002); |
FAIL_NIL(gSounds[2], "\p Failed to allocate the sound resource") |
gSounds[3] = HY_GetSoundResource(6003); |
FAIL_NIL(gSounds[3], "\p Failed to allocate the sound resource") |
gSounds[4] = HY_GetSoundResource(6004); |
FAIL_NIL(gSounds[4], "\p Failed to allocate the sound resource") |
gSounds[5] = HY_GetSoundResource(6005); |
FAIL_NIL(gSounds[5], "\p Failed to allocate the sound resource") |
return noErr; |
error: |
if (theErr == noErr) |
theErr = paramErr; |
return theErr; |
} |
#endif |
/************************************************************************************ |
InitDrawSprocket |
************************************************************************************/ |
OSStatus InitDrawSprocket (void) |
{ |
OSStatus theErr = noErr; |
DSpContextAttributes screenData; |
RGBColor fade; |
// Create a Draw Sprocket context for the screen. |
theErr = DSpStartup(); |
FAIL_OSERR (theErr, "\pError: Failed to start up DrawSprocket") |
// fill in our requirements. Anything we place here we need to have for our game to work properly. |
screenData.frequency = 0; |
screenData.displayWidth = 640; |
screenData.displayHeight = 480; |
screenData.reserved1 = 0; |
screenData.reserved2 = 0; |
screenData.colorNeeds = kDSpColorNeeds_Require; |
screenData.colorTable = gAppColorTable; |
screenData.contextOptions = 0; |
screenData.backBufferDepthMask = kDSpDepthMask_8; |
screenData.displayDepthMask = kDSpDepthMask_8; |
screenData.backBufferBestDepth = 8; |
screenData.displayBestDepth = 8; |
screenData.pageCount = 2; |
screenData.gameMustConfirmSwitch = false; |
screenData.reserved3[0] = 0; |
screenData.reserved3[1] = 0; |
screenData.reserved3[2] = 0; |
screenData.reserved3[3] = 0; |
theErr = DSpUserSelectContext(&screenData, 0,NULL, &gDrawContext); |
FAIL_OSERR (theErr, "\p Failed to retrieve a drawing context") |
// We should now alter the screenData to reflect things that would be useful to have, but aren't |
// requirements. |
#if qUsePageFlip |
screenData.contextOptions |= kDSpContextOption_PageFlip; |
screenData.pageCount = 3; |
#endif |
#if (!qSyncToDrawVBL) |
screenData.contextOptions |= kDSpContextOption_DontSyncVBL; |
#endif |
// Reserve the screen and set it to active. |
theErr = DSpContext_Reserve (gDrawContext, &screenData); |
FAIL_OSERR (theErr, "\pFailed to reserve the context") |
#if 0 |
theErr = DSpContext_SetMaxFrameRate (gDrawContext, 60); |
FAIL_OSERR (theErr, "\p Failed to set the maximum frame rate") |
#endif |
fade = kBlack; // DrawSprocket requires this to be a non-const param |
theErr = DSpContext_FadeGammaOut (gDrawContext, &fade); |
FAIL_OSERR (theErr, "\p Failed to fade out") |
theErr = DSpContext_SetState (gDrawContext, kDSpContextState_Active); |
FAIL_OSERR (theErr, "\pFailed to activate the draw context") |
theErr = DSpContext_FadeGammaIn (gDrawContext, &fade); |
FAIL_OSERR (theErr, "\p Failed to fade in") |
return noErr; |
error: |
if (theErr == noErr) |
theErr = paramErr; |
return theErr; |
} |
/************************************************************************************ |
LoadGameGraphics |
************************************************************************************/ |
OSStatus LoadGameGraphics (void) |
{ |
OSStatus theErr = noErr; |
// Preload and lock all of our game's graphics so that everything runs smoothly. |
gShipGraphics = TGraphicCollection::NewCollection (kShipResourceID); |
FAIL_NIL (gShipGraphics, "\pcouldn't load friendly ship graphics") |
gShipGraphics->LockCollection(); |
gShotGraphics = TGraphicCollection::NewCollection (kShotResourceID); |
FAIL_NIL (gShotGraphics, "\pcouldn't load friendly shot graphics") |
gShotGraphics->LockCollection(); |
// This version uses the same graphics for the enemy and friendly units, but you can |
// insert your own favorite graphics instead. |
#if 0 |
gEnemyGraphics = TGraphicCollection::NewCollection (kEnemyResourceID); |
FAIL_NIL (gEnemyGraphics, "\pcouldn't load enemy graphics") |
gEnemyGraphics->LockCollection(); |
#endif |
return noErr; |
error: |
if (theErr == noErr) |
theErr = paramErr; |
return theErr; |
} |
/************************************************************************************ |
CreateGame |
************************************************************************************/ |
OSStatus CreateGame (void) |
{ |
OSStatus theErr = noErr; |
Rect boundsRect = {0,0, 480, 640}; |
TShipSpriteData shipData; |
TEnemySpriteData enemyData; |
// Load the Grid and Tiles. Note that we do load the tile graphics here as well -- |
// we could move that to LoadGameGraphics if we wanted. |
// Load the tile grid information |
theGrid = new TTileGrid(); |
theErr = theGrid->CreateGridFromResource(kGridResourceID); |
FAIL_OSERR (theErr, "\p Failed to load the grid resource") |
// Initialize the world boundaries in 16.16 fixed point coordinates. |
gWorldBounds.left = 0; |
gWorldBounds.top = 0; |
gWorldBounds.right = theGrid->GetGridWidth() * (32 << 16); |
gWorldBounds.bottom = theGrid->GetGridHeight() * (32 << 16); |
// Create groups for all of our game's sprites |
gFriendlyShipGroup = new TSpriteCollection (); |
FAIL_NIL (gFriendlyShipGroup, "\pcouldn't create friendly ship group") |
gEnemyShipGroup = new TSpriteCollection (); |
FAIL_NIL (gEnemyShipGroup, "\pcouldn't create enemy ship group") |
gFriendlyShotGroup = new TSpriteCollection (); |
FAIL_NIL (gFriendlyShotGroup, "\pcouldn't create friendly shot group") |
gEnemyShotGroup = new TSpriteCollection (); |
FAIL_NIL (gEnemyShotGroup, "\pcouldn't create enemy shot group") |
// Create the good guy ship |
shipData.spriteData.spriteType = TShipSprite::kSpriteType; |
shipData.spriteData.initialX = (100) << 16; |
shipData.spriteData.initialY = (100) << 16; |
shipData.spriteData.initialXVelocity = 0; |
shipData.spriteData.initialYVelocity = 0; |
shipData.spriteData.visibility = kVisible; |
shipData.spriteData.face = 0; |
shipData.spriteData.collectionID = 1000; |
shipData.spriteData.preloadedCollection = gShipGraphics; |
shipData.rotateInterval = 1; |
shipData.shotInterval = 1; |
shipData.shotsGroup = gFriendlyShotGroup; |
gFriendlyShip = new TShipSprite(&shipData); |
gFriendlyShip->AddToGroup (gFriendlyShipGroup); |
// Create the enemy ship |
// We are using the same graphics here, but this can be changed if you want |
// a separate villain. |
enemyData.spriteData.spriteType = TEnemySprite::kSpriteType; |
enemyData.spriteData.initialX = (1200) << 16; |
enemyData.spriteData.initialY = (1200) << 16; |
enemyData.spriteData.initialXVelocity = 0; |
enemyData.spriteData.initialYVelocity = 0; |
enemyData.spriteData.visibility = kVisible; |
enemyData.spriteData.face = 0; |
enemyData.spriteData.collectionID = 1000; |
enemyData.spriteData.preloadedCollection = gShipGraphics; |
enemyData.rotateInterval = 1; |
enemyData.shotInterval = 1; |
enemyData.shotsGroup = gEnemyShotGroup; |
gEnemyShip = new TEnemySprite(&enemyData); |
gEnemyShip->AddToGroup (gEnemyShipGroup); |
return noErr; |
error: |
if (theErr == noErr) |
theErr = paramErr; |
return theErr; |
} |
OSStatus RunGame (void) |
{ |
// Is game currently running? |
Boolean running = true; |
// We need a separate boolean to determine is the sound key is still being held down -- if it is, we |
// don't toggle. Otherwise we'd keep turning the sound off and on. |
Boolean soundKeyDown = false; |
OSStatus theErr = noErr; |
//DrawSprocket will return us a CGrafPtr to draw into. |
CGrafPtr buffer; |
//The center of the tile grid is tracked by a camera position. In this version of the code, this |
//position is identical to the ship, but it could actually be any arbitrary point. Missile-CAM! |
SInt32 cameraX, cameraY; |
SInt32 tileTop, tileLeft; |
Rect clipping = {0,0,480,640}; |
#if qShowTiming |
UnsignedWide startMicroSec, endMicroSec; |
Str255 theString; |
long frame; |
#endif |
// We play a beep to signal the start of the game. |
SysBeep(2); |
HideCursor(); |
// Basic structure of the game loop is: |
// * erase all sprites |
// * draw all sprites in their new locations |
// * refresh the screen |
// * move and hit test the sprites based on any queued commands. |
// Erasing and drawing is relative to a clipping rectangle and a graphics scale. |
// If at all possible, keep different clipping areas in the game from overlapping. |
// failing that, do all erases in all clip areas before any sprites are drawn. |
// For the current version (fixed map), all scaling data is constant, so we can |
// set it once and ignore it. If we are changing the scaling data, then we need to |
// move this section into the loop. Note that scaling data will be different |
// for erases and draws in that case. |
// Set the initial camera location. |
gFriendlyShip->GetCurrentWorldLocation(&cameraX, &cameraY); |
#if __profile__ |
ProfilerInit(collectDetailed, PPCTimeBase, 200, 30); |
#endif |
#if qShowTiming |
Microseconds(&startMicroSec); |
#endif |
#if qSyncTiming |
theTimer.AcceptCommands(true); |
#endif |
while (running) |
{ |
/************* Point at the Current Buffer ***************************/ |
theErr = DSpContext_GetBackBuffer( gDrawContext,kDSpBufferKind_Normal, &buffer ); |
#if qDebugging |
FAIL_OSERR(theErr, "\p Failed to retrieve a drawing surface.") |
#endif |
SetPort ((GrafPtr) buffer); |
SetDestinationBuffer (buffer->portPixMap, NULL); |
/************* Set the camera location ***************************/ |
gFriendlyShip->GetCurrentWorldLocation(&cameraX, &cameraY); |
SetBufferClip (&clipping); |
SetWorldOrigin(cameraX, cameraY); |
/************* Draw the Tile Grid ************************/ |
tileLeft = (cameraX >> 16) - 320; |
tileTop = (cameraY >> 16) - 240; |
theGrid->DrawGrid (&clipping, tileTop,tileLeft); |
/************** Show the time to draw the current frame *******/ |
#if qShowTiming |
Microseconds(&endMicroSec); |
WideSubtract((wide *) &endMicroSec, (wide *) &startMicroSec); |
Microseconds(&startMicroSec); // start timing the next frame |
frame = 1000000.0/endMicroSec.lo; |
RGBForeColor (&kWhite); |
NumToString (frame, theString); |
MoveTo (10,470); |
DrawString (theString); |
NumToString (gShotsOnBoard, theString); |
MoveTo (10, 450); |
DrawString (theString); |
RGBForeColor (&kBlack); |
#endif |
/************* Draw all the sprites ***************/ |
gEnemyShipGroup->DrawSpriteGroup (); |
gFriendlyShipGroup->DrawSpriteGroup (); |
gEnemyShotGroup->DrawSpriteGroup (); |
gFriendlyShotGroup->DrawSpriteGroup (); |
/************* Refresh the screen ***************/ |
theErr = DSpContext_SwapBuffers( gDrawContext, NULL, NULL); |
#if qDebugging |
FAIL_OSERR (theErr,"\p Failed to swap the buffers.") |
#endif |
/************* Process Commands *************************************/ |
// If we are syncing our timing, we'll make sure we have at least one command to process, |
// and then loop until all of the commands are completed. Otherwise we just grab one key |
// state and call through the loop once. |
#if qSyncTiming |
// Wait for a command to actually show up |
while (!theTimer.IsCommandWaiting()) |
; |
// Process all waiting commands. |
while (theTimer.RetrieveCommand (&gCommandKeys)) |
#else |
theTimer.RetrieveCommand (&gCommandKeys); |
#endif |
{ |
gFriendlyShipGroup->ProcessSpriteGroup(); |
gEnemyShipGroup->ProcessSpriteGroup(); |
gFriendlyShotGroup->ProcessSpriteGroup(); |
gEnemyShotGroup->ProcessSpriteGroup(); |
gFriendlyShotGroup->HitTest (gEnemyShipGroup); |
gEnemyShotGroup->HitTest (gFriendlyShipGroup); |
// Check for exit game |
if (CheckKey ((unsigned char *) &gCommandKeys, kExitGame)) |
running = false; |
// Check for debugger break |
if (CheckKey ((unsigned char *) &gCommandKeys, kDebugger)) |
{ |
FlushEvents (everyEvent,0); |
Debugger(); |
} |
#if qUsingSound |
// Give the sound API some time to service tasks. |
HY_ServiceTasks(); |
// play some sounds. |
if (CheckKey ((unsigned char *) &gCommandKeys, kOne) && gPlayingSound) |
{ |
HY_PlaySoundHandle (1, gSounds[0], NULL, 0, false); |
} |
if (CheckKey ((unsigned char *) &gCommandKeys, kTwo) && gPlayingSound) |
{ |
HY_PlaySoundHandle (1, gSounds[1], NULL, 0, false); |
} |
if (CheckKey ((unsigned char *) &gCommandKeys, kThree) && gPlayingSound) |
{ |
HY_PlaySoundHandle (1, gSounds[2], NULL, 0, false); |
} |
if (CheckKey ((unsigned char *) &gCommandKeys, kFour) && gPlayingSound) |
{ |
HY_PlaySoundHandle (1, gSounds[3], NULL, 0, false); |
} |
// toggle the sound setting |
if (CheckKey ((unsigned char *) &gCommandKeys,kSoundToggle)) |
{ |
if (!soundKeyDown) |
{ |
soundKeyDown = true; |
gPlayingSound = !gPlayingSound; |
if (!gPlayingSound) |
{ |
HY_StopSample(1); |
HY_StopSample(2); |
HY_StopSample(3); |
HY_StopSample(4); |
} |
} |
} |
else |
{ |
soundKeyDown = false; |
} |
#endif |
} |
} |
#if __profile__ |
ProfilerSetStatus(false); |
ProfilerDump("\pMoofWarsDump"); |
ProfilerTerm(); |
#endif |
ShowCursor(); |
// We want to flush all the keyboard events we haven't been taking. |
theTimer.AcceptCommands (false); |
FlushEvents(everyEvent, 0); |
return noErr; |
#if qDebugging |
error: |
return theErr; |
#endif |
} |
OSStatus CloseGame (void) |
{ |
// This doesn't clean up everything just yet, but it should! |
if (gFriendlyShipGroup != NULL) |
{ |
delete gFriendlyShipGroup; |
gFriendlyShipGroup = NULL; |
} |
if (gEnemyShipGroup != NULL) |
{ |
delete gEnemyShipGroup; |
gEnemyShipGroup = NULL; |
} |
if (gFriendlyShotGroup != NULL) |
{ |
delete gFriendlyShotGroup; |
gFriendlyShotGroup = NULL; |
} |
if (gEnemyShotGroup != NULL) |
{ |
delete gEnemyShotGroup; |
gEnemyShotGroup = NULL; |
} |
if (theGrid != NULL) |
{ |
delete theGrid; |
theGrid = NULL; |
} |
if (gShipGraphics != NULL) |
{ |
gShipGraphics->DisposeReference; |
gShipGraphics = NULL; |
} |
if (gShotGraphics != NULL) |
{ |
gShotGraphics->DisposeReference; |
gShotGraphics = NULL; |
} |
if (gDrawContext != NULL) |
{ |
DSpContext_SetState (gDrawContext, kDSpContextState_Inactive); |
DSpContext_Release( gDrawContext); |
DSpShutdown(); |
} |
if (gAppColorTable) |
DisposeCTable (gAppColorTable); |
return noErr; |
} |
Boolean CheckKey (unsigned char *PtrToKeyMap, short theKey) |
{ |
unsigned char theByte, theBit; |
short byteIndex; |
byteIndex = theKey >> 3; |
theByte = *(unsigned char *)(PtrToKeyMap + byteIndex); |
theBit = 1L<<(theKey & 7); |
return (theByte & theBit); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-14