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.