This is WorldMapView.m in view mode; [Download] [Up]
//
// $Id: WorldMapView.m,v 1.8 1997/10/31 04:52:16 nygard Exp $
//
//
// This file is a part of Empire, a game of exploration and conquest.
// Copyright (C) 1996 Steve Nygard
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// You may contact the author by:
// e-mail: nygard@telusplanet.net
//
#import "Empire.h"
RCSID ("$Id: WorldMapView.m,v 1.8 1997/10/31 04:52:16 nygard Exp $");
#import "WorldMapView.h"
#import "Brain.h"
#import "Map.h"
#import "EmpireImageVendor.h"
#import "Map.h"
#import "MapView.h" // To pick up delegate protocol definition (no longer..)
#import "EmpireProtocols.h" // To pick up delegate protocol definition
#define GRIDSIZE 4.0
//======================================================================
// The World Map View provides a small view of the entire world. I'm
// not sure what the normal map view would look like if it were scaled
// down to this size.
//
// Much of the interface should be the same as MapView.
//
//======================================================================
@implementation WorldMapView
- initWithFrame:(NSRect)frameRect
{
EmpireImageVendor *vendor = [EmpireImageVendor instance];
Player p;
[super initWithFrame:frameRect];
[vendor attach:self];
for (p = p_neutral; p <= p_player3; p++)
playerColors[p] = [vendor colorForPlayer:p];
terrainColors[0] = [[NSColor blackColor] retain];
terrainColors[1] = [[NSColor colorWithCalibratedRed:0 green:0 blue:153 / 255.0 alpha:1.0] retain];
terrainColors[2] = [[NSColor colorWithCalibratedRed:0 green:85 / 255.0 blue:0 alpha:1.0] retain];
terrainColors[3] = [playerColors[0] retain];
compressEvents = NO;
return self;
}
//----------------------------------------------------------------------
- (void) dealloc
{
int l;
[[EmpireImageVendor instance] detach:self];
for (l = 0; l < 4; l++)
{
SNRelease (terrainColors[l]);
}
if (map != nil)
[map detach:self];
[super dealloc];
}
//----------------------------------------------------------------------
- (BOOL) acceptsFirstResponder
{
return YES;
}
//----------------------------------------------------------------------
- (BOOL) acceptsFirstMouse:(NSEvent *)theEvent
{
return YES;
}
//----------------------------------------------------------------------
#define RCOUNT 16
// This builds up lists of RCOUNT rectangles for the different colors,
// and then fills them as a group when full. This gets pretty good
// performance.
- (void) drawRect:(NSRect)rect
{
EMMapLocation location1, location2;
int row, column;
EMMapSize mapSize;
NSPoint aPoint;
MapToken **mapPtrs = [map mapPtrs];
int l;
NSRect blackRects[RCOUNT];
NSRect playerRects[4][RCOUNT];
NSRect terrainRects[4][RCOUNT];
int blackCount;
int playerCount[4];
int terrainCount[4];
if (map != nil)
{
mapSize = [map mapSize];
blackCount = 0;
for (l = 0; l < 4; l++)
playerCount[l] = terrainCount[l] = 0;
aPoint.x = NSMinX (rect);
aPoint.y = NSMinY (rect);
location1 = [self getLocationForPoint:aPoint];
aPoint.x += NSWidth (rect);
aPoint.y += NSHeight (rect);
location2 = [self getLocationForPoint:aPoint];
for (row = location2.row; row <= location1.row; row++)
{
aPoint.y = GRIDSIZE * (float)(mapSize.height - 1 - row);
for (column = location1.column; column <= location2.column; column++)
{
MapToken mapToken = mapPtrs[row][column];
Terrain terrain;
Player player;
BOOL explored;
EMMapTokenComponents (mapToken, &terrain, &player, NULL, &explored);
aPoint.x = GRIDSIZE * (float)column;
if (explored == NO)
{
blackRects[blackCount++] = NSMakeRect(aPoint.x, aPoint.y, GRIDSIZE, GRIDSIZE);
if (blackCount == RCOUNT)
{
PSsetgray (NSBlack);
NSRectFillList (blackRects, blackCount);
blackCount = 0;
}
}
else if (player >= p_player1 && player <= p_player3)
{
playerRects[player][playerCount[player]++] = NSMakeRect (aPoint.x, aPoint.y, GRIDSIZE, GRIDSIZE);
if (playerCount[player] == RCOUNT)
{
[playerColors[player] set];
NSRectFillList (playerRects[player], playerCount[player]);
playerCount[player] = 0;
}
}
else
{
terrainRects[terrain][terrainCount[terrain]++] = NSMakeRect (aPoint.x, aPoint.y, GRIDSIZE, GRIDSIZE);
if (terrainCount[terrain] == RCOUNT)
{
[terrainColors[terrain] set];
NSRectFillList (terrainRects[terrain], terrainCount[terrain]);
terrainCount[terrain] = 0;
}
}
}
}
if (blackCount > 0)
{
PSsetgray (NSBlack);
NSRectFillList (blackRects, blackCount);
blackCount = 0;
}
for (l = 0; l < 4; l++)
{
if (playerCount[l] > 0)
{
[playerColors[l] set];
NSRectFillList (playerRects[l], playerCount[l]);
playerCount[l] = 0;
}
if (terrainCount[l] > 0)
{
[terrainColors[l] set];
NSRectFillList (terrainRects[l], terrainCount[l]);
terrainCount[l] = 0;
}
}
}
}
//----------------------------------------------------------------------
- (Map *) map
{
return map;
}
//----------------------------------------------------------------------
- (void) setMap:(Map *)aMap
{
EMMapSize mapSize;
if (aMap == nil)
return;
if (map != nil)
{
[map detach:self];
[map release];
}
map = aMap;
[map attach:self];
[map retain];
mapSize = [map mapSize];
[self setFrameSize:NSMakeSize (GRIDSIZE * (float)mapSize.width, GRIDSIZE * (float)mapSize.height)];
[self setNeedsDisplay:YES];
}
//----------------------------------------------------------------------
- (void) setCompressEvents:(BOOL)flag
{
compressEvents = flag;
}
//----------------------------------------------------------------------
- (EMMapLocation) getLocationForPoint:(NSPoint)point
{
EMMapSize mapSize;
EMMapLocation target;
NSAssert (map != nil, @"Map was nil.");
mapSize = [map mapSize];
target.row = mapSize.height - (int)(point.y / GRIDSIZE) - 1;
target.column = point.x / GRIDSIZE;
target.row = (target.row >= mapSize.height) ? mapSize.height - 1 : target.row;
target.row = (target.row <= 0) ? 0 : target.row;
target.column = (target.column >= mapSize.width) ? mapSize.width - 1 : target.column;
target.column = (target.column < 0) ? 0 : target.column;
return target;
}
//----------------------------------------------------------------------
- (NSRect) getRectForLocation:(EMMapLocation)target
{
EMMapSize mapSize;
NSAssert (map != nil, @"Map was nil.");
mapSize = [map mapSize];
return NSMakeRect (GRIDSIZE * (float)target.column, (mapSize.height - 1 - target.row) * GRIDSIZE, GRIDSIZE, GRIDSIZE);
}
//----------------------------------------------------------------------
- (NSRect) getRectAround3x3Location:(EMMapLocation)target
{
EMMapLocation location1, location2;
EMMapSize mapSize;
NSAssert (map != nil, @"Map was nil.");
mapSize = [map mapSize];
location1.row = target.row - 1;
location1.row = (location1.row < 0) ? 0 : location1.row;
location1.row = (location1.row >= mapSize.height) ? mapSize.height - 1 : location1.row;
location2.row = target.row + 1;
location2.row = (location2.row < 0) ? 0 : location2.row;
location2.row = (location2.row >= mapSize.height) ? mapSize.height - 1 : location2.row;
location1.column = target.column - 1;
location1.column = (location1.column < 0) ? 0 : location1.column;
location1.column = (location1.column >= mapSize.width) ? mapSize.width - 1 : location1.column;
location2.column = target.column + 1;
location2.column = (location2.column < 0) ? 0 : location2.column;
location2.column = (location2.column >= mapSize.width) ? mapSize.width - 1 : location2.column;
return NSMakeRect ((float)location1.column * GRIDSIZE, (mapSize.height - 1 - location2.row) * GRIDSIZE,
(float)(location2.column - location1.column + 1) * GRIDSIZE,
(float)(location2.row - location1.row + 1) * GRIDSIZE);
}
//----------------------------------------------------------------------
- (void) scrollLocationToVisible:(EMMapLocation)target
{
NSRect aRect = [self getRectAround3x3Location:target];
[self scrollRectToVisible:aRect];
}
//----------------------------------------------------------------------
- (void) centerLocation:(EMMapLocation)target ifNotVisible:(BOOL)notVisibleFlag
{
NSRect aRect;
NSRect visibleRect;
aRect = [self getRectAround3x3Location:target];
visibleRect = [self visibleRect];
aRect.origin.x = NSMinX (aRect) + (NSWidth (aRect) / 2) - (NSWidth (visibleRect) / 2);
aRect.origin.y = NSMinY (aRect) + (NSHeight (aRect) / 2) - (NSHeight (visibleRect) / 2);
aRect.size.width = NSWidth (visibleRect);
aRect.size.height = NSHeight (visibleRect);
aRect = NSIntersectionRect ([self bounds] , aRect);
[self scrollRectToVisible:aRect];
}
//----------------------------------------------------------------------
- (void) displayLocation:(EMMapLocation)target
{
EMMapSize mapSize;
NSRect aRect;
NSAssert (map != nil, @"Map was nil.");
mapSize = [map mapSize];
NSAssert (target.row >= 0 && target.column >= 0
&& target.row < mapSize.height && target.column < mapSize.width, @"Cell out of range.");
aRect = [self getRectForLocation:target];
[self scrollRectToVisible:aRect];
[self setNeedsDisplayInRect:aRect];
[self displayIfNeeded];
}
//----------------------------------------------------------------------
- (void) displayAround3x3Location:(EMMapLocation)target
{
EMMapSize mapSize;
NSRect aRect;
NSAssert (map != nil, @"Map was nil.");
mapSize = [map mapSize];
NSAssert (target.row >= 0 && target.column >= 0
&& target.row < mapSize.height && target.column < mapSize.width, @"Location out of range.");
aRect = [self getRectAround3x3Location:target];
[self scrollRectToVisible:aRect];
[self setNeedsDisplayInRect:aRect];
[self displayIfNeeded];
}
//----------------------------------------------------------------------
- (void) vendorImagesUpdated:(BOOL)player1:(BOOL)player2:(BOOL)player3:(BOOL)other
{
EmpireImageVendor *vendor = [EmpireImageVendor instance];
Player p;
for (p = p_neutral; p <= p_player3; p++)
playerColors[p] = [vendor colorForPlayer:p];
terrainColors[3] = playerColors[0];
[self setNeedsDisplay:YES];
}
//======================================================================
// Map Observer
//======================================================================
- (void) refreshMap
{
[self setNeedsDisplay:YES];
}
//----------------------------------------------------------------------
- (void) refreshLocation:(EMMapLocation)target
{
[self displayLocation:target];
//[self displayIfNeeded];
}
//----------------------------------------------------------------------
- (void) refresh3x3Location:(EMMapLocation)target
{
[self displayAround3x3Location:target];
}
//----------------------------------------------------------------------
- (void) mouseDown:(NSEvent *)theEvent
{
NSPoint aPoint;
EMMapLocation mapLocation;
NSRect visibleRect;
BOOL scrolled = NO;
NSPoint mouseLocation;
EMMapLocation lastLocation;
BOOL periodicOn = NO;
unsigned int originalModifierFlags = [theEvent modifierFlags];
unsigned int modifierFlags;
lastLocation.row = -1;
lastLocation.column = -1;
if (delegate == nil)
{
[super mouseDown:theEvent];
return;
}
mouseLocation = [theEvent locationInWindow];
while ([theEvent type] != NSLeftMouseUp)
{
visibleRect = [self visibleRect];
switch ([theEvent type])
{
case NSLeftMouseUp:
break;
case NSPeriodic:
case NSLeftMouseDown:
case NSLeftMouseDragged:
if ([theEvent type] == NSPeriodic)
{
mouseLocation = [[self window] mouseLocationOutsideOfEventStream];
modifierFlags = originalModifierFlags;
}
else
{
mouseLocation = [theEvent locationInWindow];
modifierFlags = [theEvent modifierFlags];
}
aPoint = [self convertPoint:mouseLocation fromView:nil];
mapLocation = [self getLocationForPoint:aPoint];
if (compressEvents == NO
|| mapLocation.row != lastLocation.row || mapLocation.column != lastLocation.column
|| [theEvent type] == NSPeriodic
|| (originalModifierFlags & NSControlKeyMask != 0))
{
lastLocation = mapLocation;
[delegate mouseDown:modifierFlags atLocation:mapLocation];
}
//if (compressEvents == NO)
{
if (periodicOn == NO)
{
[NSEvent startPeriodicEventsAfterDelay:0.1 withPeriod:0.05];
periodicOn = YES;
}
}
if (NSPointInRect(mouseLocation, visibleRect) == NO)
{
scrolled = YES;
if (periodicOn == NO)
{
[NSEvent startPeriodicEventsAfterDelay:0.1 withPeriod:0.05];
periodicOn = YES;
}
}
else if (compressEvents == YES)
{
[NSEvent stopPeriodicEvents];
periodicOn = NO;
}
break;
default:
break;
}
if (scrolled)
scrolled = NO;
theEvent = [[self window] nextEventMatchingMask:(NSLeftMouseUpMask | NSLeftMouseDraggedMask | NSPeriodicMask)];
}
[NSEvent stopPeriodicEvents];
// Mouse up event has been consumed by this point.
[self mouseUp:theEvent];
}
//----------------------------------------------------------------------
- (void) mouseUp:(NSEvent *)theEvent
{
NSPoint point;
EMMapLocation mapLocation;
if ([theEvent type] == NSLeftMouseUp && delegate != nil)
{
//NSLog (@"here.");
point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
mapLocation = [self getLocationForPoint:point];
//NSLog (@"delegate: %@", delegate);
[delegate mouseUp:[theEvent modifierFlags] atLocation:mapLocation];
}
else
{
[super mouseUp:theEvent];
}
}
//----------------------------------------------------------------------
- (void) keyDown:(NSEvent *)theEvent
{
if (delegate != nil)
{
[delegate keyDown:theEvent];
}
else
{
[super keyDown:theEvent];
}
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.