This is Map.m in view mode; [Download] [Up]
//
// $Id: Map.m,v 1.10 1997/10/31 04:51:50 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: Map.m,v 1.10 1997/10/31 04:51:50 nygard Exp $");
#import "Map.h"
#define MAP_CLASSNAME @"Map"
#define Map_VERSION 0
//======================================================================
// The Map is central to the game. It represents the terrain, the units
// of the player, and the last known location of the units of other
// players. (Fog of war.)
//
// Maps are copied across the wire in distributed games, since the
// complete state of the world is derived by combining knowledge from
// each map.
//======================================================================
@implementation Map
+ (void) initialize
{
if (self == [Map class])
{
[self setVersion:Map_VERSION];
}
}
//----------------------------------------------------------------------
- initMapWithSize:(EMMapSize)size;
{
int l;
[super init];
mapSize = size;
mapData = (MapToken *)malloc (sizeof (MapToken) * mapSize.width * mapSize.height);
NSAssert (mapData != NULL, @"Error malloc()'ing map data");
mapPointers = (MapToken **)malloc (sizeof (MapToken *) * mapSize.height);
NSAssert (mapPointers != NULL, @"Error malloc()'ing map pointers");
memset ((char *)mapData, 0, sizeof (MapToken) * mapSize.width * mapSize.height);
for (l = 0; l < mapSize.height; l++)
mapPointers[l] = &mapData[l * mapSize.width];
observers = [[NSMutableArray array] retain];
//NSLog (@"Map version: %d", [Map version]);
return self;
}
//----------------------------------------------------------------------
- (void) dealloc
{
// And notify observers?
SNRelease (observers);
if (mapData != NULL)
free (mapData);
if (mapPointers != NULL)
free (mapPointers);
[super dealloc];
}
//----------------------------------------------------------------------
- copyWithZone:(NSZone *)zone
{
MapToken *newMapData;
Map *newMap = [[Map allocWithZone:zone] initMapWithSize:mapSize];
int l;
newMapData = [newMap mapData];
for (l = 0; l < mapSize.width * mapSize.height; l++)
newMapData[l] = mapData[l];
return newMap;
}
//----------------------------------------------------------------------
- copyAndStripIconsFromZone:(NSZone *)zone
{
MapToken *newMapData;
int l;
Map *newMap = [[Map allocWithZone:zone] initMapWithSize:mapSize];
newMapData = [newMap mapData];
for (l = 0; l < mapSize.width * mapSize.height; l++)
{
if (EMIconComponent (mapData[l]) != i_none)
newMapData[l] = mapData[l] & ~MT_ICON_MASK;
else
newMapData[l] = mapData[l];
}
return newMap;
}
//----------------------------------------------------------------------
- (void) encodeWithCoder:(NSCoder *)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeValuesOfObjCTypes:"ii", &mapSize.width, &mapSize.height];
[aCoder encodeArrayOfObjCType:"i" count:mapSize.width * mapSize.height at:mapData];
}
//----------------------------------------------------------------------
- initWithCoder:(NSCoder *)aDecoder
{
int l;
[super initWithCoder:aDecoder];
//NSLog (@"version of map in archive: %d", [aDecoder versionForClassName:MAP_CLASSNAME]);
[aDecoder decodeValuesOfObjCTypes:"ii", &mapSize.width, &mapSize.height];
mapData = (MapToken *)malloc (sizeof (MapToken) * mapSize.width * mapSize.height);
NSAssert (mapData != NULL, @"Error malloc()'ing map data");
[aDecoder decodeArrayOfObjCType:"i" count:mapSize.width * mapSize.height at:mapData];
mapPointers = (MapToken **)malloc (sizeof (MapToken *) * mapSize.height);
NSAssert (mapPointers != NULL, @"Error malloc()'ing map pointers");
for (l = 0; l < mapSize.height; l++)
mapPointers[l] = &mapData[l * mapSize.width];
observers = [[NSMutableArray array] retain];
return self;
}
//----------------------------------------------------------------------
// We want to support actual copying of maps, for distributed game,
// since there is very frequent use of the data.
//----------------------------------------------------------------------
- replacementObjectForPortCoder:(NSPortCoder *)encoder
{
if ([encoder isBycopy] == YES)
return self;
return [super replacementObjectForPortCoder:encoder];
}
//----------------------------------------------------------------------
- (EMMapSize) mapSize
{
return mapSize;
}
//----------------------------------------------------------------------
- (int) percentExplored
{
int l;
int total = mapSize.width * mapSize.height;
int explored = 0;
NSAssert (total != 0, @"Total size of map is 0.");
for (l = 0; l < total; l++)
if ((mapData[l] & MT_EXPLORED_MASK) == 0)
explored++;
return 100 * (float)explored / total;
}
//----------------------------------------------------------------------
- (MapToken *) mapData
{
return mapData;
}
//----------------------------------------------------------------------
- (MapToken **) mapPtrs
{
return mapPointers;
}
//----------------------------------------------------------------------
- (MapToken) tokenAtLocation:(EMMapLocation)target
{
if (target.row < 0 || target.column < 0
|| target.row >= mapSize.height || target.column >= mapSize.width)
{
return MT_EXPLORED_MASK;
}
return mapPointers[target.row][target.column];
}
//----------------------------------------------------------------------
- (void) get3x3Tokens:(MapToken *)tokens aroundLocation:(EMMapLocation)target
{
int count = 0;
int d_row, d_col;
int t_row, t_col;
for (d_row = -1; d_row <= 1; d_row++)
{
for (d_col = -1; d_col <= 1; d_col++)
{
t_row = target.row + d_row;
t_col = target.column + d_col;
if (t_row < 0 || t_col < 0 || t_row >= mapSize.height || t_col >= mapSize.width)
tokens[count] = 0;
else
tokens[count] = mapPointers[t_row][t_col];
count++;
}
}
}
//----------------------------------------------------------------------
// We need this method for when we explore a location.
//----------------------------------------------------------------------
- (void) get5x5Tokens:(MapToken *)tokens aroundLocation:(EMMapLocation)target
{
int count = 0;
int d_row, d_col;
int t_row, t_col;
for (d_row = -2; d_row <= 2; d_row++)
{
for (d_col = -2; d_col <= 2; d_col++)
{
t_row = target.row + d_row;
t_col = target.column + d_col;
if (t_row < 0 || t_col < 0 || t_row >= mapSize.height || t_col >= mapSize.width)
tokens[count] = MT_EXPLORED_MASK;
else
tokens[count] = mapPointers[t_row][t_col];
count++;
}
}
}
//----------------------------------------------------------------------
- (void) setToken:(MapToken)token atLocation:(EMMapLocation)target
{
if (target.row >= 0 && target.column >= 0
&& target.row < mapSize.height && target.column < mapSize.width)
{
if (mapPointers[target.row][target.column] != token)
{
mapPointers[target.row][target.column] = token;
[self refreshLocation:target];
}
}
}
//----------------------------------------------------------------------
- (void) set3x3Tokens:(MapToken *)tokens aroundLocation:(EMMapLocation)target
{
MapToken original[9];
int count = 0;
int d_row, d_col;
int t_row, t_col;
BOOL changed = NO;
[self get3x3Tokens:original aroundLocation:target];
for (count = 0; count < 9; count++)
{
if (original[count] != tokens[count])
{
changed = YES;
break;
}
}
count = 0;
if (changed == YES)
{
for (d_row = -1; d_row <= 1; d_row++)
{
for (d_col = -1; d_col <= 1; d_col++)
{
t_row = target.row + d_row;
t_col = target.column + d_col;
if (t_row >= 0 && t_col >= 0 && t_row < mapSize.height && t_col < mapSize.width)
mapPointers[t_row][t_col] = tokens[count];
count++;
}
}
[self refresh3x3Location:target];
}
}
//----------------------------------------------------------------------
- (void) set3x3TokensTo:(MapToken)token aroundLocation:(EMMapLocation)target
{
MapToken original[9];
int d_row, d_col;
int t_row, t_col;
BOOL changed = NO;
int l;
[self get3x3Tokens:original aroundLocation:target];
for (l = 0; l < 9; l++)
{
if (original[l] != token)
{
changed = YES;
break;
}
}
if (changed == YES)
{
for (d_row = -1; d_row <= 1; d_row++)
{
for (d_col = -1; d_col <= 1; d_col++)
{
t_row = target.row + d_row;
t_col = target.column + d_col;
if (t_row >= 0 && t_col >= 0 && t_row < mapSize.height && t_col < mapSize.width)
mapPointers[t_row][t_col] = token;
}
}
[self refresh3x3Location:target];
}
}
//----------------------------------------------------------------------
- (void) put:(Player)player:(Icon)icon atLocation:(EMMapLocation)target
{
if (target.row >= 0 && target.column >= 0 && target.row < mapSize.height && target.column < mapSize.width)
{
MapToken target_token = mapPointers[target.row][target.column];
Terrain target_terrain;
Icon target_icon;
Player targetPlayer;
EMMapTokenComponents (target_token, &target_terrain, &targetPlayer, &target_icon, NULL);
// Since we remove destroyed enemies from *thier* map, not ours...
if ((target_icon == i_none || targetPlayer != player) && target_terrain != t_city)
{
[self setToken:EMCreateMapToken (target_terrain, player, icon, YES) atLocation:target];
}
}
}
//----------------------------------------------------------------------
- (void) remove:(Icon)icon atLocation:(EMMapLocation)target
{
if (target.row >= 0 && target.column >= 0 && target.row < mapSize.height && target.column < mapSize.width)
{
MapToken target_token = mapPointers[target.row][target.column];
Terrain target_terrain;
Icon target_icon;
UnitType target_unit_type;
UnitType this_unit_type;
EMMapTokenComponents (target_token, &target_terrain, NULL, &target_icon, NULL);
this_unit_type = EMConvertIconToUnitType (icon);
target_unit_type = EMConvertIconToUnitType (target_icon);
if (this_unit_type == target_unit_type && target_terrain != t_city)
{
[self setToken:EMCreateMapToken (target_terrain, p_neutral, i_none, YES) atLocation:target];
}
}
}
//----------------------------------------------------------------------
- (void) setCityAtLocation:(EMMapLocation)target toPlayer:(Player)number
{
if (target.row >= 0 && target.column >= 0 && target.row < mapSize.height && target.column < mapSize.width)
{
MapToken target_token = mapPointers[target.row][target.column];
Terrain target_terrain;
Icon target_icon;
EMMapTokenComponents (target_token, &target_terrain, NULL, &target_icon, NULL);
NSAssert (target_terrain == t_city, @"There is not a city at that location.");
[self setToken:EMCreateMapToken (target_terrain, number, target_icon, YES) atLocation:target];
}
}
//----------------------------------------------------------------------
- (void) clearMapTo:(MapToken)token
{
int l;
for (l = 0; l < mapSize.width * mapSize.height; l++)
mapData[l] = token;
[self refreshMap];
}
//----------------------------------------------------------------------
- (void) setMapExplored:(BOOL)isExplored
{
int l;
if (isExplored == YES)
{
for (l = 0; l < mapSize.width * mapSize.height; l++)
mapData[l] &= ~MT_EXPLORED_MASK;
}
else
{
for (l = 0; l < mapSize.width * mapSize.height; l++)
mapData[l] |= MT_EXPLORED_MASK;
}
}
//----------------------------------------------------------------------
// Remove icons, leaving only terrain and player cities.
// To be used in preparation for production view.
//----------------------------------------------------------------------
- (void) stripIcons
{
int l;
for (l = 0; l < mapSize.width * mapSize.height; l++)
if (EMIconComponent (mapData[l]) != i_none)
mapData[l] &= ~MT_ICON_MASK;
}
//----------------------------------------------------------------------
// This is for when a player resigns, or has been destroyed.
//----------------------------------------------------------------------
- (void) stripIconsOfPlayer:(Player)number
{
Terrain terrain;
Player player;
BOOL explored;
int l;
for (l = 0; l < mapSize.width * mapSize.height; l++)
{
EMMapTokenComponents (mapData[l], &terrain, &player, NULL, &explored);
if (player == number)
mapData[l] = EMCreateMapToken (terrain, p_neutral, i_none, explored);
}
[self refreshMap];
[self strippedIconsOfPlayer:number];
}
//----------------------------------------------------------------------
- (int) countTerrainType:(Terrain)terrain
{
int count = 0;
int l;
for (l = 0; l < mapSize.width * mapSize.height; l++)
{
if (EMTerrainComponent (mapData[l]) == terrain)
count++;
}
return count;
}
//----------------------------------------------------------------------
- (void) explore3x3AroundLocation:(EMMapLocation)target
{
MapToken newArea[9];
int l;
[self get3x3Tokens:newArea aroundLocation:target];
for (l = 0; l < 9; l++)
newArea[l] &= ~MT_EXPLORED_MASK;
[self set3x3Tokens:newArea aroundLocation:target];
}
//======================================================================
// Observer Pattern
//======================================================================
- (void) refreshMap
{
NSEnumerator *objectEnumerator = [observers objectEnumerator];
id tmp;
while (tmp = [objectEnumerator nextObject])
{
if ([tmp respondsToSelector:@selector (refreshMap)] == YES)
[tmp refreshMap];
}
}
//----------------------------------------------------------------------
- (void) refreshLocation:(EMMapLocation)target
{
NSEnumerator *objectEnumerator = [observers objectEnumerator];
id tmp;
while (tmp = [objectEnumerator nextObject])
{
if ([tmp respondsToSelector:@selector (refreshLocation:)] == YES)
[tmp refreshLocation:target];
}
}
//----------------------------------------------------------------------
- (void) refresh3x3Location:(EMMapLocation)target
{
NSEnumerator *objectEnumerator = [observers objectEnumerator];
id tmp;
while (tmp = [objectEnumerator nextObject])
{
if ([tmp respondsToSelector:@selector (refresh3x3Location:)] == YES)
[tmp refresh3x3Location:target];
}
}
//----------------------------------------------------------------------
- (void) strippedIconsOfPlayer:(Player)number
{
NSEnumerator *objectEnumerator = [observers objectEnumerator];
id tmp;
while (tmp = [objectEnumerator nextObject])
{
if ([tmp respondsToSelector:@selector (strippedIconsOfPlayer:)] == YES)
[tmp strippedIconsOfPlayer:number];
}
}
//----------------------------------------------------------------------
- (void) attach:observer
{
[observers addObject:observer];
}
//----------------------------------------------------------------------
- (void) detach:observer
{
[observers removeObject:observer];
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.