ftp.nice.ch/pub/next/games/action/Tetris1.3.N.bs.tar.gz#/Tetris1.3/Source/TetApp.m

This is TetApp.m in view mode; [Download] [Up]

#import <appkit/Button.h>
#import <appkit/ButtonCell.h>
#import <appkit/Panel.h>
#import <appkit/Window.h>
#import <appkit/TextField.h>
#import <appkit/graphics.h>
#import <string.h>
#import <ctype.h>

#import "TetApp.h"
#import "NextMatrix.h"
#import "ScoreKeeper.h"
#import "TetMatrix.h"

@implementation TetApp

- initForColor
{
	const NXScreen *deepestScreen;
	const char *str;


	str = NXGetDefaultValue([NXApp appName], "ColorOff");
	if (str != NULL && (strcmp(str, "YES") == 0)) { 
		colorOff = YES;
		gameInColor = NO;
#ifdef DEBUG
		fprintf(stderr, "Game wants to be B&W\n");
#endif
	} else {
		colorOff = NO;
		deepestScreen = [NXApp colorScreen];
		
		if ( deepestScreen->depth  != NX_TwoBitGrayDepth ) {
			// Then 12 bit color should be more than enough
			[tetrisWindow setDepthLimit:NX_TwelveBitRGBDepth];
			gameInColor = YES;
		} else {
			gameInColor = NO;
		}
	}
	return self;
}


+ new
{
	self = [super new];
	[self setDelegate:self];
	[self initForColor];
	started = paused = NO;
	numRandomRows = 4;
	return self;
}


- setLevelLeft:anObject
{
    levelLeft = anObject;
    [[levelLeft cell] setHighlightsBy:NX_CONTENTS | NX_CHANGEGRAY];
    [levelLeft sendActionOn:NX_MOUSEDOWNMASK];
    return self;
}

- setLevelRight:anObject
{
    levelRight = anObject;
    [[levelRight cell] setHighlightsBy:NX_CONTENTS | NX_CHANGEGRAY];
    [levelRight sendActionOn:NX_MOUSEDOWNMASK];
    return self;
}

- (BOOL) isGameColor
{
	return gameInColor;
}

- setTetrisWindow:anObject
{
	tetrisWindow = anObject;
	[tetrisWindow setDelegate:self];
	[tetrisWindow setMiniwindowIcon:"Tetris"];
	return self;
}


- appDidInit:sender
{
	const char *str;
	int levelValue;

	[controlWindow removeFromEventMask:NX_KEYDOWNMASK|NX_KEYUPMASK];
	[controlWindow orderFront:self];

	str = NXGetDefaultValue([NXApp appName], "CurrentLevel");
	if (str != NULL) { 
		sscanf(str, "%d", &levelValue);
    	[level setIntValue: levelValue];
		[self updateLeft: levelValue];
		[self updateRight: levelValue];
#ifdef DEBUG
		fprintf(stderr, "Setting current level to %d\n", levelValue);
#endif
	}

	str = NXGetDefaultValue([NXApp appName], "RandomRows");
	if (str != NULL) { 
		sscanf(str, "%d", &numRandomRows);
		[randomField setIntValue:numRandomRows];
		[randomSlider setIntValue:numRandomRows];
#ifdef DEBUG
		fprintf(stderr, "Setting number Random rows to %d\n", numRandomRows);
#endif
	}
	str = NXGetDefaultValue([NXApp appName], "ShowNext");
	if (str != NULL) {
		if (strcmp(str, "YES") == 0) {
			[showNextSwitch setIntValue: YES];
			[showNext showNext:showNextSwitch]; // ID is actually ignored
		}
	}
	[colorSwitch setIntValue: colorOff];

	[tetrisWindow orderWindow:NX_ABOVE relativeTo:0];
	[tetrisWindow makeKeyWindow];

	return self;
}

- (BOOL) gamePaused
{
	return paused;
}

- keyDown:(NXEvent *)theEvent
{
	unsigned short charCode;
	printf("Keydown in TetApp\n");

	charCode = theEvent->data.key.charCode;
	if (isupper(charCode))
	  charCode = tolower(charCode);

	switch (charCode) {
	 case 13:						  // Pause if the user hits return
		[self pause:self];
	}
	return self;
}

- resignActiveApp
{
    if (started && !paused)
    	[self pause:self];
    return [super resignActiveApp];
}

- updateLeft:(int) theLevel
{
	if (theLevel <= MIN_LEVEL) {
		[[levelLeft setEnabled:NO] setIcon:"scrollMenuLeftD"];
	} else {
		[[levelLeft setEnabled:YES] setIcon:"scrollMenuLeft"];
	}
	return self;
}

- updateRight:(int) theLevel
{
	if (theLevel >= MAX_LEVEL) {
    	[[levelRight setEnabled:NO] setIcon:"scrollMenuRightD"];
	} else {
		[[levelRight setEnabled:YES] setIcon:"scrollMenuRight"];
	}
	return self;
}

