This is robotView.m in view mode; [Download] [Up]
#import <appkit/NXImage.h> #import "robotView.h" #import "robotsController.h" #define RAND_X (random() % gridwidth) #define RAND_Y (random() % gridheight) #define RAND_OF(x) (random() % x) @implementation robotView - squareAtX:(int)i Y:(int)j { if ((i < 0) || (i >= gridwidth) || (j < 0) || (j >= gridheight)) { return nil; } return mySquares[gridwidth * j + i]; } - (BOOL)robotWithIDisFast:(int)idno { int i; aRobot *tmpBot; if (idno == NOROBOT) return NO; for (i = 0; i < [robotStorage count]; i++) { tmpBot = [robotStorage elementAt:i]; if (tmpBot->idnumber == idno) { if (tmpBot->speed == FAST) { return YES; } else { return NO; } } } return NO; } - (BOOL)isSafeX:(int)x Y:(int)y { int i, j, k; aSquare *testSquare = [self squareAtX:x Y:y]; if ((testSquare == nil) || ([testSquare hasRobotID] != NOROBOT) || [testSquare hasScrap]) { return NO; } for (i = -1; i <= 1; i++) { for (j = -1; j <= 1; j++) { if (nil == (testSquare = [self squareAtX:x + i Y:y + j])) continue; switch (abs (i) + abs (j)) { case 0: { /* This is the center square... We've already checked it. */ break; } case 1: { /* This is NSEW. Check the three next to it, too. */ if ([testSquare hasScrap]) break; if ([testSquare hasRobotID] != NOROBOT) return NO; for (k = -1; k <= 1; k++) { if (nil == (testSquare = [self squareAtX:(x + ((i != 0) ? 2 * i : k)) Y :(y + ((j != 0) ? 2 * j : k))])) { continue; } if ([self robotWithIDisFast:[testSquare hasRobotID]]) { return NO; } } break; } case 2: { if ([testSquare hasScrap]) break; if ([testSquare hasRobotID] != NOROBOT) return NO; if (nil == (testSquare = [self squareAtX:x + i * 2 Y:y + j * 2])) continue; if ([self robotWithIDisFast:[testSquare hasRobotID]]) return NO; break; } } /* End switch. */ } /* End for i */ } /* End for j */ return YES; } - drawGrid { NXRect myRect; NXSetRect (&myRect, 0, 0, gridwidth * GRIDSIZE + 2, gridheight * GRIDSIZE + 2); PSsetgray (NX_BLACK); NXEraseRect (&myRect); NXFrameRect (&myRect); /* NXSetRect (&myRect, 0, 0, GRIDSIZE, GRIDSIZE); PSsetgray (NX_LTGRAY); NXRectFill (&bounds); PSsetgray (NX_BLACK); for (y = 0; y < gridheight; y++) { myRect.origin.y = y * GRIDSIZE; for (x = 0; x < gridwidth; x++) { myRect.origin.x = x * GRIDSIZE; NXFrameRect (&myRect); } } */ return self; } - drawScrapAtX:(int)x Y:(int)y { NXRect scrapRect; NXSetRect (&scrapRect, x * GRIDSIZE + 1, y * GRIDSIZE + 1, GRIDSIZE, GRIDSIZE); [self lockFocus]; /* PSsetgray (NX_BLACK); NXRectFill (&scrapRect); */ [scrapImage composite:NX_SOVER toPoint:&scrapRect.origin]; [self unlockFocus]; return self; } - advanceLevel { int i, j; NXRunAlertPanel ("Level Cleared", "Level %d: Crushed %d robots into %d heaps.", "Cool", NULL, NULL, level, initialRobots, scrapheaps); for (i = 0; i < gridwidth; i++) { for (j = 0; j < gridheight; j++) { [[self squareAtX:i Y:j] init]; } } valuePerRobot += level * (5 + (initialRobots / scrapheaps)); initialRobots += level * 3 + RAND_OF (level * 5); /* This next line will be modified to %70, or so I guess. */ initialRobots = MIN (initialRobots, gridwidth * gridheight - 1); teleports += MIN (level, 3); level++; return self; } - newScrap { scrapheaps++; return self; } - teleportSafely:(BOOL)isSafe { int newX, newY; do { newX = RAND_X; newY = RAND_Y; } while ([[self squareAtX:newX Y:newY] hasScrap] || ([[self squareAtX:newX Y:newY] hasRobotID] != NOROBOT)); if (isSafe) { int i, newX, newY; for (i = 0; i < gridwidth * gridheight * 10; i++) { newX = RAND_X; newY = RAND_Y; if ([self isSafeX:newX Y:newY] && ![[self squareAtX:playerX Y:playerY] hasScrap]) { playerX = newX; playerY = newY; teleports--; [myDelegate showTeleports:teleports]; return self; } } { int x, y; teleports -= 4; [myDelegate showTeleports:teleports]; NXRunAlertPanel ("Nowhere To Run!!", "You NUKE all robots within 2 squares.", "Bye, 4 teleports", NULL, NULL); [self lockFocus]; PSsetgray (BACKGROUND); for (x = playerX - 2; x <= playerX + 2; x++) for (y = playerY - 2; y <= playerY + 2; y++) { aSquare *nukeSquare = [self squareAtX:x Y:y]; if (!nukeSquare) continue; if ([nukeSquare hasRobotID] != NOROBOT) { NXRect roboRect; NXSetRect (&roboRect, x * GRIDSIZE + 1, y * GRIDSIZE + 1, GRIDSIZE, GRIDSIZE); NXRectFill (&roboRect); [self deleteRobotID:[nukeSquare hasRobotID]]; } } [self unlockFocus]; } return self; } /* End isSafe */ else { playerX = newX; playerY = newY; } return self; } /* Clear any leftovers from last level. Init all the robots. */ - initLevel { NXRect myRect; int x, y; [self lockFocus]; NXSetRect (&myRect, 0, 0, gridwidth * GRIDSIZE + 2, gridheight * GRIDSIZE + 2); PSsetgray (NX_LTGRAY); NXRectFill (&bounds); [self drawGrid]; [self unlockFocus]; /* We'll teleport the player later */ playerX = gridwidth / 2; playerY = gridheight / 2; scrapheaps = 0; [myDelegate showRobots:initialRobots]; [myDelegate showHeaps:scrapheaps]; [myDelegate showLevel:level]; [myDelegate showScore:score]; [myDelegate showTeleports:teleports]; [myDelegate showValue:valuePerRobot]; /* Place all the robots. */ while ([robotStorage count] < initialRobots) { aRobot newRobot; x = RAND_X; y = RAND_Y; if ([[self squareAtX:x Y:y] hasRobotID] == NOROBOT) { id tmpId; newRobot.x = x; newRobot.y = y; newRobot.idnumber = [robotStorage count]; newRobot.speed = 1 + (RAND_OF (10) > 6); tmpId = [self squareAtX:x Y:y]; [tmpId addRobot:&newRobot]; [robotStorage addElement:&newRobot]; } } [self teleportSafely:NO]; return self; } - moveRobotsOfSpeed:(int)robotSpeed { int i; aRobot *tmpRobot; /* Delete the record of all the robots that are going to move this round from the squares that they are currently in. */ for (i = 0; i < [robotStorage count]; i++) { tmpRobot = [robotStorage elementAt:i]; if (tmpRobot->speed >= robotSpeed) { [tmpRobot->occupiedSquare removeRobot:tmpRobot]; } } /* Move all the robots (but don't place them yet). */ [self lockFocus]; for (i = 0; i < [robotStorage count]; i++) { tmpRobot = [robotStorage elementAt:i]; /* If we're handling all robots... */ if ((tmpRobot->speed >= robotSpeed) && (robotSpeed == NORMAL)) { NXRect robotRect; /* Erase the robot. */ NXSetRect (&robotRect, tmpRobot->x * GRIDSIZE + 1, tmpRobot->y * GRIDSIZE + 1, GRIDSIZE, GRIDSIZE); PSsetgray (BACKGROUND); NXRectFill (&robotRect); } if (tmpRobot->speed < robotSpeed) /* If this one is slow. */ continue; /* We just continue the loop. */ if (playerX > tmpRobot->x) tmpRobot->x++; if (playerX < tmpRobot->x) tmpRobot->x--; if (playerY > tmpRobot->y) tmpRobot->y++; if (playerY < tmpRobot->y) tmpRobot->y--; [[self squareAtX:tmpRobot->x Y:tmpRobot->y] addRobot:tmpRobot]; } [self unlockFocus]; if (robotSpeed == NORMAL) [self moveRobotsOfSpeed:FAST]; return self; } - doMove:(int)movetype whileSafe:(BOOL)repeat { int deltaX = 0, deltaY = 0, i = 0; NXRect playerRect; /* Erase the player. */ NXSetRect (&playerRect, playerX * GRIDSIZE + 1, playerY * GRIDSIZE + 1, GRIDSIZE, GRIDSIZE); [self lockFocus]; PSsetgray (BACKGROUND); NXRectFill (&playerRect); [self unlockFocus]; switch (movetype) { case DOWNLEFT: { if ((playerX > 0) && (playerY > 0)) { deltaX--; deltaY--; } break; } case DOWN: { if (playerY > 0) { deltaY--; } break; } case DOWNRIGHT: { if ((playerX < (gridwidth - 1)) && (playerY > 0)) { deltaX++; deltaY--; } break; } case LEFT: { if (playerX > 0) { deltaX--; } break; } case WAIT: { break; } case RIGHT: { if (playerX < (gridwidth - 1)) { deltaX++; } break; } case UPLEFT: { if ((playerX > 0) && (playerY < (gridheight - 1))) { deltaX--; deltaY++; } break; } case UP: { if (playerY < (gridheight - 1)) { deltaY++; } break; } case UPRIGHT: { if ((playerX < (gridwidth - 1)) && (playerY < (gridheight - 1))) { deltaX++; deltaY++; } break; } case TELEPORT: { [self teleportSafely:(repeat && (teleports > 0))]; repeat = NO; break; } case SCREWDRIVER: { int x, y; if (teleports > 0) { teleports--; [myDelegate showTeleports:teleports]; } else { return self; } for (x = playerX - 1; x <= playerX + 1; x++) { for (y = playerY - 1; y <= playerY + 1; y++) { aSquare *frySquare = [self squareAtX:x Y:y]; if ((frySquare != nil) && ([frySquare hasRobotID] != NOROBOT)) { NXRect roboRect; [self lockFocus]; PSsetgray (BACKGROUND); NXSetRect (&roboRect, x * GRIDSIZE + 1, y * GRIDSIZE + 1, GRIDSIZE, GRIDSIZE); NXRectFill (&roboRect); [self unlockFocus]; [self deleteRobotID:[frySquare hasRobotID]]; } } } break; } default: { printf ("ooops\n"); } } if ([[self squareAtX:(playerX + deltaX) Y :(playerY + deltaY)] hasScrap]) { if ((playerX + deltaX * 2 >= 0) && (playerY + deltaY * 2 >= 0) && (playerX + deltaX * 2 <= gridwidth - 1) && (playerY + deltaY * 2 <= gridheight - 1) && [[self squareAtX:(playerX + deltaX) Y :(playerY + deltaY)] moveScrap: [self squareAtX:(playerX + deltaX * 2) Y :(playerY + deltaY * 2)]]) { NXRect oldScrapRect; NXSetRect (&oldScrapRect, (playerX + deltaX) * GRIDSIZE + 1, (playerY + deltaY) * GRIDSIZE + 1, GRIDSIZE, GRIDSIZE); [self drawScrapAtX:(playerX + deltaX * 2) Y :(playerY + deltaY * 2)]; /* Erase the old scrap. */ [self lockFocus]; PSsetgray (BACKGROUND); NXRectFill (&oldScrapRect); [self unlockFocus]; playerX += deltaX; playerY += deltaY; [self moveRobotsOfSpeed:NORMAL]; } } else { playerX += deltaX; playerY += deltaY; [self moveRobotsOfSpeed:NORMAL]; } while ([robotStorage count] && i < [robotStorage count]) { aRobot *tmpRobot = [robotStorage elementAt:i]; if (tmpRobot->speed == DEAD) { [robotStorage removeElementAt:i]; } else { i++; } } if (([[self squareAtX:playerX Y:playerY] hasRobotID] != NOROBOT) || ([[self squareAtX:playerX Y:playerY] hasScrap])) { playerstate = WIPED; [self display]; return self; } if ([robotStorage count] == 0) { repeat = NO; [self advanceLevel]; [self initLevel]; } else { [myDelegate showRobots:[robotStorage count]]; [myDelegate showHeaps:scrapheaps]; [myDelegate showScore:score]; } [self display]; if (repeat) { if ([self isSafeX:playerX + deltaX Y:playerY + deltaY]) return[self doMove:movetype whileSafe:repeat]; } return self; } - keyDown:(NXEvent *)theEvent { if (theEvent->type != NX_KEYDOWN) return[super keyDown:theEvent]; switch (theEvent->data.key.charCode) { case '1': { [self doMove:DOWNLEFT whileSafe:(0 != (theEvent->flags & NX_COMMANDMASK))]; break; } case '2': { [self doMove:DOWN whileSafe:(0 != (theEvent->flags & NX_COMMANDMASK))]; break; } case '3': { [self doMove:DOWNRIGHT whileSafe:(0 != (theEvent->flags & NX_COMMANDMASK))]; break; } case '4': { [self doMove:LEFT whileSafe:(0 != (theEvent->flags & NX_COMMANDMASK))]; break; } case '5': { [self doMove:WAIT whileSafe:(0 != (theEvent->flags & NX_COMMANDMASK))]; break; } case '6': { [self doMove:RIGHT whileSafe:(0 != (theEvent->flags & NX_COMMANDMASK))]; break; } case '7': { [self doMove:UPLEFT whileSafe:(0 != (theEvent->flags & NX_COMMANDMASK))]; break; } case '8': { [self doMove:UP whileSafe:(0 != (theEvent->flags & NX_COMMANDMASK))]; break; } case '9': { [self doMove:UPRIGHT whileSafe:(0 != (theEvent->flags & NX_COMMANDMASK))]; break; } case 't': { [self doMove:TELEPORT whileSafe:(0 != (theEvent->flags & NX_COMMANDMASK))]; break; } case 'a': { [self doMove:SCREWDRIVER whileSafe:NO]; break; } default: { return[super keyDown:theEvent]; } } return self; } - init { int j; NXSize imagesize; imagesize.width = imagesize.height = GRIDSIZE; [super init]; srandom (time (0)); level = 1; score = 0; teleports = 1; playerstate = HEALTHY; initialRobots = 10; valuePerRobot = 10; if (mySquares) { for (j = 0; j < gridheight * gridwidth; j++) { [mySquares[j] free]; } free (mySquares); } /* Subtract 2 for the border. */ gridheight = (int)(bounds.size.height - 2) / GRIDSIZE; gridwidth = (int)(bounds.size.width - 2) / GRIDSIZE; mySquares = (id *)malloc (gridheight * gridwidth * sizeof (id)); for (j = 0; j < gridheight * gridwidth; j++) { mySquares[j] = [[aSquare alloc] init]; [mySquares[j] setDelegate:self]; } [robotStorage initCount:0 elementSize:sizeof (aRobot) description :"{iiic@}"]; [self initLevel]; slowRobotImage = [[NXImage alloc] initFromSection:"slowrobot"]; fastRobotImage = [[NXImage alloc] initFromSection:"fastrobot"]; scrapImage = [[NXImage alloc] initFromSection:"scrap"]; personImage = [[NXImage alloc] initFromSection:"person"]; wipedImage = [[NXImage alloc] initFromSection:"wiped"]; [[self window] makeKeyAndOrderFront:self]; [[self window] makeFirstResponder:self]; [self display]; return self; } - drawRobot:(aRobot *) theRobot { NXPoint roboPoint; roboPoint.x = theRobot->x * GRIDSIZE + 1; roboPoint.y = theRobot->y * GRIDSIZE + 1; switch (theRobot->speed) { case FAST: { [fastRobotImage composite:NX_SOVER toPoint:&roboPoint]; break; } case NORMAL: { [slowRobotImage composite:NX_SOVER toPoint:&roboPoint]; break; } default: { return self; } } /* NXRect roboRect; switch (theRobot->speed) { case FAST: { PSsetrgbcolor (1.0, 0.0, 0.0); break; } case NORMAL: { PSsetrgbcolor (0.0, 1.0, 0.0); break; } default: { return self; } } NXSetRect (&roboRect, theRobot->x * GRIDSIZE + 1, theRobot->y * GRIDSIZE + 1, GRIDSIZE, GRIDSIZE); NXRectFill (&roboRect); */ return self; } - drawSelf:(const NXRect *)rects :(int)rectCount { int i; aRobot *tmpRobot; NXRect playerRect; //[self drawGrid]; for (i = 0; i < [robotStorage count]; i++) { tmpRobot = [robotStorage elementAt:i]; [self drawRobot:tmpRobot]; } /* Draw the player. */ switch (playerstate) { case WIPED: { NXSetRect (&playerRect, (playerX - 1) * GRIDSIZE + 1, (playerY - 1) * GRIDSIZE + 1, GRIDSIZE, GRIDSIZE); [wipedImage composite:NX_SOVER toPoint:&(playerRect.origin)]; [myDelegate playerDead:self]; [[self window] makeFirstResponder:[self window]]; playerstate = UNSTARTED; break; } case HEALTHY: { NXSetRect (&playerRect, playerX * GRIDSIZE + 1, playerY * GRIDSIZE + 1, GRIDSIZE, GRIDSIZE); [personImage composite:NX_SOVER toPoint:&(playerRect.origin)]; break; } } return self; } - deleteRobot:(aRobot *) deadRobot { int i = 0; aRobot *tmpRobot; do { tmpRobot = [robotStorage elementAt:i]; } while ((tmpRobot->idnumber != deadRobot->idnumber) && (++i < [robotStorage count])); if (i < [robotStorage count]) { score += valuePerRobot; if (tmpRobot->speed == FAST) { score += valuePerRobot / 2; } tmpRobot->speed = DEAD; } return self; } - deleteRobotID:(int)deadRobotID { int i; aRobot *tmpRobot; if (deadRobotID == NOROBOT) { return self; } for (i = 0; i < [robotStorage count]; i++) { tmpRobot = [robotStorage elementAt:i]; if (tmpRobot->idnumber == deadRobotID) { [tmpRobot->occupiedSquare removeRobot:tmpRobot]; [self deleteRobot:tmpRobot]; return self; } } return self; } - scrapRobotID:(int)deadRobotID { int i; aRobot *tmpRobot; for (i = 0; i < [robotStorage count]; i++) { tmpRobot = [robotStorage elementAt:i]; if (tmpRobot->idnumber == deadRobotID) { [self drawScrapAtX:tmpRobot->x Y:tmpRobot->y]; [self deleteRobot:tmpRobot]; return self; } } /* Trouble if we get here!! */ i = i / (i - i); return self; } - (int)playerState { return playerstate; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.