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.
Source/SpaceInvaders.c
//¥ ------------------------------------------------------------------------------------------ ¥ |
//¥ |
//¥ Copyright ©1995, Chris De Salvo |
//¥ Not to be distributed without expressed consent |
//¥ |
//¥ Written by Chris De Salvo |
//¥ |
//¥ ------------------------------------------------------------------------------------------ ¥ |
//¥ ------------------------------ Includes |
#include <Fonts.h> |
#include <stdio.h> |
#include <string.h> |
#include "ErrorHandler.h" |
#include "EventHandler.h" |
#include "GameObject.h" |
#include "Graphics.h" |
#include "ObjectActions.h" |
#include "SIResources.h" |
#include "SoundHandler.h" |
#include "SpaceInvaders.h" |
#include "Sprite.h" |
#include "NetSprocketSupport.h" |
#include "CommonStuff.h" |
//¥ ------------------------------ Private Definitions |
//#define RAND(x) ((Random() & 0x7FFF) % (x)) |
#define kPlayerVelocity 2L //¥ Speed at which player moves |
#define kPlayerShotVelocity 6L //¥ Speed at which player shots travel |
#define kPointsVelocity -2L //¥ Vertical speed of the "points" object (negative is up) |
#define kEnemyVelocity 5L //¥ Speed at which enemies move |
#define kEnemyShotVelocity 4L //¥ Speed at which enemy shots drop |
#define kEnemyOffset 8 //¥ Space between columns of enemies |
//¥ ------------------------------ Private Types |
enum |
{ |
scPlayer, |
scPlayer2, |
scPlayerShot, |
scPoints, |
scEnemy, |
scEnemyShot, |
scNumSprites |
}; |
//¥ ------------------------------ Private Variables |
static SpritePtr gSpriteCache[scNumSprites]; //¥ Sprite artwork is cached here so that multiple items using |
//¥ the same artwork only need one copy. |
static long gScore; |
static short gWave; |
static short gEnemyGas; |
static int gEnemyNewDirection; |
static unsigned long gFrameRateBaseTime; //¥ Base time for this game to count frame rate |
float gGreenAccum; |
float gRedAccum; |
extern int gMyRand; |
extern int gHisRand; |
extern int gMyCallsToRand; |
extern int gHisCallsToRand; |
//¥ ------------------------------ Private Functions |
static void AddPlayers(void); |
static void AddEnemies(void); |
static void CollideShotsToEnemies(void); |
static void AddPoints(short x, short y); |
static void DisplayGameOver(CGrafPtr backBuff); |
static void DropEnemies(void); |
static void CollideShotsToPlayers(void); |
static void AdvanceEnemies(void); |
static void DisplayFrameRate(void); |
static void EndGame(CGrafPtr backBuff); |
static void GetGreenInput(void); |
static void GetRedInput(void); |
//¥ ------------------------------ Public Variables |
Boolean gGameInProgress = false; |
Boolean gTwoPlayers = false; |
GameObjectPtr gEnemyList = nil; |
GameObjectPtr gEnemyShotList = nil; |
GameObjectPtr gPlayerList = nil; |
GameObjectPtr gGreenPlayerShotList = nil; |
GameObjectPtr gRedPlayerShotList = nil; |
GameObjectPtr gMiscObjectList = nil; |
int gEnemyTask; |
int gEnemiesChangeDirection; |
short gEnemyVelocity; |
short gNumEnemies; |
unsigned long gEnemyLevel; |
unsigned long gNumEnemiesProcessed; |
int gNumGreenPlayerLives = 0; |
int gNumRedPlayerLives = 0; |
Boolean gNetPlay; |
extern Boolean gReceivedInput; |
//¥ -------------------- InitNewGame |
static void InitNewRound(short wave) |
{ |
GameObjectDisposeList(&gEnemyList); |
GameObjectDisposeList(&gEnemyShotList); |
GameObjectDisposeList(&gPlayerList); |
GameObjectDisposeList(&gGreenPlayerShotList); |
GameObjectDisposeList(&gRedPlayerShotList); |
GameObjectDisposeList(&gMiscObjectList); |
AddPlayers(); |
AddEnemies(); |
gEnemyTask = kEnemyMovingRight; |
gEnemiesChangeDirection = 0; |
gEnemyVelocity = kEnemyVelocity; |
gEnemyLevel = 1; |
gWave = wave; |
} |
static void NextRound(void) |
{ |
InitNewRound(gWave + 1); |
} |
void |
InitNewGame(short wave) |
{ |
int i; |
for (i = 0; i < numInputs; i++) |
ISpElement_Flush(gInputElements[i]); |
gGreenAccum = 0; |
gRedAccum = 0; |
gGameInProgress = true; |
gScore = 0L; |
gFrameRateBaseTime = 0L; |
for (i = 0; i < scNumSprites; i++) |
SpriteDispose(&(gSpriteCache[i])); |
gSpriteCache[scPlayer] = SpriteLoad(kSPRTPlayer); |
if (! gSpriteCache[scPlayer]) |
FatalError("Could not load player tank."); |
gSpriteCache[scPlayer2] = SpriteLoad(kSPRTPlayer2); |
if (! gSpriteCache[scPlayer]) |
FatalError("Could not load player 2 tank."); |
gSpriteCache[scPlayerShot] = SpriteLoad(kSPRTPlayerShot); |
if (! gSpriteCache[scPlayerShot]) |
FatalError("Could not load player shot."); |
gSpriteCache[scPoints] = SpriteLoad(kSPRTPoints); |
if (! gSpriteCache[scPoints]) |
FatalError("Could no load points."); |
gSpriteCache[scEnemy] = SpriteLoad(kSPRTEnemy); |
if (! gSpriteCache[scEnemy]) |
FatalError("Could no load enemy."); |
gSpriteCache[scEnemyShot] = SpriteLoad(kSPRTEnemyShot); |
if (! gSpriteCache[scEnemyShot]) |
FatalError("Could no load enemy shot."); |
gNumGreenPlayerLives = 3; |
if (gTwoPlayers) |
gNumRedPlayerLives = 3; |
else |
gNumRedPlayerLives = 0; |
GraphicsActive(); |
ISpResume(); |
InitNewRound(wave); |
} |
//¥ -------------------- GameLoop |
void |
GameLoop() |
{ |
CGrafPtr backBuff; |
ISpElementEvent event; |
Boolean wasEvent; |
if (gNetPlay) |
{ |
if (gIAmHost) |
{ |
GetGreenInput(); |
SendInputState(gGameKeys.greenLeft, gGameKeys.greenRight, gGameKeys.greenFire); |
GetRedInput(); |
} |
else |
{ |
GetRedInput(); |
SendInputState(gGameKeys.redLeft, gGameKeys.redRight, gGameKeys.redFire); |
GetGreenInput(); |
} |
} |
else |
{ |
GetGreenInput(); |
if (gTwoPlayers) |
GetRedInput(); |
} |
//¥ Perform player/missile collission detection |
CollideShotsToEnemies(); |
CollideShotsToPlayers(); |
//¥ If any enemy hit a boundry on the last run, switch directions |
if (gEnemiesChangeDirection) |
{ |
DropEnemies(); |
gEnemiesChangeDirection = 0; |
gEnemyTask = kEnemyDropping; |
} |
gEnemyGas = gWave + 1; |
//¥ Get a reference to the back buffer |
DSpContext_GetBackBuffer(gDisplayContext, kDSpBufferKind_Normal, &backBuff); |
//¥ Check the abort key |
ISpElement_GetNextEvent(gInputElements[abort], sizeof (event), &event, &wasEvent); |
if (gGotEndGameMessage || (wasEvent && (event.data == kISpButtonDown))) |
{ |
if (gNetPlay && !gGotEndGameMessage) |
SendEndGame(); |
EndGame(backBuff); |
return; |
} |
//¥ Have all game objects perform their actions |
AdvanceEnemies(); |
GameObjectListAdvance(gPlayerList); |
GameObjectListAdvance(gEnemyShotList); |
GameObjectListAdvance(gGreenPlayerShotList); |
GameObjectListAdvance(gRedPlayerShotList); |
GameObjectListAdvance(gMiscObjectList); |
//¥ Draw all game objects |
GameObjectListDraw(gEnemyList, backBuff); |
GameObjectListDraw(gPlayerList, backBuff); |
GameObjectListDraw(gEnemyShotList, backBuff); |
GameObjectListDraw(gGreenPlayerShotList, backBuff); |
GameObjectListDraw(gRedPlayerShotList, backBuff); |
GameObjectListDraw(gMiscObjectList, backBuff); |
//¥ Check for end of wave/game |
if ((gNumGreenPlayerLives < 1) && (gNumRedPlayerLives < 1)) |
{ |
EndGame(backBuff); |
return; |
} |
if (gNumEnemies < 1) |
{ |
NextRound(); |
} |
//¥ Update the frame rate display information |
DisplayFrameRate(); |
//¥ Redraw the entire screen. This is done last so that if the game over screen was drawn it gets blit for free |
GraphicsUpdateScreen(); |
} |
static Boolean GetAutoFireButton(ISpElementReference inElement) |
{ |
OSStatus error; |
UInt32 input; |
Boolean wasEvent; |
Boolean fire = false; |
// poll |
error = ISpElement_GetSimpleState(inElement, &input); |
if (!error && (input == kISpButtonDown)) |
{ fire = true; } |
// but don't miss fast clicks or macros |
do |
{ |
ISpElementEvent event; |
error = ISpElement_GetNextEvent(inElement, sizeof(ISpElementEvent), &event, &wasEvent); |
if (!error && wasEvent && (event.data == kISpButtonDown)) |
{ |
fire = true; |
break; |
} |
} while(wasEvent && !error); |
// flush the queue |
ISpElement_Flush(inElement); |
return fire; |
} |
void GetGreenInput(void) |
{ |
UInt32 input; |
if (!gNetPlay || (gNetPlay && gIAmHost)) // in netplay, the host is the green player, and the joiner the red |
{ |
//¥ Check the movement axis |
ISpElement_GetSimpleState(gInputElements[greenMovement], &input); |
gGameKeys.greenLeft = false; |
gGameKeys.greenRight = false; |
if (input < 0x2FFFFFFF) |
{ gGameKeys.greenLeft = true; } |
else if (input > 0xBFFFFFFF) |
{ gGameKeys.greenRight = true; } |
else if (input < 0x5FFFFFFF) |
{ |
gGreenAccum += ((float) input - (float) 0x5FFFFFFF) / (float) 0x3FFFFFFF; |
if (gGreenAccum < -1) { gGameKeys.greenLeft = true; gGreenAccum += 1; } |
} |
else if (input > 0x9FFFFFFF) |
{ |
gGreenAccum += ((float) input - (float) 0x9FFFFFFF) / (float) 0x3FFFFFFF; |
if (gGreenAccum > 1) { gGameKeys.greenRight = true; gGreenAccum -= 1; } |
} |
//¥ Check the fire button |
gGameKeys.greenFire = GetAutoFireButton(gInputElements[greenFire]); |
} |
else if (gNetPlay && !gIAmHost) //wait for player 1's input |
{ |
gReceivedInput = false; |
while (!gReceivedInput && !gGotEndGameMessage) |
HandleNetworking(); |
} |
} |
void GetRedInput(void) |
{ |
UInt32 input; |
if (!gNetPlay || (gNetPlay && !gIAmHost)) // in netplay, the host is the green player, and the joiner the red |
{ |
//¥ Check the movement axis |
ISpElement_GetSimpleState(gInputElements[redMovement], &input); |
gGameKeys.redLeft = false; |
gGameKeys.redRight = false; |
if (input < 0x3FFFFFFF) |
{ gGameKeys.redLeft = true; } |
else if (input > 0xAFFFFFFF) |
{ gGameKeys.redRight = true; } |
else if (input < 0x5FFFFFFF) |
{ |
gRedAccum += ((float) input - (float) 0x5FFFFFFF) / (float) 0x2FFFFFFF; |
if (gRedAccum < -1) { gGameKeys.redLeft = true; gRedAccum += 1; } |
} |
else if (input > 0x9FFFFFFF) |
{ |
gRedAccum += ((float) input - (float) 0x9FFFFFFF) / (float) 0x2FFFFFFF; |
if (gRedAccum > 1) { gGameKeys.redRight = true; gRedAccum -= 1; } |
} |
//¥ Check the fire button |
gGameKeys.redFire = GetAutoFireButton(gInputElements[redFire]); |
} |
else if (gNetPlay && gIAmHost) //wait for player 2's input |
{ |
gReceivedInput = false; |
while (!gReceivedInput && !gGotEndGameMessage) |
HandleNetworking(); |
} |
} |
//¥ -------------------- AddPlayers |
static void |
AddPlayers(void) |
{ |
Rect r; |
GameObjectPtr go; |
go = GameObjectAllocate(); |
if (! go) |
FatalError("Could not allocate player object."); |
GameObjectAddToList(&gPlayerList, go); |
SetRect(&r, 20, 0, 620, 0); |
GameObjectSetBounds(go, &r); |
GameObjectSetSprite(go, gSpriteCache[scPlayer]); |
go->kind = objectGreenPlayer; |
go->screenX = 20; |
go->screenY = 412; |
go->velocityH = kPlayerVelocity; |
go->velocityV = 0; |
go->action = GreenPlayerAction; |
//¥ Sloppy way to do this, but hey, I'm in a hurry |
if (gTwoPlayers) |
{ |
go = GameObjectAllocate(); |
if (! go) |
FatalError("Could not allocate player 2 object."); |
GameObjectAddToList(&gPlayerList, go); |
SetRect(&r, 20, 0, 620, 0); |
GameObjectSetBounds(go, &r); |
GameObjectSetSprite(go, gSpriteCache[scPlayer2]); |
go->kind = objectRedPlayer; |
go->screenX = 640 - 20; |
go->screenY = 412; |
go->velocityH = kPlayerVelocity; |
go->velocityV = 0; |
go->action = RedPlayerAction; |
} |
} |
//¥ -------------------- AddEnemies |
static void |
AddEnemies(void) |
{ |
Rect r; |
GameObjectPtr go; |
int i, j; |
int w, h; |
int x, x2, y; |
gNumEnemies = 0; |
//¥ Find dimensions of enemy sprite so we can center the rows to begin with |
w = SpriteWidth(gSpriteCache[scEnemy], 0); |
w += kEnemyOffset; |
h = SpriteHeight(gSpriteCache[scEnemy], 0); |
h += kEnemyOffset; |
x2 = w * kNumEnemyColumns; |
x2 = 320 - (x2 / 2); |
y = 100; |
SetRect(&r, 20, 20, 620, 400); |
for (i = 0; i < kNumEnemyRows; i++) |
{ |
x = x2; |
for (j = 0; j < kNumEnemyColumns; j++) |
{ |
go = GameObjectAllocate(); |
if (! go) |
FatalError("Could not allocate enemy object."); |
GameObjectAddToList(&gEnemyList, go); |
GameObjectSetBounds(go, &r); |
GameObjectSetSprite(go, gSpriteCache[scEnemy]); |
go->kind = objectEnemy; |
go->screenX = x; |
go->screenY = y; |
go->velocityH = kEnemyVelocity; |
go->velocityV = 0; |
go->action = EnemyAction; |
x += w; |
gNumEnemies++; |
} |
y += h; |
} |
} |
//¥ -------------------- PlayerShoot |
void |
PlayerShoot(GameObjectPtr whichPlayer) |
{ |
Rect r; |
GameObjectPtr go; |
GameObjectPtr shotList; |
if (whichPlayer->kind == objectGreenPlayer) |
{ |
if (gGreenPlayerShotList) |
return; |
else |
shotList = gGreenPlayerShotList; |
} |
else |
{ |
if (gRedPlayerShotList) |
return; |
else |
shotList = gRedPlayerShotList; |
} |
SoundHandlerPlay(soundPlayerFire, whichPlayer->screenX, whichPlayer->screenY); |
go = GameObjectAllocate(); |
if (! go) |
FatalError("Could not allocate player shot."); |
GameObjectAddToList(&shotList, go); |
SetRect(&r, 20, 0, 620, 0); |
GameObjectSetBounds(go, &r); |
GameObjectSetSprite(go, gSpriteCache[scPlayerShot]); |
go->screenX = whichPlayer->screenX; |
go->screenY = whichPlayer->screenY - SpriteHeight(whichPlayer->sprite, whichPlayer->frame) - 1; |
go->velocityH = 0; |
go->velocityV = kPlayerShotVelocity; |
go->action = PlayerShotAction; |
if (whichPlayer->kind == objectRedPlayer) |
{ |
go->kind = objectRedPlayerShot; |
if (! gRedPlayerShotList) |
gRedPlayerShotList = shotList; |
} |
else |
{ |
go->kind = objectGreenPlayerShot; |
if (! gGreenPlayerShotList) |
gGreenPlayerShotList = shotList; |
} |
} |
//¥ -------------------- CollideShotsToEnemies |
static void |
CollideShotsToEnemies() |
{ |
GameObjectPtr shot; |
GameObjectPtr target; |
if (! gEnemyList) |
return; |
//¥ Iterate over the green player shots |
if (gGreenPlayerShotList) |
{ |
for (shot = gGreenPlayerShotList; shot; shot = shot->next) |
{ |
//¥ Iterate over the enemies |
for (target = gEnemyList; target; target = target->next) |
{ |
Rect u; //¥ Union of shot and enemy screen rects |
SectRect(&shot->screenRect, &target->screenRect, &u); |
if (! EmptyRect(&u)) |
{ |
SoundHandlerPlay(soundEnemyHit, target->screenX, target->screenY); |
shot->action = PlayerShotDestroy; |
target->action = EnemyDestroy; |
AddPoints(target->screenX, target->screenY); |
} |
} |
} |
} |
//¥ Iterate over the red player shots |
if (gRedPlayerShotList) |
{ |
for (shot = gRedPlayerShotList; shot; shot = shot->next) |
{ |
//¥ Iterate over the enemies |
for (target = gEnemyList; target; target = target->next) |
{ |
Rect u; //¥ Union of shot and enemy screen rects |
SectRect(&shot->screenRect, &target->screenRect, &u); |
if (! EmptyRect(&u)) |
{ |
SoundHandlerPlay(soundEnemyHit, target->screenX, target->screenY); |
shot->action = PlayerShotDestroy; |
target->action = EnemyDestroy; |
AddPoints(target->screenX, target->screenY); |
} |
} |
} |
} |
} |
//¥ -------------------- CollideShotsToPlayers |
static void |
CollideShotsToPlayers(void) |
{ |
GameObjectPtr shot; |
GameObjectPtr target; |
GameObjectPtr next; |
if (! gEnemyShotList || ! gPlayerList) |
return; |
target = gPlayerList; |
next = target->next; |
while (target != nil) |
{ |
if (target->refCon > 0) |
return; |
//¥ Iterate over the enemy shots |
for (shot = gEnemyShotList; shot; shot = shot->next) |
{ |
Rect u; //¥ Union of shot and enemy screen rects |
SectRect(&shot->screenRect, &target->screenRect, &u); |
if (! EmptyRect(&u)) |
{ |
SoundHandlerPlay(soundPlayerHit,target->screenX, target->screenY); |
shot->action = EnemyShotDestroy; |
target->action = PlayerDestroy; |
if (target->kind == objectGreenPlayer) |
{ |
gNumGreenPlayerLives--; |
if (gNumGreenPlayerLives < 1) |
GameObjectRemoveFromList(&gPlayerList, target); |
} |
else |
{ |
gNumRedPlayerLives--; |
if (gNumRedPlayerLives < 1) |
GameObjectRemoveFromList(&gPlayerList, target); |
} |
} |
} |
target = next; |
next = target->next; |
} |
} |
//¥ -------------------- AddPoints |
static void |
AddPoints(short x, short y) |
{ |
Rect r; |
GameObjectPtr go; |
gScore += 100L; |
go = GameObjectAllocate(); |
if (! go) |
FatalError("Could not allocate player shot."); |
GameObjectAddToList(&gMiscObjectList, go); |
SetRect(&r, 0, 0, 640, 440); |
GameObjectSetBounds(go, &r); |
GameObjectSetSprite(go, gSpriteCache[scPoints]); |
go->screenX = x; |
go->screenY = y; |
go->velocityH = 0; |
go->velocityV = kPointsVelocity; |
go->action = PointsAction; |
} |
//¥ -------------------- DisplayGameOver |
static void |
DisplayGameOver(CGrafPtr backBuff) |
{ |
GrafPtr oldPort; |
Str255 str = "\pGame Over!"; |
short width; |
short offset; |
GetPort(&oldPort); |
SetPort((GrafPtr) backBuff); |
TextFont(geneva); |
TextFace(bold); |
TextSize(48); |
//¥ Find the width of our string |
width = StringWidth(str); |
//¥ Find an offset that will center the string in the buffer |
offset = backBuff->portRect.right - backBuff->portRect.left; |
offset /= 2; |
offset -= width / 2; |
MoveTo(offset, 200); |
RGBForeColor(&rgbYellow); |
DrawString(str); |
MoveTo(offset - 2, 200); |
RGBForeColor(&rgbBlue); |
DrawString(str); |
MoveTo(offset - 4, 200); |
RGBForeColor(&rgbRed); |
DrawString(str); |
RGBForeColor(&rgbBlack); |
SetPort(oldPort); |
GraphicsSetRectDirty(&backBuff->portRect); |
} |
//¥ -------------------- DropEnemies |
static void |
DropEnemies() |
{ |
GameObjectPtr current, next; |
gEnemyNewDirection = gEnemiesChangeDirection; |
do |
{ |
current = gEnemyList; |
gNumEnemiesProcessed = 0; |
do |
{ |
next = current->next; |
current->action(current); |
current = next; |
} while (next); |
} while (gNumEnemiesProcessed); |
gEnemyLevel++; |
} |
//¥ -------------------- EnemyShoot |
void |
EnemyShoot(GameObjectPtr whichEnemy) |
{ |
Rect r; |
GameObjectPtr go; |
go = GameObjectAllocate(); |
if (! go) |
FatalError("Could not allocate enemy shot."); |
SoundHandlerPlay(soundEnemyFire, whichEnemy->screenX, whichEnemy->screenY); |
GameObjectAddToList(&gEnemyShotList, go); |
SetRect(&r, 20, 0, 620, 412); |
GameObjectSetBounds(go, &r); |
GameObjectSetSprite(go, gSpriteCache[scEnemyShot]); |
go->screenX = whichEnemy->screenX; |
go->screenY = whichEnemy->screenY + 1; |
go->velocityH = 0; |
go->velocityV = kEnemyShotVelocity; |
go->action = EnemyShotAction; |
} |
//¥ -------------------- AdvanceEnemies |
static void |
AdvanceEnemies() |
{ |
GameObjectPtr current, next; |
unsigned long oldProcessed; |
do |
{ |
gNumEnemiesProcessed = 0; |
current = gEnemyList; |
do |
{ |
oldProcessed = gNumEnemiesProcessed; |
next = current->next; |
current->action(current); |
//¥ If we moved an alien, use up some alien gas |
if (oldProcessed != gNumEnemiesProcessed) |
gEnemyGas--; |
current = next; |
} while (next && gEnemyGas); |
//¥ If no enemies were processed then they're all at the same level, so move on |
if (gNumEnemiesProcessed == 0) |
{ |
gEnemyLevel++; |
if (gEnemyTask == kEnemyDropping) |
gEnemyTask = gEnemyNewDirection; |
} |
} while (gEnemyGas && (gNumEnemies > 0)); |
} |
//¥ -------------------- DisplayFrameRate |
static void |
DisplayFrameRate(void) |
{ |
static unsigned long lastTime = 0; |
static unsigned long frames = 0; |
unsigned long elapsedTime; |
Str255 str; |
GrafPtr oldPort; |
CGrafPtr underlay; |
GDHandle device, oldDevice; |
Rect r; |
//¥ Initialize the stats at the beginning of each game |
//¥ gFrameRateBaseTime is reset in InitNewGame() |
if (gFrameRateBaseTime == 0) |
{ |
gFrameRateBaseTime = TickCount(); |
lastTime = 0L; |
frames = 0L; |
} |
//¥ Bump the frame counter |
frames++; |
//¥ Find the total elapsed time and convert it to seconds |
elapsedTime = TickCount() - gFrameRateBaseTime; |
if ( ( elapsedTime - lastTime ) > 120 ) |
{ |
lastTime = elapsedTime; |
elapsedTime /= 60; |
sprintf((char *) str + 1, "FPS: %0.4ld", frames / elapsedTime); |
str[0] = strlen ((char *) str + 1); |
GraphicsGetUnderlayGrafPort(&underlay, &device); |
GetPort(&oldPort); |
oldDevice = GetGDevice(); |
SetPort((GrafPtr) underlay); |
SetGDevice(device); |
RGBForeColor(&rgbBlack); |
SetRect(&r, 5, 420, 90, 435); |
PaintRect(&r); |
MoveTo(5, 435); |
TextFont(systemFont); |
TextFace(bold); |
TextSize(12); |
RGBForeColor(&rgbYellow); |
DrawString(str); |
RGBForeColor(&rgbBlack); |
SetPort(oldPort); |
SetGDevice(oldDevice); |
GraphicsSetUnderlayRectDirty(&r); |
} |
} |
//¥ -------------------- EndGame |
static void |
EndGame(CGrafPtr backBuff) |
{ |
Boolean OKHit; |
ISpSuspend(); |
DisplayGameOver(backBuff); |
GraphicsUpdateScreen(); |
GraphicsPaused(); |
ShowCursor(); |
gGameInProgress = false; |
if (gNetGame) |
{ |
if (gIAmHost) |
gNetState = kHosting; |
else |
gNetState = kJoining; |
OKHit = WaitForAllPlayers(); |
if (OKHit == false) |
ShutdownNetworking(); |
else |
{ |
gNetState = kStarting; |
SendStartGame(); |
InitNewGame(1); |
} |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-14