- start:sender
{
	int levelValue = [level intValue];
	
	if (started) {
    	if (paused)
		  [self pause:sender];
    	[tetrisView stop:sender];
		[[tetrisView window] disableFlushWindow];
		[showNext end:self];
		[startButton setTitle:"New game"];
    	[pauseButton setEnabled:NO];
		[levelLeft setTransparent:NO];
		[levelRight setTransparent:NO];
		[self updateLeft: levelValue];
		[self updateRight: levelValue];
		[[[tetrisView window] reenableFlushWindow] flushWindow];
		started = NO;
	} else {
		[[tetrisView window] disableFlushWindow];
		[showNext start:self];
		[startButton setTitle:"Abort"];
		[pauseButton setEnabled:YES];
		[scoreKeeper setZero];
		[tetrisView setScoreKeeper:scoreKeeper];
		[[levelLeft setTransparent:YES] setEnabled:NO];
		[[levelRight setTransparent:YES] setEnabled:NO];
		[[[tetrisView window] reenableFlushWindow] flushWindow];
		[tetrisView newGame:levelValue];
		started = YES;
	}
	return self;
}

- pause:sender
{
	[[tetrisView window] disableFlushWindow];
	if (paused) {
    	[pauseButton setTitle:"Pause"];
		[pauseDisplay setStringValueNoCopy:""];
		[tetrisView continue:sender];
		paused = NO;
	} else {
		[tetrisView pause:sender];
		[pauseButton setTitle:"Continue"];
		[pauseDisplay setStringValueNoCopy:"PAUSED"];
		paused = YES;
	}
	[[[tetrisView window] reenableFlushWindow] flushWindow];
	return self;
}

- gameOver
{
	int levelValue = [level intValue];
	
	[[tetrisView window] disableFlushWindow];
	[showNext end:self];
	[startButton setTitle:"New game"];
	[pauseButton setEnabled:NO];
	[levelLeft setTransparent:NO];
	[levelRight setTransparent:NO];
	[self updateLeft: levelValue];
	[self updateRight: levelValue];
	[[[tetrisView window] reenableFlushWindow] flushWindow];
	NXPing();
	started = NO;
	
	[scoreKeeper updateHighScores:levelValue];
	return self;
}

- levelLeft:sender
{
	int levelValue = [level intValue];
	
	if (levelValue != MIN_LEVEL) {
    	[level setIntValue:--levelValue];
		[self updateLeft: levelValue];
		[self updateRight: levelValue];
	}
	return self;
}

- levelRight:sender
{
	int levelValue = [level intValue];
	
	if (levelValue != MAX_LEVEL) {
    	[level setIntValue:++levelValue];
		[self updateLeft: levelValue];
		[self updateRight: levelValue];
	}
	return self;
}

/*
 * Set the number of rows where random pieces will appear.
 */
- setRandomRows:sender
{
	int tmp;
	tmp = [sender intValue];

	// Will always be valid since slider is the only object that can call me!?
	if (tmp >= 0  && tmp <=10) {
		numRandomRows = tmp;
		[randomField setIntValue: tmp];
	} else {
		[randomField setIntValue:numRandomRows];
	}
	return self;
}

/*
 * Let user use monochrome blocks to get better speed.
 */
- adjustColor:sender
{
	int value = [sender intValue];
	colorOff = value;
	if ( (colorOff == NO) && ([NXApp colorScreen] != NX_TwoBitGrayDepth)) {
		gameInColor = YES;
	} 
	if (colorOff == YES) {
		[tetrisWindow setDepthLimit:NX_TwoBitGrayDepth];
	} else {
		[tetrisWindow setDepthLimit:NX_TwelveBitRGBDepth];
	}
	if (value == YES) {
		fprintf(stderr, "Turing color off\n");
	} else {
		fprintf(stderr, "Turing color on\n");
	}
	return self;
}

/*
 * User has clicked quit.
 *   If the game is in progress then verify the quit.
 *   Save high scores and default values.
 */
- terminate:sender
{
	char buf[20];

	if (started &&
		 NXRunAlertPanel("Quit", "Game is still in progress. Really quit?",
							  "Quit", "Cancel", NULL) == NX_ALERTALTERNATE)
	  return self;

	// Clean up and die
	[scoreKeeper writeScores];
	sprintf(buf,"%d", [level intValue]);
	NXWriteDefault ([NXApp appName], "CurrentLevel", buf);
	NXWriteDefault ([NXApp appName], "ColorOff", ([colorSwitch intValue]) ? "YES" : "NO");
	sprintf(buf,"%d", numRandomRows);
	NXWriteDefault ([NXApp appName], "RandomRows", buf);
	NXWriteDefault ([NXApp appName], "ShowNext", ([showNextSwitch intValue]) ? "YES" : "NO");
	return [super terminate:sender];
}

/*
 *  Allow the user to set the blocks images that make up the pieces
 */
- setBlocks:sender
{
	return self;
}

- windowWillMiniaturize:sender toMiniwindow:miniwindow
{
    if (started && !paused)
    	[self pause:sender];
    return self;
}

- windowDidMove:sender
{
	NXRect aRect;
	float newX, newY;

	[[tetrisView window] getFrame:&aRect];
	newX = aRect.origin.x + aRect.size.width + 5.; 
	newY = aRect.origin.y;
	[controlWindow moveTo: newX :newY];

	return self;
}

/*
 * Must bring the control panel to the front too.
 */
- windowDidBecomeKey:sender
{
	[controlWindow orderFront:self];
	return self;
}
@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.