protected virtual void SetMapPlayers(ScnFile file, List <string> players, MapPlayers mapPlayers) { int i = 0; foreach (var scnSection in file.Entries) { if (scnSection.Name != "SetStartLocation") { continue; } int x = Convert.ToInt32(scnSection.Values[0]); int y = Convert.ToInt32(scnSection.Values[1]); if (x != 0 && y != 0) { var multi = new PlayerReference { Name = "Multi" + i, Team = i + 2, Playable = true, Faction = "Random" }; mapPlayers.Players.Add(multi.Name, multi); i++; } } numMultiStarts = i; }
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."); }
protected override void SetMapPlayers(ScnFile file, List <string> players, MapPlayers mapPlayers) { var teamHasUnits = new Func <int, bool>(playerIndex => { bool correctPlayer = false; foreach (var scnSection in file.Entries) { if (scnSection.Name == "SetDefaultTeam") { int defaultTeam = Convert.ToInt32(scnSection.Values[0]); correctPlayer = defaultTeam == playerIndex; continue; } if (correctPlayer && (scnSection.Name == "AddBuildingAt" || scnSection.Name == "PutUnitAt")) { return(true); } } return(false); }); // Single player, examine sides int teamIndex = 0; int sideIndex = 0; int[] allianceArray = new[] { 0, 0, 0, 0, 0, 0, 0, 0 }; var nameFactionDict = new Dictionary <string, string>() { { "Freedom Guard", "fguard" }, { "Imperium", "imperium" }, }; var factionColors = new[] { Color.FromArgb(234, 189, 25), Color.FromArgb(124, 60, 234) }; var newPlayers = new List <PlayerReference>(); // Add players foreach (var scnSection in file.Entries) { if (scnSection.Name == "SetTeam") { teamIndex = Convert.ToInt32(scnSection.Values[0]); // to skip creeps and normal continue; } if (scnSection.Name == "SetTeamSide") { sideIndex = Convert.ToInt32(scnSection.Values[0]); if (sideIndex > 1) // No togran yet. { sideIndex = 0; } continue; } if (scnSection.Name == "SetAlliance" && teamHasUnits(teamIndex)) { if (teamIndex == 8) { continue; // It's just creeps } for (int allianceI = 0; allianceI < 8; allianceI++) { allianceArray[allianceI] = Convert.ToInt32(scnSection.Values[allianceI]); } var enemyIndices = new List <int>(); var allyIndices = new List <int>(); for (int ei = 0; ei < 8; ei++) { if (allianceArray[ei] == 0) { enemyIndices.Add(ei); } else if (ei != teamIndex && allianceArray[ei] == 2) { allyIndices.Add(ei); } } // Create player at this point PlayerReference newPlayer = new PlayerReference { Team = teamIndex, Name = sideIndex.ToString(), Faction = nameFactionDict.Values.ToArray()[sideIndex], Color = factionColors[sideIndex], Enemies = enemyIndices.Select(x => x.ToString()).ToArray(), Allies = allyIndices.Select(x => x.ToString()).ToArray(), }; if (teamIndex == 0) { // First is always playable faction newPlayer.Playable = true; newPlayer.AllowBots = false; newPlayer.Required = true; newPlayer.LockSpawn = true; newPlayer.LockTeam = true; } newPlayers.Add(newPlayer); } } // Ensure names are unique var factionCountIndex = new Dictionary <string, int>() { { "fguard", 0 }, { "imperium", 0 } }; foreach (var newPlayer in newPlayers) { // Sort out unique names sideIndex = Convert.ToInt32(newPlayer.Name); var sideName = nameFactionDict.Keys.ToArray()[sideIndex]; int currentFactionCount = factionCountIndex[newPlayer.Faction]; if (currentFactionCount > 0) { sideName += " " + currentFactionCount; } currentFactionCount++; factionCountIndex[newPlayer.Faction] = currentFactionCount; newPlayer.Name = sideName; // And unique colors if (newPlayer.Team > 1 && newPlayer.Team != 8) { int newColorIndex = newPlayer.Team - 2; newPlayer.Color = namedColorMapping.Values.ToArray()[newColorIndex]; } } foreach (var newPlayer in newPlayers) { // Sort out alliances teamIndex = newPlayer.Team; var allyNames = new List <string>(); var enemyNames = new List <string>(); foreach (var allyOrEnemy in newPlayers) { if (allyOrEnemy.Team == teamIndex) { continue; } if (newPlayer.Allies.Contains(allyOrEnemy.Team.ToString())) { allyNames.Add(allyOrEnemy.Name); } else if (newPlayer.Enemies.Contains(allyOrEnemy.Team.ToString())) { enemyNames.Add(allyOrEnemy.Name); } } newPlayer.Allies = allyNames.ToArray(); newPlayer.Enemies = enemyNames.ToArray(); } // Increase the team indices by two to skip creeps and neutral. foreach (var newPlayer in newPlayers) { newPlayer.Team += 2; mapPlayers.Players.Add(newPlayer.Name, newPlayer); } }