home *** CD-ROM | disk | FTP | other *** search
- /* 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
-