This is City.m in view mode; [Download] [Up]
// // $Id: City.m,v 1.13 1997/10/31 04:51:34 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: City.m,v 1.13 1997/10/31 04:51:34 nygard Exp $"); #import "City.h" #import "Map.h" #import "EmPlayer.h" #import "Unit.h" #import "Orders.subproj/Orders.h" #import "PathSegment.h" static int _cityNumber = 0; #if 1 // Production times for 50 % production efficiency. int unit_production_times[][2] = { // initial production, subsequent production { 0, 0 }, // u_unknown { 6, 5 }, // u_army { 12, 10 }, // u_fighter { 30, 25 }, // u_transport { 24, 20 }, // u_submarine { 24, 20 }, // u_destroyer { 42, 35 }, // u_cruiser { 48, 40 }, // u_carrier { 60, 50 }, // u_battleship { 24, 1000 } // u_hovercraft }; #else // These are more suitable for testing... int unit_production_times[][2] = { // initial production, subsequent production { 0, 0 }, // u_unknown { 2, 1 }, // u_army { 2, 1000 }, // u_fighter { 2, 100 }, // u_transport { 2, 200 }, // u_submarine { 2, 200 }, // u_destroyer { 2, 350 }, // u_cruiser { 48, 40 }, // u_carrier { 60, 50 }, // u_battleship { 1, 1000 } // u_hovercraft }; #endif //====================================================================== // Cities produce units for a player. They may be sent across the // wire in distributed games. // // The encoding needs to be revised if we want to support saved games. //====================================================================== #define City_VERSION 1 @implementation City + (void) initialize { if (self == [City class]) { [self setVersion:City_VERSION]; } } //---------------------------------------------------------------------- // Perhaps a city shouldn't be required to know about maps and tokens... //---------------------------------------------------------------------- - initAtLocation:(EMMapLocation)theCityLocation ofMap:(Map *)map { MapToken mapTokens[9]; int l; [super init]; cityLocation = theCityLocation; // Mutable? cityName = [[NSString stringWithFormat:@"City #%d", _cityNumber++] retain]; NSAssert (cityName != nil, @"City name is nil."); owner = nil; cityUnits = [[NSMutableArray array] retain]; port = NO; // Perhaps the map should be updated first? for (l = 0; l < 9; l++) mapTokens[l] = -1; [map get3x3Tokens:mapTokens aroundLocation:cityLocation]; for (l = 0; l < 9; l++) { if (mapTokens[l] != -1 && EMTerrainComponent (mapTokens[l]) == t_water) port = YES; } observers = [[NSMutableArray array] retain]; flightPath = nil; productionType = u_unknown; firstUnit = YES; [self setProduction:u_army]; return self; } //---------------------------------------------------------------------- - (void) dealloc { SNRelease (cityName); SNRelease (cityUnits); SNRelease (observers); SNRelease (flightPath); [super dealloc]; } //---------------------------------------------------------------------- - (void) encodeWithCoder:(NSCoder *)aCoder { //NSAssert (owner == nil, @"Won't encode owner."); [super encodeWithCoder:aCoder]; [aCoder encodeValuesOfObjCTypes:"iic", &cityLocation.row, &cityLocation.column, &port]; [aCoder encodeObject:cityName]; // Cities are only encoded when they've been captured -- production type, and // other player specific things need not be encoded. } //---------------------------------------------------------------------- - initWithCoder:(NSCoder *)aDecoder { [super initWithCoder:aDecoder]; [aDecoder decodeValuesOfObjCTypes:"iic", &cityLocation.row, &cityLocation.column, &port]; cityName = [[aDecoder decodeObject] retain]; owner = nil; cityUnits = [[NSMutableArray array] retain]; observers = [[NSMutableArray array] retain]; productionType = u_unknown; firstUnit = YES; [self setProduction:u_army]; return self; } //---------------------------------------------------------------------- // We really do want cities sent bycopy. //---------------------------------------------------------------------- - replacementObjectForPortCoder:(NSPortCoder *)encoder { if ([encoder isBycopy] == YES) return self; return [super replacementObjectForPortCoder:encoder]; } //---------------------------------------------------------------------- - (NSString *) description { return [NSString stringWithFormat:@"%@: %@ at (%d,%d), owner: %@", NSStringFromClass ([self class]), cityName, cityLocation.row, cityLocation.column, owner]; } //---------------------------------------------------------------------- - (EMMapLocation) cityLocation { return cityLocation; } //---------------------------------------------------------------------- - (BOOL) isAPort { return port; } //---------------------------------------------------------------------- - (NSString *) cityName { return cityName; } //---------------------------------------------------------------------- - (void) setCityName:(NSString *)aName { SNRelease (cityName); cityName = aName; [cityName retain]; } //---------------------------------------------------------------------- - (EmPlayer *) owner { return owner; } //---------------------------------------------------------------------- - (void) setOwner:(EmPlayer *)aPlayer { owner = aPlayer; } //---------------------------------------------------------------------- // Figures out the production efficiency based on current owner. //---------------------------------------------------------------------- - (int) productionEfficiency { if (owner == nil) return 50; return [owner productionEfficiency]; } //---------------------------------------------------------------------- - (float) productionTimeMultiplier { int pe = [self productionEfficiency]; float r; // Arbitrary value to avoid division by zero. if (pe == 0) r = 100; else r = 50.0 / pe; return r; } //---------------------------------------------------------------------- - (int) turnsToConstruct:(int *)turnArray { float ptm = [self productionTimeMultiplier]; int l; if (turnArray != NULL) { for (l = u_army; l <= u_hovercraft; l++) turnArray[l - u_army] = unit_production_times[l][0] * ptm; if (productionType != u_unknown) turnArray[productionType - u_army] = turnsUntilConstructed; } return turnsUntilConstructed; } //---------------------------------------------------------------------- - (void) defaultTurnsToConstruct:(int *)turnArray { float ptm = [self productionTimeMultiplier]; int l; for (l = u_army; l <= u_hovercraft; l++) turnArray[l - u_army] = unit_production_times[l][0] * ptm; } //---------------------------------------------------------------------- - (NSArray *) cityUnits { return cityUnits; } //---------------------------------------------------------------------- - (UnitType) productionType { return productionType; } //---------------------------------------------------------------------- - (void) setProduction:(UnitType)newProductionType { NSAssert (newProductionType >= u_army && newProductionType <= u_hovercraft, @"Invalid unit type."); if (productionType == newProductionType) return; firstUnit = YES; productionType = newProductionType; if (productionType != u_unknown) turnsUntilConstructed = unit_production_times[productionType][0] * [self productionTimeMultiplier]; else turnsUntilConstructed = 0; if (owner != nil) [owner cityProductionChanged:self]; } //====================================================================== // Turn phases //====================================================================== - (void) startOfTurn { NSEnumerator *unitEnumerator; Unit *unit; unitEnumerator = [cityUnits objectEnumerator]; while (unit = [unitEnumerator nextObject]) { [unit repairDamage]; //[unit refuel]; } if (productionType == u_unknown) { [self setProduction:u_army]; } else if (productionType >= u_army && productionType <= u_hovercraft) { // Produce new units... turnsUntilConstructed--; if (turnsUntilConstructed == 0) { Unit *newUnit; // Create unit newUnit = [[Unit alloc] initWithUnitType:productionType inCity:self]; //NSLog (@"%@ produced %@", self, newUnit); if (productionType == u_fighter && flightPath != nil) { OMoveTo *tmpOrder = [flightPath copy]; [tmpOrder setUnit:newUnit]; [newUnit setOrder:tmpOrder]; //printf ("Orders(1) for '%s' set to a flight path...\n", [newUnit unitName]); } // Add to player, city [owner addUnit:newUnit]; //[self unitDidEnter:newUnit]; // done in init // reset production firstUnit = NO; turnsUntilConstructed = unit_production_times[productionType][1] * [self productionTimeMultiplier]; } } } //====================================================================== // Observer Pattern //====================================================================== - (void) attach:observer { [observers addObject:observer]; } //---------------------------------------------------------------------- - (void) detach:observer { [observers removeObject:observer]; } //---------------------------------------------------------------------- - (void) unitDidExit:(Unit *)aUnit { NSEnumerator *objectEnumerator; id tmp; [cityUnits removeObject:aUnit]; objectEnumerator = [observers objectEnumerator]; while (tmp = [objectEnumerator nextObject]) { if ([tmp respondsToSelector:@selector (unitDidExit:)] == YES) [tmp unitDidExit:aUnit]; } } //---------------------------------------------------------------------- - (void) unitDidEnter:(Unit *)aUnit { NSEnumerator *objectEnumerator; id tmp; [cityUnits addObject:aUnit]; // Send fighters that enter the city along the flight path. if ([aUnit unitType] == u_fighter && flightPath != nil) { OMoveTo *tmpOrder = [flightPath copy]; [tmpOrder setUnit:aUnit]; [aUnit setOrder:tmpOrder]; } objectEnumerator = [observers objectEnumerator]; while (tmp = [objectEnumerator nextObject]) { if ([tmp respondsToSelector:@selector (unitDidEnter:)] == YES) [tmp unitDidEnter:aUnit]; } } //---------------------------------------------------------------------- - (void) cityWasLost { NSEnumerator *objectEnumerator; id tmp; Unit *unit; // Notify all observers. Observers don't detach -- they are // detached here. objectEnumerator = [observers objectEnumerator]; while (tmp = [objectEnumerator nextObject]) { if ([tmp respondsToSelector:@selector (cityWasLost)] == YES) [tmp cityWasLost]; } [observers removeAllObjects]; // Now, destroy all units within city. unit = [cityUnits lastObject]; while (unit != nil) { [owner destroyUnit:unit wasDisbanded:NO]; //[cityUnits removeLastObject]; unit = [cityUnits lastObject]; } // Reset instance vars to default. owner = nil; productionType = u_unknown; firstUnit = YES; [self setProduction:u_army]; } //---------------------------------------------------------------------- - (void) unitIconHasChanged:(Unit *)aUnit { NSEnumerator *objectEnumerator; id tmp; objectEnumerator = [observers objectEnumerator]; while (tmp = [objectEnumerator nextObject]) { if ([tmp respondsToSelector:@selector (unitIconHasChanged:)] == YES) [tmp unitIconHasChanged:aUnit]; } } //---------------------------------------------------------------------- - (PathSegment *) flightPathInMapView:(MapView *)mapView { PathSegment *path = nil; if (flightPath != nil) { path = [[PathSegment alloc] initPathFromLocation:cityLocation toLocation:[flightPath destination] in:mapView]; } return path; } //---------------------------------------------------------------------- - (void) setFlightPath:(OMoveTo *)newFlightPath { SNRelease (flightPath); flightPath = [newFlightPath retain]; } @end //====================================================================== @implementation City (Extensions) - (NSString *) attributesInspectorClassName { return @"CityAttributesInspector"; } //---------------------------------------------------------------------- - (NSString *) unitsInspectorClassName { return @"CityUnitsInspector"; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.