added TilesetBuilder command line, added Tileset extractor
removing all copyrighted raw tileset files
225
BGBS.tsx
Normal file
@@ -0,0 +1,225 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<tileset>
|
||||
<name value="Temperat" />
|
||||
<template>
|
||||
<cell x="0" y="0" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="12" y="0" />
|
||||
<cell x="13" y="0" />
|
||||
<cell x="13" y="1" />
|
||||
<cell x="12" y="1" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="14" y="1" />
|
||||
<cell x="15" y="1" />
|
||||
<cell x="15" y="0" />
|
||||
<cell x="14" y="0" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="13" y="2" />
|
||||
<cell x="13" y="3" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="12" y="3" />
|
||||
<cell x="11" y="3" />
|
||||
<cell x="10" y="3" />
|
||||
<cell x="9" y="3" />
|
||||
<cell x="8" y="3" />
|
||||
<cell x="8" y="2" />
|
||||
<cell x="9" y="2" />
|
||||
<cell x="10" y="2" />
|
||||
<cell x="11" y="2" />
|
||||
<cell x="12" y="2" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="14" y="2" />
|
||||
<cell x="14" y="3" />
|
||||
<cell x="15" y="3" />
|
||||
<cell x="15" y="2" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="16" y="2" />
|
||||
<cell x="17" y="2" />
|
||||
<cell x="17" y="3" />
|
||||
<cell x="16" y="3" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="18" y="3" />
|
||||
<cell x="19" y="3" />
|
||||
<cell x="19" y="2" />
|
||||
<cell x="18" y="2" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="18" y="1" />
|
||||
<cell x="18" y="0" />
|
||||
<cell x="19" y="0" />
|
||||
<cell x="19" y="1" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="17" y="1" />
|
||||
<cell x="16" y="1" />
|
||||
<cell x="16" y="0" />
|
||||
<cell x="17" y="0" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="18" y="4" />
|
||||
<cell x="18" y="5" />
|
||||
<cell x="19" y="5" />
|
||||
<cell x="19" y="4" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="18" y="6" />
|
||||
<cell x="18" y="7" />
|
||||
<cell x="19" y="7" />
|
||||
<cell x="19" y="6" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="16" y="5" />
|
||||
<cell x="15" y="5" />
|
||||
<cell x="15" y="4" />
|
||||
<cell x="16" y="4" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="14" y="4" />
|
||||
<cell x="13" y="4" />
|
||||
<cell x="13" y="5" />
|
||||
<cell x="14" y="5" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="12" y="5" />
|
||||
<cell x="11" y="5" />
|
||||
<cell x="11" y="4" />
|
||||
<cell x="12" y="4" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="10" y="4" />
|
||||
<cell x="9" y="4" />
|
||||
<cell x="9" y="5" />
|
||||
<cell x="10" y="5" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="8" y="5" />
|
||||
<cell x="7" y="5" />
|
||||
<cell x="7" y="4" />
|
||||
<cell x="8" y="4" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="6" y="4" />
|
||||
<cell x="5" y="4" />
|
||||
<cell x="5" y="5" />
|
||||
<cell x="6" y="5" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="0" y="6" />
|
||||
<cell x="1" y="6" />
|
||||
<cell x="1" y="7" />
|
||||
<cell x="0" y="7" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="2" y="7" />
|
||||
<cell x="3" y="7" />
|
||||
<cell x="3" y="6" />
|
||||
<cell x="2" y="6" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="4" y="7" />
|
||||
<cell x="5" y="7" />
|
||||
<cell x="5" y="6" />
|
||||
<cell x="4" y="6" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="6" y="7" />
|
||||
<cell x="7" y="7" />
|
||||
<cell x="7" y="6" />
|
||||
<cell x="6" y="6" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="8" y="6" />
|
||||
<cell x="8" y="7" />
|
||||
<cell x="9" y="7" />
|
||||
<cell x="9" y="6" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="10" y="6" />
|
||||
<cell x="10" y="7" />
|
||||
<cell x="11" y="7" />
|
||||
<cell x="11" y="6" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="12" y="6" />
|
||||
<cell x="12" y="7" />
|
||||
<cell x="13" y="7" />
|
||||
<cell x="13" y="6" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="14" y="6" />
|
||||
<cell x="14" y="7" />
|
||||
<cell x="15" y="7" />
|
||||
<cell x="15" y="6" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="16" y="6" />
|
||||
<cell x="16" y="7" />
|
||||
<cell x="17" y="7" />
|
||||
<cell x="17" y="6" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="1" y="8" />
|
||||
<cell x="1" y="9" />
|
||||
<cell x="0" y="9" />
|
||||
<cell x="0" y="8" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="2" y="8" />
|
||||
<cell x="2" y="9" />
|
||||
<cell x="3" y="9" />
|
||||
<cell x="3" y="8" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="4" y="8" />
|
||||
<cell x="4" y="9" />
|
||||
<cell x="5" y="9" />
|
||||
<cell x="5" y="8" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="6" y="8" />
|
||||
<cell x="6" y="9" />
|
||||
<cell x="7" y="9" />
|
||||
<cell x="7" y="8" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="8" y="8" />
|
||||
<cell x="8" y="9" />
|
||||
<cell x="9" y="9" />
|
||||
<cell x="9" y="8" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="10" y="8" />
|
||||
<cell x="10" y="9" />
|
||||
<cell x="11" y="9" />
|
||||
<cell x="11" y="8" />
|
||||
<cell x="12" y="8" />
|
||||
<cell x="12" y="9" />
|
||||
<cell x="13" y="9" />
|
||||
<cell x="13" y="8" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="14" y="8" />
|
||||
<cell x="14" y="9" />
|
||||
<cell x="15" y="9" />
|
||||
<cell x="15" y="8" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="16" y="8" />
|
||||
<cell x="16" y="9" />
|
||||
<cell x="17" y="9" />
|
||||
<cell x="17" y="8" />
|
||||
</template>
|
||||
<template>
|
||||
<cell x="18" y="8" />
|
||||
<cell x="18" y="9" />
|
||||
<cell x="19" y="9" />
|
||||
<cell x="19" y="8" />
|
||||
</template>
|
||||
</tileset>
|
||||
@@ -58,6 +58,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="D2kLoadScreen.cs" />
|
||||
<Compile Include="Render\RenderBuildingSeparateTurret.cs" />
|
||||
<Compile Include="Widgets\Logic\D2kInstallFromCDLogic.cs" />
|
||||
<Compile Include="Widgets\Logic\D2kInstallLogic.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -21,14 +21,17 @@ namespace OpenRA.TilesetBuilder
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
//Console.WriteLine("{0} {1}",args[0], args[1]);
|
||||
//Console.WriteLine("{0} {1} {2} {3}",args[0], args[1], args[2], args[3]);
|
||||
if (args.Length < 1)
|
||||
{
|
||||
Application.Run(new frmBuilder("", "0"));
|
||||
Application.Run(new frmBuilder("", "0", false, "Tilesets"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.Run(new frmBuilder(args[0], args[1]));
|
||||
if (args.Contains("--export"))
|
||||
Application.Run(new frmBuilder(args[0], args[1], true, args[3]));
|
||||
else
|
||||
Application.Run(new frmBuilder(args[0], args[1], false, "Tilesets"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
OpenRA.TilesetBuilder/defaults.yaml
Normal file
@@ -0,0 +1,38 @@
|
||||
Terrain:
|
||||
TerrainType@Sand:
|
||||
Type: Sand
|
||||
AcceptSmudge: True
|
||||
Color: 208, 192, 160
|
||||
TerrainType@Rock:
|
||||
Type: Rock
|
||||
AcceptSmudge: True
|
||||
Color: 206, 140, 66
|
||||
TerrainType@Cliff:
|
||||
Type: Cliff
|
||||
AcceptSmudge: False
|
||||
Color: 74, 41, 16
|
||||
TerrainType@Rough:
|
||||
Type: Rough
|
||||
AcceptSmudge: True
|
||||
Color: 88, 116, 116
|
||||
TerrainType@Concrete:
|
||||
Type: Concrete
|
||||
AcceptSmudge: False
|
||||
Color: 208, 192, 160
|
||||
TerrainType@Dune:
|
||||
Type: Dune
|
||||
AcceptSmudge: True
|
||||
Color: 239, 222, 140
|
||||
TerrainType@Spice:
|
||||
Type: Spice
|
||||
AcceptSmudge: False
|
||||
Color: 239, 148, 74
|
||||
TerrainType@SpiceBlobs:
|
||||
Type: SpiceBlobs
|
||||
AcceptSmudge: False
|
||||
Color: 206, 115, 66
|
||||
TerrainType@Ice:
|
||||
Type: Ice
|
||||
AcceptSmudge: False
|
||||
Color: 255, 255, 255
|
||||
IsWater: True
|
||||
@@ -62,8 +62,8 @@ namespace OpenRA.TilesetBuilder
|
||||
rbitmap.Palette = tpal.AsSystemPalette();
|
||||
}
|
||||
|
||||
surface1.Image = (Bitmap)rbitmap; //(Bitmap)Image.FromFile(src);
|
||||
surface1.Image.SetResolution(96, 96); // people keep being noobs about DPI, and GDI+ cares.
|
||||
surface1.Image = (Bitmap)rbitmap;
|
||||
surface1.Image.SetResolution(96, 96); // people keep being noobs about DPI, and GDI+ cares.
|
||||
surface1.TerrainTypes = new int[surface1.Image.Width / size, surface1.Image.Height / size]; /* all passable by default */
|
||||
surface1.Templates = new List<Template>();
|
||||
surface1.Size = surface1.Image.Size;
|
||||
@@ -72,60 +72,66 @@ namespace OpenRA.TilesetBuilder
|
||||
}
|
||||
}
|
||||
|
||||
public frmBuilder( string src, string tsize )
|
||||
public frmBuilder(string src, string tsize, bool AutoExport, string OutputDir)
|
||||
{
|
||||
InitializeComponent();
|
||||
Dictionary<string, TerrainTypeInfo> DefTerrain = new Dictionary<string, TerrainTypeInfo>();
|
||||
InitializeComponent();
|
||||
Dictionary<string, TerrainTypeInfo> DefTerrain = new Dictionary<string, TerrainTypeInfo>();
|
||||
|
||||
int size = int.Parse(tsize);
|
||||
int size = int.Parse(tsize);
|
||||
|
||||
var yaml = MiniYaml.DictFromFile("tsbdefaults.yaml");
|
||||
DefTerrain = yaml["Terrain"].NodesDict.Values.Select(y => new TerrainTypeInfo(y)).ToDictionary(t => t.Type);
|
||||
int i = 0;
|
||||
surface1.icon = new Bitmap[DefTerrain.Keys.Count];
|
||||
TerrainType = new TerrainTypeInfo[DefTerrain.Keys.Count];
|
||||
surface1.Enabled = false;
|
||||
foreach (var deftype in DefTerrain)
|
||||
{
|
||||
Bitmap icon = new Bitmap(16, 16);
|
||||
int x, y;
|
||||
// Loop through the images pixels to reset color.
|
||||
for (x = 0; x < icon.Width; x++)
|
||||
{
|
||||
for (y = 0; y < icon.Height; y++)
|
||||
var yaml = MiniYaml.DictFromFile("OpenRA.TilesetBuilder/defaults.yaml");
|
||||
DefTerrain = yaml["Terrain"].NodesDict.Values.Select(y => new TerrainTypeInfo(y)).ToDictionary(t => t.Type);
|
||||
int i = 0;
|
||||
surface1.icon = new Bitmap[DefTerrain.Keys.Count];
|
||||
TerrainType = new TerrainTypeInfo[DefTerrain.Keys.Count];
|
||||
surface1.Enabled = false;
|
||||
foreach (var deftype in DefTerrain)
|
||||
{
|
||||
Color newColor = deftype.Value.Color;
|
||||
icon.SetPixel(x, y, newColor);
|
||||
Bitmap icon = new Bitmap(16, 16);
|
||||
int x, y;
|
||||
// Loop through the images pixels to reset color.
|
||||
for (x = 0; x < icon.Width; x++)
|
||||
{
|
||||
for (y = 0; y < icon.Height; y++)
|
||||
{
|
||||
Color newColor = deftype.Value.Color;
|
||||
icon.SetPixel(x, y, newColor);
|
||||
}
|
||||
}
|
||||
surface1.icon[i] = icon;
|
||||
TerrainType[i] = deftype.Value;
|
||||
|
||||
ToolStripButton TerrainTypeButton = new ToolStripButton(deftype.Key, icon, TerrainTypeSelectorClicked);
|
||||
TerrainTypeButton.ToolTipText = deftype.Key;
|
||||
TerrainTypeButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;
|
||||
TerrainTypeButton.Tag = i.ToString();
|
||||
i++;
|
||||
tsTerrainTypes.Items.Add(TerrainTypeButton);
|
||||
}
|
||||
}
|
||||
surface1.icon[i] = icon;
|
||||
TerrainType[i] = deftype.Value;
|
||||
|
||||
ToolStripButton TerrainTypeButton = new ToolStripButton(deftype.Key, icon, TerrainTypeSelectorClicked);
|
||||
TerrainTypeButton.ToolTipText = deftype.Key;
|
||||
TerrainTypeButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText;
|
||||
TerrainTypeButton.Tag = i.ToString();
|
||||
i++;
|
||||
tsTerrainTypes.Items.Add(TerrainTypeButton);
|
||||
}
|
||||
if (src.Length > 0)
|
||||
{
|
||||
srcfile = src;
|
||||
this.size = size;
|
||||
surface1.TileSize = size;
|
||||
surface1.Image = (Bitmap)Image.FromFile(src);
|
||||
surface1.Image.SetResolution(96, 96); // people keep being noobs about DPI, and GDI+ cares.
|
||||
surface1.TerrainTypes = new int[surface1.Image.Width / size, surface1.Image.Height / size]; /* all passable by default */
|
||||
surface1.Templates = new List<Template>();
|
||||
surface1.Size = surface1.Image.Size;
|
||||
surface1.Enabled = true;
|
||||
Load();
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateNewTileset();
|
||||
}
|
||||
|
||||
if (src.Length > 0)
|
||||
{
|
||||
srcfile = src;
|
||||
this.size = size;
|
||||
surface1.TileSize = size;
|
||||
surface1.Image = (Bitmap)Image.FromFile(src);
|
||||
surface1.Image.SetResolution(96, 96); // people keep being noobs about DPI, and GDI+ cares.
|
||||
surface1.TerrainTypes = new int[surface1.Image.Width / size, surface1.Image.Height / size]; /* all passable by default */
|
||||
surface1.Templates = new List<Template>();
|
||||
surface1.Size = surface1.Image.Size;
|
||||
surface1.Enabled = true;
|
||||
Load();
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateNewTileset();
|
||||
}
|
||||
if (AutoExport)
|
||||
{
|
||||
Export(OutputDir);
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
|
||||
public new void Load()
|
||||
@@ -225,94 +231,7 @@ namespace OpenRA.TilesetBuilder
|
||||
|
||||
void ExportClicked(object sender, EventArgs e)
|
||||
{
|
||||
var dir = Path.Combine(Path.GetDirectoryName(srcfile), "output");
|
||||
Directory.CreateDirectory(dir);
|
||||
var tilesetName = txtTilesetName.Text;
|
||||
var tilesetID = txtID.Text;
|
||||
var tilesetPalette = txtPal.Text;
|
||||
var tilesetExt = txtExt.Text;
|
||||
|
||||
if (tilesetName.Length < 1) { tilesetName = "Temperat"; }
|
||||
if (tilesetID.Length < 1) { tilesetID = "TEMPERAT"; }
|
||||
if (tilesetPalette.Length < 1) { tilesetPalette = "temperat"; }
|
||||
if (tilesetExt.Length < 1) { tilesetExt = ".tem,.shp"; }
|
||||
// Create a Tileset definition
|
||||
// Todo: Pull this info from the gui
|
||||
var tilesetFile = "";
|
||||
//var mixFile = "";
|
||||
tilesetFile = tilesetName.ToLower();
|
||||
if (tilesetFile.Length < 8)
|
||||
{
|
||||
tilesetFile = tilesetName.ToLower() + ".yaml";
|
||||
//mixFile = tilesetName.ToLower() + ".mix";
|
||||
}
|
||||
else
|
||||
{
|
||||
tilesetFile = tilesetName.ToLower().Substring(0, 8) + ".yaml";
|
||||
//mixFile = tilesetName.ToLower().Substring(0, 8) + ".mix";
|
||||
}
|
||||
|
||||
string[] Ext = tilesetExt.Split(',');
|
||||
var tileset = new TileSet()
|
||||
{
|
||||
Name = tilesetName,
|
||||
Id = tilesetID.ToUpper(),
|
||||
TileSize = size,
|
||||
Palette = tilesetPalette.ToLower(),
|
||||
Extensions = new string[] { Ext[0], Ext[1] }
|
||||
};
|
||||
|
||||
// List of files to add to the mix file
|
||||
List<string> fileList = new List<string>();
|
||||
|
||||
// Export palette (use the embedded palette)
|
||||
var p = surface1.Image.Palette.Entries.ToList();
|
||||
fileList.Add(ExportPalette(p, Path.Combine(dir, tileset.Palette)));
|
||||
|
||||
// Export tile artwork
|
||||
foreach (var t in surface1.Templates)
|
||||
fileList.Add(ExportTemplate(t, surface1.Templates.IndexOf(t), tileset.Extensions.First(), dir));
|
||||
|
||||
// Add the terraintypes
|
||||
// Todo: add support for multiple/different terraintypes
|
||||
foreach (var tt in TerrainType)
|
||||
{
|
||||
tileset.Terrain.Add(tt.Type, tt);
|
||||
}
|
||||
|
||||
// Add the templates
|
||||
ushort cur = 0;
|
||||
foreach (var tp in surface1.Templates)
|
||||
{
|
||||
var template = new TileTemplate()
|
||||
{
|
||||
Id = cur,
|
||||
Image = "t{0:00}".F(cur),
|
||||
Size = new int2(tp.Width,tp.Height),
|
||||
};
|
||||
|
||||
// Todo: add support for different terraintypes
|
||||
// Todo: restrict cells? this doesn't work: .Where( c => surface1.TerrainTypes[c.Key.X, c.Key.Y] != 0 )
|
||||
foreach (var t in tp.Cells)
|
||||
{
|
||||
string ttype = "Clear";
|
||||
//ttype = TerrainType[surface1.TerrainTypes[t.Key.X, t.Key.Y]].Type;
|
||||
template.Tiles.Add((byte)((t.Key.X - tp.Left) + tp.Width * (t.Key.Y - tp.Top)), ttype);
|
||||
}
|
||||
|
||||
tileset.Templates.Add(cur, template);
|
||||
cur++;
|
||||
}
|
||||
|
||||
tileset.Save(Path.Combine(dir, tilesetFile));
|
||||
//throw new NotImplementedException("NotI");
|
||||
//PackageWriter.CreateMix(Path.Combine(dir, mixFile),fileList);
|
||||
|
||||
// Cleanup
|
||||
//foreach (var file in fileList)
|
||||
//File.Delete(file);
|
||||
|
||||
Console.WriteLine("Finished export");
|
||||
Export("Tilesets");
|
||||
}
|
||||
|
||||
string ExportPalette(List<Color> p, string file)
|
||||
@@ -338,14 +257,14 @@ namespace OpenRA.TilesetBuilder
|
||||
bw.Write((uint)totalTiles);
|
||||
bw.Write((ushort)t.Width);
|
||||
bw.Write((ushort)t.Height);
|
||||
bw.Write((uint)0); // filesize placeholder
|
||||
bw.Write((uint)0); // filesize placeholder
|
||||
bw.Flush();
|
||||
bw.Write((uint)ms.Position + 24); // image start
|
||||
bw.Write((uint)0); // 0 (32bits)
|
||||
bw.Write((uint)ms.Position + 24); // image start
|
||||
bw.Write((uint)0); // 0 (32bits)
|
||||
bw.Write((uint)0x2c730f8c); // magic?
|
||||
bw.Write((uint)0); // flags start
|
||||
bw.Write((uint)0); // walk start
|
||||
bw.Write((uint)0); // index start
|
||||
bw.Write((uint)0); // flags start
|
||||
bw.Write((uint)0); // walk start
|
||||
bw.Write((uint)0); // index start
|
||||
|
||||
Bitmap src = surface1.Image.Clone(new Rectangle(0, 0, surface1.Image.Width, surface1.Image.Height),
|
||||
surface1.Image.PixelFormat);
|
||||
@@ -409,6 +328,95 @@ namespace OpenRA.TilesetBuilder
|
||||
return filename;
|
||||
}
|
||||
|
||||
public void Export (string OutputDir)
|
||||
{
|
||||
var dir = Path.Combine(Path.GetDirectoryName(srcfile), Platform.SupportDir+OutputDir);
|
||||
Directory.CreateDirectory(dir);
|
||||
var tilesetName = txtTilesetName.Text;
|
||||
var tilesetID = txtID.Text;
|
||||
var tilesetPalette = txtPal.Text;
|
||||
var tilesetExt = txtExt.Text;
|
||||
|
||||
if (tilesetName.Length < 1) { tilesetName = "Temperat"; }
|
||||
if (tilesetID.Length < 1) { tilesetID = "TEMPERAT"; }
|
||||
if (tilesetPalette.Length < 1) { tilesetPalette = "temperat"; }
|
||||
if (tilesetExt.Length < 1) { tilesetExt = ".tem,.shp"; }
|
||||
// Create a Tileset definition
|
||||
// Todo: Pull this info from the GUI
|
||||
var tilesetFile = "";
|
||||
//var mixFile = "";
|
||||
tilesetFile = tilesetName.ToLower();
|
||||
if (tilesetFile.Length < 8)
|
||||
{
|
||||
tilesetFile = tilesetName.ToLower() + ".yaml";
|
||||
//mixFile = tilesetName.ToLower() + ".mix";
|
||||
}
|
||||
else
|
||||
{
|
||||
tilesetFile = tilesetName.ToLower().Substring(0, 8) + ".yaml";
|
||||
//mixFile = tilesetName.ToLower().Substring(0, 8) + ".mix";
|
||||
}
|
||||
|
||||
string[] Ext = tilesetExt.Split(',');
|
||||
var tileset = new TileSet()
|
||||
{
|
||||
Name = tilesetName,
|
||||
Id = tilesetID.ToUpper(),
|
||||
TileSize = size,
|
||||
Palette = tilesetPalette.ToLower(),
|
||||
Extensions = new string[] { Ext[0], Ext[1] }
|
||||
};
|
||||
|
||||
// List of files to add to the mix file
|
||||
List<string> fileList = new List<string>();
|
||||
|
||||
// Export palette (use the embedded palette)
|
||||
var p = surface1.Image.Palette.Entries.ToList();
|
||||
fileList.Add(ExportPalette(p, Path.Combine(dir, tileset.Palette)));
|
||||
|
||||
// Export tile artwork
|
||||
foreach (var t in surface1.Templates)
|
||||
fileList.Add(ExportTemplate(t, surface1.Templates.IndexOf(t), tileset.Extensions.First(), dir));
|
||||
|
||||
// Add the terraintypes
|
||||
foreach (var tt in TerrainType)
|
||||
{
|
||||
tileset.Terrain.Add(tt.Type, tt);
|
||||
}
|
||||
|
||||
// Add the templates
|
||||
ushort cur = 0;
|
||||
foreach (var tp in surface1.Templates)
|
||||
{
|
||||
var template = new TileTemplate()
|
||||
{
|
||||
Id = cur,
|
||||
Image = "t{0:00}".F(cur),
|
||||
Size = new int2(tp.Width,tp.Height),
|
||||
};
|
||||
|
||||
foreach (var t in tp.Cells)
|
||||
{
|
||||
string ttype = "Clear";
|
||||
ttype = TerrainType[surface1.TerrainTypes[t.Key.X, t.Key.Y]].Type;
|
||||
template.Tiles.Add((byte)((t.Key.X - tp.Left) + tp.Width * (t.Key.Y - tp.Top)), ttype);
|
||||
}
|
||||
|
||||
tileset.Templates.Add(cur, template);
|
||||
cur++;
|
||||
}
|
||||
|
||||
tileset.Save(Path.Combine(dir, tilesetFile));
|
||||
//throw new NotImplementedException("NotI");
|
||||
//PackageWriter.CreateMix(Path.Combine(dir, mixFile),fileList);
|
||||
|
||||
// Cleanup
|
||||
//foreach (var file in fileList)
|
||||
//File.Delete(file);
|
||||
|
||||
Console.WriteLine("Finished export");
|
||||
}
|
||||
|
||||
private void toolStripContainer1_TopToolStripPanel_Click(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
|
||||
@@ -214,6 +214,35 @@ namespace OpenRA.Utility
|
||||
x += frame.FrameWidth;
|
||||
}
|
||||
}
|
||||
else if (args.Contains("--tileset"))
|
||||
{
|
||||
int f = 0;
|
||||
var tileset = new Bitmap(frame.FrameWidth * 20, frame.FrameHeight * 40, PixelFormat.Format8bppIndexed);
|
||||
tileset.Palette = palette.AsSystemPalette();
|
||||
|
||||
for (int h = 0; h < 40; h++)
|
||||
{
|
||||
for (int w = 0; w < 20; w++)
|
||||
{
|
||||
if (h * 20 + w < FrameCount)
|
||||
{
|
||||
Console.WriteLine(f);
|
||||
frame = srcImage[f];
|
||||
|
||||
var data = tileset.LockBits(new Rectangle(w * frame.Width, h * frame.Height, frame.Width, frame.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
|
||||
for (var i = 0; i < frame.Height; i++)
|
||||
Marshal.Copy(frame.Image, i * frame.Width,
|
||||
new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Width);
|
||||
|
||||
tileset.UnlockBits(data);
|
||||
f++;
|
||||
}
|
||||
}
|
||||
}
|
||||
bitmap = tileset;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int f = startFrame; f < endFrame; f++)
|
||||
|
||||
@@ -54,14 +54,13 @@ namespace OpenRA.Utility
|
||||
{
|
||||
Console.WriteLine("Usage: OpenRA.Utility.exe [OPTION] [ARGS]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" --settings-value KEY Get value of KEY from settings.yaml");
|
||||
Console.WriteLine(" --shp PNGFILE FRAMEWIDTH Convert a single PNG with multiple frames appended after another to a SHP");
|
||||
Console.WriteLine(" --png SHPFILE PALETTE [--transparent] Convert a SHP to a PNG containing all of its frames, optionally setting up transparency");
|
||||
Console.WriteLine(" --extract MOD[,MOD]* FILES Extract files from mod packages");
|
||||
Console.WriteLine(" --tmp-png MOD[,MOD]* THEATER FILES Extract terrain tiles to PNG");
|
||||
Console.WriteLine(" --remap SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP Remap SHPs to another palette");
|
||||
Console.WriteLine(" --r8 R8FILE PALETTE STARTFRAME ENDFRAME FILENAME [--transparent]");
|
||||
Console.WriteLine(" [--infrantry] [--vehicle] [--projectile] [--building] [--wall] Convert Dune 2000 DATA.R8 to PNGs choosing start- and endframe as well as unit type for correct offset to append multiple frames to one PNG named by filename optionally setting up transparency");
|
||||
Console.WriteLine(" --settings-value KEY Get value of KEY from settings.yaml");
|
||||
Console.WriteLine(" --shp PNGFILE FRAMEWIDTH Convert a single PNG with multiple frames appended after another to a SHP");
|
||||
Console.WriteLine(" --png SHPFILE PALETTE [--transparent] Convert a SHP to a PNG containing all of its frames, optionally setting up transparency");
|
||||
Console.WriteLine(" --extract MOD[,MOD]* FILES Extract files from mod packages");
|
||||
Console.WriteLine(" --tmp-png MOD[,MOD]* THEATER FILES Extract terrain tiles to PNG");
|
||||
Console.WriteLine(" --remap SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP Remap SHPs to another palette");
|
||||
Console.WriteLine(" --r8 R8FILE PALETTE START END FILENAME [--transparent] [--infrantry] [--vehicle] [--projectile] [--building] [--wall] [--tileset] Convert Dune 2000 DATA.R8 to PNGs choosing start- and endframe as well as type for correct offset to append multiple frames to one PNG named by filename optionally setting up transparency.");
|
||||
}
|
||||
|
||||
static string GetNamedArg(string[] args, string arg)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
# construction yard crane animations missing
|
||||
# welding animation (factories) missing
|
||||
# chimney animation (refinery) missing
|
||||
# create a tileset extractor for gamefiles to remove copyrighted content from distribution (convert BLOX*.R8 to TMP files)
|
||||
# add more spice tiles and make them fit
|
||||
# add game logic for concrete plates (use terrain overlay from bridges/ressources)
|
||||
# allow placing turrets on walls
|
||||
@@ -37,5 +36,4 @@
|
||||
# reinforcements have arrived is played twice when ordering via starport
|
||||
# add shroud (Dune's 32x32 tiles differ completely from RA/CnC)
|
||||
# black spots on buildings should be transparent
|
||||
# gamefile extraction (setup/setup.z) from CD fails
|
||||
# TilesetBuilder does not support TerrainTypes other then "Clear"
|
||||
# gamefile extraction (setup/setup.z) from CD fails
|
||||
BIN
mods/d2k/bits/cursor.pal
Normal file
@@ -9,16 +9,16 @@ Folders:
|
||||
./mods/d2k
|
||||
./mods/d2k/bits
|
||||
./mods/d2k/uibits
|
||||
./mods/d2k/tilesets/bloxbase
|
||||
~^/Content/d2k
|
||||
~^/Content/d2k/GAMESFX
|
||||
~^/Content/d2k/Music
|
||||
~^/Content/d2k/Tilesets
|
||||
~^/Content/d2k/SHPs
|
||||
./mods/ra/bits
|
||||
./mods/ra/uibits
|
||||
~^/Content/ra
|
||||
|
||||
Packages:
|
||||
arrakis.mix
|
||||
~main.mix
|
||||
redalert.mix
|
||||
conquer.mix
|
||||
@@ -81,8 +81,7 @@ Voices:
|
||||
mods/d2k/voices.yaml
|
||||
|
||||
TileSets:
|
||||
mods/d2k/tilesets/arrakis.yaml
|
||||
mods/d2k/tilesets/bloxbase.yaml
|
||||
mods/d2k/tilesets/base.yaml
|
||||
|
||||
TileSize: 32
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 801 KiB |
|
Before Width: | Height: | Size: 801 KiB |
|
Before Width: | Height: | Size: 801 KiB |
|
Before Width: | Height: | Size: 801 KiB |
|
Before Width: | Height: | Size: 801 KiB |
|
Before Width: | Height: | Size: 801 KiB |
|
Before Width: | Height: | Size: 801 KiB |
|
Before Width: | Height: | Size: 751 KiB |
@@ -101,6 +101,8 @@ MCVA:
|
||||
Offset:-1,-1
|
||||
TransformSounds:
|
||||
NoTransformSounds: AI_DPLOY.AUD
|
||||
RenderUnit:
|
||||
Image: DMCV
|
||||
|
||||
COMBATA:
|
||||
Inherits: ^COMBAT
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
Mobile:
|
||||
Crushes: crate
|
||||
TerrainSpeeds:
|
||||
Clear: 80
|
||||
Rough: 40
|
||||
Road: 100
|
||||
Sand: 80
|
||||
Rock: 90
|
||||
Concrete: 100
|
||||
Spice: 70
|
||||
Beach: 40
|
||||
SpiceBlobs: 70
|
||||
Dune: 40
|
||||
ROT: 5
|
||||
SelectionDecorations:
|
||||
Selectable:
|
||||
@@ -35,11 +36,12 @@
|
||||
Mobile:
|
||||
Crushes: crate
|
||||
TerrainSpeeds:
|
||||
Clear: 80
|
||||
Rough: 70
|
||||
Road: 100
|
||||
Sand: 80
|
||||
Rock: 90
|
||||
Concrete: 100
|
||||
Spice: 70
|
||||
Beach: 70
|
||||
SpiceBlobs: 70
|
||||
Dune: 40
|
||||
ROT: 5
|
||||
SelectionDecorations:
|
||||
Selectable:
|
||||
@@ -74,11 +76,13 @@
|
||||
Crushes: crate
|
||||
SharesCell: true
|
||||
TerrainSpeeds:
|
||||
Clear: 90
|
||||
Rough: 80
|
||||
Road: 100
|
||||
Spice: 80
|
||||
Beach: 80
|
||||
Sand: 80
|
||||
Rock: 90
|
||||
Concrete: 100
|
||||
Spice: 70
|
||||
SpiceBlobs: 70
|
||||
Dune: 40
|
||||
Rough: 60
|
||||
SelectionDecorations:
|
||||
Selectable:
|
||||
Voice: GenericVoice
|
||||
@@ -140,7 +144,7 @@
|
||||
Building:
|
||||
Dimensions: 1,1
|
||||
Footprint: x
|
||||
TerrainTypes: Clear,Road
|
||||
TerrainTypes: Rock, Concrete
|
||||
GivesBuildableArea:
|
||||
Capturable:
|
||||
CapturableBar:
|
||||
|
||||
@@ -101,6 +101,8 @@ MCVH:
|
||||
Offset:-1,-1
|
||||
TransformSounds:
|
||||
NoTransformSounds: HI_DPLOY.AUD
|
||||
RenderUnit:
|
||||
Image: DMCV
|
||||
|
||||
COMBATH:
|
||||
Inherits: ^COMBAT
|
||||
|
||||
@@ -101,6 +101,8 @@ MCVO:
|
||||
Offset:-1,-1
|
||||
TransformSounds:
|
||||
NoTransformSounds: OI_DPLOY.AUD
|
||||
RenderUnit:
|
||||
Image: DMCV
|
||||
|
||||
COMBATO:
|
||||
Inherits: ^COMBAT
|
||||
|
||||
@@ -61,30 +61,30 @@ Player:
|
||||
Name:Omnius
|
||||
RallypointTestBuilding: conyarda
|
||||
BuildingFractions:
|
||||
refa: 30%
|
||||
refh: 30%
|
||||
refo: 30%
|
||||
powra: 35%
|
||||
powrh: 35%
|
||||
powro: 35%
|
||||
barra: 1%
|
||||
barrh: 1%
|
||||
barro: 1%
|
||||
lighta: 1%
|
||||
lighth: 1%
|
||||
lighto: 1%
|
||||
heavya: 1%
|
||||
heavyh: 1%
|
||||
heavyo: 1%
|
||||
researcha: 1%
|
||||
researchh: 1%
|
||||
researcho: 1%
|
||||
refa: 25.1%
|
||||
refh: 25.1%
|
||||
refo: 25.1%
|
||||
barra: 0.1%
|
||||
barrh: 0.1%
|
||||
barro: 0.1%
|
||||
lighta: 0.1%
|
||||
lighth: 0.1%
|
||||
lighto: 0.1%
|
||||
heavya: 0.1%
|
||||
heavyh: 0.1%
|
||||
heavyo: 0.1%
|
||||
researcha: 0.1%
|
||||
researchh: 0.1%
|
||||
researcho: 0.1%
|
||||
repaira: 0.1%
|
||||
repairh: 0.1%
|
||||
repairo: 0.1%
|
||||
radara: 10%
|
||||
radaro: 10%
|
||||
radarh: 10%
|
||||
radara: 0.1%
|
||||
radaro: 0.1%
|
||||
radarh: 0.1%
|
||||
powra: 35%
|
||||
powrh: 35%
|
||||
powro: 35%
|
||||
UnitsToBuild:
|
||||
trike: 30%
|
||||
raider: 30%
|
||||
@@ -181,7 +181,7 @@ World:
|
||||
ValuePerUnit: 35
|
||||
Name: Spice
|
||||
PipColor: Yellow
|
||||
AllowedTerrainTypes: Clear
|
||||
AllowedTerrainTypes: Sand
|
||||
AllowUnderActors: false
|
||||
SmudgeLayer@CRATER:
|
||||
Type:Crater
|
||||
@@ -222,7 +222,7 @@ CRATE:
|
||||
Name: Crate
|
||||
Crate:
|
||||
Lifetime: 120
|
||||
TerrainTypes: Clear, Rough, Road, Water, Beach
|
||||
TerrainTypes: Sand, Dune, Rock
|
||||
GiveCashCrateAction:
|
||||
Amount: 1000
|
||||
SelectionShares: 50
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
Crushes: crate, infantry
|
||||
RevealsShroud:
|
||||
Range: 4
|
||||
RenderUnit:
|
||||
Image: MCV
|
||||
MustBeDestroyed:
|
||||
BaseBuilding:
|
||||
-AttackMove:
|
||||
@@ -181,7 +179,7 @@ SIEGE:
|
||||
Chance: 75
|
||||
AutoTarget:
|
||||
|
||||
Missile:
|
||||
MISSILE:
|
||||
Inherits: ^Tank
|
||||
Valued:
|
||||
Cost: 800
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
mcv:
|
||||
dmcv:
|
||||
idle:
|
||||
Start: 0
|
||||
Facings: 32
|
||||
@@ -874,6 +874,15 @@ allyrepair:
|
||||
Length: *
|
||||
Tick: 160
|
||||
|
||||
parach:
|
||||
open:
|
||||
Start: 0
|
||||
Length: 5
|
||||
idle:
|
||||
Start: 5
|
||||
Length: 11
|
||||
|
||||
|
||||
spicebloom:
|
||||
make:
|
||||
Start: 0
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
General:
|
||||
Name: Arrakis
|
||||
TileSize: 32
|
||||
Id: ARRAKIS
|
||||
Palette: arrakis.pal
|
||||
Extensions: .arr,.shp
|
||||
|
||||
Terrain:
|
||||
TerrainType@Clear:
|
||||
Type: Clear
|
||||
Buildable: True
|
||||
AcceptSmudge: True
|
||||
IsWater: False
|
||||
Color: 255,255,255,255
|
||||
TerrainType@Spice:
|
||||
Type: Spice
|
||||
Buildable: False
|
||||
AcceptSmudge: False
|
||||
IsWater: False
|
||||
Color: 255,255,255,255
|
||||
|
||||
Templates:
|
||||
Template@0:
|
||||
Id: 0
|
||||
Image: t00
|
||||
Size: 1,1
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
Template@1:
|
||||
Id: 1
|
||||
Image: t01
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@2:
|
||||
Id: 2
|
||||
Image: t02
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@3:
|
||||
Id: 3
|
||||
Image: t03
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@4:
|
||||
Id: 4
|
||||
Image: t04
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@5:
|
||||
Id: 5
|
||||
Image: t05
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@6:
|
||||
Id: 6
|
||||
Image: t06
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@7:
|
||||
Id: 7
|
||||
Image: t07
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@8:
|
||||
Id: 8
|
||||
Image: t08
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@9:
|
||||
Id: 9
|
||||
Image: t09
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@10:
|
||||
Id: 10
|
||||
Image: t10
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@11:
|
||||
Id: 11
|
||||
Image: t11
|
||||
Size: 5,3
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
6: Clear
|
||||
1: Clear
|
||||
5: Clear
|
||||
10: Clear
|
||||
11: Clear
|
||||
12: Clear
|
||||
13: Clear
|
||||
14: Clear
|
||||
9: Clear
|
||||
4: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
7: Clear
|
||||
8: Clear
|
||||
Template@12:
|
||||
Id: 12
|
||||
Image: t12
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@13:
|
||||
Id: 13
|
||||
Image: t13
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@14:
|
||||
Id: 14
|
||||
Image: t14
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@15:
|
||||
Id: 15
|
||||
Image: t15
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@16:
|
||||
Id: 16
|
||||
Image: t16
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@17:
|
||||
Id: 17
|
||||
Image: t17
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@18:
|
||||
Id: 18
|
||||
Image: t18
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@19:
|
||||
Id: 19
|
||||
Image: t19
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@20:
|
||||
Id: 20
|
||||
Image: t20
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@21:
|
||||
Id: 21
|
||||
Image: t21
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@22:
|
||||
Id: 22
|
||||
Image: t22
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@23:
|
||||
Id: 23
|
||||
Image: t23
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@24:
|
||||
Id: 24
|
||||
Image: t24
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
Template@25:
|
||||
Id: 25
|
||||
Image: t25
|
||||
Size: 2,2
|
||||
PickAny: False
|
||||
Tiles:
|
||||
0: Clear
|
||||
1: Clear
|
||||
3: Clear
|
||||
2: Clear
|
||||
|
||||