void IUtilityCommand.Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. Game.ModData = utility.ModData; var filename = args[1]; var file = new IniFile(File.Open(args[1], FileMode.Open)); var basic = file.GetSection("Basic"); var mapSection = file.GetSection("Map"); var tileset = mapSection.GetValue("Theater", ""); var iniSize = mapSection.GetValue("Size", "0, 0, 0, 0").Split(',').Select(int.Parse).ToArray(); var iniBounds = mapSection.GetValue("LocalSize", "0, 0, 0, 0").Split(',').Select(int.Parse).ToArray(); var size = new Size(iniSize[2], 2 * iniSize[3]); var author = args.Length > 2 ? args[2] : "Westwood Studios"; if (!utility.ModData.DefaultTerrainInfo.TryGetValue(tileset, out var terrainInfo)) { throw new InvalidDataException("Unknown tileset {0}".F(tileset)); } var map = new Map(Game.ModData, terrainInfo, size.Width, size.Height) { Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)), Author = author, Bounds = new Rectangle(iniBounds[0], iniBounds[1], iniBounds[2], 2 * iniBounds[3] + 2 * iniBounds[1]), RequiresMod = utility.ModData.Manifest.Id }; var fullSize = new int2(iniSize[2], iniSize[3]); ReadTiles(map, file, fullSize); ReadActors(map, file, "Structures", fullSize); ReadActors(map, file, "Units", fullSize); ReadActors(map, file, "Infantry", fullSize); ReadTerrainActors(map, file, fullSize); ReadWaypoints(map, file, fullSize); ReadOverlay(map, file, fullSize); ReadLighting(map, file); ReadLamps(map, file); var spawnCount = map.ActorDefinitions.Count(n => n.Value.Value == "mpspawn"); var mapPlayers = new MapPlayers(map.Rules, spawnCount); map.PlayerDefinitions = mapPlayers.ToMiniYaml(); var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap"; map.Save(ZipFileLoader.Create(dest)); Console.WriteLine(dest + " saved."); }
void IUtilityCommand.Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. Game.ModData = utility.ModData; var map = MapImporter.Import(args[1], utility.ModData.Manifest.Id, args[2]); if (map == null) { return; } var filename = Path.GetFileNameWithoutExtension(args[1]) + ".oramap"; map.Save(ZipFileLoader.Create(filename)); Console.WriteLine(filename + " saved."); }
void IUtilityCommand.Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. Game.ModData = utility.ModData; var rules = Ruleset.LoadDefaultsForTileSet(utility.ModData, "ARRAKIS"); var map = D2kMapImporter.Import(args[1], utility.ModData.Manifest.Id, args[2], rules); if (map == null) { return; } var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap"; map.Save(ZipFileLoader.Create(dest)); Console.WriteLine(dest + " saved."); }
public static int ImportOriginalMaps(ModData modData, Dictionary <string, string> info) { string[] files = { }; var unpackedFilesCount = 0; if (info.ContainsKey("OriginalMaps")) { files = info["OriginalMaps"].Split(','); } if (files.Length == 0) { return(0); } var path = Platform.ResolvePath(Platform.SupportDir); var contentPath = Path.Combine(path, "maps"); if (!Directory.Exists(contentPath)) { Directory.CreateDirectory(contentPath); } var d2Path = Path.Combine(contentPath, "d2"); if (!Directory.Exists(d2Path)) { Directory.CreateDirectory(d2Path); } var originalPath = Path.Combine(d2Path, "original"); if (!Directory.Exists(originalPath)) { Directory.CreateDirectory(originalPath); } foreach (var s in files) { var filename = s.Trim(); var mapFilename = Path.Combine(originalPath, Path.GetFileNameWithoutExtension(filename) + ".oramap"); try { if (!File.Exists(mapFilename)) { if (modData.DefaultFileSystem.Exists(filename)) { var rules = Ruleset.LoadDefaults(modData); var map = D2MapImporter.Import(filename, modData.Manifest.Id, "arrakis2", rules); if (map != null) { map.Save(ZipFileLoader.Create(mapFilename)); Console.WriteLine("Original map {0} saved to {1}", filename, mapFilename); } } } } catch (Exception e) { Console.WriteLine(e.ToString()); } } return(unpackedFilesCount); }
public SaveMapLogic(Widget widget, ModData modData, Action <string> onSave, Action onExit, Map map, List <MiniYamlNode> playerDefinitions, List <MiniYamlNode> actorDefinitions) { var title = widget.Get <TextFieldWidget>("TITLE"); title.Text = map.Title; var author = widget.Get <TextFieldWidget>("AUTHOR"); author.Text = map.Author; var visibilityPanel = Ui.LoadWidget("MAP_SAVE_VISIBILITY_PANEL", null, new WidgetArgs()); var visOptionTemplate = visibilityPanel.Get <CheckboxWidget>("VISIBILITY_TEMPLATE"); visibilityPanel.RemoveChildren(); foreach (MapVisibility visibilityOption in Enum.GetValues(typeof(MapVisibility))) { // To prevent users from breaking the game only show the 'Shellmap' option when it is already set. if (visibilityOption == MapVisibility.Shellmap && !map.Visibility.HasFlag(visibilityOption)) { continue; } var checkbox = (CheckboxWidget)visOptionTemplate.Clone(); checkbox.GetText = () => visibilityOption.ToString(); checkbox.IsChecked = () => map.Visibility.HasFlag(visibilityOption); checkbox.OnClick = () => map.Visibility ^= visibilityOption; visibilityPanel.AddChild(checkbox); } var visibilityDropdown = widget.Get <DropDownButtonWidget>("VISIBILITY_DROPDOWN"); visibilityDropdown.OnMouseDown = _ => { visibilityDropdown.RemovePanel(); visibilityDropdown.AttachPanel(visibilityPanel); }; var writableDirectories = new List <SaveDirectory>(); SaveDirectory selectedDirectory = null; var directoryDropdown = widget.Get <DropDownButtonWidget>("DIRECTORY_DROPDOWN"); { Func <SaveDirectory, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) => { var item = ScrollItemWidget.Setup(template, () => selectedDirectory == option, () => selectedDirectory = option); item.Get <LabelWidget>("LABEL").GetText = () => option.DisplayName; return(item); }; foreach (var kv in modData.MapCache.MapLocations) { var folder = kv.Key as Folder; if (folder == null) { continue; } try { using (var fs = File.Create(Path.Combine(folder.Name, ".testwritable"), 1, FileOptions.DeleteOnClose)) { // Do nothing: we just want to test whether we can create the file } writableDirectories.Add(new SaveDirectory(folder, kv.Value.ToString(), kv.Value)); } catch { // Directory is not writable } } if (map.Package != null) { selectedDirectory = writableDirectories.FirstOrDefault(k => k.Folder.Contains(map.Package.Name)); if (selectedDirectory == null) { selectedDirectory = writableDirectories.FirstOrDefault(k => Directory.GetDirectories(k.Folder.Name).Any(f => f.Contains(map.Package.Name))); } } // Prioritize MapClassification.User directories over system directories if (selectedDirectory == null) { selectedDirectory = writableDirectories.OrderByDescending(kv => kv.Classification).First(); } directoryDropdown.GetText = () => selectedDirectory?.DisplayName ?? ""; directoryDropdown.OnClick = () => directoryDropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 210, writableDirectories, setupItem); } var mapIsUnpacked = map.Package != null && map.Package is Folder; var filename = widget.Get <TextFieldWidget>("FILENAME"); filename.Text = map.Package == null ? "" : mapIsUnpacked?Path.GetFileName(map.Package.Name) : Path.GetFileNameWithoutExtension(map.Package.Name); var fileType = mapIsUnpacked ? MapFileType.Unpacked : MapFileType.OraMap; var fileTypes = new Dictionary <MapFileType, MapFileTypeInfo>() { { MapFileType.OraMap, new MapFileTypeInfo { Extension = ".oramap", UiLabel = ".oramap" } }, { MapFileType.Unpacked, new MapFileTypeInfo { Extension = "", UiLabel = "(unpacked)" } } }; var typeDropdown = widget.Get <DropDownButtonWidget>("TYPE_DROPDOWN"); { Func <KeyValuePair <MapFileType, MapFileTypeInfo>, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) => { var item = ScrollItemWidget.Setup(template, () => fileType == option.Key, () => { typeDropdown.Text = option.Value.UiLabel; fileType = option.Key; }); item.Get <LabelWidget>("LABEL").GetText = () => option.Value.UiLabel; return(item); }; typeDropdown.Text = fileTypes[fileType].UiLabel; typeDropdown.OnClick = () => typeDropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 210, fileTypes, setupItem); } var close = widget.Get <ButtonWidget>("BACK_BUTTON"); close.OnClick = () => { Ui.CloseWindow(); onExit(); }; var save = widget.Get <ButtonWidget>("SAVE_BUTTON"); save.OnClick = () => { if (string.IsNullOrEmpty(filename.Text)) { return; } map.Title = title.Text; map.Author = author.Text; if (actorDefinitions != null) { map.ActorDefinitions = actorDefinitions; } if (playerDefinitions != null) { map.PlayerDefinitions = playerDefinitions; } map.RequiresMod = modData.Manifest.Id; var combinedPath = Platform.ResolvePath(Path.Combine(selectedDirectory.Folder.Name, filename.Text + fileTypes[fileType].Extension)); try { if (!(map.Package is IReadWritePackage package) || package.Name != combinedPath) { selectedDirectory.Folder.Delete(combinedPath); if (fileType == MapFileType.OraMap) { package = ZipFileLoader.Create(combinedPath); } else { package = new Folder(combinedPath); } } map.Save(package); Console.WriteLine("Saved current map at {0}", combinedPath); Ui.CloseWindow(); onSave(map.Uid); } catch (Exception e) { Log.Write("debug", "Failed to save map at {0}: {1}", combinedPath, e.Message); Log.Write("debug", "{0}", e.StackTrace); ConfirmationDialogs.ButtonPrompt( title: "Failed to save map", text: "See debug.log for details.", onConfirm: () => { }, confirmText: "OK"); } }; }
protected void Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. Game.ModData = ModData = utility.ModData; var filename = args[1]; using (var stream = File.OpenRead(filename)) { var file = new IniFile(stream); var basic = file.GetSection("Basic"); var player = basic.GetValue("Player", string.Empty); if (!string.IsNullOrEmpty(player)) { singlePlayer = !player.StartsWith("Multi"); } var mapSection = file.GetSection("Map"); var format = GetMapFormatVersion(basic); ValidateMapFormat(format); // The original game isn't case sensitive, but we are. var tileset = GetTileset(mapSection).ToUpperInvariant(); if (!ModData.DefaultTileSets.ContainsKey(tileset)) { throw new InvalidDataException("Unknown tileset {0}".F(tileset)); } Map = new Map(ModData, ModData.DefaultTileSets[tileset], MapSize, MapSize) { Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)), Author = "Westwood Studios", }; Map.RequiresMod = ModData.Manifest.Id; SetBounds(Map, mapSection); ReadPacks(file, filename); ReadTrees(file); LoadVideos(file, "BASIC"); LoadBriefing(file); ReadActors(file); LoadSmudges(file, "SMUDGE"); var waypoints = file.GetSection("Waypoints"); LoadWaypoints(waypoints); // Create default player definitions only if there are no players to import MapPlayers = new MapPlayers(Map.Rules, Players.Count == 0 ? spawnCount : 0); foreach (var p in Players) { LoadPlayer(file, p); } Map.PlayerDefinitions = MapPlayers.ToMiniYaml(); } Map.FixOpenAreas(); var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap"; Map.Save(ZipFileLoader.Create(dest)); Console.WriteLine(dest + " saved."); }
protected void Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. Game.ModData = ModData = utility.ModData; var filename = args[1]; var flag = args[2]; if (string.IsNullOrWhiteSpace(flag)) { flag = "VH"; } bool flipHorizontal = flag.Contains("H"); bool flipVertical = flag.Contains("V"); MirrorType mirrorType = MirrorType.Horizontal; if (flipVertical) { mirrorType = MirrorType.Vertical; } if (flipHorizontal && flipVertical) { mirrorType = MirrorType.HorizontalAndVertical; } var targetPath = "..\\mods\\dr\\maps"; var package = new Folder(targetPath).OpenPackage(filename, ModData.ModFiles); if (package == null) { Console.WriteLine("Couldn't find map file: " + filename); return; } Map = new Map(ModData, package); var size = Map.MapSize; switch (mirrorType) { case MirrorType.Horizontal: size = size.WithX(size.X / 2); break; case MirrorType.Vertical: size = size.WithY(size.Y / 2); break; case MirrorType.HorizontalAndVertical: size = size / 2; break; } // Tiles for (int x = 0; x < size.X; x++) { for (int y = 0; y < size.Y; y++) { var pos = new CPos(x, y); var transformTile = new TileTransform() { Tile = Map.Tiles[pos], MirrorType = mirrorType, Position = pos }; foreach (var tt in transformTile.GetTransforms(Map)) { var newPos = tt.Position; Map.Tiles[newPos] = tt.Tile; } } } // Actors actorIndex = GetHighestActorIndex(); int multiCount = 0; var actorDefs = new List <ActorReference>(); var removeActors = new List <MiniYamlNode>(); foreach (var a in Map.ActorDefinitions) { var existing = new ActorReference(a.Value.Value, a.Value.ToDictionary()); var pos = existing.GetOrDefault <LocationInit>().Value; var owner = existing.Get <OwnerInit>(); if (pos.X < 0 || pos.X >= size.X || pos.Y < 0 || pos.Y >= size.Y) { removeActors.Add(a); continue; } var actor = new ActorTransform() { Actor = existing, Position = pos, MirrorType = mirrorType, }; if (actor.Actor.Type == "mpspawn") { multiCount++; } foreach (var at in actor.GetTransforms(Map)) { var ar = new ActorReference(actor.Actor.Type) { new LocationInit(at.Position), owner }; actorDefs.Add(ar); if (at.Actor.Type == "mpspawn") { multiCount++; } } } foreach (var a in actorDefs) { Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + ++actorIndex, a.Save())); } foreach (var a in removeActors) { Map.ActorDefinitions.Remove(a); } if (multiCount > 0) { var mapPlayers = new MapPlayers(Map.Rules, multiCount); Map.PlayerDefinitions = mapPlayers.ToMiniYaml(); } // Resources for (int x = 0; x < size.X; x++) { for (int y = 0; y < size.Y; y++) { var pos = new CPos(x, y); var resource = new ResourceTransform() { Tile = Map.Resources[pos], MirrorType = mirrorType, Position = pos }; foreach (var rt in resource.GetTransforms(Map)) { var newPos = rt.Position; Map.Resources[newPos] = rt.Tile; } } } var dest = Path.Combine(targetPath, Path.GetFileNameWithoutExtension(filename) + ".oramap"); Map.Save(ZipFileLoader.Create(dest)); Console.WriteLine(dest + " saved."); }
protected void Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. Game.ModData = ModData = utility.ModData; var filename = args[1]; using (var stream = File.OpenRead(filename)) { var headerString = stream.ReadASCII(4); var headerVers = stream.ReadInt32(); if (headerString != "MAP_") { throw new ArgumentException("Map file did not start with MAP_"); } if (headerVers < 0x300) { throw new ArgumentException("Map version was too low."); } var width = stream.ReadInt32(); var height = stream.ReadInt32(); stream.ReadInt32(); // Tileset num??? var tilesetName = "BARREN"; filename = filename.ToLowerInvariant(); var scnFilename = filename.Replace(".map", ".scn"); using (var scn = File.OpenRead(scnFilename)) { var scnFile = new ScnFile(scn); foreach (var scnSection in scnFile.Entries) { if (scnSection.Name != "SetDefaultTerrain") { continue; } tilesetName = scnSection.ValuesStr.ToUpperInvariant(); } } Map = new Map(ModData, ModData.DefaultTileSets[tilesetName], width + 2, height + 2) { Title = Path.GetFileNameWithoutExtension(filename), Author = "Dark Reign", }; Map.RequiresMod = ModData.Manifest.Id; SetBounds(Map, width + 2, height + 2); var byte1Hash = new HashSet <byte>(); var byte2Hash = new HashSet <byte>(); var byte3Hash = new HashSet <byte>(); var byte4Hash = new HashSet <byte>(); var byte5Hash = new HashSet <byte>(); var byte6Hash = new HashSet <byte>(); var unknownTileTypeHash = new HashSet <int>(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var byte1 = stream.ReadUInt8(); // Tile type 0-63, with art variations repeated 1-4 var byte2 = stream.ReadUInt8(); // Which art variation to use. 0 = 1-4, 1 = 5-8 var byte3 = stream.ReadUInt8(); // Base elevation, defaults to 2. var byte4 = stream.ReadUInt8(); // Unknown, defaults to 36. Seems to be elevation related. var byte5 = stream.ReadUInt8(); // Unknown, defaults to 73. Seems to be elevation related. var byte6 = stream.ReadUInt8(); // Unknown, defaults to 146. Seems to be elevation related. if (!byte1Hash.Contains(byte1)) { byte1Hash.Add(byte1); } if (!byte2Hash.Contains(byte2)) { byte2Hash.Add(byte2); } if (!byte3Hash.Contains(byte3)) { byte3Hash.Add(byte3); } if (!byte4Hash.Contains(byte4)) { byte4Hash.Add(byte4); } if (!byte5Hash.Contains(byte5)) { byte5Hash.Add(byte5); } if (!byte6Hash.Contains(byte6)) { byte6Hash.Add(byte6); } var subindex = (byte)(byte1 / 64); byte variation = (byte)(subindex * (byte2 + 1)); int tileType = byte1 % 64; if (tileType >= 16) { unknownTileTypeHash.Add(tileType); tileType = 1; // TODO: Handle edge sprites } Map.Tiles[new CPos(x + 1, y + 1)] = new TerrainTile((ushort)tileType, variation); // types[i, j], byte1 } } // What's after the tiles? Water/Taelon? stream.ReadInt32(); // Always one stream.ReadInt32(); // Always 256 int length = stream.ReadInt32(); // Byte length of remaining data byte1Hash = new HashSet <byte>(); var byteList = new List <byte>(); for (int i = 0; i < length; i++) { var byte1 = stream.ReadUInt8(); if (!byte1Hash.Contains(byte1)) { byte1Hash.Add(byte1); } byteList.Add(byte1); } using (var scn = File.OpenRead(scnFilename)) { var scnFile = new ScnFile(scn); MapPlayers = new MapPlayers(Map.Rules, 0); SetMapPlayers(scnFile, Players, MapPlayers); // Place start locations int i = 0; foreach (var scnSection in scnFile.Entries) { if (scnSection.Name != "SetStartLocation") { continue; } int divisor = 24; int x = Convert.ToInt32(scnSection.Values[0]) / divisor; int y = Convert.ToInt32(scnSection.Values[1]) / divisor; if (x != 0 && y != 0) { var ar = new ActorReference("mpspawn") { new LocationInit(new CPos(x + 1, y + 1)), new OwnerInit("Neutral") }; Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + i++, ar.Save())); } } // Parse map thingies foreach (var scnSection in scnFile.Entries) { if (scnSection.Name != "AddThingAt") { continue; } string type = scnSection.Values[1]; int x = Convert.ToInt32(scnSection.Values[2]); int y = Convert.ToInt32(scnSection.Values[3]); var matchingActor = string.Empty; if (thingNames.ContainsKey(type)) { matchingActor = thingNames[type]; } else if (!knownUnknownThings.Contains(type)) { throw new Exception("Unknown thing name: " + type); } if (x >= 0 && y >= 0 && !string.IsNullOrEmpty(matchingActor)) { var ar = new ActorReference(matchingActor) { new LocationInit(new CPos(x + 1, y + 1)), new OwnerInit("Neutral") }; Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + i++, ar.Save())); } } int currentTeam = 0; if (!skipActors) { // Units foreach (var scnSection in scnFile.Entries) { if (scnSection.Name == "SetDefaultTeam") { currentTeam = Convert.ToInt32(scnSection.ValuesStr); continue; } if (scnSection.Name != "PutUnitAt") { continue; } int playerIndex = GetMatchingPlayerIndex(currentTeam); // to skip creeps and neutral if necessary string type = scnSection.Values[1]; int x = Convert.ToInt32(scnSection.Values[2]); int y = Convert.ToInt32(scnSection.Values[3]); var matchingActor = string.Empty; if (unitNames.ContainsKey(type)) { matchingActor = unitNames[type]; } else if (!knownUnknownUnits.Contains(type)) { throw new Exception("Unknown unit name: " + type); } if (x >= 0 && y >= 0 && !string.IsNullOrEmpty(matchingActor)) { var ar = new ActorReference(matchingActor) { new LocationInit(new CPos(x + 1, y + 1)), new OwnerInit(MapPlayers.Players.Values.First(p => p.Team == playerIndex).Name) }; Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + i++, ar.Save())); } } // Do buildings foreach (var scnSection in scnFile.Entries) { if (scnSection.Name == "SetDefaultTeam") { currentTeam = Convert.ToInt32(scnSection.ValuesStr); continue; } if (scnSection.Name != "AddBuildingAt") { continue; } int playerIndex = GetMatchingPlayerIndex(currentTeam); // to skip creeps and neutral if necessary string type = scnSection.Values[1]; int x = Convert.ToInt32(scnSection.Values[2]); int y = Convert.ToInt32(scnSection.Values[3]); var matchingActor = string.Empty; if (buildingNames.ContainsKey(type)) { matchingActor = buildingNames[type]; } else if (!knownUnknownBuildings.Contains(type)) { throw new Exception("Unknown building name: " + type); } var isResource = type == "impww" || type == "impmn"; var ownerName = isResource ? "Neutral" : MapPlayers.Players.Values.First(p => p.Team == playerIndex).Name; if (isResource == true) { throw new ArgumentException("FART"); } if (x >= 0 && y >= 0 && !string.IsNullOrEmpty(matchingActor)) { var ar = new ActorReference(matchingActor) { new LocationInit(new CPos(x + 1, y + 1)), new OwnerInit(ownerName) }; Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + i++, ar.Save())); } } } // Do resources foreach (var scnSection in scnFile.Entries) { if (scnSection.Name != "AddBuildingAt") { continue; } string type = scnSection.Values[1]; int x = Convert.ToInt32(scnSection.Values[2]); int y = Convert.ToInt32(scnSection.Values[3]); var isResource = type == "impww" || type == "impmn"; if (!isResource) { continue; } var matchingActor = string.Empty; if (buildingNames.ContainsKey(type)) { matchingActor = buildingNames[type]; } if (x >= 0 && y >= 0 && !string.IsNullOrEmpty(matchingActor)) { var ar = new ActorReference(matchingActor) { new LocationInit(new CPos(x + 1, y + 1)), new OwnerInit("Neutral") }; Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + i++, ar.Save())); } } } // Reset teams var foreach (var playersValue in MapPlayers.Players.Values) { playersValue.Team = 0; } Map.PlayerDefinitions = MapPlayers.ToMiniYaml(); } Map.FixOpenAreas(); var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap"; Map.Save(ZipFileLoader.Create(dest)); Console.WriteLine(dest + " saved."); }
private void Run(Utility utility, string[] args) { // HACK: The engine code assumes that Game.modData is set. Game.ModData = modData = utility.ModData; var filename = args[1]; if (!Game.ModData.DefaultFileSystem.Exists(filename)) { throw new IOException($"Couldn't find map {filename} in maps.vol or filesystem."); } using (var stream = Game.ModData.DefaultFileSystem.Open(filename)) { var tag = stream.ReadUInt32(); // always 4113 var unknown = stream.ReadUInt32(); // always 0 var lgTileWidth = stream.ReadInt32(); var tileHeight = stream.ReadInt32(); // always 64 var numTileSets = stream.ReadInt32(); // always 512 // Update map header fields // Round height up to nearest power of 2 var newHeight = tileHeight; newHeight -= 1; newHeight |= (newHeight >> 1); newHeight |= (newHeight >> 2); newHeight |= (newHeight >> 4); newHeight |= (newHeight >> 8); newHeight |= (newHeight >> 16); newHeight++; var width = 1 << lgTileWidth; // Calculate map width var height = newHeight; map = new Map(modData, modData.DefaultTileSets["default"], width + 2, (int)height + 2) { Title = Path.GetFileNameWithoutExtension(filename), Author = "OpenOP2", RequiresMod = modData.Manifest.Id, }; var tiles = new List <int>(); for (var i = 0; i < width * height; i++) { var tile = stream.ReadInt32(); tiles.Add(tile); } var clipRect = new ClipRect() { X1 = stream.ReadInt32(), Y1 = stream.ReadInt32(), X2 = stream.ReadInt32(), Y2 = stream.ReadInt32(), }; SetBounds(map, width, height); // map.SetBounds(new PPos(clipRect.X1, clipRect.Y1), new PPos(width - clipRect.X2, (int)height - clipRect.Y2)); // map.SetBounds(new PPos(clipRect.X1, clipRect.Y1), new PPos(clipRect.X1 + clipRect.X2, clipRect.Y1 - clipRect.Y2)); // Read in tileset mappings var tileIds = new List <TileSetInfo>(); var tilesetStartIndices = new List <uint>(); var tilesetTileIndex = 0; for (int i = 0; i < numTileSets; i++) { var stringLength = stream.ReadInt32(); if (stringLength <= 0) { continue; } var tilesetMapping = new TileSetInfo() { TileSetName = stream.ReadASCII(stringLength), NumTiles = stream.ReadInt32(), }; tilesetStartIndices.Add((uint)tilesetTileIndex); tilesetTileIndex += tilesetMapping.NumTiles; tileIds.Add(tilesetMapping); } var testString = stream.ReadASCII(10); if (!testString.StartsWith("TILE SET")) { throw new IOException("Couldn't find TILE SET tag."); } var numMappings = stream.ReadInt32(); var mappings = new TileSetMapping[numMappings]; for (var i = 0; i < numMappings; i++) { mappings[i] = new TileSetMapping { TileSetIndex = stream.ReadInt16(), TileIndex = stream.ReadInt16(), NumTileReplacements = stream.ReadInt16(), CycleDelay = stream.ReadInt16(), }; } var numTerrainTypes = stream.ReadInt32(); var terrains = new TerrainType[numTerrainTypes]; stream.Seek(numTerrainTypes * 264, SeekOrigin.Current); var checkTag = stream.ReadUInt32(); if (checkTag != tag) { throw new IOException("Format error: Tag did not match header tag."); } var checkTag2 = stream.ReadInt32(); // the same all the time? var numActors = stream.ReadInt32(); // I think? // TODO: The rest of the tiles // Actually place the tiles for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var tileXUpper = x >> 5; var tileXLower = x & 0x1F; var tileOffset = (((tileXUpper * height) + y) << 5) + tileXLower; var tile = tiles[tileOffset]; var tile2XUpper = tile >> 5; var tile2XLower = tile & 0x1F; // Get the tile mapping index var cellType = (tile & 0x1F); var tileMappingIndex = (tile & 0xFFE0) >> 5; var actorMappingIndex = (tile & 0x7FF0000) >> 11; var lava = (tile & 0x00000001) >> 27; var lavaPossible = (tile & 0x00000001) >> 28; var expand = (tile & 0x00000001) >> 29; var microbe = (tile & 0x00000001) >> 30; var wallOrBuilding = (tile & 0x00000001) >> 31; if (actorMappingIndex != 0 || lavaPossible != 0 || wallOrBuilding != 0) { throw new Exception("Actor mapping was " + actorMappingIndex); } var thisMapping = mappings[tileMappingIndex]; var startIndex = tilesetStartIndices[thisMapping.TileSetIndex]; map.Tiles[new CPos(x + 1, y + 1)] = new TerrainTile((ushort)(startIndex + thisMapping.TileIndex), 0); } } } mapPlayers = new MapPlayers(map.Rules, 0); map.PlayerDefinitions = mapPlayers.ToMiniYaml(); map.FixOpenAreas(); var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap"; var mapLocations = Game.ModData.Manifest.MapFolders; var userMapPath = mapLocations.First(mapLocation => mapLocation.Value == "User"); var targetPath = Path.Combine(Platform.ResolvePath(userMapPath.Key.Substring(1)), dest); map.Save(ZipFileLoader.Create(targetPath)); Console.WriteLine(targetPath + " saved."); }