internal static BlendTileData Parse(BinaryReader reader, MapParseContext context, HeightMapData heightMapData) { return(ParseAsset(reader, context, version => { if (version < 6) { throw new InvalidDataException(); } if (heightMapData == null) { throw new InvalidDataException("Expected HeightMapData asset before BlendTileData asset."); } var width = heightMapData.Width; var height = heightMapData.Height; var result = new BlendTileData(); result.NumTiles = reader.ReadUInt32(); if (result.NumTiles != width * height) { throw new InvalidDataException(); } result.Tiles = reader.ReadUInt16Array2D(width, height); var blendBitSize = GetBlendBitSize(version); result.Blends = reader.ReadUIntArray2D(width, height, blendBitSize); result.ThreeWayBlends = reader.ReadUIntArray2D(width, height, blendBitSize); result.CliffTextures = reader.ReadUIntArray2D(width, height, blendBitSize); if (version > 6) { var passabilityWidth = heightMapData.Width; if (version == 7) { // C&C Generals clips partial bytes from each row of passability data, passabilityWidth = ((passabilityWidth + 1) / 8) * 8; } // If terrain is passable, there's a 0 in the data file. result.Impassability = reader.ReadSingleBitBooleanArray2D(passabilityWidth, heightMapData.Height); } if (version >= 10) { result.ImpassabilityToPlayers = reader.ReadSingleBitBooleanArray2D(heightMapData.Width, heightMapData.Height); } if (version >= 11) { result.PassageWidths = reader.ReadSingleBitBooleanArray2D(heightMapData.Width, heightMapData.Height); } if (version >= 14 && version < 25) { result.Taintability = reader.ReadSingleBitBooleanArray2D(heightMapData.Width, heightMapData.Height); } if (version >= 15) { result.ExtraPassability = reader.ReadSingleBitBooleanArray2D(heightMapData.Width, heightMapData.Height); } if (version >= 16 && version < 25) { result.Flammability = reader.ReadByteArray2DAsEnum <TileFlammability>(heightMapData.Width, heightMapData.Height); } if (version >= 17) { result.Visibility = reader.ReadSingleBitBooleanArray2D(heightMapData.Width, heightMapData.Height); } if (version >= 24) { // TODO: Are these in the right order? result.Buildability = reader.ReadSingleBitBooleanArray2D(heightMapData.Width, heightMapData.Height); result.ImpassabilityToAirUnits = reader.ReadSingleBitBooleanArray2D(heightMapData.Width, heightMapData.Height); result.TiberiumGrowability = reader.ReadSingleBitBooleanArray2D(heightMapData.Width, heightMapData.Height); } if (version >= 25) { result.DynamicShrubberyDensity = reader.ReadByteArray2D(heightMapData.Width, heightMapData.Height); } result.TextureCellCount = reader.ReadUInt32(); var blendsCount = reader.ReadUInt32(); if (blendsCount > 0) { // Usually minimum value is 1, but some files (perhaps Generals, not Zero Hour?) have 0. blendsCount--; } result.ParsedCliffTextureMappingsCount = reader.ReadUInt32(); var cliffBlendsCount = result.ParsedCliffTextureMappingsCount; if (cliffBlendsCount > 0) { // Usually minimum value is 1, but some files (perhaps Generals, not Zero Hour?) have 0. cliffBlendsCount--; } var textureCount = reader.ReadUInt32(); result.Textures = new BlendTileTexture[textureCount]; for (var i = 0; i < textureCount; i++) { result.Textures[i] = BlendTileTexture.Parse(reader); } // Can be a variety of values, don't know what it means. result.MagicValue1 = reader.ReadUInt32(); result.MagicValue2 = reader.ReadUInt32(); if (result.MagicValue2 != 0) { throw new InvalidDataException(); } result.BlendDescriptions = new BlendDescription[blendsCount]; for (var i = 0; i < blendsCount; i++) { result.BlendDescriptions[i] = BlendDescription.Parse(reader, version); } result.CliffTextureMappings = new CliffTextureMapping[cliffBlendsCount]; for (var i = 0; i < cliffBlendsCount; i++) { result.CliffTextureMappings[i] = CliffTextureMapping.Parse(reader); } return result; })); }
internal static BlendTileData Parse(BinaryReader reader, MapParseContext context, HeightMapData heightMapData) { return(ParseAsset(reader, context, version => { if (version < 6 || version > 8) { throw new InvalidDataException(); } if (heightMapData == null) { throw new InvalidDataException("Expected HeightMapData asset before BlendTileData asset."); } var width = heightMapData.Width; var height = heightMapData.Height; var numTiles = reader.ReadUInt32(); if (numTiles != width * height) { throw new InvalidDataException(); } var tiles = reader.ReadUInt16Array2D(width, height); var blends = reader.ReadUInt16Array2D(width, height); var threeWayBlends = reader.ReadUInt16Array2D(width, height); var cliffTextures = reader.ReadUInt16Array2D(width, height); bool[,] passability = null; if (version > 6) { var passabilityWidth = heightMapData.Width; if (version == 7) { // C&C Generals clips partial bytes from each row of passability data, // if the border width is large enough to fully contain the clipped data. if (passabilityWidth % 8 <= 6 && passabilityWidth % 8 <= heightMapData.BorderWidth) { passabilityWidth -= passabilityWidth % 8; } } // If terrain is passable, there's a 0 in the data file. passability = reader.ReadSingleBitBooleanArray2D(passabilityWidth, heightMapData.Height); } var textureCellCount = reader.ReadUInt32(); var blendsCount = reader.ReadUInt32(); if (blendsCount > 0) { // Usually minimum value is 1, but some files (perhaps Generals, not Zero Hour?) have 0. blendsCount--; } var parsedCliffBlendsCount = reader.ReadUInt32(); var cliffBlendsCount = parsedCliffBlendsCount; if (cliffBlendsCount > 0) { // Usually minimum value is 1, but some files (perhaps Generals, not Zero Hour?) have 0. cliffBlendsCount--; } var textureCount = reader.ReadUInt32(); var textures = new BlendTileTexture[textureCount]; for (var i = 0; i < textureCount; i++) { textures[i] = BlendTileTexture.Parse(reader); } var magicValue1 = reader.ReadUInt32(); if (magicValue1 != 0) { throw new InvalidDataException(); } var magicValue2 = reader.ReadUInt32(); if (magicValue2 != 0) { throw new InvalidDataException(); } var blendDescriptions = new BlendDescription[blendsCount]; for (var i = 0; i < blendsCount; i++) { blendDescriptions[i] = BlendDescription.Parse(reader); } var cliffTextureMappings = new CliffTextureMapping[cliffBlendsCount]; for (var i = 0; i < cliffBlendsCount; i++) { cliffTextureMappings[i] = CliffTextureMapping.Parse(reader); } return new BlendTileData { NumTiles = numTiles, Tiles = tiles, Blends = blends, ThreeWayBlends = threeWayBlends, CliffTextures = cliffTextures, Passability = passability, TextureCellCount = textureCellCount, Textures = textures, MagicValue1 = magicValue1, MagicValue2 = magicValue2, BlendDescriptions = blendDescriptions, ParsedCliffTextureMappingsCount = parsedCliffBlendsCount, CliffTextureMappings = cliffTextureMappings }; })); }