This is ArcadeApp.m in view mode; [Download] [Up]
// (C) Copyright 1992 Jim Patterson #import <appkit/appkit.h> #import <objc/objc.h> #import <appkit/ClipView.h> #import <dpsclient/event.h> #import <soundkit/soundkit.h> #import "ArcadeApp.h" #import "Animator.h" #import "LessonPlan.h" #import "GameView.h" #import "PerformanceEvaluator.h" // Time between timer interrupts to scroll screen vertically #define TA_CYCLE_TIME 0.1 // Number of points to scroll vertically each cycle (must be even!) #define TA_DEFAULT_CYCLE_DELTA 5 #define TA_ENDGAME_CYCLE_DELTA 15 @implementation ArcadeApp + new { self = [super new]; startedWithFile = NO; // other stuff here when necessary return self; } - appDidInit:sender { NXRect clipViewFrame; int i; id gameFont; // initialize Animator instance timer = [Animator newChronon:TA_CYCLE_TIME adaptation:0.0 target:self action:@selector(cycleOnce:) autoStart:NO eventMask:NX_KEYDOWNMASK ]; // further initialize LessonPlan instance [lessonPlan postInitialize]; if (!startedWithFile) { for (i=0; i < 128; i++) [lessonPlan deselectKey:i]; [lessonPlan selectKeysBetween:'a' :'z']; // select upper & lower case letters [lessonPlan selectKey:TA_KEY_LEFTSHIFT]; [lessonPlan selectKey:TA_KEY_RIGHTSHIFT]; [[lessonPlan lessonNumMatrix] selectCellAt:2:0]; [lessonPlan setLessonNum: 3]; } [lessonPlan flushKeyboard]; // setup sound objects explosionSound = [Sound newFromMachO:"explosion.snd"]; keyHitSound = [Sound newFromMachO:"keyHit.snd"]; // further initialize view hierarchy NXSetRect(&clipViewFrame, TA_CLIPVIEW_X,TA_CLIPVIEW_Y, TA_CLIPVIEW_W,TA_CLIPVIEW_H); clipView = [ClipView newFrame:&clipViewFrame]; [clipView setBackgroundGray:NX_LTGRAY]; [[gameWindow contentView] addSubview:clipView]; [gameWindow makeFirstResponder:self]; [[gameWindow contentView] lockFocus]; strcpy(personalFileName,"untitled"); return self; } - appDidHide:sender { [self stopGame:self]; return self; } - setGameWindow:anObject { gameWindow = anObject; return self; } - setGameView:anObject { gameView = anObject; return self; } - setLessonPlan:anObject { lessonPlan = anObject; return self; } - setPerformanceEvaluator:anObject {performanceEvaluator = anObject; return self; } - setSpeedSlider:anObject { speedSlider = anObject; return self; } - setPauseButton:anObject {pauseButton = anObject; return self; } - setInstructionsScrollView:anObject {instructionsScrollView = anObject; return self; } - lessonPlan {return lessonPlan;} - performanceEvaluator {return performanceEvaluator; } - gameWindow {return gameWindow; } - speedChanged:sender { int t = [sender tag]; if (t == 0) cycleDelta = [sender intValue]; // sender was the slider else { cycleDelta +=t; // else it was a speedup/slowdown key if (cycleDelta > 20) cycleDelta = 20; else if (cycleDelta <1) cycleDelta = 1; [speedSlider setIntValue:cycleDelta]; } return self; } - startNewGame:sender { NXRect gameViewFrame; NXPoint aPoint; if ([pauseButton state]) { // unpause if we were paused [timer startEntry]; [pauseButton setState:0]; } // Don't start a new game if we are already playing if ([timer isTicking]) return self; // turn off pause button if it is on [pauseButton setState:0]; // give user a get-ready message aPoint.x = 0; aPoint.y = TA_GAMEVIEW_H - TA_CLIPVIEW_H; [clipView rawScroll:&aPoint]; // create a new GameView [gameWindow disableDisplay]; [self getReadyPanel]; [gameWindow reenableDisplay]; gameView = [GameView standardNewFrame]; [gameWindow disableDisplay]; [clipView setDocView:gameView]; aPoint.x = 0; aPoint.y = -TA_CLIPVIEW_H; [clipView rawScroll:&aPoint]; // orient gameView within clipView [gameWindow reenableDisplay]; [gameView display]; [clipView setBackgroundGray:NX_LTGRAY]; // reorient from the beginning gameProgress = 0; gamePhase = 0; cycleDelta = [speedSlider intValue]; currentLowestLetter = [gameView lowestLetter]; // figure out which letter we are looking for [timer startEntry]; return self; } - stopGame:sender { NXPoint aPoint; if (([timer isTicking]) || ([pauseButton state])) { [timer stopEntry]; [pauseButton setState:0]; aPoint.x = 0; aPoint.y = TA_GAMEVIEW_H - TA_CLIPVIEW_H; [clipView rawScroll:&aPoint]; [performanceEvaluator tellGameCompleted:NO]; [performanceEvaluator summarize]; [performanceEvaluator sortKeyInfo]; [performanceEvaluator flush]; } return self; } - playerLoses:sender { NXPoint aPoint; [explosionSound play]; [timer stopEntry]; aPoint.x = 0; aPoint.y = TA_GAMEVIEW_H - TA_CLIPVIEW_H; [clipView rawScroll:&aPoint]; [performanceEvaluator tellGameCompleted:NO]; [performanceEvaluator summarize]; [performanceEvaluator sortKeyInfo]; [performanceEvaluator flush]; sleep(3); return self; } - playerWins:sender { NXPoint aPoint; [timer stopEntry]; aPoint.x = 0; aPoint.y = TA_GAMEVIEW_H - TA_CLIPVIEW_H; [clipView rawScroll:&aPoint]; [performanceEvaluator tellGameCompleted:YES]; [performanceEvaluator summarize]; [performanceEvaluator sortKeyInfo]; [performanceEvaluator flush]; sleep(3); return self; } - cycleOnce:sender { NXPoint aPoint; NXRect aRect; int dangerLevel; if (gamePhase == 2) gameProgress += TA_ENDGAME_CYCLE_DELTA; else gameProgress += cycleDelta; aPoint.x = 0; aPoint.y = gameProgress - TA_CLIPVIEW_H; [clipView rawScroll:&aPoint]; // set's clip view's bounds.origin to aPoint switch (gamePhase) { case 0: // starting phase...waiting for signal to change background to black if (gameProgress >= TA_GAMEVIEW_TOBLACK_H) { [clipView setBackgroundGray:NX_BLACK]; gamePhase = 1; } break; case 1: // playing phase...waiting for signal to change background to gray if (gameProgress >= TA_GAMEVIEW_SPEEDUP_H) { [clipView setBackgroundGray:NX_LTGRAY]; gamePhase = 2; } break; case 2: // winding down phase...waiting for signal to stop scrolling if (gameProgress >= TA_GAMEVIEW_STOP_H) [self playerWins:self]; break; } dangerLevel = TA_GAMEVIEW_Y + TA_GAMEVIEW_HEADER_H + TA_CLIPVIEW_H + [gameView lowestNonemptyRow]*TA_LINE_HEIGHT - gameProgress; if (dangerLevel < 0) if (gameProgress + dangerLevel < 2750) [self playerLoses:self]; return self; } - pauseGame:sender { if ([sender state]) [timer stopEntry]; else [timer startEntry]; return self; } - keyDown:(NXEvent *) theEvent { char key; if (![timer isTicking]) return self; key = (char) theEvent->data.key.charCode; // correct key was hit if (key == currentLowestLetter) { [gameView lowestLetterWasHit:gameProgress]; // notify view of letter hit currentLowestLetter = [gameView lowestLetter]; // find out new char to look for } else if ((key == (int)'\'') && (currentLowestLetter == ',')) { // comma == apostrophe [gameView lowestLetterWasHit:gameProgress]; // notify view of letter hit currentLowestLetter = [gameView lowestLetter]; // find out new char to look for } else if ((key == (int)',') && (currentLowestLetter == '\'')) { // comma == apostrophe [gameView lowestLetterWasHit:gameProgress]; // notify view of letter hit currentLowestLetter = [gameView lowestLetter]; // find out new char to look for } else [performanceEvaluator logKeyMiss:currentLowestLetter]; return self; } - getReadyPanel { [[gameWindow contentView] lockFocus]; [self boxWithStr:"Get Ready !"]; [[gameWindow contentView] unlockFocus]; return self; } - boxWithStr:(char *) str { // warning: must lockFocus before calling this float boxX,boxY,boxW,boxH,strX,strY,strW,strH; NXRect aRect; boxX = TA_CLIPVIEW_X+TA_GAMEVIEW_TRAILER_XMARGIN; boxY = TA_CLIPVIEW_Y+(TA_CLIPVIEW_H - TA_GAMEVIEW_TRAILER_BOX_H)/2; boxW = TA_GAMEVIEW_TRAILER_BOX_W; boxH = TA_GAMEVIEW_TRAILER_BOX_H; // clear box area and draw border PSsetgray(NX_DKGRAY); NXSetRect(&aRect,boxX,boxY,boxW,boxH); NXDrawGroove(&aRect,&aRect); // draw str centered vertically and horizontally PSstringwidth(str,&strW,&strH); strX = boxX + (boxW - strW)/2; strY = boxY + (boxH - strH)/2; PSsetgray(NX_BLACK); PSmoveto(strX,strY); PSscale(1,-1); PSshow(str); return self; } - saveAs:sender { NXTypedStream *tstream; id sPanel; sPanel = [SavePanel new]; [sPanel setRequiredFileType:"ta"]; if ([sPanel runModal]) { tstream = NXOpenTypedStreamForFile([sPanel filename], NX_WRITEONLY); [performanceEvaluator writeInfo:tstream]; [lessonPlan writeInfo:tstream]; NXCloseTypedStream(tstream); strcpy(personalFileName,[sPanel filename]); } return self; } - save:sender { NXTypedStream *tstream; id sPanel; if (strcmp(personalFileName,"untitled") == 0) [self saveAs:sender]; else { tstream = NXOpenTypedStreamForFile(personalFileName,NX_WRITEONLY); [performanceEvaluator writeInfo:tstream]; [lessonPlan writeInfo:tstream]; NXCloseTypedStream(tstream); } return self; } - open:sender { NXStream *tstream; id oPanel; const char *fileTypes[2]={"ta",NULL}; oPanel = [OpenPanel new]; if ([oPanel runModalForTypes:fileTypes]) { tstream = NXOpenTypedStreamForFile([oPanel filename],NX_READONLY); [performanceEvaluator readInfo:tstream]; [lessonPlan readInfo:tstream]; NXCloseTypedStream(tstream); strcpy(personalFileName,[oPanel filename]); } return self; } - printInstructions:sender { [[instructionsScrollView docView] printPSCode:sender]; return self; } - (BOOL) appAcceptsAnotherFile:sender { return YES; } - (int) appOpenFile:(const char *) filename type:(const char *) aType { NXStream *tstream; tstream = NXOpenTypedStreamForFile(filename,NX_READONLY); [performanceEvaluator readInfo:tstream]; [lessonPlan readInfo:tstream]; NXCloseTypedStream(tstream); strcpy(personalFileName,filename); startedWithFile = YES; return YES; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.