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.