Initial commit: OpenRA game engine
Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
530
OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs
Normal file
530
OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs
Normal file
@@ -0,0 +1,530 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Terrain;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Mods.D2k.UtilityCommands
|
||||
{
|
||||
public sealed class D2kMapImporter
|
||||
{
|
||||
const int MapCordonWidth = 2;
|
||||
|
||||
// PlayerReference colors in D2k missions only affect chat text and minimap colors because actors use specific palette colors.
|
||||
// So using the colors from the original game's minimap.
|
||||
public static Dictionary<string, (string Faction, Color Color)> PlayerReferenceDataByPlayerName = new()
|
||||
{
|
||||
{ "Neutral", ("Random", Color.White) },
|
||||
{ "Atreides", ("atreides", Color.FromArgb(90, 115, 148)) },
|
||||
{ "Harkonnen", ("harkonnen", Color.FromArgb(214, 74, 66)) },
|
||||
{ "Ordos", ("ordos", Color.FromArgb(90, 148, 115)) },
|
||||
{ "Corrino", ("corrino", Color.FromArgb(115, 0, 123)) },
|
||||
{ "Fremen", ("fremen", Color.FromArgb(132, 132, 132)) },
|
||||
{ "Smugglers", ("smuggler", Color.FromArgb(123, 41, 16)) },
|
||||
{ "Mercenaries", ("mercenary", Color.FromArgb(156, 132, 8)) }
|
||||
};
|
||||
|
||||
public static Dictionary<int, (string Actor, string Owner)> ActorDataByActorCode = new()
|
||||
{
|
||||
{ 20, ("wormspawner", "Creeps") },
|
||||
{ 23, ("mpspawn", "Neutral") },
|
||||
{ 41, ("spicebloom.spawnpoint", "Neutral") },
|
||||
{ 42, ("spicebloom.spawnpoint", "Neutral") },
|
||||
{ 43, ("spicebloom.spawnpoint", "Neutral") },
|
||||
{ 44, ("spicebloom.spawnpoint", "Neutral") },
|
||||
{ 45, ("spicebloom.spawnpoint", "Neutral") },
|
||||
|
||||
// Atreides:
|
||||
{ 4, ("wall", "Atreides") },
|
||||
{ 5, ("wind_trap", "Atreides") },
|
||||
{ 8, ("construction_yard", "Atreides") },
|
||||
{ 11, ("barracks", "Atreides") },
|
||||
{ 14, ("refinery", "Atreides") },
|
||||
{ 17, ("outpost", "Atreides") },
|
||||
{ 63, ("light_factory", "Atreides") },
|
||||
{ 69, ("silo", "Atreides") },
|
||||
{ 72, ("heavy_factory", "Atreides") },
|
||||
{ 75, ("repair_pad", "Atreides") },
|
||||
{ 78, ("medium_gun_turret", "Atreides") },
|
||||
{ 120, ("high_tech_factory", "Atreides") },
|
||||
{ 123, ("large_gun_turret", "Atreides") },
|
||||
{ 126, ("research_centre", "Atreides") },
|
||||
{ 129, ("starport", "Atreides") },
|
||||
{ 132, ("palace", "Atreides") },
|
||||
{ 180, ("light_inf", "Atreides") },
|
||||
{ 181, ("trooper", "Atreides") },
|
||||
{ 182, ("fremen", "Atreides") },
|
||||
{ 183, ("sardaukar", "Atreides") },
|
||||
{ 184, ("engineer", "Atreides") },
|
||||
{ 185, ("harvester", "Atreides") },
|
||||
{ 186, ("mcv", "Atreides") },
|
||||
{ 187, ("trike", "Atreides") },
|
||||
{ 188, ("quad", "Atreides") },
|
||||
{ 189, ("combat_tank_a", "Atreides") },
|
||||
{ 190, ("missile_tank", "Atreides") },
|
||||
{ 191, ("siege_tank", "Atreides") },
|
||||
{ 192, ("carryall", "Atreides") },
|
||||
{ 194, ("sonic_tank", "Atreides") },
|
||||
|
||||
// Harkonnen:
|
||||
{ 204, ("wall", "Harkonnen") },
|
||||
{ 205, ("wind_trap", "Harkonnen") },
|
||||
{ 208, ("construction_yard", "Harkonnen") },
|
||||
{ 211, ("barracks", "Harkonnen") },
|
||||
{ 214, ("refinery", "Harkonnen") },
|
||||
{ 217, ("outpost", "Harkonnen") },
|
||||
{ 263, ("light_factory", "Harkonnen") },
|
||||
{ 269, ("silo", "Harkonnen") },
|
||||
{ 272, ("heavy_factory", "Harkonnen") },
|
||||
{ 275, ("repair_pad", "Harkonnen") },
|
||||
{ 278, ("medium_gun_turret", "Harkonnen") },
|
||||
{ 320, ("high_tech_factory", "Harkonnen") },
|
||||
{ 323, ("large_gun_turret", "Harkonnen") },
|
||||
{ 326, ("research_centre", "Harkonnen") },
|
||||
{ 329, ("starport", "Harkonnen") },
|
||||
{ 332, ("palace", "Harkonnen") },
|
||||
{ 360, ("light_inf", "Harkonnen") },
|
||||
{ 361, ("trooper", "Harkonnen") },
|
||||
{ 362, ("fremen", "Harkonnen") },
|
||||
{ 363, ("mpsardaukar", "Harkonnen") },
|
||||
{ 364, ("engineer", "Harkonnen") },
|
||||
{ 365, ("harvester", "Harkonnen") },
|
||||
{ 366, ("mcv", "Harkonnen") },
|
||||
{ 367, ("trike", "Harkonnen") },
|
||||
{ 368, ("quad", "Harkonnen") },
|
||||
{ 369, ("combat_tank_h", "Harkonnen") },
|
||||
{ 370, ("missile_tank", "Harkonnen") },
|
||||
{ 371, ("siege_tank", "Harkonnen") },
|
||||
{ 372, ("carryall", "Harkonnen") },
|
||||
{ 374, ("devastator", "Harkonnen") },
|
||||
|
||||
// Ordos:
|
||||
{ 404, ("wall", "Ordos") },
|
||||
{ 405, ("wind_trap", "Ordos") },
|
||||
{ 408, ("construction_yard", "Ordos") },
|
||||
{ 411, ("barracks", "Ordos") },
|
||||
{ 414, ("refinery", "Ordos") },
|
||||
{ 417, ("outpost", "Ordos") },
|
||||
{ 463, ("light_factory", "Ordos") },
|
||||
{ 469, ("silo", "Ordos") },
|
||||
{ 472, ("heavy_factory", "Ordos") },
|
||||
{ 475, ("repair_pad", "Ordos") },
|
||||
{ 478, ("medium_gun_turret", "Ordos") },
|
||||
{ 520, ("high_tech_factory", "Ordos") },
|
||||
{ 523, ("large_gun_turret", "Ordos") },
|
||||
{ 526, ("research_centre", "Ordos") },
|
||||
{ 529, ("starport", "Ordos") },
|
||||
{ 532, ("palace", "Ordos") },
|
||||
{ 560, ("light_inf", "Ordos") },
|
||||
{ 561, ("trooper", "Ordos") },
|
||||
{ 562, ("saboteur", "Ordos") },
|
||||
{ 563, ("sardaukar", "Ordos") },
|
||||
{ 564, ("engineer", "Ordos") },
|
||||
{ 565, ("harvester", "Ordos") },
|
||||
{ 566, ("mcv", "Ordos") },
|
||||
{ 567, ("raider", "Ordos") },
|
||||
{ 568, ("quad", "Ordos") },
|
||||
{ 569, ("combat_tank_o", "Ordos") },
|
||||
{ 570, ("missile_tank", "Ordos") },
|
||||
{ 571, ("siege_tank", "Ordos") },
|
||||
{ 572, ("carryall", "Ordos") },
|
||||
{ 574, ("deviator", "Ordos") },
|
||||
|
||||
// Corrino:
|
||||
{ 580, ("wall", "Corrino") },
|
||||
{ 581, ("wind_trap", "Corrino") },
|
||||
{ 582, ("construction_yard", "Corrino") },
|
||||
{ 583, ("barracks", "Corrino") },
|
||||
{ 584, ("refinery", "Corrino") },
|
||||
{ 585, ("outpost", "Corrino") },
|
||||
{ 587, ("light_factory", "Corrino") },
|
||||
{ 588, ("palace", "Corrino") },
|
||||
{ 589, ("silo", "Corrino") },
|
||||
{ 590, ("heavy_factory", "Corrino") },
|
||||
{ 591, ("repair_pad", "Corrino") },
|
||||
{ 592, ("medium_gun_turret", "Corrino") },
|
||||
{ 593, ("high_tech_factory", "Corrino") },
|
||||
{ 594, ("large_gun_turret", "Corrino") },
|
||||
{ 595, ("research_centre", "Corrino") },
|
||||
{ 596, ("starport", "Corrino") },
|
||||
{ 597, ("sietch", "Corrino") },
|
||||
{ 598, ("light_inf", "Corrino") },
|
||||
{ 599, ("trooper", "Corrino") },
|
||||
{ 600, ("sardaukar", "Corrino") },
|
||||
{ 601, ("fremen", "Corrino") },
|
||||
{ 602, ("engineer", "Corrino") },
|
||||
{ 603, ("harvester", "Corrino") },
|
||||
{ 604, ("mcv", "Corrino") },
|
||||
{ 605, ("trike", "Corrino") },
|
||||
{ 606, ("quad", "Corrino") },
|
||||
{ 607, ("combat_tank_h", "Corrino") },
|
||||
{ 608, ("missile_tank", "Corrino") },
|
||||
{ 609, ("siege_tank", "Corrino") },
|
||||
{ 610, ("carryall", "Corrino") },
|
||||
|
||||
// Fremen:
|
||||
{ 620, ("wall", "Fremen") },
|
||||
{ 621, ("wind_trap", "Fremen") },
|
||||
{ 622, ("construction_yard", "Fremen") },
|
||||
{ 623, ("barracks", "Fremen") },
|
||||
{ 624, ("refinery", "Fremen") },
|
||||
{ 625, ("outpost", "Fremen") },
|
||||
{ 627, ("light_factory", "Fremen") },
|
||||
{ 628, ("palace", "Fremen") },
|
||||
{ 629, ("silo", "Fremen") },
|
||||
{ 630, ("heavy_factory", "Fremen") },
|
||||
{ 631, ("repair_pad", "Fremen") },
|
||||
{ 632, ("medium_gun_turret", "Fremen") },
|
||||
{ 633, ("high_tech_factory", "Fremen") },
|
||||
{ 634, ("large_gun_turret", "Fremen") },
|
||||
{ 635, ("research_centre", "Fremen") },
|
||||
{ 636, ("starport", "Fremen") },
|
||||
{ 637, ("sietch", "Fremen") },
|
||||
{ 638, ("light_inf", "Fremen") },
|
||||
{ 639, ("trooper", "Fremen") },
|
||||
{ 640, ("fremen", "Fremen") },
|
||||
{ 641, ("nsfremen", "Fremen") },
|
||||
{ 642, ("engineer", "Fremen") },
|
||||
{ 643, ("harvester", "Fremen") },
|
||||
{ 644, ("mcv", "Fremen") },
|
||||
{ 645, ("trike", "Fremen") },
|
||||
{ 646, ("quad", "Fremen") },
|
||||
{ 647, ("combat_tank_a", "Fremen") },
|
||||
{ 648, ("missile_tank", "Fremen") },
|
||||
{ 649, ("siege_tank", "Fremen") },
|
||||
{ 650, ("carryall", "Fremen") },
|
||||
{ 652, ("sonic_tank", "Fremen") },
|
||||
|
||||
// Smugglers:
|
||||
{ 660, ("wall", "Smugglers") },
|
||||
{ 661, ("wind_trap", "Smugglers") },
|
||||
{ 662, ("construction_yard", "Smugglers") },
|
||||
{ 663, ("barracks", "Smugglers") },
|
||||
{ 664, ("refinery", "Smugglers") },
|
||||
{ 666, ("outpost", "Smugglers") },
|
||||
{ 667, ("light_factory", "Smugglers") },
|
||||
{ 668, ("silo", "Smugglers") },
|
||||
{ 669, ("heavy_factory", "Smugglers") },
|
||||
{ 670, ("repair_pad", "Smugglers") },
|
||||
{ 671, ("medium_gun_turret", "Smugglers") },
|
||||
{ 672, ("high_tech_factory", "Smugglers") },
|
||||
{ 673, ("large_gun_turret", "Smugglers") },
|
||||
{ 674, ("research_centre", "Smugglers") },
|
||||
{ 675, ("starport", "Smugglers") },
|
||||
{ 676, ("palace", "Smugglers") },
|
||||
{ 677, ("light_inf", "Smugglers") },
|
||||
{ 678, ("trooper", "Smugglers") },
|
||||
{ 679, ("saboteur", "Smugglers") },
|
||||
{ 680, ("engineer", "Smugglers") },
|
||||
{ 681, ("harvester", "Smugglers") },
|
||||
{ 682, ("mcv", "Smugglers") },
|
||||
{ 683, ("trike", "Smugglers") },
|
||||
{ 684, ("quad", "Smugglers") },
|
||||
{ 685, ("combat_tank_o", "Smugglers") },
|
||||
{ 686, ("missile_tank", "Smugglers") },
|
||||
{ 687, ("siege_tank", "Smugglers") },
|
||||
{ 688, ("carryall", "Smugglers") },
|
||||
|
||||
// Mercenaries:
|
||||
{ 700, ("wall", "Mercenaries") },
|
||||
{ 701, ("wind_trap", "Mercenaries") },
|
||||
{ 702, ("construction_yard", "Mercenaries") },
|
||||
{ 703, ("barracks", "Mercenaries") },
|
||||
{ 704, ("refinery", "Mercenaries") },
|
||||
{ 705, ("outpost", "Mercenaries") },
|
||||
{ 707, ("light_factory", "Mercenaries") },
|
||||
{ 708, ("silo", "Mercenaries") },
|
||||
{ 709, ("heavy_factory", "Mercenaries") },
|
||||
{ 710, ("repair_pad", "Mercenaries") },
|
||||
{ 711, ("medium_gun_turret", "Mercenaries") },
|
||||
{ 712, ("high_tech_factory", "Mercenaries") },
|
||||
{ 713, ("large_gun_turret", "Mercenaries") },
|
||||
{ 714, ("research_centre", "Mercenaries") },
|
||||
{ 715, ("starport", "Mercenaries") },
|
||||
{ 716, ("palace", "Mercenaries") },
|
||||
{ 717, ("light_inf", "Mercenaries") },
|
||||
{ 718, ("trooper", "Mercenaries") },
|
||||
{ 719, ("saboteur", "Mercenaries") },
|
||||
{ 720, ("harvester", "Mercenaries") },
|
||||
{ 721, ("harvester", "Mercenaries") },
|
||||
{ 722, ("mcv", "Mercenaries") },
|
||||
{ 723, ("trike", "Mercenaries") },
|
||||
{ 724, ("quad", "Mercenaries") },
|
||||
{ 725, ("combat_tank_o", "Mercenaries") },
|
||||
{ 726, ("missile_tank", "Mercenaries") },
|
||||
{ 727, ("siege_tank", "Mercenaries") },
|
||||
{ 728, ("carryall", "Mercenaries") },
|
||||
};
|
||||
|
||||
readonly Ruleset rules;
|
||||
readonly FileStream stream;
|
||||
readonly string tilesetName;
|
||||
readonly TerrainTile clearTile;
|
||||
|
||||
Map map;
|
||||
Size mapSize;
|
||||
DefaultTerrain terrainInfo;
|
||||
List<DefaultTerrainTemplateInfo> tileSetsFromYaml;
|
||||
int playerCount;
|
||||
|
||||
D2kMapImporter(string filename, string tileset, Ruleset rules)
|
||||
{
|
||||
tilesetName = tileset;
|
||||
this.rules = rules;
|
||||
|
||||
try
|
||||
{
|
||||
clearTile = new TerrainTile(0, 0);
|
||||
stream = File.OpenRead(filename);
|
||||
|
||||
if (stream.Length == 0 || stream.Length % 4 != 0)
|
||||
throw new ArgumentException("The map is in an unrecognized format!", nameof(filename));
|
||||
|
||||
Initialize(filename);
|
||||
FillMap();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
map = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static Map Import(string filename, string mod, string tileset, Ruleset rules)
|
||||
{
|
||||
var importer = new D2kMapImporter(filename, tileset, rules);
|
||||
var map = importer.map;
|
||||
if (map == null)
|
||||
return null;
|
||||
|
||||
map.RequiresMod = mod;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
void Initialize(string mapFile)
|
||||
{
|
||||
mapSize = new Size(stream.ReadUInt16(), stream.ReadUInt16());
|
||||
terrainInfo = Game.ModData.DefaultTerrainInfo["ARRAKIS"] as DefaultTerrain;
|
||||
|
||||
if (terrainInfo == null)
|
||||
throw new InvalidDataException("The D2k map importer requires the DefaultTerrain parser.");
|
||||
|
||||
map = new Map(Game.ModData, terrainInfo, new Size(mapSize.Width + 2 * MapCordonWidth, mapSize.Height + 2 * MapCordonWidth))
|
||||
{
|
||||
Title = Path.GetFileNameWithoutExtension(mapFile),
|
||||
Author = "Westwood Studios"
|
||||
};
|
||||
|
||||
var tl = new PPos(MapCordonWidth, MapCordonWidth);
|
||||
var br = new PPos(MapCordonWidth + mapSize.Width - 1, MapCordonWidth + mapSize.Height - 1);
|
||||
map.SetBounds(tl, br);
|
||||
|
||||
// Get all templates from the tileset YAML file that have at least one frame and an Image property corresponding to the requested tileset
|
||||
// Each frame is a tile from the Dune 2000 tileset files, with the Frame ID being the index of the tile in the original file
|
||||
tileSetsFromYaml = terrainInfo.TemplatesInDefinitionOrder
|
||||
.Cast<DefaultTerrainTemplateInfo>()
|
||||
.Where(templateInfo => templateInfo.Frames != null && string.Equals(templateInfo.Images[0], tilesetName, StringComparison.InvariantCultureIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
var players = new MapPlayers(map.Rules, playerCount);
|
||||
map.PlayerDefinitions = players.ToMiniYaml();
|
||||
}
|
||||
|
||||
void FillMap()
|
||||
{
|
||||
var actorNodes = new List<MiniYamlNode>();
|
||||
var playerNodes = new List<MiniYamlNode>();
|
||||
while (stream.Position < stream.Length)
|
||||
{
|
||||
var tileInfo = stream.ReadUInt16();
|
||||
var tileSpecialInfo = stream.ReadUInt16();
|
||||
var tile = GetTile(tileInfo);
|
||||
|
||||
var locationOnMap = GetCurrentTilePositionOnMap();
|
||||
|
||||
map.Tiles[locationOnMap] = tile;
|
||||
|
||||
// Spice
|
||||
if (tileSpecialInfo == 1)
|
||||
map.Resources[locationOnMap] = new ResourceTile(1, 1);
|
||||
if (tileSpecialInfo == 2)
|
||||
map.Resources[locationOnMap] = new ResourceTile(1, 2);
|
||||
|
||||
// Actors
|
||||
if (ActorDataByActorCode.TryGetValue(tileSpecialInfo, out var kvp))
|
||||
{
|
||||
if (!rules.Actors.ContainsKey(kvp.Actor.ToLowerInvariant()))
|
||||
Console.WriteLine($"Ignoring unknown actor type: `{kvp.Actor.ToLowerInvariant()}`");
|
||||
else
|
||||
{
|
||||
var a = new ActorReference(kvp.Actor)
|
||||
{
|
||||
new LocationInit(locationOnMap),
|
||||
new OwnerInit(kvp.Owner)
|
||||
};
|
||||
|
||||
actorNodes.Add(new MiniYamlNode("Actor" + (map.ActorDefinitions.Count + actorNodes.Count), a.Save()));
|
||||
|
||||
if (map.PlayerDefinitions.Concat(playerNodes).All(
|
||||
x => x.Value.NodeWithKey("Name").Value.Value != kvp.Owner))
|
||||
{
|
||||
var playerInfo = PlayerReferenceDataByPlayerName[kvp.Owner];
|
||||
var playerReference = new PlayerReference
|
||||
{
|
||||
Name = kvp.Owner,
|
||||
OwnsWorld = kvp.Owner == "Neutral",
|
||||
NonCombatant = kvp.Owner == "Neutral",
|
||||
Faction = playerInfo.Faction,
|
||||
Color = playerInfo.Color
|
||||
};
|
||||
|
||||
var node = new MiniYamlNode($"{nameof(PlayerReference)}@{kvp.Owner}", FieldSaver.SaveDifferences(playerReference, new PlayerReference()));
|
||||
playerNodes.Add(node);
|
||||
}
|
||||
|
||||
if (kvp.Actor == "mpspawn")
|
||||
playerCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map.ActorDefinitions = map.ActorDefinitions.Concat(actorNodes).ToArray();
|
||||
map.PlayerDefinitions = map.PlayerDefinitions.Concat(playerNodes).ToArray();
|
||||
}
|
||||
|
||||
CPos GetCurrentTilePositionOnMap()
|
||||
{
|
||||
var tileIndex = (int)stream.Position / 4 - 2;
|
||||
|
||||
var x = tileIndex % mapSize.Width + MapCordonWidth;
|
||||
var y = tileIndex / mapSize.Width + MapCordonWidth;
|
||||
|
||||
return new CPos(x, y);
|
||||
}
|
||||
|
||||
TerrainTile GetTile(int tileIndex)
|
||||
{
|
||||
// Some tiles are duplicates of other tiles, just on a different tileset
|
||||
if (string.Equals(tilesetName, "bloxbgbs.r8", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
if (tileIndex == 355)
|
||||
return new TerrainTile(441, 0);
|
||||
|
||||
if (tileIndex == 375)
|
||||
return new TerrainTile(442, 0);
|
||||
}
|
||||
|
||||
if (string.Equals(tilesetName, "bloxtree.r8", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
var indices = new[] { 683, 684, 685, 706, 703, 704, 705, 726, 723, 724, 725, 746, 743, 744, 745, 747 };
|
||||
for (var i = 0; i < 16; i++)
|
||||
if (tileIndex == indices[i])
|
||||
return new TerrainTile(474, (byte)i);
|
||||
|
||||
indices = [369, 370, 389, 390];
|
||||
for (var i = 0; i < 4; i++)
|
||||
if (tileIndex == indices[i])
|
||||
return new TerrainTile(117, (byte)i);
|
||||
|
||||
indices = [661, 662, 681, 682];
|
||||
for (var i = 0; i < 4; i++)
|
||||
if (tileIndex == indices[i])
|
||||
return new TerrainTile(251, (byte)i);
|
||||
|
||||
if (tileIndex == 322)
|
||||
return new TerrainTile(215, 0);
|
||||
}
|
||||
|
||||
if (string.Equals(tilesetName, "bloxwast.r8", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
if (tileIndex == 342)
|
||||
return new TerrainTile(250, 0);
|
||||
|
||||
if (tileIndex == 383)
|
||||
return new TerrainTile(121, 1);
|
||||
|
||||
if (tileIndex == 384)
|
||||
return new TerrainTile(1046, 0);
|
||||
|
||||
if (tileIndex == 579)
|
||||
return new TerrainTile(80, 0);
|
||||
|
||||
if (tileIndex == 597)
|
||||
return new TerrainTile(80, 0);
|
||||
|
||||
if (tileIndex == 598)
|
||||
return new TerrainTile(470, 0);
|
||||
|
||||
if (tileIndex == 599)
|
||||
return new TerrainTile(470, 1);
|
||||
|
||||
if (tileIndex == 608)
|
||||
return new TerrainTile(58, 0);
|
||||
|
||||
if (tileIndex == 627)
|
||||
return new TerrainTile(248, 0);
|
||||
|
||||
if (tileIndex == 628)
|
||||
return new TerrainTile(248, 1);
|
||||
|
||||
if (tileIndex == 719)
|
||||
return new TerrainTile(275, 0);
|
||||
|
||||
var indices = new[] { 340, 341, 360, 361 };
|
||||
for (var i = 0; i < 4; i++)
|
||||
if (tileIndex == indices[i])
|
||||
return new TerrainTile(308, (byte)i);
|
||||
|
||||
indices = [660, 661, 662, 680, 681, 682];
|
||||
for (var i = 0; i < 6; i++)
|
||||
if (tileIndex == indices[i])
|
||||
return new TerrainTile(443, (byte)i);
|
||||
|
||||
indices = [609, 610, 629, 630];
|
||||
for (var i = 0; i < 4; i++)
|
||||
if (tileIndex == indices[i])
|
||||
return new TerrainTile(251, (byte)i);
|
||||
}
|
||||
|
||||
// Get the first tileset template that contains the Frame ID of the original map's tile with the requested index
|
||||
var template = tileSetsFromYaml.FirstOrDefault(x => x.Frames.Contains(tileIndex));
|
||||
|
||||
// HACK: The arrakis.yaml tileset file seems to be missing some tiles, so just get a replacement for them
|
||||
// Also used for duplicate tiles that are taken from only tileset
|
||||
// Just get a template that contains a tile with the same ID as requested
|
||||
template ??= terrainInfo.TemplatesInDefinitionOrder
|
||||
.Cast<DefaultTerrainTemplateInfo>()
|
||||
.FirstOrDefault(templateInfo => templateInfo.Frames != null && templateInfo.Frames.Contains(tileIndex));
|
||||
|
||||
if (template == null)
|
||||
{
|
||||
var pos = GetCurrentTilePositionOnMap();
|
||||
Console.WriteLine($"Tile with index {tileIndex} could not be found in the tileset YAML file!");
|
||||
Console.WriteLine($"Defaulting to a \"clear\" tile for coordinates ({pos.X}, {pos.Y})!");
|
||||
return clearTile;
|
||||
}
|
||||
|
||||
var templateIndex = template.Id;
|
||||
var frameIndex = template.Frames.IndexOf(tileIndex);
|
||||
|
||||
return new TerrainTile(templateIndex, (byte)((frameIndex == -1) ? 0 : frameIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
44
OpenRA.Mods.D2k/UtilityCommands/ImportD2kMapCommand.cs
Normal file
44
OpenRA.Mods.D2k/UtilityCommands/ImportD2kMapCommand.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using OpenRA.FileSystem;
|
||||
|
||||
namespace OpenRA.Mods.D2k.UtilityCommands
|
||||
{
|
||||
sealed class ImportD2kMapCommand : IUtilityCommand
|
||||
{
|
||||
string IUtilityCommand.Name => "--import-d2k-map";
|
||||
|
||||
bool IUtilityCommand.ValidateArguments(string[] args)
|
||||
{
|
||||
return args.Length >= 3;
|
||||
}
|
||||
|
||||
[Desc("FILENAME", "TILESET", "Convert a legacy Dune 2000 MAP file to the OpenRA format.")]
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user