/// <summary> /// Create a new building /// </summary> /// <param name="position">Position of the new building</param> /// <param name="size">Size of the new building</param> /// <param name="data">Data about the building</param> /// <returns>True if the building was able to be created.</returns> public bool CreateBuilding(Pair<int> position, Pair<int> size, BuildingData data) { var newBuilding = new Building(position, size, data); this.Add(newBuilding); // Place this new building's Guid into the world grid var buildingIsoPosition = Geometry.ToIsometricGrid(position); for (int y = 0; y < data.Footprint.Length; ++y) { for (int x = 0; x < data.Footprint[y].Length; ++x) { if (data.Footprint[y][x]) { int gridX = this.WorldIsoToGridX(buildingIsoPosition.x + x - data.FootprintIndexOffsetX); int gridY = this.WorldIsoToGridY(buildingIsoPosition.y + y - data.FootprintIndexOffsetY); // Sanity checks before we place the building if (gridX < 0 || gridX >= this.grid.Length || gridY < 0 || gridY >= this.grid.Length) { Logger.Log(LogLevel.Error, "Creating a building outside grid limits", string.Format("Trying to build building {0} at position: Iso: {1},{2} World: {3}, {4}. Outside world boundry of {5}", data.Name, gridX, gridY, position.x, position.y, this.grid.Length)); continue; } if (this.grid[gridY][gridX] != -1) { Logger.Log(LogLevel.Error, "Creating a building on top of another building", string.Format("Trying to build building {0} at position: Iso: {1},{2} World: {3}, {4}. Building {5} already exists at location.", data.Name, gridX, gridY, position.x, position.y, this.grid[gridY][gridX])); } this.grid[gridY][gridX] = newBuilding.Guid; } } } return true; }
/// <summary> /// Create an instance of a building ScreenElement /// </summary> public Building(Pair<int> position, Pair<int> size, BuildingData data) : base(position.y) { this.Clickable = true; this.Position = position; this.Size = size; this.data = data; this.deleteButton = new DeleteBuildingButton(this); this.deleteButton.Position = new Pair<int>(this.Position.x + this.Size.x + this.data.ImageOffsetX - (2 * this.deleteButton.Size.x / 3), this.Position.y + this.Size.y + this.data.ImageOffsetY - this.deleteButton.Size.y); this.deleteButton.Enabled = false; this.editButton = new EditBuildingButton(this); this.editButton.Position = new Pair<int>(this.Position.x + this.data.ImageOffsetX - (this.deleteButton.Size.x / 3), this.Position.y + this.Size.y + this.data.ImageOffsetY - this.deleteButton.Size.y); this.editButton.Enabled = false; }
/// <summary> /// Create a new building /// </summary> /// <param name="position">Position of the new building</param> /// <param name="size">Size of the new building</param> /// <param name="data">Data about the building</param> /// <returns>True if the building was able to be created.</returns> public bool CreateBuilding(Pair <int> position, Pair <int> size, BuildingData data) { var newBuilding = new Building(position, size, data); this.Add(newBuilding); // Place this new building's Guid into the world grid var buildingIsoPosition = Geometry.ToIsometricGrid(position); for (int y = 0; y < data.Footprint.Length; ++y) { for (int x = 0; x < data.Footprint[y].Length; ++x) { if (data.Footprint[y][x]) { int gridX = this.WorldIsoToGridX(buildingIsoPosition.x + x - data.FootprintIndexOffsetX); int gridY = this.WorldIsoToGridY(buildingIsoPosition.y + y - data.FootprintIndexOffsetY); // Sanity checks before we place the building if (gridX < 0 || gridX >= this.grid.Length || gridY < 0 || gridY >= this.grid.Length) { Logger.Log(LogLevel.Error, "Creating a building outside grid limits", string.Format("Trying to build building {0} at position: Iso: {1},{2} World: {3}, {4}. Outside world boundry of {5}", data.Name, gridX, gridY, position.x, position.y, this.grid.Length)); continue; } if (this.grid[gridY][gridX] != -1) { Logger.Log(LogLevel.Error, "Creating a building on top of another building", string.Format("Trying to build building {0} at position: Iso: {1},{2} World: {3}, {4}. Building {5} already exists at location.", data.Name, gridX, gridY, position.x, position.y, this.grid[gridY][gridX])); } this.grid[gridY][gridX] = newBuilding.Guid; } } } return(true); }
/// <summary> /// Load a building from Config /// </summary> /// <param name="config"></param> /// <returns></returns> private BuildingData LoadBuilding(Config config, string key) { // Create the building data BuildingData data = new BuildingData(); data.Key = key; data.Name = config.GetStringValue(key, "title", ""); data.Type = DataType.Building; data.InToolbox = config.GetBoolValue(key, "toolbox", false); data.ImageName = config.GetStringValue(key, "image", ""); data.IconImageName = config.GetStringValue(key, "icon", null); data.FootprintImageName = config.GetStringValue(key, "footprint", ""); data.ImageOffsetY = config.GetIntValue(key, "imageOffsetY", 0); data.ImageOffsetX = config.GetIntValue(key, "imageOffsetX", 0); data.FootprintOffsetY = config.GetIntValue(key, "footprintOffsetY", 0); data.FootprintOffsetX = config.GetIntValue(key, "footprintOffsetX", 0); data.Cost = config.GetIntValue(key, "cost", 0); data.Specs = new Dictionary<BuildingStat, int>(); // Load the specs into an enum and int pair var specsString = config.GetStringValue(key, "specs", ""); if (!string.IsNullOrEmpty(specsString)) { var specs = specsString.Split(';'); foreach (var spec in specs) { var nameValue = spec.Split(','); if (nameValue.Length != 2) { string msg = string.Format("Invalid Catalog.ini file. Element {0} ({1}) did not have a name and value.", key, spec); Logger.Log(LogLevel.Error, "LoadingCatalog", msg); throw new Exception(msg); } try { BuildingStat stat = (BuildingStat)Enum.Parse(typeof(BuildingStat), nameValue[0]); int value = Int32.Parse(nameValue[1]); data.Specs.Add(stat, value); } catch (Exception e) { var msg = string.Format("Invalid Catalog.ini file. Element {0} ({1}) was an unrecognized BuildingStat-Int pair. ex: {2}", e.Message); Logger.Log(LogLevel.Error, "LoadingCatalog", msg); throw new Exception(msg); } } } return data; }
/// <summary> /// Create a ghost building to build a new type of building /// </summary> /// <param name="data"></param> public GhostBuilding(BuildingData data) : base(data) { this.Position = Input.IsoWorld.Clone(); }
/// <summary> /// Load all of the image content for the buildings /// </summary> /// <param name="contentMan">XNA Content manager</param> public void LoadContent(ContentManager contentMan) { foreach (var element in this.catalog) { Texture2D image = contentMan.Load <Texture2D>(element.Value.ImageName); int size = image.Width * image.Height; element.Value.Image = image; Texture2D iconimage = contentMan.Load <Texture2D>(element.Value.IconImageName); element.Value.IconImage = iconimage; if (element.Value is BuildingData) { BuildingData buildingData = element.Value as BuildingData; Color[] imageData = new Color[size]; image.GetData <Color>(imageData, 0, size); buildingData.ImageData = imageData; Texture2D footimage = contentMan.Load <Texture2D>(buildingData.FootprintImageName); buildingData.FootprintImage = footimage; size = footimage.Width * footimage.Height; Color[] footimageData = new Color[size]; footimage.GetData <Color>(footimageData, 0, size); // I spent waaay too much time thinking about this, so it's entirely possible that I'm overlooking a simpler solution. // I'm looping over the footprint image mask to determine which squares each building takes up. // You can specify an offset to the center of the building mask in buildings.ini (just like you can for the center of the image; note: these two centers should be the same) // Using that center value, we find if the center is on a type0 (first grid piece lines up with the left side) or a type1 (first grid piece is one half width from the left side) bool isType0 = buildingData.FootprintOffsetX % Constants.TILE_WIDTH == 0; int worldYOffset = ((buildingData.FootprintOffsetX % Constants.TILE_WIDTH == 0) ^ (buildingData.FootprintOffsetY % Constants.TILE_HEIGHT == 0)) ? Constants.TILE_HEIGHT / 2 : 0; int minFootprintX = (-footimage.Width + Constants.TILE_WIDTH / 2) / Constants.TILE_WIDTH; int maxFootprintX = (footimage.Height - worldYOffset - Constants.TILE_HEIGHT / 2) / Constants.TILE_HEIGHT; // int minFootprintY = 0; int maxFootprintY = maxFootprintX - minFootprintX + 1; buildingData.Footprint = new bool[maxFootprintY][]; for (int i = 0; i < maxFootprintY; ++i) { buildingData.Footprint[i] = new bool[maxFootprintY]; } int startCenterX = buildingData.FootprintOffsetX + Constants.TILE_WIDTH / 2; int startCenterY = -1 * buildingData.FootprintOffsetY + Constants.TILE_HEIGHT / 2 - worldYOffset; var isometricCenterIndex = Geometry.ToIsometricGrid(new Pair <int>(startCenterX, startCenterY)); buildingData.FootprintIndexOffsetX = isometricCenterIndex.x - minFootprintX; buildingData.FootprintIndexOffsetY = isometricCenterIndex.y; for (int y = 0; y <= footimage.Height - Constants.TILE_HEIGHT; y += Constants.TILE_HEIGHT / 2) { int xStart = (isType0 ^ ((int)Math.Abs(y - buildingData.FootprintOffsetY) % Constants.TILE_HEIGHT == 0)) ? Constants.TILE_WIDTH / 2 : 0; for (int x = xStart; x <= footimage.Width - Constants.TILE_WIDTH; x += Constants.TILE_WIDTH) { int qX = x + Constants.TILE_WIDTH / 2; int qY = y + Constants.TILE_HEIGHT / 2 - worldYOffset; var isometricQueryPosition = Geometry.ToIsometricGrid(new Pair <int>(qX, qY)); buildingData.Footprint[isometricQueryPosition.y][isometricQueryPosition.x - minFootprintX] = footimageData[qX + qY * footimage.Width] != Color.Transparent; } } } } }