This is GameBrain.m in view mode; [Download] [Up]
/* Generated by Interface Builder */ #import <gamekit/gamekit.h> #import <daymisckit/daymisckit.h> #import <stdio.h> #import <string.h> #import <objc/objc-runtime.h> @implementation GameBrain - init // designated initializer sets up game variables { // to sensible values. [super init]; level = 0; paused = NO; ranOnce = NO; aborting = NO; printLevel = NO; initDone = NO; return self; } /* methods to get at important variables */ - highScoreController { return highScoreController; } - oneUpView { return oneUpView; } - scoreKeeper { return scoreKeeper; } - scorePlayer { return scorePlayer; } - soundPlayer { return soundPlayer; } - mainStrings { return strings; } - gameScreen { return gameScreen; } - gameWindow { return gameWindow; } - preferencesBrain { return preferencesBrain; } - infoController { return infoController; } - gameInfo { return gameInfo; } - (BOOL)aborting { return aborting; } - makeGameInfo { return [[GameInfo alloc] init]; } - (int)startLevel { return [preferencesBrain startLevel]; } - (int)tableNum { return tableNum; } - (int)level { return level; } - (int)speed { return [preferencesBrain speed]; } - (int)paused { return paused; } - (BOOL)playerCheated { return playerCheated; } - gameOver:sender // end the game, take high scores, etc. { // calls gameOver method (this is IB wrapper) [self gameOver]; return self; } - pauseGame:sender // toggle pause status of the game { const char *title = [pauseMenuCell title]; if (!strcmp(title,[strings valueForStringKey:"Pause"])) { [self pause]; } else { [self unpause]; } return self; } - (int)pause // pause game { if ([gameScreen gameState]==GAMEOVER) return NO; // no pausing if over [gameTimer pauseTiming:self]; #ifdef NOISYDEBUG fprintf(stderr, "Pause timer, elapsed time is %s\n", [gameTimer stringValue]); #endif [pauseMenuCell setTitle:[strings valueForStringKey:"Unpause"]]; [gameScreen pause:self]; if (!paused) [gameWindow setTitle:[strings valueForStringKey:"PausedTitle"]]; paused = YES; return YES; } - unpause // unpause game { if ([gameScreen gameState]==GAMEOVER) [pauseMenuCell setEnabled:NO]; [pauseMenuCell setTitle:[strings valueForStringKey:"Pause"]]; [gameScreen unpause:self]; [gameWindow setTitle:[strings valueForStringKey:"GameName"]]; paused = NO; #ifdef NOISYDEBUG fprintf(stderr, "Unpause game timer\n"); #endif [gameTimer continueTiming:self]; return self; } - startNewGame:sender // starts a new game { if (![self askAbortGame:GK_ABORT]) return nil; if ([gameScreen gameState] != GAMEOVER) { aborting = YES; [self gameOver]; } [scoreKeeper resetScore]; [scoreKeeper updateTopScoreText]; [scoreKeeper updateScoreText]; level = 0; playerCheated = NO; ranOnce = YES; [pauseMenuCell setEnabled:YES]; [self layerWindows]; level = [preferencesBrain startLevel] - 1; // so all level init is done [preferencesBrain startingGame]; [oneUpView setNumUp:[gameInfo numOneUps]]; [self nextLevel]; // by the nextLevel method. if (paused) [self unpause]; [gameWindow makeKeyAndOrderFront:self]; // use sender's tag to determine which HS table to use. (Expert, Beg., etc) tableNum = 0; // should be the prefs default here ***** if ([sender respondsTo:@selector(tag)]) { int theTag = [sender tag]; if (theTag > 0) tableNum = theTag; } //[highScoreController table:tableNum]; // get applicable high score table currentSlot = [self buildNewSlot]; #ifdef NOISYDEBUG fprintf(stderr, "Starting time is: %s\n", [[currentSlot startTime] stringValue]); #endif [gameTimer startTiming:self]; [gameScreen restartGame]; #ifdef GK_USE_MUSICKIT if ([preferencesBrain music] && ([gameScreen gameState] != GAMEOVER)) [scorePlayer play:self]; #endif aborting = NO; return self; } - unpauseGame:sender // unpause the game { return [self pauseGame:sender]; // handles toggle of menuCell } - nextLevel // move to next level-- called when level is // completed and to start game { level++; [levelText setIntValue:level]; [gameScreen setUpScreen]; return self; } - nextLevel:sender // this is can be called from the interface; it considers // the user to have cheated since they haven't completed the level normally. { playerCheated = YES; return [self nextLevel]; } - buildNewSlot { // build a high score slot at the start of a game. id newSlot; if (gameInfo) { // use class in GameInfo...must be linked in already! newSlot = [[objc_lookUpClass([[gameInfo slotType] stringValue]) alloc] init]; } else newSlot = [[HighScoreSlot alloc] init]; gameTimer = [[DAYStopwatch alloc] init]; [newSlot setElapsedTime:gameTimer]; [newSlot setStartTime:[[DAYTime alloc] initWithCurrentTime]]; [newSlot setPlayerName:[preferencesBrain defaultPlayerName]]; [newSlot setUserName:[NXApp userLoginName]]; [newSlot setMachineName:[NXApp realHostName]]; [newSlot setStartLevel:[preferencesBrain startLevel]]; [newSlot setEndLevel:[preferencesBrain startLevel]]; return newSlot; } - currentHighScoreSlot { // update the slot and return it. [currentSlot setEndLevel:level]; if ([gameScreen gameState] != GAMEOVER) [currentSlot setEndTime:[[DAYTime alloc] initWithCurrentTime]]; [currentSlot setFinalScore:[scoreKeeper currentScore]]; [gameTimer calcElapsedTime:self]; #ifdef NOISYDEBUG fprintf(stderr, "Current elapsed time is: %s\n", [gameTimer stringValue]); #endif return currentSlot; } - gameOver // tidy up game, allow high score name entry { [gameTimer pauseTiming:self]; // stop the timer now that the game is over // implies a -calcElapsedTime: message, so we don't send it from here [currentSlot setEndTime:[[DAYTime alloc] initWithCurrentTime]]; #ifdef NOISYDEBUG fprintf(stderr, "Ending elapsed time is: %s\n", [gameTimer stringValue]); fprintf(stderr, "Ending time is: %s (%s elapsed)\n", [[currentSlot endTime] stringValue], [[currentSlot elapsedTime] stringValue]); #endif gameTimer = nil; // remove demo mode title... if ([gameScreen demoMode]) [gameWindow setTitle:[strings valueForStringKey:"GameName"]]; // if not demo, it's possible to get a high score entry... else if ([gameScreen gameState] != GAMEOVER) [highScoreController putInHighScores:[self currentHighScoreSlot]]; [pauseMenuCell setEnabled:NO]; #ifdef GK_USE_MUSICKIT [scorePlayer stop:self]; #endif currentSlot = nil; [gameScreen gameOver]; // change gameView's state to GAMEOVER if (paused) [self unpause]; return self; } - printGame:sender // print game screen w/score, level, etc. { char titleString[80]; if (printLevel) sprintf(titleString, [strings valueForStringKey:"PrintTitleLevel"], level, [scoreKeeper currentScore], [highScoreController highestScore]); else sprintf(titleString,[strings valueForStringKey:"PrintTitle"], [scoreKeeper currentScore], [highScoreController highestScore]); [self pause]; // bringing up the print panel will do this anyway, // indirectly, via the delegate methods, but that would screw up the // window title bar we want to put up here: (score, highest score) [gameWindow setTitle:titleString]; [gameWindow smartPrintPSCode:self]; if (paused) [gameWindow setTitle:[strings valueForStringKey:"PausedTitle"]]; else [gameWindow setTitle:[strings valueForStringKey:"GameName"]]; return self; } // Application DELEGATE methods. Special things to do on startup, unhide, // hide, and so on. - buildAlert { if (!alert) alert = NXGetAlertPanel([strings valueForStringKey:"GameName"], [strings valueForStringKey:"LoadingMessage"], NULL, NULL, NULL); return self; } - appWillInit:sender // after init, but before 1st event. { [self buildAlert]; [alert makeKeyAndOrderFront:self]; [loadingText setStringValue:[strings valueForStringKey:"LoadInit"]]; NXPing(); return self; } - appDidInit:sender // after init, but before 1st event. { NXEvent *theEvent = (NXEvent *)malloc(sizeof(NXEvent)); if (!gameInfo) gameInfo = [self makeGameInfo]; [pauseMenuCell setEnabled:NO]; if (alert != loadingPanel) [alert orderOut:self]; // methods to load the stuff that takes a while. [loadingPanel makeKeyAndOrderFront:self]; // automatically make a bunch of the needed connections if they // haven't already been made in the .nib file and inform the // main objects that the app is up and running. if (!gameWindow) gameWindow = [gameScreen window]; if (![gameWindow delegate]) [gameWindow setDelegate:self]; [infoController appDidInit:sender]; [loadingText setStringValue:[strings valueForStringKey:"LoadPrefs"]]; NXPing(); [preferencesBrain appDidInit:sender]; [[levelText window] setFrameUsingName:"Stats"]; [[levelText window] setFrameAutosaveName:"Stats"]; [gameWindow setFrameUsingName:"Game"]; [gameWindow setFrameAutosaveName:"Game"]; [loadingText setStringValue:[strings valueForStringKey:"LoadSound"]]; NXPing(); [soundPlayer appDidInit:sender]; [loadingText setStringValue:[strings valueForStringKey:"LoadImages"]]; NXPing(); [gameScreen appDidInit:sender]; #ifdef GK_USE_MUSICKIT [loadingText setStringValue:[strings valueForStringKey:"LoadScore"]]; NXPing(); [scorePlayer appDidInit:sender]; #endif [loadingText setStringValue:[strings valueForStringKey:"LoadHighs"]]; NXPing(); [highScoreController appDidInit:sender]; [levelText setIntValue:1]; [scoreKeeper appDidInit:sender]; if (oneUpView) [scoreKeeper addDelegate:oneUpView]; [loadingPanel orderOut:self]; [[gameScreen animate:self] update]; // start up animation if ((alert != loadingPanel) && alert) NXFreeAlertPanel(alert); // the app-defined event will be the first one, used to bring up the // various panels that may turn up during the start up sequence. // (i.e. welcome, readme, shareware alert.) theEvent->type = NX_APPDEFINED; theEvent->data.compound.subtype = GK_STARTUP; DPSPostEvent(theEvent, YES); // post as the next event to be serviced. return self; } - startUp // handle the startup app-defined event { BOOL firstTimeRun = [preferencesBrain firstTimeCheck]; if ([infoController notRegistered]) { // shareware alert always... NXRunAlertPanel( [strings valueForStringKey:"SharewareAlert"], [strings valueForStringKey:"SharewareMessage"], [strings valueForStringKey:"Understand"], NULL, NULL); } if (!firstTimeRun && [preferencesBrain autoStart]) [self startNewGame:self]; [self layerWindows]; if (firstTimeRun) { // welcome and readme char *str = malloc(128); sprintf(str, [strings valueForStringKey:"Welcome1"], [infoController versionString]); NXRunAlertPanel([strings valueForStringKey:"Welcome"], str, [strings valueForStringKey:"LetsPlay"], NULL, NULL); free(str); [infoController readme:self]; } initDone = YES; return self; } - applicationDefined:(NXEvent *)theEvent // initial startup readme panels { // a subclass could add other event types, but don't forget to call super! // You'd probably want to structure your code more or less like what // you see here (switch), if you have several event types declared. switch (theEvent->data.compound.subtype) { // switch allows me to // easily add more event types if I need to do so. case GK_STARTUP : { [self startUp]; break; } default : { break; } } return self; } - appDidBecomeActive:sender { // why the "initDone" ivar? // don't want to order the window up until we've got return values from // the alert panels that turn up when the game starts. Since this message // is sent after the alert comes up but before the user replies (this // message is sent when the event loop becomes active, including launch) // we need to NOT order the gamewindow, etc. out until the start up // sequence is complete. This is a hack that removes an annoying bug // that occured with panels popping up and making a general mess of the // screen...since in 2.x this message was _NOT_ sent on the initial // launch's activation of the event loop. The 3.x behavior is more // correct, I suppose, but it was annoying to track down why this was // happening. Anyway, this works around the problem just fine. if (initDone) [self layerWindows]; return self; } - appDidHide:sender { [self pause]; return self; // pause game on Command-h } - appDidResignActive:sender { if ([gameScreen demoMode]) return self; [self pause]; return self; // pause game on app deactivate } - layerWindows { [gameWindow makeKeyAndOrderFront:self]; [gameWindow makeFirstResponder:gameScreen]; if ([preferencesBrain autoUnPause]) [self unpause]; // make sure the windows are layered properly // need to check delegate to be sure it responds... // Note: NeXT has said, for portability, that we shouldn't depend on // a method to return zero if sent to a nil object unless that method // returns an id, in which case nil will be "returned". Thus, the // first half of the condition below has been put in to deal with // when there's no delegate. It's not really needed on Intel or Moto // hardware, but I'm keeping later ports in mind here, too... if (![[levelText window] delegate] || // if no delegate, assume window up [[[levelText window] delegate] windowUp]) [[levelText window] orderFront:self]; [gameWindow orderFront:self]; return self; } - appDidUnhide:sender { return [self layerWindows]; } - appWillTerminate:sender // update DEFAULTS here { [preferencesBrain writeDefaults:self]; return self; } - (BOOL)askAbortGame:(int)why { if (([gameScreen gameState] != GAMEOVER) && (![gameScreen demoMode]) && ([preferencesBrain alert])) { BOOL flag = (why == GK_EXIT); // Verify that player wants to leave game [self pause]; if (NXRunAlertPanel(([highScoreController slotIsEligible:[self currentHighScoreSlot]] ? [strings valueForStringKey:"HaveScore"] : NULL), (flag ? [strings valueForStringKey:"ReallyQuit"] : [strings valueForStringKey:"ThrowAway"]), (flag ? [strings valueForStringKey:"Yes2"] : [strings valueForStringKey:"Yes1"]), (flag ? [strings valueForStringKey:"No2"] : [strings valueForStringKey:"No1"]), NULL) != NX_ALERTDEFAULT) { [self unpause]; // unpause if we're aborting the game abort. :-> return NO; } } return YES; } - abortGame:sender { if ([self askAbortGame:GK_ABORT]) { aborting = YES; [self gameOver]; } return self; } - quit:sender { if (![self askAbortGame:GK_EXIT]) return self; if ([infoController notRegistered]) { if (ranOnce) { NXRunAlertPanel([strings valueForStringKey:"Goodbye"], [strings valueForStringKey:"Enjoyed"], [strings valueForStringKey:"NoForget"], NULL, NULL); } else { NXRunAlertPanel([strings valueForStringKey:"Goodbye"], [strings valueForStringKey:"TryMe"], [strings valueForStringKey:"TryLater"], NULL, NULL); } } [highScoreController closeServers]; // make sure server knows that we left. return [NXApp terminate:sender]; } - windowDidResginMain:sender // do pause if window loses main status { [self pause]; return self; // pause game } - windowDidResignKey:sender // do pause if window loses key status { [self pause]; return self; // pause game } - windowDidBecomeKey:sender // do unpause if window gains key status { [gameWindow makeFirstResponder:gameScreen]; if ([preferencesBrain autoUnPause]) [self unpause]; // unpause on unhide*/ return self; } - windowDidDeminiaturize:sender // clean off crap left by the new { // border animation in 3.0. yuck! [gameScreen update]; [[infoController niftyView] update]; return self; } - windowDidMove:sender // move status with game window { NXRect gameFrame, statsFrame; [gameWindow getFrame:&gameFrame]; [[levelText window] getFrame:&statsFrame]; [[levelText window] moveTo:(NX_X(&gameFrame) - NX_WIDTH(&statsFrame) + 1) :NX_Y(&gameFrame) + NX_HEIGHT(&gameFrame) - NX_HEIGHT(&statsFrame)]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.