This is GameView.m in view mode; [Download] [Up]
/* Generated by Interface Builder */
#import "GameView.h"
#import "Animator.h" // timer controller
#import "GameBrain.h" // Partner in crime
#import "PreferencesBrain.h" // for user's preferences
#import <appkit/color.h> // Colors
#import <appkit/Application.h> // event stuff, misc.
#import <appkit/Speaker.h> // for dragging
#import <appkit/Listener.h> // for dragging
#import <appkit/NXImage.h> // for tiff rendering
#import <appkit/OpenPanel.h> // for setting backgrounds
#import <appkit/publicWraps.h> // used to set up dragging (get windownum)
#import <appkit/nextstd.h> // for NX_FREE, etc.
#import <dpsclient/psops.h> // PSsetgray()
#import <dpsclient/wraps.h> // PScompositerect()
#import <libc.h> // for random(), etc.
#import <math.h> // for floor(), etc.
#import <stdio.h> // for standard C file operations
@implementation GameView
- initFrame:(const NXRect *)frm // designated initializer for a view
{
char *slashPos;
[super initFrame:frm];
// seed random number generator
srandom(time(0));
// some defaults
demoMode = NO;
grayBorder = YES;
// get .app wrapper pathname and then load .snd files
appPath = (char *)malloc(256);
strcpy(appPath, NXArgv[0]);
if (slashPos = strrchr(appPath, '/')) {
sprintf(slashPos+1, "\0");
} else {
strcpy(appPath, "./");
}
// initialize game variables
state = GAMEOVER;
demoWait = 0;
doingBorder = NO;
grayBorder = YES;
backColor = NXConvertRGBToColor(0.333, 0.333, 0.333); // dark gray default
backIsColor = YES; // default bg is dark gray...
[self allocateGState];
return self;
}
- loadPix
{
const char *tmpStr;
char *okStr; float r, g, b;
// set background
okStr = malloc(8);
tmpStr = NXGetDefaultValue([NXApp appName], "BackColor");
if (tmpStr) {
backIsColor = NO;
sscanf(tmpStr, "%s %f %f %f", &okStr[0], &r, &g, &b);
backColor = NXConvertRGBToColor(r, g, b);
if (okStr[0] == 'Y') {
backIsColor = YES;
}
}
free(okStr);
if (!backIsColor)
[self setBackgroundFile:
NXGetDefaultValue([NXApp appName], "BackGround")
andRemember:NO];
return self;
}
- animate:sender
{ // method to start the animation - called by appDidInit
// set up Animator: (autoUpdate) this handles moving viruses and
// makes sure the columns fall when they should. The animator is
// an object that handles timed entries "smartly".
animator = [[Animator alloc] initChronon:[self speedTime]
adaptation:0.0 target:self
action:@selector(autoUpdate:) autoStart:YES eventMask:0];
return self;
}
- (BOOL)demoMode // if last game was demo
{ return demoMode; }
- (float)speedTime // returns time between animation frames
{ return GRANULARITY; // return delay between clock ticks
} // 0.05 is about as fast as should be used.
- (int)gameState // tell caller our state... if in demo, game is over
{ if (demoMode) return GAMEOVER; return state; }
- autoUpdate:sender // called by timed entry to update screen periodically
{ // ALL animation is controlled from here!!!
cycles++;
// you would do updates to various screen objects and
// then do a [self updateSelf:&bounds :1];
return self;
}
- updateSelf:(NXRect *)rects :(int)rectCount // redraws the screen.
{ // it redraws only what has changed since last redraw.
NXPing();
return self;
}
- mouseDown:(NXEvent *)event // handle mouseDown events.
{
[controller pauseGame:self]; // pause/unpause game
return self;
}
- (BOOL)acceptsFirstMouse // let us grab activating mousedowns
{ // 1st click is to become 1st responder, NOT pause/unpause
return NO;
}
- setKey:(int)keyIndex val:(char)keyVal // change key we respond to
{
keys[keyIndex] = keyVal;
return self;
}
- pause:sender // set pause status.
{
paused = YES;
return self;
}
- unpause:sender // remove paused status
{
paused = NO;
return self;
}
- (BOOL)isPaused // tell caller is we're paused
{ return paused; }
- keyDown:(NXEvent *)myevent // handle keyDown events.
{
if (myevent->data.key.charSet == NX_ASCIISET &&
(myevent->flags&(NX_CONTROLMASK|NX_ALTERNATEMASK|NX_COMMANDMASK)) == 0)
{
if (myevent->data.key.charCode == 'p') { // allow pause
if (paused) [controller unpause];
else [controller pause];
} else if (paused) { // any keyDown unpauses game (except 'p').
[controller unpause];
} else if (myevent->data.key.charCode == 'n') { // allow new game
if (([self gameState] != GAMEOVER) && ([preferences alert])) {
// if game in progress, alert user about this
if (NXRunAlertPanel(NULL,
"Do you want to throw away the current game?",
"You betcha!", "Um, no.", NULL) != NX_ALERTDEFAULT) {
return self; // allow "graceful escape"
}
}
if ([self gameState] != GAMEOVER) {
[controller gameOver]; // Force Game Over.
state = GAMEOVER;
}
[controller startNewGame:self]; // re-start the game
}
} else return [super keyDown:myevent];
return self;
}
- (BOOL)acceptsFirstResponder // to grab keyboard events
{ return YES; }
- getPreferences
{
soundEffects = [preferences effects];
music = [preferences music];
return self;
}
- soundOn // turn on sound effects
{
soundEffects = YES;
return self;
}
- soundOff // turn off sound effects
{
soundEffects = NO;
return self;
}
- musicOn // turn on music
{
music = YES;
return self;
}
- musicOff // turn off music
{
music = NO;
return self;
}
- free // get rid of support objects
{
[animator free];
[self unregisterWindow];
return [super free];
}
- setUpScreen
{
if ((demoMode)||(doingBorder)) [self display];
return self;
}
- changeBorder:(BOOL)borderOn
{ // move view about in the window & do sizing
// NOT USED in PacMan...it's best if you don't use it, in fact.
NXRect wFrame;
if (borderOn == grayBorder) return self;
if (borderOn) {
[window getFrame:&wFrame];
NXInsetRect(&wFrame, -BEZELSIZE, -BEZELSIZE);
[self moveBy:BEZELSIZE :BEZELSIZE];
[window placeWindowAndDisplay:&wFrame];
} else {
[window getFrame:&wFrame];
NXInsetRect(&wFrame, BEZELSIZE, BEZELSIZE);
[self moveBy:-BEZELSIZE :-BEZELSIZE];
[window placeWindowAndDisplay:&wFrame];
}
grayBorder = borderOn;
return self;
}
- restartGame
{
return self;
}
//// Background handling methods stolen from BreakApp:
//
- setBackgroundFile:(const char *)fileName andRemember:(BOOL)remember
// This methods allows changing the file used to paint the background of the
// playing field. Set fileName to NULL to revert to the default. Set
// remember to YES if you wish the write the value out in the defaults.
{
[backGround free];
backGround = [[NXImage allocFromZone:[self zone]] initSize:&bounds.size];
if (fileName) {
[backGround useFromFile:fileName];
if (remember) {
NXWriteDefault ([NXApp appName], "BackGround", fileName);
}
} else {
[backGround useFromSection:"BackGround.eps"];
if (remember) {
NXRemoveDefault ([NXApp appName], "BackGround");
}
}
backIsColor = NO;
[self writeColor];
[backGround setBackgroundColor:NX_COLORWHITE];
[backGround setScalable:YES];
[self display];
return self;
}
// The following two methods allow changing the background image from
// menu items or buttons.
- changeBackground:sender
{
const char *const types[] = {"tiff", "eps", NULL};
if ([[OpenPanel new] runModalForTypes:types]) {
[self setBackgroundFile:[[OpenPanel new] filename] andRemember:YES];
[self display];
}
return self;
}
- revertBackground:sender
{
[self setBackgroundFile:NULL andRemember:YES];
[self display];
return self;
}
- back1:sender
{
char *tempStr;
tempStr = malloc(256);
sprintf(tempStr, "%sBack1.tiff", appPath);
[self setBackgroundFile:tempStr andRemember:YES];
free(tempStr);
[self display];
return self;
}
- back2:sender
{
char *tempStr;
tempStr = malloc(256);
sprintf(tempStr, "%sBack2.tiff", appPath);
[self setBackgroundFile:tempStr andRemember:YES];
free(tempStr);
[self display];
return self;
}
- back3:sender
{
char *tempStr;
tempStr = malloc(256);
sprintf(tempStr, "%sBack3.tiff", appPath);
[self setBackgroundFile:tempStr andRemember:YES];
free(tempStr);
[self display];
return self;
}
- drawBackground:(NXRect *)rect
// drawBackground: just draws the specified piece of the background by
// compositing from the background image.
{
NXRect tmpRect = *rect;
if (backIsColor) {
NXSetColor(backColor);
NXRectFill(rect);
return self;
}
NX_X(&tmpRect) = floor(NX_X(&tmpRect));
NX_Y(&tmpRect) = floor(NX_Y(&tmpRect));
if (NXDrawingStatus == NX_DRAWING) {
PSsetgray (NX_WHITE);
PScompositerect (NX_X(&tmpRect), NX_Y(&tmpRect),
NX_WIDTH(&tmpRect), NX_HEIGHT(&tmpRect), NX_SOVER);
}
[backGround composite:NX_SOVER fromRect:&tmpRect toPoint:&tmpRect.origin];
return self;
}
- sizeTo:(NXCoord)width :(NXCoord)height
{
[super sizeTo:width :height];
[backGround setSize:&bounds.size];
return self;
}
// deal with drag and drop colors:
- acceptColor:(NXColor)color atPoint:(NXPoint *)aPoint
{
backIsColor = YES;
backColor = color;
[[self writeColor] update];
return self;
}
- writeColor
{
char def[256];
char bic[16] = "YES";
float r, g, b;
if (!backIsColor) sprintf(bic, "NO");
NXConvertColorToRGB(backColor, &r, &g, &b);
sprintf(def, "%s %f %f %f", bic, r, g, b);
NXWriteDefault ([NXApp appName], "BackColor", def);
return self;
}
// The drag and drop .tiff/.eps is borrowed and modified from the
// Adobe example NX_ImportAdv which demonstrates tiff/eps handling.
// I've taken the code chunk for drag and drop and modified it to
// work for setting backgrounds.
/*
* Registers the document window with the Workspace Manager so that when the
* user picks up an icon in the Workspace and drags it over our document window
* and lets go, iconEntered:... and iconReleasedAt::ok: messages will be
* sent to the DrawDocument from the Workspace Manager. Allows the user to
* drag PostScript and TIFF files into the document.
*/
- registerWindow
{
unsigned int windowNum;
id speaker = [NXApp appSpeaker];
listenerId = [Listener new];
[listenerId setDelegate:self];
[listenerId usePrivatePort];
[listenerId addPort];
NXConvertWinNumToGlobal([window windowNum], &windowNum);
[speaker setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
[speaker registerWindow:windowNum toPort:[listenerId listenPort]];
return self;
}
/* Undoes what registerWindow does. */
- unregisterWindow
{
unsigned int windowNum;
id speaker = [NXApp appSpeaker];
if (listenerId)
{
[speaker setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
NXConvertWinNumToGlobal([window windowNum], &windowNum);
[speaker unregisterWindow:windowNum];
[listenerId free];
}
return self;
}
/*
* Called whenever an icon is dragged from the Workspace over the document
* window. At this point, all that is done is to salt away the list of files
* represented by the icon. All the real work is done in iconReleasedAt::ok:.
*/
- (int)iconEntered:(int)windowNum at:(double)x :(double)y
iconWindow:(int)iconWindowNum iconX:(double)iconX iconY:(double)iconY
iconWidth:(double)iconWidth iconHeight:(double)iconHeight
pathList:(char *)pathList
{
if (!iconPathList || strcmp(iconPathList, pathList))
{ // if new list of files, copy it in for us to look at later
NX_FREE(iconPathList);
NX_MALLOC(iconPathList, char, strlen(pathList)+1);
strcpy(iconPathList, pathList);
}
return 0;
}
/*
* Goes through the list of files associated with the icon dragged
* from the Workspace and checks if any of them are PostScript or TIFF.
* If any are, then the GraphicView is asked to load those in as objects.
* Very important: an NX_DURING handler is required around all the processing
* of this method since an uncaught raised error will cause this method not
* to return and thus hang the Workspace Manager for a while.
*/
- (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag
{
volatile int foundOne = NO;
char *file, *tab, *extension;
NX_DURING
file = iconPathList;
tab = strchr(file, '\t');
if (tab)
*tab = '\0';
extension = strrchr(file, '.');
if (extension) {
if (!strcmp(extension, ".eps") || !strcmp(extension, ".tiff")) {
[self setBackgroundFile:file andRemember:YES];
foundOne = YES;
}
}
if (foundOne) {
[NXApp activateSelf:YES];
[window makeKeyAndOrderFront:self];
}
NX_HANDLER
NX_ENDHANDLER
*flag = foundOne;
return 0;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.