Finished classic graphics mode (besides RA mix encryption).

* Added RA template reading.
* Added support for RA infantry remapping.
* Fixed bugs in text indicator scaling.
* Added separate scaling factors for classic mode.
* Added automatic extra scaling to tool list preview graphics to compensate for the smaller classic graphics.
* Fixed swapped power usage and production of RA Gap Generator.
* Set correct preview House for the Ants and Queen Ant (and larvae).
* Fixed logic to load mix files from inside other mix files.
* Fixed logic to only apply remap to a specific rectangle inside an image.
* Fixed logic to load TD remap schemes.
* Added logic to give classic dummy image semitransparent edges.
* Fixed logic to check the amount of frames of a sprite in classic mode without side effects.
* Fixed bug where the Template tool and the "new from image" dialog used a tile size derived from the map scale factor instead of the preview scale factor to determine in which cell the user clicks.
This commit is contained in:
Nyerguds 2023-06-16 21:46:44 +02:00
parent b611342c18
commit 3f673f8ace
38 changed files with 710 additions and 285 deletions

View File

@ -393,6 +393,7 @@
<Compile Include="RedAlert\GamePluginRA.cs" /> <Compile Include="RedAlert\GamePluginRA.cs" />
<Compile Include="RedAlert\House.cs" /> <Compile Include="RedAlert\House.cs" />
<Compile Include="RedAlert\HouseTypes.cs" /> <Compile Include="RedAlert\HouseTypes.cs" />
<Compile Include="RedAlert\InfantryClassicRemap.cs" />
<Compile Include="RedAlert\InfantryTypes.cs" /> <Compile Include="RedAlert\InfantryTypes.cs" />
<Compile Include="RedAlert\MissionTypes.cs" /> <Compile Include="RedAlert\MissionTypes.cs" />
<Compile Include="RedAlert\OverlayTypes.cs" /> <Compile Include="RedAlert\OverlayTypes.cs" />

View File

@ -405,6 +405,7 @@ namespace MobiusEditor.Controls
PreRender?.Invoke(this, new RenderEventArgs(pe.Graphics, fullInvalidation ? null : invalidateCells)); PreRender?.Invoke(this, new RenderEventArgs(pe.Graphics, fullInvalidation ? null : invalidateCells));
Image mapImg = mapImage; Image mapImg = mapImage;
MapRenderer.SetRenderSettings(pe.Graphics, SmoothScale);
if (mapImg != null) if (mapImg != null)
{ {
pe.Graphics.Transform = compositeTransform; pe.Graphics.Transform = compositeTransform;
@ -412,7 +413,6 @@ namespace MobiusEditor.Controls
var oldCompositingQuality = pe.Graphics.CompositingQuality; var oldCompositingQuality = pe.Graphics.CompositingQuality;
var oldInterpolationMode = pe.Graphics.InterpolationMode; var oldInterpolationMode = pe.Graphics.InterpolationMode;
var oldPixelOffsetMode = pe.Graphics.PixelOffsetMode; var oldPixelOffsetMode = pe.Graphics.PixelOffsetMode;
MapRenderer.SetRenderSettings(pe.Graphics, SmoothScale);
pe.Graphics.DrawImage(mapImg, 0, 0); pe.Graphics.DrawImage(mapImg, 0, 0);
pe.Graphics.CompositingMode = oldCompositingMode; pe.Graphics.CompositingMode = oldCompositingMode;
pe.Graphics.CompositingQuality = oldCompositingQuality; pe.Graphics.CompositingQuality = oldCompositingQuality;

View File

@ -360,7 +360,7 @@ namespace MobiusEditor.Dialogs
} }
templateTypeMapPanel.MapImage = selected.Thumbnail; templateTypeMapPanel.MapImage = selected.Thumbnail;
var templateTypeMetrics = new CellMetrics(selected.ThumbnailIconWidth, selected.ThumbnailIconHeight); var templateTypeMetrics = new CellMetrics(selected.ThumbnailIconWidth, selected.ThumbnailIconHeight);
templateTypeNavigationWidget = new NavigationWidget(templateTypeMapPanel, templateTypeMetrics, Globals.OriginalTileSize, false); templateTypeNavigationWidget = new NavigationWidget(templateTypeMapPanel, templateTypeMetrics, Globals.PreviewTileSize, false);
templateTypeNavigationWidget.MouseoverSize = Size.Empty; templateTypeNavigationWidget.MouseoverSize = Size.Empty;
templateTypeNavigationWidget.Activate(); templateTypeNavigationWidget.Activate();
} }

View File

@ -24,8 +24,6 @@ namespace MobiusEditor
{ {
static Globals() static Globals()
{ {
SetTileSize(false);
double minScale = 1.0 / Math.Min(OriginalTileWidth, OriginalTileHeight);
// Startup options // Startup options
UseClassicGraphics = Properties.Settings.Default.UseClassicGraphics; UseClassicGraphics = Properties.Settings.Default.UseClassicGraphics;
// Defaults // Defaults
@ -36,16 +34,10 @@ namespace MobiusEditor
OutlineAllCrates = Properties.Settings.Default.DefaultOutlineAllCrates; OutlineAllCrates = Properties.Settings.Default.DefaultOutlineAllCrates;
CratesOnTop = Properties.Settings.Default.DefaultCratesOnTop; CratesOnTop = Properties.Settings.Default.DefaultCratesOnTop;
ShowMapGrid = Properties.Settings.Default.DefaultShowMapGrid; ShowMapGrid = Properties.Settings.Default.DefaultShowMapGrid;
ExportTileScale = Math.Min(1, Math.Max(minScale, Math.Abs(Properties.Settings.Default.DefaultExportScale)));
ExportSmoothScale = Properties.Settings.Default.DefaultExportScale < 0;
// Fine tuning // Fine tuning
ZoomToBoundsOnLoad = Properties.Settings.Default.ZoomToBoundsOnLoad; ZoomToBoundsOnLoad = Properties.Settings.Default.ZoomToBoundsOnLoad;
MapGridColor = Properties.Settings.Default.MapGridColor; MapGridColor = Properties.Settings.Default.MapGridColor;
MapBackColor = Color.FromArgb(255, Properties.Settings.Default.MapBackColor); MapBackColor = Color.FromArgb(255, Properties.Settings.Default.MapBackColor);
MapTileScale = Math.Min(1, Math.Max(minScale, Math.Abs(Properties.Settings.Default.MapScale)));
MapSmoothScale = Properties.Settings.Default.MapScale < 0;
PreviewTileScale = Math.Min(1, Math.Max(minScale, Math.Abs(Properties.Settings.Default.PreviewScale)));
PreviewSmoothScale = Properties.Settings.Default.PreviewScale < 0;
UndoRedoStackSize = Properties.Settings.Default.UndoRedoStackSize; UndoRedoStackSize = Properties.Settings.Default.UndoRedoStackSize;
MinimumClampSize = Properties.Settings.Default.MinimumClampSize; MinimumClampSize = Properties.Settings.Default.MinimumClampSize;
// Behavior tweaks // Behavior tweaks
@ -69,14 +61,8 @@ namespace MobiusEditor
public const string MegafilePath = @"DATA"; public const string MegafilePath = @"DATA";
public const string GameTextFilenameFormat = @"DATA\TEXT\MASTERTEXTFILE_{0}.LOC"; public const string GameTextFilenameFormat = @"DATA\TEXT\MASTERTEXTFILE_{0}.LOC";
public static void SetTileSize(bool classic) public static int OriginalTileWidth { get { return UseClassicGraphics ? 24 : 128; } }
{ public static int OriginalTileHeight { get { return UseClassicGraphics ? 24 : 128; } }
OriginalTileWidth = classic ? 24 : 128;
OriginalTileHeight = classic ? 24 : 128;
}
public static int OriginalTileWidth { get; private set; }
public static int OriginalTileHeight { get; private set; }
public static Size OriginalTileSize => new Size(OriginalTileWidth, OriginalTileHeight); public static Size OriginalTileSize => new Size(OriginalTileWidth, OriginalTileHeight);
public const int PixelWidth = 24; public const int PixelWidth = 24;
@ -92,21 +78,50 @@ namespace MobiusEditor
public static bool CratesOnTop { get; set; } public static bool CratesOnTop { get; set; }
public static bool OutlineAllCrates { get; set; } public static bool OutlineAllCrates { get; set; }
public static bool ShowMapGrid { get; set; } public static bool ShowMapGrid { get; set; }
public static double ExportTileScale { get; private set; }
public static bool ExportSmoothScale { get; private set; } public static double ExportTileScale
{
get
{
double defExpScale = UseClassicGraphics ? Properties.Settings.Default.DefaultExportScaleClassic : Properties.Settings.Default.DefaultExportScale;
return Math.Max(GetMinScale(), Math.Abs(defExpScale));
}
}
public static bool ExportSmoothScale
{
get
{
return (UseClassicGraphics ? Properties.Settings.Default.DefaultExportScaleClassic : Properties.Settings.Default.DefaultExportScale) < 0;
}
}
public static bool ZoomToBoundsOnLoad { get; private set; } public static bool ZoomToBoundsOnLoad { get; private set; }
public static Color MapGridColor { get; private set; } public static Color MapGridColor { get; private set; }
public static Color MapBackColor { get; private set; } public static Color MapBackColor { get; private set; }
public static double MapTileScale { get; private set; } private static double GetMinScale(){ return 1.0 / Math.Min(OriginalTileWidth, OriginalTileHeight); }
public static bool MapSmoothScale { get; private set; } public static double MapTileScale => Math.Max(GetMinScale(), Math.Abs(UseClassicGraphics ? Properties.Settings.Default.MapScaleClassic : Properties.Settings.Default.MapScale));
public static bool MapSmoothScale => (UseClassicGraphics ? Properties.Settings.Default.MapScaleClassic : Properties.Settings.Default.MapScale) < 0;
public static int MapTileWidth => Math.Max(1, (int)(OriginalTileWidth * MapTileScale)); public static int MapTileWidth => Math.Max(1, (int)(OriginalTileWidth * MapTileScale));
public static int MapTileHeight => Math.Max(1, (int)(OriginalTileHeight * MapTileScale)); public static int MapTileHeight => Math.Max(1, (int)(OriginalTileHeight * MapTileScale));
public static Size MapTileSize => new Size(MapTileWidth, MapTileHeight); public static Size MapTileSize => new Size(MapTileWidth, MapTileHeight);
public static double PreviewTileScale { get; private set; } public static double PreviewTileScale
public static bool PreviewSmoothScale { get; private set; } {
get
{
double prevTileScale = Math.Max(GetMinScale(), Math.Abs(Properties.Settings.Default.PreviewScale));
if (UseClassicGraphics)
{
// Adjust to classic graphics' considerably smaller overall size
prevTileScale = prevTileScale * 128 / 24;
}
return prevTileScale;
}
}
public static bool PreviewSmoothScale => Properties.Settings.Default.PreviewScale < 0;
public static int PreviewTileWidth => Math.Max(1, (int)(OriginalTileWidth * PreviewTileScale)); public static int PreviewTileWidth => Math.Max(1, (int)(OriginalTileWidth * PreviewTileScale));
public static int PreviewTileHeight => (int)(OriginalTileHeight * PreviewTileScale); public static int PreviewTileHeight => (int)(OriginalTileHeight * PreviewTileScale);
public static Size PreviewTileSize => new Size(PreviewTileWidth, PreviewTileHeight); public static Size PreviewTileSize => new Size(PreviewTileWidth, PreviewTileHeight);

View File

@ -28,5 +28,7 @@ namespace MobiusEditor.Interface
bool IsFixedWing { get; } bool IsFixedWing { get; }
/// <summary>True if this object can harvest resources. This affects the default orders for placing it on the map.</summary> /// <summary>True if this object can harvest resources. This affects the default orders for placing it on the map.</summary>
bool IsHarvester { get; } bool IsHarvester { get; }
/// <summary>True if this techno type adapts to its house colors.</summary>
bool CanRemap { get; }
} }
} }

View File

@ -2435,9 +2435,14 @@ namespace MobiusEditor
if (!gotBeacon) if (!gotBeacon)
{ {
// Beacon only exists in rematered graphics. Get fallback. // Beacon only exists in rematered graphics. Get fallback.
Globals.TheTilesetManager.GetTileData("armor", 6, out waypoint); int icn = plugin.GameType == GameType.RedAlert ? 15 : 12;
Globals.TheTilesetManager.GetTileData("mouse", icn, out waypoint);
}
Globals.TheTilesetManager.GetTileData("mine.shp", 3, out Tile cellTrigger);
if (cellTrigger == null)
{
Globals.TheTilesetManager.GetTileData("mine", 3, out cellTrigger);
} }
Globals.TheTilesetManager.GetTileData("mine", 3, out Tile cellTrigger);
LoadNewIcon(mapToolStripButton, templateTile?.Image, plugin, 0); LoadNewIcon(mapToolStripButton, templateTile?.Image, plugin, 0);
LoadNewIcon(smudgeToolStripButton, smudge?.Thumbnail, plugin, 1); LoadNewIcon(smudgeToolStripButton, smudge?.Thumbnail, plugin, 1);
//LoadNewIcon(overlayToolStripButton, overlayTile?.Image, plugin, 2); //LoadNewIcon(overlayToolStripButton, overlayTile?.Image, plugin, 2);

View File

@ -267,7 +267,7 @@ namespace MobiusEditor.Model
render.Item2(g); render.Item2(g);
if (this.IsFake) if (this.IsFake)
{ {
MapRenderer.RenderFakeBuildingLabel(g, mockBuilding, Point.Empty, Globals.PreviewTileSize, Globals.PreviewTileScale, false); MapRenderer.RenderFakeBuildingLabel(g, mockBuilding, Point.Empty, Globals.PreviewTileSize, false);
} }
} }
this.Thumbnail = th; this.Thumbnail = th;

View File

@ -32,6 +32,10 @@ namespace MobiusEditor.Model
public bool IsFixedWing => false; public bool IsFixedWing => false;
public bool IsExpansionUnit => (Flag & UnitTypeFlag.IsExpansionUnit) == UnitTypeFlag.IsExpansionUnit; public bool IsExpansionUnit => (Flag & UnitTypeFlag.IsExpansionUnit) == UnitTypeFlag.IsExpansionUnit;
public bool IsHarvester => false; public bool IsHarvester => false;
public bool CanRemap => (this.Flag & UnitTypeFlag.NoRemap) != UnitTypeFlag.NoRemap;
public string ClassicGraphicsSource { get; private set; }
public Byte[] ClassicGraphicsRemap { get; private set; }
private Size _RenderSize; private Size _RenderSize;
public Size GetRenderSize(Size cellSize) public Size GetRenderSize(Size cellSize)
{ {
@ -41,17 +45,23 @@ namespace MobiusEditor.Model
public Bitmap Thumbnail { get; set; } public Bitmap Thumbnail { get; set; }
private string nameId; private string nameId;
public InfantryType(sbyte id, string name, string textId, string ownerHouse, UnitTypeFlag flags) public InfantryType(sbyte id, string name, string textId, string ownerHouse, string remappedFrom, byte[] remapTable, UnitTypeFlag flags)
{ {
this.ID = id; this.ID = id;
this.Name = name; this.Name = name;
this.nameId = textId; this.nameId = textId;
this.OwnerHouse = ownerHouse; this.OwnerHouse = ownerHouse;
this.Flag = flags; this.Flag = flags;
this.ClassicGraphicsSource = remappedFrom;
this.ClassicGraphicsRemap = remapTable;
} }
public InfantryType(sbyte id, string name, string textId, string ownerHouse, UnitTypeFlag flags)
: this(id, name, textId, ownerHouse, null, null, flags)
{
}
public InfantryType(sbyte id, string name, string textId, string ownerHouse) public InfantryType(sbyte id, string name, string textId, string ownerHouse)
: this(id, name, textId, ownerHouse, UnitTypeFlag.None) : this(id, name, textId, ownerHouse, null, null, UnitTypeFlag.None)
{ {
} }
@ -89,7 +99,17 @@ namespace MobiusEditor.Model
? Globals.TheGameTextManager[nameId] + " (" + Name.ToUpperInvariant() + ")" ? Globals.TheGameTextManager[nameId] + " (" + Name.ToUpperInvariant() + ")"
: Name.ToUpperInvariant(); : Name.ToUpperInvariant();
Bitmap oldImage = Thumbnail; Bitmap oldImage = Thumbnail;
if (Globals.TheTilesetManager.GetTileData(Name, 4, out Tile tile)) Tile tile;
// RA classic infantry remap support.
if (this.ClassicGraphicsSource != null && Globals.TheTilesetManager is TilesetManagerClassic tsmc)
{
tsmc.GetTeamColorTileData(this.Name, 4, null, out tile, true, false, this.ClassicGraphicsSource, this.ClassicGraphicsRemap);
}
else
{
Globals.TheTilesetManager.GetTeamColorTileData(this.Name, 4, null, out tile, true, false);
}
if (tile != null && tile.Image != null)
{ {
_RenderSize = tile.Image.Size; _RenderSize = tile.Image.Size;
} }

View File

@ -1412,7 +1412,7 @@ namespace MobiusEditor.Model
} }
using (Graphics g = Graphics.FromImage(croppedBitmap)) using (Graphics g = Graphics.FromImage(croppedBitmap))
{ {
MapRenderer.SetRenderSettings(g, true); MapRenderer.SetRenderSettings(g, smooth);
Matrix transform = new Matrix(); Matrix transform = new Matrix();
transform.Scale(previewScale, previewScale); transform.Scale(previewScale, previewScale);
transform.Translate((scaledSize.Width - mapBounds.Width) / 2, (scaledSize.Height - mapBounds.Height) / 2); transform.Translate((scaledSize.Width - mapBounds.Width) / 2, (scaledSize.Height - mapBounds.Height) / 2);

View File

@ -37,6 +37,7 @@ namespace MobiusEditor.Model
public bool IsAircraft => false; public bool IsAircraft => false;
public bool IsFixedWing => false; public bool IsFixedWing => false;
public bool IsHarvester => false; public bool IsHarvester => false;
public bool CanRemap => false;
private string nameId; private string nameId;
public Size GetRenderSize(Size cellSize) public Size GetRenderSize(Size cellSize)
@ -186,7 +187,14 @@ namespace MobiusEditor.Model
: Name.ToUpperInvariant(); : Name.ToUpperInvariant();
var oldImage = Thumbnail; var oldImage = Thumbnail;
string tileName = GraphicsSource; string tileName = GraphicsSource;
if (Globals.TheTilesetManager.GetTileData(tileName, DisplayIcon, out Tile tile)) Tile tile;
// If the graphics source doesn't yield a result, fall back on actual name.
// This fixes the graphics source override for the ore mine not working in classic mode.
if (!Globals.TheTilesetManager.GetTileData(tileName, DisplayIcon, out tile))
{
Globals.TheTilesetManager.GetTileData(this.Name, DisplayIcon, out tile);
}
if (tile != null)
{ {
var tileSize = Globals.PreviewTileSize; var tileSize = Globals.PreviewTileSize;
var renderSize = new Size(tileSize.Width * Size.Width, tileSize.Height * Size.Height); var renderSize = new Size(tileSize.Width * Size.Width, tileSize.Height * Size.Height);

View File

@ -35,12 +35,14 @@ namespace MobiusEditor.Model
IsArmed = 1 << 3, IsArmed = 1 << 3,
/// <summary>Can harvest resources. This affects the default orders for placing it on the map.</summary> /// <summary>Can harvest resources. This affects the default orders for placing it on the map.</summary>
IsHarvester = 1 << 4, IsHarvester = 1 << 4,
/// <summary>Can attack units. This affects the default orders for placing it on the map.</summary>
NoRemap = 1 << 5,
/// <summary>Is a unit that is filtered out of the lists if expansion units are disabled.</summary> /// <summary>Is a unit that is filtered out of the lists if expansion units are disabled.</summary>
IsExpansionUnit = 1 << 5, IsExpansionUnit = 1 << 6,
/// <summary>Can show a mobile gap area-of-effect radius indicator.</summary> /// <summary>Can show a mobile gap area-of-effect radius indicator.</summary>
IsGapGenerator = 1 << 6, IsGapGenerator = 1 << 7,
/// <summary>Can show a radar jamming area-of-effect radius indicator.</summary> /// <summary>Can show a radar jamming area-of-effect radius indicator.</summary>
IsJammer = 1 << 7, IsJammer = 1 << 8,
} }
public static class UnitTypeIDMask public static class UnitTypeIDMask
@ -72,6 +74,7 @@ namespace MobiusEditor.Model
public bool IsArmed => (this.Flag & UnitTypeFlag.IsArmed) == UnitTypeFlag.IsArmed; public bool IsArmed => (this.Flag & UnitTypeFlag.IsArmed) == UnitTypeFlag.IsArmed;
public bool IsHarvester => (this.Flag & UnitTypeFlag.IsHarvester) == UnitTypeFlag.IsHarvester; public bool IsHarvester => (this.Flag & UnitTypeFlag.IsHarvester) == UnitTypeFlag.IsHarvester;
public bool IsExpansionUnit => (this.Flag & UnitTypeFlag.IsExpansionUnit) == UnitTypeFlag.IsExpansionUnit; public bool IsExpansionUnit => (this.Flag & UnitTypeFlag.IsExpansionUnit) == UnitTypeFlag.IsExpansionUnit;
public bool CanRemap => (this.Flag & UnitTypeFlag.NoRemap) != UnitTypeFlag.NoRemap;
private Size _RenderSize; private Size _RenderSize;
private string nameId; private string nameId;

View File

@ -13,7 +13,7 @@
// GNU General Public License along with permitted additional restrictions // GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
//#define CLASSICIMPLEMENTED #define CLASSICIMPLEMENTED
using MobiusEditor.Dialogs; using MobiusEditor.Dialogs;
using MobiusEditor.Interface; using MobiusEditor.Interface;
@ -133,7 +133,6 @@ namespace MobiusEditor
private static void LoadEditorClassic() private static void LoadEditorClassic()
{ {
Globals.SetTileSize(true);
// The system should scan all mix archives for known filenames of other mix archives so it can do recursive searches. // The system should scan all mix archives for known filenames of other mix archives so it can do recursive searches.
// Mix files should be given in order or depth, so first give ones that are in the folder, then ones that may occur inside others. // Mix files should be given in order or depth, so first give ones that are in the folder, then ones that may occur inside others.
// The order of load determines the file priority; only the first found occurrence of a file is used. // The order of load determines the file priority; only the first found occurrence of a file is used.

View File

@ -12,7 +12,7 @@ namespace MobiusEditor.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.2.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@ -131,6 +131,15 @@ namespace MobiusEditor.Properties {
} }
} }
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("1.0")]
public double DefaultExportScaleClassic {
get {
return ((double)(this["DefaultExportScaleClassic"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")] [global::System.Configuration.DefaultSettingValueAttribute("True")]
@ -167,6 +176,15 @@ namespace MobiusEditor.Properties {
} }
} }
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("1.0")]
public double MapScaleClassic {
get {
return ((double)(this["MapScaleClassic"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("1")] [global::System.Configuration.DefaultSettingValueAttribute("1")]

View File

@ -38,6 +38,9 @@
<Setting Name="DefaultExportScale" Type="System.Double" Scope="Application"> <Setting Name="DefaultExportScale" Type="System.Double" Scope="Application">
<Value Profile="(Default)">-0.5</Value> <Value Profile="(Default)">-0.5</Value>
</Setting> </Setting>
<Setting Name="DefaultExportScaleClassic" Type="System.Double" Scope="Application">
<Value Profile="(Default)">1.0</Value>
</Setting>
<Setting Name="ZoomToBoundsOnLoad" Type="System.Boolean" Scope="Application"> <Setting Name="ZoomToBoundsOnLoad" Type="System.Boolean" Scope="Application">
<Value Profile="(Default)">True</Value> <Value Profile="(Default)">True</Value>
</Setting> </Setting>
@ -50,6 +53,9 @@
<Setting Name="MapScale" Type="System.Double" Scope="Application"> <Setting Name="MapScale" Type="System.Double" Scope="Application">
<Value Profile="(Default)">0.5</Value> <Value Profile="(Default)">0.5</Value>
</Setting> </Setting>
<Setting Name="MapScaleClassic" Type="System.Double" Scope="Application">
<Value Profile="(Default)">1.0</Value>
</Setting>
<Setting Name="PreviewScale" Type="System.Double" Scope="Application"> <Setting Name="PreviewScale" Type="System.Double" Scope="Application">
<Value Profile="(Default)">1</Value> <Value Profile="(Default)">1</Value>
</Setting> </Setting>

View File

@ -30,7 +30,7 @@ namespace MobiusEditor.RedAlert
public static readonly BuildingType Pillbox = new BuildingType(4, "pbox", "TEXT_STRUCTURE_RA_PBOX", 0, 15, 1, 1, null, "Greece"); public static readonly BuildingType Pillbox = new BuildingType(4, "pbox", "TEXT_STRUCTURE_RA_PBOX", 0, 15, 1, 1, null, "Greece");
public static readonly BuildingType CamoPillbox = new BuildingType(5, "hbox", "TEXT_STRUCTURE_RA_HBOX", 0, 15, 1, 1, null, "Greece"); public static readonly BuildingType CamoPillbox = new BuildingType(5, "hbox", "TEXT_STRUCTURE_RA_HBOX", 0, 15, 1, 1, null, "Greece");
public static readonly BuildingType Command = new BuildingType(6, "dome", "TEXT_STRUCTURE_RA_DOME", 0, 40, 2, 2, null, "Greece", BuildingTypeFlag.Bib); public static readonly BuildingType Command = new BuildingType(6, "dome", "TEXT_STRUCTURE_RA_DOME", 0, 40, 2, 2, null, "Greece", BuildingTypeFlag.Bib);
public static readonly BuildingType GapGenerator = new BuildingType(7, "gap", "TEXT_STRUCTURE_RA_GAP", 60, 0, 1, 2, "0 1", "Greece", 13, BuildingTypeFlag.IsGapGenerator); public static readonly BuildingType GapGenerator = new BuildingType(7, "gap", "TEXT_STRUCTURE_RA_GAP", 0, 60, 1, 2, "0 1", "Greece", 13, BuildingTypeFlag.IsGapGenerator);
public static readonly BuildingType Turret = new BuildingType(8, "gun", "TEXT_STRUCTURE_RA_GUN", 0, 40, 1, 1, null, "Greece", BuildingTypeFlag.Turret); public static readonly BuildingType Turret = new BuildingType(8, "gun", "TEXT_STRUCTURE_RA_GUN", 0, 40, 1, 1, null, "Greece", BuildingTypeFlag.Turret);
public static readonly BuildingType AAGun = new BuildingType(9, "agun", "TEXT_STRUCTURE_RA_AGUN", 0, 50, 1, 2, "0 1", "Greece", BuildingTypeFlag.Turret); public static readonly BuildingType AAGun = new BuildingType(9, "agun", "TEXT_STRUCTURE_RA_AGUN", 0, 50, 1, 2, "0 1", "Greece", BuildingTypeFlag.Turret);
public static readonly BuildingType FlameTurret = new BuildingType(10, "ftur", "TEXT_STRUCTURE_RA_FTUR", 0, 20, 1, 1, null, "USSR"); public static readonly BuildingType FlameTurret = new BuildingType(10, "ftur", "TEXT_STRUCTURE_RA_FTUR", 0, 20, 1, 1, null, "USSR");
@ -52,7 +52,7 @@ namespace MobiusEditor.RedAlert
public static readonly BuildingType Mission = new BuildingType(26, "miss", "TEXT_STRUCTURE_RA_MISS", 0, 0, 3, 2, null, "Greece", BuildingTypeFlag.Bib); public static readonly BuildingType Mission = new BuildingType(26, "miss", "TEXT_STRUCTURE_RA_MISS", 0, 0, 3, 2, null, "Greece", BuildingTypeFlag.Bib);
public static readonly BuildingType ShipYard = new BuildingType(27, "syrd", "TEXT_STRUCTURE_RA_SYRD", 0, 30, 3, 3, null, "Greece"); public static readonly BuildingType ShipYard = new BuildingType(27, "syrd", "TEXT_STRUCTURE_RA_SYRD", 0, 30, 3, 3, null, "Greece");
public static readonly BuildingType SubPen = new BuildingType(28, "spen", "TEXT_STRUCTURE_RA_SPEN", 0, 30, 3, 3, null, "USSR"); public static readonly BuildingType SubPen = new BuildingType(28, "spen", "TEXT_STRUCTURE_RA_SPEN", 0, 30, 3, 3, null, "USSR");
public static readonly BuildingType MissileSilo = new BuildingType(29, "mslo", "TEXT_STRUCTURE_RA_MSLO", 0, 100, 2, 1, null, "Greece", new[] { TheaterTypes.Temperate, TheaterTypes.Snow }); public static readonly BuildingType MissileSilo = new BuildingType(29, "mslo", "TEXT_STRUCTURE_RA_MSLO", 0, 100, 2, 1, null, "Greece");
public static readonly BuildingType ForwardCom = new BuildingType(30, "fcom", "TEXT_STRUCTURE_RA_FCOM", 0, 200, 2, 2, "00 11", "USSR", BuildingTypeFlag.Bib); public static readonly BuildingType ForwardCom = new BuildingType(30, "fcom", "TEXT_STRUCTURE_RA_FCOM", 0, 200, 2, 2, "00 11", "USSR", BuildingTypeFlag.Bib);
public static readonly BuildingType Tesla = new BuildingType(31, "tsla", "TEXT_STRUCTURE_RA_TSLA", 0, 150, 1, 2, "0 1", "USSR"); public static readonly BuildingType Tesla = new BuildingType(31, "tsla", "TEXT_STRUCTURE_RA_TSLA", 0, 150, 1, 2, "0 1", "USSR");
public static readonly BuildingType FakeWeapon = new BuildingType(32, "weaf", "TEXT_STRUCTURE_RA_WEAF", 0, 2, 3, 2, null, "Greece", "weap2", "weap", BuildingTypeFlag.Bib | BuildingTypeFlag.Fake); public static readonly BuildingType FakeWeapon = new BuildingType(32, "weaf", "TEXT_STRUCTURE_RA_WEAF", 0, 2, 3, 2, null, "Greece", "weap2", "weap", BuildingTypeFlag.Bib | BuildingTypeFlag.Fake);
@ -103,9 +103,9 @@ namespace MobiusEditor.RedAlert
public static readonly BuildingType Barrel = new BuildingType(82, "barl", "TEXT_STRUCTURE_RA_BARL", 0, 0, 1, 1, null, "Neutral", BuildingTypeFlag.NoRemap); public static readonly BuildingType Barrel = new BuildingType(82, "barl", "TEXT_STRUCTURE_RA_BARL", 0, 0, 1, 1, null, "Neutral", BuildingTypeFlag.NoRemap);
public static readonly BuildingType Barrel3 = new BuildingType(83, "brl3", "TEXT_STRUCTURE_RA_BRL3", 0, 0, 1, 1, null, "Neutral", BuildingTypeFlag.NoRemap); public static readonly BuildingType Barrel3 = new BuildingType(83, "brl3", "TEXT_STRUCTURE_RA_BRL3", 0, 0, 1, 1, null, "Neutral", BuildingTypeFlag.NoRemap);
public static readonly BuildingType Queen = new BuildingType(84, "quee", "TEXT_STRUCTURE_RA_QUEE", 0, 0, 2, 1, null, "Special"); public static readonly BuildingType Queen = new BuildingType(84, "quee", "TEXT_STRUCTURE_RA_QUEE", 0, 0, 2, 1, null, "BadGuy");
public static readonly BuildingType Larva1 = new BuildingType(85, "lar1", "TEXT_STRUCTURE_RA_LAR1", 0, 0, 1, 1, null, "Special", BuildingTypeFlag.NoRemap); public static readonly BuildingType Larva1 = new BuildingType(85, "lar1", "TEXT_STRUCTURE_RA_LAR1", 0, 0, 1, 1, null, "BadGuy", BuildingTypeFlag.NoRemap);
public static readonly BuildingType Larva2 = new BuildingType(86, "lar2", "TEXT_STRUCTURE_RA_LAR2", 0, 0, 1, 1, null, "Special", BuildingTypeFlag.NoRemap); public static readonly BuildingType Larva2 = new BuildingType(86, "lar2", "TEXT_STRUCTURE_RA_LAR2", 0, 0, 1, 1, null, "BadGuy", BuildingTypeFlag.NoRemap);
private static readonly BuildingType[] Types; private static readonly BuildingType[] Types;

View File

@ -442,6 +442,7 @@ namespace MobiusEditor.RedAlert
{ {
Bitmap mapImg = new Bitmap(Map.Metrics.Width * Globals.MapTileWidth, Map.Metrics.Height * Globals.MapTileHeight); Bitmap mapImg = new Bitmap(Map.Metrics.Width * Globals.MapTileWidth, Map.Metrics.Height * Globals.MapTileHeight);
mapImg.SetResolution(96, 96); mapImg.SetResolution(96, 96);
mapImg.RemoveAlphaOnCurrent();
MapImage = mapImg; MapImage = mapImg;
} }
} }

View File

@ -0,0 +1,154 @@
namespace MobiusEditor.RedAlert
{
/// <summary>
/// Split off into its own thing to avoid creating clutter in the InfantryTypes class file.
/// </summary>
public static class InfantryClassicRemap
{
public static byte[] RemapCiv2 =
{
0,1,2,3,4,5,6,209,8,9,10,11,12,13,12,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,187,188,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,209, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,167, 13,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
public static byte[] RemapCiv4 = {
0,1,2,3,4,5,6,187,8,9,10,11,12,13,14,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,118,110,119, // 96..111
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,188,207, // 192..207
208,209,182,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
public static byte[] RemapCiv5 = {
0,1,2,3,4,5,6,109,8,9,10,11,131,13,14,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,177,110,178, // 96..111
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // 176..191
192,193,194,195,196,197,198,199,111,201,202,203,204,205,111,207, // 192..207
208,209,182,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
public static byte[] RemapCiv6 = {
0,1,2,3,4,5,6,120,8,9,10,11,12,13,238,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,236,206,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,111, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
public static byte[] RemapCiv7 = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,131,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,157,212,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,7, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,118,119,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
public static byte[] RemapCiv8 = {
0,1,2,3,4,5,6,182,8,9,10,11,12,13,131,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,215,7,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,182, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,198,199,189,190,191, // 176..191
192,193,194,195,196,197,198,199,111,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
public static byte[] RemapCiv9 = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,7,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,163,165,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,200, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,111,13,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
public static byte[] RemapCiv10 = {
0,1,2,3,4,5,6,137,8,9,10,11,12,13,15,15, // 0..15
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 16..31
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, // 32..47
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, // 48..63
64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, // 64..79
80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, // 80..95
96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, // 96..111
112,113,114,115,116,117,129,131,120,121,122,123,124,125,126,127, // 112..127
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 128..143
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,137, // 144..159
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // 160..175
176,177,178,179,180,181,182,183,184,185,186,163,165,189,190,191, // 176..191
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // 192..207
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // 208..223
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // 224..239
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // 240..255
};
}
}

View File

@ -32,19 +32,19 @@ namespace MobiusEditor.RedAlert
public static readonly InfantryType Medic = new InfantryType(8, "medi", "TEXT_UNIT_RA_MEDI", "Greece", UnitTypeFlag.IsArmed); public static readonly InfantryType Medic = new InfantryType(8, "medi", "TEXT_UNIT_RA_MEDI", "Greece", UnitTypeFlag.IsArmed);
public static readonly InfantryType General = new InfantryType(9, "gnrl", "TEXT_UNIT_RA_GNRL", "Greece", UnitTypeFlag.IsArmed); public static readonly InfantryType General = new InfantryType(9, "gnrl", "TEXT_UNIT_RA_GNRL", "Greece", UnitTypeFlag.IsArmed);
public static readonly InfantryType Dog = new InfantryType(10, "dog", "TEXT_UNIT_RA_DOG", "USSR", UnitTypeFlag.IsArmed); public static readonly InfantryType Dog = new InfantryType(10, "dog", "TEXT_UNIT_RA_DOG", "USSR", UnitTypeFlag.IsArmed);
public static readonly InfantryType C1 = new InfantryType(11, "c1", "TEXT_UNIT_TITLE_CIV1", "Neutral", UnitTypeFlag.IsArmed); public static readonly InfantryType C1 = new InfantryType(11, "c1", "TEXT_UNIT_TITLE_CIV1", "Neutral", UnitTypeFlag.IsArmed | UnitTypeFlag.NoRemap);
public static readonly InfantryType C2 = new InfantryType(12, "c2", "TEXT_UNIT_TITLE_CIV10", "Neutral"); public static readonly InfantryType C2 = new InfantryType(12, "c2", "TEXT_UNIT_TITLE_CIV10", "Neutral", "c1", InfantryClassicRemap.RemapCiv2, UnitTypeFlag.NoRemap);
public static readonly InfantryType C3 = new InfantryType(13, "c3", "TEXT_UNIT_TITLE_CIV3", "Neutral"); public static readonly InfantryType C3 = new InfantryType(13, "c3", "TEXT_UNIT_TITLE_CIV3", "Neutral", "c2", null, UnitTypeFlag.NoRemap);
public static readonly InfantryType C4 = new InfantryType(14, "c4", "TEXT_UNIT_TITLE_CIV4", "Neutral"); public static readonly InfantryType C4 = new InfantryType(14, "c4", "TEXT_UNIT_TITLE_CIV4", "Neutral", "c2", InfantryClassicRemap.RemapCiv4, UnitTypeFlag.NoRemap);
public static readonly InfantryType C5 = new InfantryType(15, "c5", "TEXT_UNIT_TITLE_CIV11", "Neutral"); public static readonly InfantryType C5 = new InfantryType(15, "c5", "TEXT_UNIT_TITLE_CIV11", "Neutral", "c2", InfantryClassicRemap.RemapCiv5, UnitTypeFlag.NoRemap);
public static readonly InfantryType C6 = new InfantryType(16, "c6", "TEXT_UNIT_TITLE_CIV12", "Neutral"); public static readonly InfantryType C6 = new InfantryType(16, "c6", "TEXT_UNIT_TITLE_CIV12", "Neutral", "c1", InfantryClassicRemap.RemapCiv6, UnitTypeFlag.NoRemap);
public static readonly InfantryType C7 = new InfantryType(17, "c7", "TEXT_UNIT_TITLE_CIV7", "Neutral", UnitTypeFlag.IsArmed); public static readonly InfantryType C7 = new InfantryType(17, "c7", "TEXT_UNIT_TITLE_CIV7", "Neutral", "c1", InfantryClassicRemap.RemapCiv7, UnitTypeFlag.IsArmed | UnitTypeFlag.NoRemap);
public static readonly InfantryType C8 = new InfantryType(18, "c8", "TEXT_UNIT_TITLE_CIV8", "Neutral"); public static readonly InfantryType C8 = new InfantryType(18, "c8", "TEXT_UNIT_TITLE_CIV8", "Neutral", "c1", InfantryClassicRemap.RemapCiv8, UnitTypeFlag.NoRemap);
public static readonly InfantryType C9 = new InfantryType(19, "c9", "TEXT_UNIT_TITLE_CIV9", "Neutral"); public static readonly InfantryType C9 = new InfantryType(19, "c9", "TEXT_UNIT_TITLE_CIV9", "Neutral", "c1", InfantryClassicRemap.RemapCiv10, UnitTypeFlag.NoRemap);
public static readonly InfantryType C10 = new InfantryType(20, "c10", "TEXT_UNIT_RA_SCIENTIST", "Neutral"); public static readonly InfantryType C10 = new InfantryType(20, "c10", "TEXT_UNIT_RA_SCIENTIST", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType Einstein = new InfantryType(21, "einstein", "TEXT_UNIT_RA_EINSTEIN", "Neutral"); public static readonly InfantryType Einstein = new InfantryType(21, "einstein", "TEXT_UNIT_RA_EINSTEIN", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType Delphi = new InfantryType(22, "delphi", "TEXT_UNIT_RA_DELPHI", "Neutral", UnitTypeFlag.IsArmed); public static readonly InfantryType Delphi = new InfantryType(22, "delphi", "TEXT_UNIT_RA_DELPHI", "Neutral", UnitTypeFlag.IsArmed | UnitTypeFlag.NoRemap);
public static readonly InfantryType DrChan = new InfantryType(23, "chan", "TEXT_UNIT_TITLE_CHAN", "Neutral"); public static readonly InfantryType DrChan = new InfantryType(23, "chan", "TEXT_UNIT_TITLE_CHAN", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType ShockTrooper = new InfantryType(24, "shok", "TEXT_UNIT_RA_SHOK", "USSR", UnitTypeFlag.IsArmed | UnitTypeFlag.IsExpansionUnit); public static readonly InfantryType ShockTrooper = new InfantryType(24, "shok", "TEXT_UNIT_RA_SHOK", "USSR", UnitTypeFlag.IsArmed | UnitTypeFlag.IsExpansionUnit);
public static readonly InfantryType Mechanic = new InfantryType(25, "mech", "TEXT_UNIT_RA_MECH", "Greece", UnitTypeFlag.IsArmed | UnitTypeFlag.IsExpansionUnit); public static readonly InfantryType Mechanic = new InfantryType(25, "mech", "TEXT_UNIT_RA_MECH", "Greece", UnitTypeFlag.IsArmed | UnitTypeFlag.IsExpansionUnit);

View File

@ -36,9 +36,9 @@ namespace MobiusEditor.RedAlert
public static readonly UnitType MCV = new UnitType(11, "mcv", "TEXT_UNIT_RA_MCV", "Greece"); public static readonly UnitType MCV = new UnitType(11, "mcv", "TEXT_UNIT_RA_MCV", "Greece");
public static readonly UnitType V2Launcher = new UnitType(12, "v2rl", "TEXT_UNIT_RA_V2RL", "USSR", UnitTypeFlag.IsArmed); public static readonly UnitType V2Launcher = new UnitType(12, "v2rl", "TEXT_UNIT_RA_V2RL", "USSR", UnitTypeFlag.IsArmed);
public static readonly UnitType ConvoyTruck = new UnitType(13, "truk", "TEXT_UNIT_RA_TRUK", "Greece"); public static readonly UnitType ConvoyTruck = new UnitType(13, "truk", "TEXT_UNIT_RA_TRUK", "Greece");
public static readonly UnitType Ant1 = new UnitType(14, "ant1", "TEXT_UNIT_RA_ANT1", "Special", UnitTypeFlag.IsArmed); public static readonly UnitType Ant1 = new UnitType(14, "ant1", "TEXT_UNIT_RA_ANT1", "BadGuy", UnitTypeFlag.IsArmed);
public static readonly UnitType Ant2 = new UnitType(15, "ant2", "TEXT_UNIT_RA_ANT2", "Special", UnitTypeFlag.IsArmed); public static readonly UnitType Ant2 = new UnitType(15, "ant2", "TEXT_UNIT_RA_ANT2", "Ukraine", UnitTypeFlag.IsArmed);
public static readonly UnitType Ant3 = new UnitType(16, "ant3", "TEXT_UNIT_RA_ANT3", "Special", UnitTypeFlag.IsArmed); public static readonly UnitType Ant3 = new UnitType(16, "ant3", "TEXT_UNIT_RA_ANT3", "Germany", UnitTypeFlag.IsArmed);
public static readonly UnitType Chrono = new UnitType(17, "ctnk", "TEXT_UNIT_RA_CTNK", "Greece", UnitTypeFlag.IsArmed | UnitTypeFlag.IsExpansionUnit); public static readonly UnitType Chrono = new UnitType(17, "ctnk", "TEXT_UNIT_RA_CTNK", "Greece", UnitTypeFlag.IsArmed | UnitTypeFlag.IsExpansionUnit);
public static readonly UnitType Tesla = new UnitType(18, "ttnk", "TEXT_UNIT_RA_TTNK", "USSR", UnitTypeFlag.IsArmed | UnitTypeFlag.HasTurret | UnitTypeFlag.IsExpansionUnit | UnitTypeFlag.IsJammer); public static readonly UnitType Tesla = new UnitType(18, "ttnk", "TEXT_UNIT_RA_TTNK", "USSR", UnitTypeFlag.IsArmed | UnitTypeFlag.HasTurret | UnitTypeFlag.IsExpansionUnit | UnitTypeFlag.IsJammer);
public static readonly UnitType MAD = new UnitType(19, "qtnk", "TEXT_UNIT_RA_QTNK", "USSR", UnitTypeFlag.IsArmed | UnitTypeFlag.IsExpansionUnit); public static readonly UnitType MAD = new UnitType(19, "qtnk", "TEXT_UNIT_RA_QTNK", "USSR", UnitTypeFlag.IsArmed | UnitTypeFlag.IsExpansionUnit);

View File

@ -200,7 +200,6 @@ namespace MobiusEditor.Render
var renderBounds = new Rectangle(topLeft.X * tileSize.Width, topLeft.Y * tileSize.Height, tileSize.Width, tileSize.Height); var renderBounds = new Rectangle(topLeft.X * tileSize.Width, topLeft.Y * tileSize.Height, tileSize.Width, tileSize.Height);
if(tile.Image != null) if(tile.Image != null)
{ {
//graphics.DrawImage(tile.Image, renderBounds);
using (Bitmap tileImg = tile.Image.RemoveAlpha()) using (Bitmap tileImg = tile.Image.RemoveAlpha())
{ {
graphics.DrawImage(tileImg, renderBounds); graphics.DrawImage(tileImg, renderBounds);
@ -458,8 +457,15 @@ namespace MobiusEditor.Render
string tileName = terrain.Type.GraphicsSource; string tileName = terrain.Type.GraphicsSource;
if (!Globals.TheTilesetManager.GetTileData(tileName, terrain.Type.DisplayIcon, out Tile tile)) if (!Globals.TheTilesetManager.GetTileData(tileName, terrain.Type.DisplayIcon, out Tile tile))
{ {
Debug.Print(string.Format("Terrain {0} ({1}) not found", tileName, terrain.Type.DisplayIcon)); // Fox for classic ore mine not using GraphicsSource override.
return (Rectangle.Empty, (g) => { }, false); if (!String.Equals(terrain.Type.GraphicsSource, terrain.Type.Name, StringComparison.InvariantCultureIgnoreCase))
{
if (!Globals.TheTilesetManager.GetTileData(terrain.Type.Name, terrain.Type.DisplayIcon, out tile))
{
Debug.Print(string.Format("Terrain {0} ({1}) not found", tileName, terrain.Type.DisplayIcon));
return (Rectangle.Empty, (g) => { }, false);
}
}
} }
var tint = terrain.Tint; var tint = terrain.Tint;
var imageAttributes = new ImageAttributes(); var imageAttributes = new ImageAttributes();
@ -504,7 +510,7 @@ namespace MobiusEditor.Render
{ {
maxIcon = Globals.TheTilesetManager.GetTileDataLength(building.Type.GraphicsSource); maxIcon = Globals.TheTilesetManager.GetTileDataLength(building.Type.GraphicsSource);
hasCollapseFrame = (gameType == GameType.TiberianDawn || gameType == GameType.SoleSurvivor) && maxIcon > 1 && maxIcon % 2 == 1; hasCollapseFrame = (gameType == GameType.TiberianDawn || gameType == GameType.SoleSurvivor) && maxIcon > 1 && maxIcon % 2 == 1;
damageIconOffs = maxIcon / 2; damageIconOffs = (maxIcon + (hasCollapseFrame ? 0 : 1)) / 2;
collapseIcon = maxIcon - 1; collapseIcon = maxIcon - 1;
} }
if (building.Type.HasTurret) if (building.Type.HasTurret)
@ -526,8 +532,9 @@ namespace MobiusEditor.Render
icon += damageIconOffs; icon += damageIconOffs;
} }
} }
ITeamColor tc = building.Type.CanRemap ? Globals.TheTeamColorManager[building.House.BuildingTeamColor] : null; ITeamColor teamColor = building.Type.CanRemap ? Globals.TheTeamColorManager[building.House.BuildingTeamColor] : null;
if (Globals.TheTilesetManager.GetTeamColorTileData(building.Type.GraphicsSource, icon, tc, out Tile tile)) Globals.TheTilesetManager.GetTeamColorTileData(building.Type.GraphicsSource, icon, teamColor, out Tile tile, true, false);
if (tile != null && tile.Image != null)
{ {
var location = new Point(topLeft.X * tileSize.Width, topLeft.Y * tileSize.Height); var location = new Point(topLeft.X * tileSize.Width, topLeft.Y * tileSize.Height);
var maxSize = new Size(building.Type.Size.Width * tileSize.Width, building.Type.Size.Height * tileSize.Height); var maxSize = new Size(building.Type.Size.Width * tileSize.Width, building.Type.Size.Height * tileSize.Height);
@ -543,7 +550,7 @@ namespace MobiusEditor.Render
int maxOverlayIcon = Globals.TheTilesetManager.GetTileDataLength(building.Type.FactoryOverlay); int maxOverlayIcon = Globals.TheTilesetManager.GetTileDataLength(building.Type.FactoryOverlay);
overlayIcon = maxOverlayIcon / 2; overlayIcon = maxOverlayIcon / 2;
} }
Globals.TheTilesetManager.GetTeamColorTileData(building.Type.FactoryOverlay, overlayIcon, Globals.TheTeamColorManager[building.House.BuildingTeamColor], out factoryOverlayTile); Globals.TheTilesetManager.GetTeamColorTileData(building.Type.FactoryOverlay, overlayIcon, Globals.TheTeamColorManager[building.House.BuildingTeamColor], out factoryOverlayTile, true, false);
} }
void render(Graphics g) void render(Graphics g)
{ {
@ -569,6 +576,7 @@ namespace MobiusEditor.Render
factory.SetResolution(96, 96); factory.SetResolution(96, 96);
using (Graphics factoryG = Graphics.FromImage(factory)) using (Graphics factoryG = Graphics.FromImage(factory))
{ {
factoryG.CopyRenderSettingsFrom(g);
var factBounds = RenderBounds(tile.Image.Size, building.Type.Size, tileScale); var factBounds = RenderBounds(tile.Image.Size, building.Type.Size, tileScale);
var ovrlBounds = RenderBounds(factoryOverlayTile.Image.Size, building.Type.Size, tileScale); var ovrlBounds = RenderBounds(factoryOverlayTile.Image.Size, building.Type.Size, tileScale);
factoryG.DrawImage(tile.Image, factBounds, 0, 0, tile.Image.Width, tile.Image.Height, GraphicsUnit.Pixel); factoryG.DrawImage(tile.Image, factBounds, 0, 0, tile.Image.Width, tile.Image.Height, GraphicsUnit.Pixel);
@ -597,8 +605,18 @@ namespace MobiusEditor.Render
public static (Rectangle, Action<Graphics>, bool) RenderInfantry(Point topLeft, Size tileSize, Infantry infantry, InfantryStoppingType infantryStoppingType) public static (Rectangle, Action<Graphics>, bool) RenderInfantry(Point topLeft, Size tileSize, Infantry infantry, InfantryStoppingType infantryStoppingType)
{ {
var icon = HumanShape[Facing32[infantry.Direction.ID]]; var icon = HumanShape[Facing32[infantry.Direction.ID]];
string teamColor = infantry.House?.UnitTeamColor; ITeamColor teamColor = infantry.Type.CanRemap ? Globals.TheTeamColorManager[infantry.House?.UnitTeamColor] : null;
if (Globals.TheTilesetManager.GetTeamColorTileData(infantry.Type.Name, icon, Globals.TheTeamColorManager[teamColor], out Tile tile)) Tile tile = null;
// RA classic infantry remap support.
if (infantry.Type.ClassicGraphicsSource != null && Globals.TheTilesetManager is TilesetManagerClassic tsmc)
{
tsmc.GetTeamColorTileData(infantry.Type.Name, icon, teamColor, out tile, true, false, infantry.Type.ClassicGraphicsSource, infantry.Type.ClassicGraphicsRemap);
}
else
{
Globals.TheTilesetManager.GetTeamColorTileData(infantry.Type.Name, icon, teamColor, out tile, true, false);
}
if (tile != null && tile.Image != null)
{ {
// These values are experimental, from comparing map editor screenshots to game screenshots. -Nyer // These values are experimental, from comparing map editor screenshots to game screenshots. -Nyer
int infantryCorrectX = tileSize.Width / -12; int infantryCorrectX = tileSize.Width / -12;
@ -724,15 +742,18 @@ namespace MobiusEditor.Render
{ {
icon = BodyShape[Facing32[unit.Direction.ID]]; icon = BodyShape[Facing32[unit.Direction.ID]];
} }
string teamColor = null; ITeamColor teamColor = null;
if (unit.House != null) if (unit.House != null && unit.Type.CanRemap)
{ {
if (!unit.House.OverrideTeamColors.TryGetValue(unit.Type.Name, out teamColor)) String teamColorName;
if (!unit.House.OverrideTeamColors.TryGetValue(unit.Type.Name, out teamColorName))
{ {
teamColor = unit.House.UnitTeamColor; teamColorName = unit.House.UnitTeamColor;
} }
teamColor = Globals.TheTeamColorManager[teamColorName];
} }
if (!Globals.TheTilesetManager.GetTeamColorTileData(unit.Type.Name, icon, Globals.TheTeamColorManager[teamColor], out Tile tile)) Globals.TheTilesetManager.GetTeamColorTileData(unit.Type.Name, icon, teamColor, out Tile tile, true, false);
if (tile == null || tile.Image == null)
{ {
Debug.Print(string.Format("Unit {0} ({1}) not found", unit.Type.Name, icon)); Debug.Print(string.Format("Unit {0} ({1}) not found", unit.Type.Name, icon));
return (Rectangle.Empty, (g) => { }, false); return (Rectangle.Empty, (g) => { }, false);
@ -795,9 +816,9 @@ namespace MobiusEditor.Render
turret2Icon = getRotorIcon(turret2Name, unit.Direction.ID, turret2Icon); turret2Icon = getRotorIcon(turret2Name, unit.Direction.ID, turret2Icon);
} }
if (turretName != null) if (turretName != null)
Globals.TheTilesetManager.GetTeamColorTileData(turretName, turretIcon, Globals.TheTeamColorManager[teamColor], out turretTile); Globals.TheTilesetManager.GetTeamColorTileData(turretName, turretIcon, teamColor, out turretTile, true, false);
if (turret2Name != null) if (turret2Name != null)
Globals.TheTilesetManager.GetTeamColorTileData(turret2Name, turret2Icon, Globals.TheTeamColorManager[teamColor], out turret2Tile); Globals.TheTilesetManager.GetTeamColorTileData(turret2Name, turret2Icon, teamColor, out turret2Tile, true, false);
} }
var tint = unit.Tint; var tint = unit.Tint;
void render(Graphics g) void render(Graphics g)
@ -822,6 +843,7 @@ namespace MobiusEditor.Render
unitBm.SetResolution(96, 96); unitBm.SetResolution(96, 96);
using (Graphics unitG = Graphics.FromImage(unitBm)) using (Graphics unitG = Graphics.FromImage(unitBm))
{ {
unitG.CopyRenderSettingsFrom(g);
if (tile != null) { if (tile != null) {
unitG.DrawImage(tile.Image, renderRect, 0, 0, tile.Image.Width, tile.Image.Height, GraphicsUnit.Pixel); unitG.DrawImage(tile.Image, renderRect, 0, 0, tile.Image.Width, tile.Image.Height, GraphicsUnit.Pixel);
} }
@ -887,11 +909,11 @@ namespace MobiusEditor.Render
ug.DrawImage(turrTile.Image, turrBounds, 0, 0, turrTile.Image.Width, turrTile.Image.Height, GraphicsUnit.Pixel); ug.DrawImage(turrTile.Image, turrBounds, 0, 0, turrTile.Image.Width, turrTile.Image.Height, GraphicsUnit.Pixel);
} }
if (turretTile != null) if (turretTile != null && turretTile.Image != null)
{ {
RenderTurret(unitG, turretTile, turretAdjust, tileSize); RenderTurret(unitG, turretTile, turretAdjust, tileSize);
} }
if (unit.Type.HasDoubleTurret && turret2Tile != null) if (unit.Type.HasDoubleTurret && turret2Tile != null && turret2Tile.Image != null)
{ {
RenderTurret(unitG, turret2Tile, turret2Adjust, tileSize); RenderTurret(unitG, turret2Tile, turret2Adjust, tileSize);
} }
@ -926,7 +948,7 @@ namespace MobiusEditor.Render
int mpId = Waypoint.GetMpIdFromFlag(waypoint.Flag); int mpId = Waypoint.GetMpIdFromFlag(waypoint.Flag);
int icon = 0; int icon = 0;
bool isDefaultIcon = true; bool isDefaultIcon = true;
bool gotIcon = false; bool gotTile = false;
Tile tile; Tile tile;
if (!soloMission && mpId >= 0 && mpId < flagColors.Length) if (!soloMission && mpId >= 0 && mpId < flagColors.Length)
{ {
@ -935,7 +957,7 @@ namespace MobiusEditor.Render
// Always paint flags as opaque. // Always paint flags as opaque.
transparencyModifier = 1.0f; transparencyModifier = 1.0f;
teamColor = flagColors[mpId]; teamColor = flagColors[mpId];
gotIcon = Globals.TheTilesetManager.GetTeamColorTileData(tileGraphics, icon, teamColor, out tile); gotTile = Globals.TheTilesetManager.GetTeamColorTileData(tileGraphics, icon, teamColor, out tile);
} }
else if (gameType == GameType.SoleSurvivor && (waypoint.Flag & WaypointFlag.CrateSpawn) == WaypointFlag.CrateSpawn) else if (gameType == GameType.SoleSurvivor && (waypoint.Flag & WaypointFlag.CrateSpawn) == WaypointFlag.CrateSpawn)
{ {
@ -943,20 +965,20 @@ namespace MobiusEditor.Render
tileGraphics = "scrate"; tileGraphics = "scrate";
//tint = Color.FromArgb(waypoint.Tint.A, Color.Green); //tint = Color.FromArgb(waypoint.Tint.A, Color.Green);
//brightness = 1.5f; //brightness = 1.5f;
gotIcon = Globals.TheTilesetManager.GetTileData(tileGraphics, icon, out tile); gotTile = Globals.TheTilesetManager.GetTileData(tileGraphics, icon, out tile);
} }
else else
{ {
gotIcon = Globals.TheTilesetManager.GetTileData(tileGraphics, icon, out tile); gotTile = Globals.TheTilesetManager.GetTileData(tileGraphics, icon, out tile);
} }
if (!gotIcon && isDefaultIcon) if (!gotTile && isDefaultIcon)
{ {
// Beacon only exists in remastered graphics. Get fallback. // Beacon only exists in remastered graphics. Get fallback.
tileGraphics = "armor"; tileGraphics = "trans.icn";
icon = 6; icon = 3;
gotIcon = Globals.TheTilesetManager.GetTeamColorTileData(tileGraphics, icon, teamColor, out tile); gotTile = Globals.TheTilesetManager.GetTeamColorTileData(tileGraphics, icon, teamColor, out tile);
} }
if (!gotIcon) if (!gotTile)
{ {
Debug.Print(string.Format("Waypoint graphics {0} ({1}) not found", tileGraphics, icon)); Debug.Print(string.Format("Waypoint graphics {0} ({1}) not found", tileGraphics, icon));
return (Rectangle.Empty, (g) => { }); return (Rectangle.Empty, (g) => { });
@ -1113,7 +1135,7 @@ namespace MobiusEditor.Render
RegionData paintAreaRel; RegionData paintAreaRel;
if (!paintAreas.TryGetValue(ovlt.Name, out paintAreaRel)) if (!paintAreas.TryGetValue(ovlt.Name, out paintAreaRel))
{ {
paintAreaRel = GetOverlayOutline(map.Theater, location, tileSize, tileScale, overlay, outlineThickness, alphaThreshold, true); paintAreaRel = GetOverlayOutline(location, tileSize, tileScale, overlay, outlineThickness, alphaThreshold, true);
paintAreas[ovlt.Name] = paintAreaRel; paintAreas[ovlt.Name] = paintAreaRel;
} }
int actualTopLeftX = location.X * tileSize.Width; int actualTopLeftX = location.X * tileSize.Width;
@ -1183,7 +1205,7 @@ namespace MobiusEditor.Render
return false; return false;
} }
public static RegionData GetOverlayOutline(TheaterType theater, Point topLeft, Size tileSize, double tileScale, Overlay overlay, float outline, byte alphaThreshold, bool relative) public static RegionData GetOverlayOutline(Point topLeft, Size tileSize, double tileScale, Overlay overlay, float outline, byte alphaThreshold, bool relative)
{ {
OverlayType ovtype = overlay.Type; OverlayType ovtype = overlay.Type;
string name = ovtype.GraphicsSource; string name = ovtype.GraphicsSource;
@ -1200,84 +1222,87 @@ namespace MobiusEditor.Render
Size maxSize = new Size(Globals.OriginalTileWidth, Globals.OriginalTileHeight); Size maxSize = new Size(Globals.OriginalTileWidth, Globals.OriginalTileHeight);
int actualOutlineX = (int)Math.Max(1, outline * tileSize.Width); int actualOutlineX = (int)Math.Max(1, outline * tileSize.Width);
int actualOutlineY = (int)Math.Max(1, outline * tileSize.Height); int actualOutlineY = (int)Math.Max(1, outline * tileSize.Height);
Byte[] imgData;
int stride;
// Make full-tile image out of the graphics.
using (Bitmap bm = new Bitmap(tileSize.Width, tileSize.Height, PixelFormat.Format32bppArgb)) using (Bitmap bm = new Bitmap(tileSize.Width, tileSize.Height, PixelFormat.Format32bppArgb))
{ {
bm.SetResolution(96, 96); bm.SetResolution(96, 96);
using (Graphics g2 = Graphics.FromImage(bm)) using (Graphics g2 = Graphics.FromImage(bm))
{ {
SetRenderSettings(g2, false);
g2.DrawImage(tile.Image, relOverlayBounds, 0, 0, tile.Image.Width, tile.Image.Height, GraphicsUnit.Pixel); g2.DrawImage(tile.Image, relOverlayBounds, 0, 0, tile.Image.Width, tile.Image.Height, GraphicsUnit.Pixel);
} }
Byte[] imgData = ImageUtils.GetImageData(bm, out int stride, PixelFormat.Format32bppArgb, true); imgData = ImageUtils.GetImageData(bm, out stride, PixelFormat.Format32bppArgb, true);
bool isOpaqueAndNotBlack(byte[] mapdata, int yVal, int xVal)
{
int address = yVal * stride + xVal * 4;
// Check alpha
if (mapdata[address + 3] < alphaThreshold)
{
return false;
}
// Check brightness to exclude shadow
byte red = mapdata[address + 2];
byte grn = mapdata[address + 1];
byte blu = mapdata[address + 0];
// Integer method.
int redBalanced = red * red * 2126;
int grnBalanced = grn * grn * 7152;
int bluBalanced = blu * blu * 0722;
int lum = (redBalanced + grnBalanced + bluBalanced) / 255 / 255;
// The integer division will automatically reduce anything near-black
// to zero, so actually checking against a threshold is unnecessary.
return lum > 0; // lum > lumThresholdSq * 1000
// Floating point method
//double redF = red / 255.0;
//double grnF = grn / 255.0;
//double bluF = blu / 255.0;
//double lum = 0.2126d * redF * redF + 0.7152d * grnF * grnF + 0.0722d * bluF * bluF;
//return lum >= lumThresholdSq;
};
//Func<byte[], int, int, bool> isOpaque_ = (mapdata, yVal, xVal) => mapdata[yVal * stride + xVal * 4 + 3] >= alphaThreshold;
List<List<Point>> blobs = BlobDetection.FindBlobs(imgData, tileSize.Width, tileSize.Height, isOpaqueAndNotBlack, true, false);
List<Point> allblobs = new List<Point>();
foreach (List<Point> blob in blobs)
{
foreach (Point p in blob)
{
allblobs.Add(p);
}
}
HashSet<Point> drawPoints = new HashSet<Point>();
HashSet<Point> removePoints = new HashSet<Point>();
foreach (Point p in allblobs)
{
Rectangle rect = new Rectangle(p.X + actualTopLeftX, p.Y + actualTopLeftY, 1, 1);
removePoints.UnionWith(rect.Points());
rect.Inflate(actualOutlineX, actualOutlineY);
rect.Intersect(overlayBounds);
if (!rect.IsEmpty)
{
drawPoints.UnionWith(rect.Points());
}
}
foreach (Point p in removePoints)
{
drawPoints.Remove(p);
}
RegionData rData;
using (Region r = new Region())
{
r.MakeEmpty();
Size pixelSize = new Size(1, 1);
foreach (Point p in drawPoints)
{
r.Union(new Rectangle(p, pixelSize));
}
rData = r.GetRegionData();
}
return rData;
} }
bool isOpaqueAndNotBlack(byte[] mapdata, int yVal, int xVal)
{
int address = yVal * stride + xVal * 4;
// Check alpha
if (mapdata[address + 3] < alphaThreshold)
{
return false;
}
// Check brightness to exclude shadow
byte red = mapdata[address + 2];
byte grn = mapdata[address + 1];
byte blu = mapdata[address + 0];
// Integer method.
int redBalanced = red * red * 2126;
int grnBalanced = grn * grn * 7152;
int bluBalanced = blu * blu * 0722;
int lum = (redBalanced + grnBalanced + bluBalanced) / 255 / 255;
// The integer division will automatically reduce anything near-black
// to zero, so actually checking against a threshold is unnecessary.
return lum > 0; // lum > lumThresholdSq * 1000
// Floating point method
//double redF = red / 255.0;
//double grnF = grn / 255.0;
//double bluF = blu / 255.0;
//double lum = 0.2126d * redF * redF + 0.7152d * grnF * grnF + 0.0722d * bluF * bluF;
//return lum >= lumThresholdSq;
};
//Func<byte[], int, int, bool> isOpaque_ = (mapdata, yVal, xVal) => mapdata[yVal * stride + xVal * 4 + 3] >= alphaThreshold;
List<List<Point>> blobs = BlobDetection.FindBlobs(imgData, tileSize.Width, tileSize.Height, isOpaqueAndNotBlack, true, false);
List<Point> allblobs = new List<Point>();
foreach (List<Point> blob in blobs)
{
foreach (Point p in blob)
{
allblobs.Add(p);
}
}
HashSet<Point> drawPoints = new HashSet<Point>();
HashSet<Point> removePoints = new HashSet<Point>();
foreach (Point p in allblobs)
{
Rectangle rect = new Rectangle(p.X + actualTopLeftX, p.Y + actualTopLeftY, 1, 1);
removePoints.UnionWith(rect.Points());
rect.Inflate(actualOutlineX, actualOutlineY);
rect.Intersect(overlayBounds);
if (!rect.IsEmpty)
{
drawPoints.UnionWith(rect.Points());
}
}
foreach (Point p in removePoints)
{
drawPoints.Remove(p);
}
RegionData rData;
using (Region r = new Region())
{
r.MakeEmpty();
Size pixelSize = new Size(1, 1);
foreach (Point p in drawPoints)
{
r.Union(new Rectangle(p, pixelSize));
}
rData = r.GetRegionData();
}
return rData;
} }
public static void RenderAllFootballAreas(Graphics graphics, Map map, Size tileSize, double tileScale, GameType gameType) public static void RenderAllFootballAreas(Graphics graphics, Map map, Size tileSize, double tileScale, GameType gameType)
@ -1337,15 +1362,15 @@ namespace MobiusEditor.Render
} }
} }
public static void RenderAllFakeBuildingLabels(Graphics graphics, Map map, Size tileSize, double tileScale) public static void RenderAllFakeBuildingLabels(Graphics graphics, Map map, Size tileSize)
{ {
foreach (var (topLeft, building) in map.Buildings.OfType<Building>()) foreach (var (topLeft, building) in map.Buildings.OfType<Building>())
{ {
RenderFakeBuildingLabel(graphics, building, topLeft, tileSize, tileScale, false); RenderFakeBuildingLabel(graphics, building, topLeft, tileSize, false);
} }
} }
public static void RenderFakeBuildingLabel(Graphics graphics, Building building, Point topLeft, Size tileSize, double tileScale, Boolean forPreview) public static void RenderFakeBuildingLabel(Graphics graphics, Building building, Point topLeft, Size tileSize, Boolean forPreview)
{ {
if (!building.Type.IsFake) if (!building.Type.IsFake)
{ {
@ -1362,11 +1387,12 @@ namespace MobiusEditor.Render
new Size(maxSize.Width * tileSize.Width, maxSize.Height * tileSize.Height) new Size(maxSize.Width * tileSize.Width, maxSize.Height * tileSize.Height)
); );
string fakeText = Globals.TheGameTextManager["TEXT_UI_FAKE"]; string fakeText = Globals.TheGameTextManager["TEXT_UI_FAKE"];
double tileScaleHor = tileSize.Width / 128.0;
using (var fakeBackgroundBrush = new SolidBrush(Color.FromArgb((forPreview ? 128 : 256) * 2 / 3, Color.Black))) using (var fakeBackgroundBrush = new SolidBrush(Color.FromArgb((forPreview ? 128 : 256) * 2 / 3, Color.Black)))
using (var fakeTextBrush = new SolidBrush(Color.FromArgb(forPreview ? building.Tint.A : 255, Color.White))) using (var fakeTextBrush = new SolidBrush(Color.FromArgb(forPreview ? building.Tint.A : 255, Color.White)))
{ {
using (var font = graphics.GetAdjustedFont(fakeText, SystemFonts.DefaultFont, buildingBounds.Width, buildingBounds.Height, using (var font = graphics.GetAdjustedFont(fakeText, SystemFonts.DefaultFont, buildingBounds.Width, buildingBounds.Height,
Math.Max(1, (int)(12 * tileScale)), Math.Max(1, (int)(24 * tileScale)), stringFormat, true)) Math.Max(1, (int)(12 * tileScaleHor)), Math.Max(1, (int)(24 * tileScaleHor)), stringFormat, true))
{ {
var textBounds = graphics.MeasureString(fakeText, font, buildingBounds.Width, stringFormat); var textBounds = graphics.MeasureString(fakeText, font, buildingBounds.Width, stringFormat);
var backgroundBounds = new RectangleF(buildingBounds.Location, textBounds); var backgroundBounds = new RectangleF(buildingBounds.Location, textBounds);
@ -1376,15 +1402,15 @@ namespace MobiusEditor.Render
} }
} }
public static void RenderAllRebuildPriorityLabels(Graphics graphics, Map map, Size tileSize, double tileScale) public static void RenderAllRebuildPriorityLabels(Graphics graphics, Map map, Size tileSize)
{ {
foreach (var (topLeft, building) in map.Buildings.OfType<Building>()) foreach (var (topLeft, building) in map.Buildings.OfType<Building>())
{ {
RenderRebuildPriorityLabel(graphics, building, topLeft, tileSize, tileScale, false); RenderRebuildPriorityLabel(graphics, building, topLeft, tileSize, false);
} }
} }
public static void RenderRebuildPriorityLabel(Graphics graphics, Building building, Point topLeft, Size tileSize, double tileScale, Boolean forPreview) public static void RenderRebuildPriorityLabel(Graphics graphics, Building building, Point topLeft, Size tileSize, Boolean forPreview)
{ {
var stringFormat = new StringFormat var stringFormat = new StringFormat
{ {
@ -1398,12 +1424,13 @@ namespace MobiusEditor.Render
); );
if (building.BasePriority >= 0) if (building.BasePriority >= 0)
{ {
double tileScaleHor = tileSize.Width / 128.0;
string priText = building.BasePriority.ToString(); string priText = building.BasePriority.ToString();
using (var baseBackgroundBrush = new SolidBrush(Color.FromArgb((forPreview ? 128 : 256) * 2 / 3, Color.Black))) using (var baseBackgroundBrush = new SolidBrush(Color.FromArgb((forPreview ? 128 : 256) * 2 / 3, Color.Black)))
using (var baseTextBrush = new SolidBrush(Color.FromArgb(forPreview ? 128 : 255, Color.Red))) using (var baseTextBrush = new SolidBrush(Color.FromArgb(forPreview ? 128 : 255, Color.Red)))
{ {
using (var font = graphics.GetAdjustedFont(priText, SystemFonts.DefaultFont, buildingBounds.Width, buildingBounds.Height, using (var font = graphics.GetAdjustedFont(priText, SystemFonts.DefaultFont, buildingBounds.Width, buildingBounds.Height,
Math.Max(1, (int)(12 * tileScale)), Math.Max(1, (int)(24 * tileScale)), stringFormat, true)) Math.Max(1, (int)(12 * tileScaleHor)), Math.Max(1, (int)(24 * tileScaleHor)), stringFormat, true))
{ {
var textBounds = graphics.MeasureString(priText, font, buildingBounds.Width, stringFormat); var textBounds = graphics.MeasureString(priText, font, buildingBounds.Width, stringFormat);
var backgroundBounds = new RectangleF(buildingBounds.Location, textBounds); var backgroundBounds = new RectangleF(buildingBounds.Location, textBounds);
@ -1415,13 +1442,14 @@ namespace MobiusEditor.Render
} }
} }
public static void RenderAllTechnoTriggers(Graphics graphics, Map map, Size tileSize, double tileScale, MapLayerFlag layersToRender) public static void RenderAllTechnoTriggers(Graphics graphics, Map map, Size tileSize, MapLayerFlag layersToRender)
{ {
RenderAllTechnoTriggers(graphics, map, tileSize, tileScale, layersToRender, Color.LimeGreen, null, false); RenderAllTechnoTriggers(graphics, map, tileSize, layersToRender, Color.LimeGreen, null, false);
} }
public static void RenderAllTechnoTriggers(Graphics graphics, Map map, Size tileSize, double tileScale, MapLayerFlag layersToRender, Color color, string toPick, bool excludePick) public static void RenderAllTechnoTriggers(Graphics graphics, Map map, Size tileSize, MapLayerFlag layersToRender, Color color, string toPick, bool excludePick)
{ {
double tileScaleHor = tileSize.Width / 128.0;
float borderSize = Math.Max(0.5f, tileSize.Width / 60.0f); float borderSize = Math.Max(0.5f, tileSize.Width / 60.0f);
foreach (var (cell, techno) in map.Technos) foreach (var (cell, techno) in map.Technos)
{ {
@ -1504,7 +1532,7 @@ namespace MobiusEditor.Render
using (var technoTriggerBrush = new SolidBrush(alphaColor)) using (var technoTriggerBrush = new SolidBrush(alphaColor))
using (var technoTriggerPen = new Pen(alphaColor, borderSize)) using (var technoTriggerPen = new Pen(alphaColor, borderSize))
using (var font = graphics.GetAdjustedFont(trigger, SystemFonts.DefaultFont, bounds.Width, bounds.Height, using (var font = graphics.GetAdjustedFont(trigger, SystemFonts.DefaultFont, bounds.Width, bounds.Height,
Math.Max(1, (int)(12 * tileScale)), Math.Max(1, (int)(24 * tileScale)), stringFormat, true)) Math.Max(1, (int)(12 * tileScaleHor)), Math.Max(1, (int)(24 * tileScaleHor)), stringFormat, true))
{ {
var textBounds = graphics.MeasureString(trigger, font, bounds.Width, stringFormat); var textBounds = graphics.MeasureString(trigger, font, bounds.Width, stringFormat);
var backgroundBounds = new RectangleF(bounds.Location, textBounds); var backgroundBounds = new RectangleF(bounds.Location, textBounds);
@ -1518,7 +1546,7 @@ namespace MobiusEditor.Render
} }
} }
public static void RenderWayPointIndicators(Graphics graphics, Map map, Size tileSize, double tileScale, Color textColor, bool forPreview, bool excludeSpecified, params Waypoint[] specified) public static void RenderWayPointIndicators(Graphics graphics, Map map, Size tileSize, Color textColor, bool forPreview, bool excludeSpecified, params Waypoint[] specified)
{ {
HashSet<Waypoint> specifiedWaypoints = specified.ToHashSet(); HashSet<Waypoint> specifiedWaypoints = specified.ToHashSet();
@ -1531,12 +1559,12 @@ namespace MobiusEditor.Render
{ {
continue; continue;
} }
RenderWayPointIndicator(graphics, waypoint, point, tileSize, tileScale, textColor, forPreview); RenderWayPointIndicator(graphics, waypoint, point, tileSize, textColor, forPreview);
} }
} }
} }
public static void RenderWayPointIndicator(Graphics graphics, Waypoint waypoint, Point topLeft, Size tileSize, double tileScale, Color textColor, bool forPreview) public static void RenderWayPointIndicator(Graphics graphics, Waypoint waypoint, Point topLeft, Size tileSize, Color textColor, bool forPreview)
{ {
var stringFormat = new StringFormat var stringFormat = new StringFormat
{ {
@ -1544,12 +1572,14 @@ namespace MobiusEditor.Render
LineAlignment = StringAlignment.Center LineAlignment = StringAlignment.Center
}; };
var paintBounds = new Rectangle(new Point(topLeft.X * tileSize.Width, topLeft.Y * tileSize.Height), tileSize); var paintBounds = new Rectangle(new Point(topLeft.X * tileSize.Width, topLeft.Y * tileSize.Height), tileSize);
// Adjust calcuations to tile size. The below adjustments are done assuming the tile is 128 wide.
double tileScaleHor = tileSize.Width / 128.0;
string wpText = waypoint.Name; string wpText = waypoint.Name;
using (var baseBackgroundBrush = new SolidBrush(Color.FromArgb(forPreview ? 64 : 128, Color.Black))) using (var baseBackgroundBrush = new SolidBrush(Color.FromArgb(forPreview ? 64 : 128, Color.Black)))
using (var baseTextBrush = new SolidBrush(Color.FromArgb(forPreview ? 128 : 255, textColor))) using (var baseTextBrush = new SolidBrush(Color.FromArgb(forPreview ? 128 : 255, textColor)))
{ {
using (var font = graphics.GetAdjustedFont(wpText, SystemFonts.DefaultFont, paintBounds.Width, paintBounds.Height, using (var font = graphics.GetAdjustedFont(wpText, SystemFonts.DefaultFont, paintBounds.Width, paintBounds.Height,
Math.Max(1, (int)(12 * tileScale)), Math.Max(1, (int)(55 * tileScale)), stringFormat, true)) Math.Max(1, (int)(12 * tileScaleHor)), Math.Max(1, (int)(55 * tileScaleHor)), stringFormat, true))
{ {
var textBounds = graphics.MeasureString(wpText, font, paintBounds.Width, stringFormat); var textBounds = graphics.MeasureString(wpText, font, paintBounds.Width, stringFormat);
var backgroundBounds = new RectangleF(paintBounds.Location, textBounds); var backgroundBounds = new RectangleF(paintBounds.Location, textBounds);
@ -1721,23 +1751,24 @@ namespace MobiusEditor.Render
} }
} }
public static void RenderCellTriggersSoft(Graphics graphics, Map map, Size tileSize, double tileScale, params String[] specifiedToExclude) public static void RenderCellTriggersSoft(Graphics graphics, Map map, Size tileSize, params String[] specifiedToExclude)
{ {
RenderCellTriggers(graphics, map, tileSize, tileScale, Color.Black, Color.White, Color.White, 0.75f, false, true, specifiedToExclude); RenderCellTriggers(graphics, map, tileSize, Color.Black, Color.White, Color.White, 0.75f, false, true, specifiedToExclude);
} }
public static void RenderCellTriggersHard(Graphics graphics, Map map, Size tileSize, double tileScale, params String[] specifiedToExclude) public static void RenderCellTriggersHard(Graphics graphics, Map map, Size tileSize, params String[] specifiedToExclude)
{ {
RenderCellTriggers(graphics, map, tileSize, tileScale, Color.Black, Color.White, Color.White, 1, false, true, specifiedToExclude); RenderCellTriggers(graphics, map, tileSize, Color.Black, Color.White, Color.White, 1, false, true, specifiedToExclude);
} }
public static void RenderCellTriggersSelected(Graphics graphics, Map map, Size tileSize, double tileScale, params String[] specifiedToDraw) public static void RenderCellTriggersSelected(Graphics graphics, Map map, Size tileSize, params String[] specifiedToDraw)
{ {
RenderCellTriggers(graphics, map, tileSize, tileScale, Color.Black, Color.Yellow, Color.Yellow, 1, true, false, specifiedToDraw); RenderCellTriggers(graphics, map, tileSize, Color.Black, Color.Yellow, Color.Yellow, 1, true, false, specifiedToDraw);
} }
public static void RenderCellTriggers(Graphics graphics, Map map, Size tileSize, double tileScale, Color fillColor, Color borderColor, Color textColor, double alphaAdjust, bool thickborder, bool excludeSpecified, params String[] specified) public static void RenderCellTriggers(Graphics graphics, Map map, Size tileSize, Color fillColor, Color borderColor, Color textColor, double alphaAdjust, bool thickborder, bool excludeSpecified, params String[] specified)
{ {
double tileScaleHor = tileSize.Width / 128.0;
Color ApplyAlpha(Color col, int baseAlpha, double alphaMul) Color ApplyAlpha(Color col, int baseAlpha, double alphaMul)
{ {
return Color.FromArgb(Math.Max(0, Math.Min(0xFF, (int)Math.Round(baseAlpha * alphaMul, MidpointRounding.AwayFromZero))), col); return Color.FromArgb(Math.Max(0, Math.Min(0xFF, (int)Math.Round(baseAlpha * alphaMul, MidpointRounding.AwayFromZero))), col);
@ -1782,7 +1813,7 @@ namespace MobiusEditor.Render
}; };
var text = cellTrigger.Trigger; var text = cellTrigger.Trigger;
using (var font = graphics.GetAdjustedFont(text, SystemFonts.DefaultFont, textBounds.Width, textBounds.Height, using (var font = graphics.GetAdjustedFont(text, SystemFonts.DefaultFont, textBounds.Width, textBounds.Height,
Math.Max(1, (int)(24 * tileScale)), Math.Max(1, (int)(48 * tileScale)), stringFormat, true)) Math.Max(1, (int)(24 * tileScaleHor)), Math.Max(1, (int)(48 * tileScaleHor)), stringFormat, true))
{ {
graphics.DrawString(text.ToString(), font, isPreview ? prevCellTriggersBrush : cellTriggersBrush, textBounds, stringFormat); graphics.DrawString(text.ToString(), font, isPreview ? prevCellTriggersBrush : cellTriggersBrush, textBounds, stringFormat);
} }
@ -1861,6 +1892,14 @@ namespace MobiusEditor.Render
} }
} }
public static void CopyRenderSettingsFrom(this Graphics target, Graphics source)
{
target.CompositingQuality = source.CompositingQuality;
target.InterpolationMode = source.InterpolationMode;
target.SmoothingMode = source.SmoothingMode;
target.PixelOffsetMode = source.PixelOffsetMode;
}
public static Rectangle RenderBounds(Size imageSize, Size cellDimensions, Size cellSize) public static Rectangle RenderBounds(Size imageSize, Size cellDimensions, Size cellSize)
{ {
double scaleFactorX = cellSize.Width / (double)Globals.OriginalTileWidth; double scaleFactorX = cellSize.Width / (double)Globals.OriginalTileWidth;

View File

@ -413,6 +413,7 @@ namespace MobiusEditor.TiberianDawn
{ {
Bitmap mapImg = new Bitmap(Map.Metrics.Width * Globals.MapTileWidth, Map.Metrics.Height * Globals.MapTileHeight); Bitmap mapImg = new Bitmap(Map.Metrics.Width * Globals.MapTileWidth, Map.Metrics.Height * Globals.MapTileHeight);
mapImg.SetResolution(96, 96); mapImg.SetResolution(96, 96);
mapImg.RemoveAlphaOnCurrent();
MapImage = mapImg; MapImage = mapImg;
} }
} }

View File

@ -28,19 +28,19 @@ namespace MobiusEditor.TiberianDawn
public static readonly InfantryType E5 = new InfantryType(4, "e5", "TEXT_UNIT_TITLE_NOD_CHEM_WARRIOR", "Badguy", UnitTypeFlag.IsArmed); public static readonly InfantryType E5 = new InfantryType(4, "e5", "TEXT_UNIT_TITLE_NOD_CHEM_WARRIOR", "Badguy", UnitTypeFlag.IsArmed);
public static readonly InfantryType E7 = new InfantryType(5, "e6", "TEXT_UNIT_TITLE_GDI_ENGINEER", "Goodguy"); public static readonly InfantryType E7 = new InfantryType(5, "e6", "TEXT_UNIT_TITLE_GDI_ENGINEER", "Goodguy");
public static readonly InfantryType Commando = new InfantryType(6, "rmbo", "TEXT_UNIT_TITLE_GDI_COMMANDO", "Goodguy", UnitTypeFlag.IsArmed); public static readonly InfantryType Commando = new InfantryType(6, "rmbo", "TEXT_UNIT_TITLE_GDI_COMMANDO", "Goodguy", UnitTypeFlag.IsArmed);
public static readonly InfantryType C1 = new InfantryType(7, "c1", "TEXT_UNIT_TITLE_CIV1", "Neutral", UnitTypeFlag.IsArmed); public static readonly InfantryType C1 = new InfantryType(7, "c1", "TEXT_UNIT_TITLE_CIV1", "Neutral", UnitTypeFlag.IsArmed | UnitTypeFlag.NoRemap);
public static readonly InfantryType C2 = new InfantryType(8, "c2", "TEXT_UNIT_TITLE_CIV2", "Neutral"); public static readonly InfantryType C2 = new InfantryType(8, "c2", "TEXT_UNIT_TITLE_CIV2", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType C3 = new InfantryType(9, "c3", "TEXT_UNIT_TITLE_CIV3", "Neutral"); public static readonly InfantryType C3 = new InfantryType(9, "c3", "TEXT_UNIT_TITLE_CIV3", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType C4 = new InfantryType(10, "c4", "TEXT_UNIT_TITLE_CIV4", "Neutral"); public static readonly InfantryType C4 = new InfantryType(10, "c4", "TEXT_UNIT_TITLE_CIV4", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType C5 = new InfantryType(11, "c5", "TEXT_UNIT_TITLE_CIV5", "Neutral"); public static readonly InfantryType C5 = new InfantryType(11, "c5", "TEXT_UNIT_TITLE_CIV5", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType C6 = new InfantryType(12, "c6", "TEXT_UNIT_TITLE_CIV6", "Neutral"); public static readonly InfantryType C6 = new InfantryType(12, "c6", "TEXT_UNIT_TITLE_CIV6", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType C7 = new InfantryType(13, "c7", "TEXT_UNIT_TITLE_CIV7", "Neutral", UnitTypeFlag.IsArmed); public static readonly InfantryType C7 = new InfantryType(13, "c7", "TEXT_UNIT_TITLE_CIV7", "Neutral", UnitTypeFlag.IsArmed | UnitTypeFlag.NoRemap);
public static readonly InfantryType C8 = new InfantryType(14, "c8", "TEXT_UNIT_TITLE_CIV8", "Neutral"); public static readonly InfantryType C8 = new InfantryType(14, "c8", "TEXT_UNIT_TITLE_CIV8", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType C9 = new InfantryType(15, "c9", "TEXT_UNIT_TITLE_CIV9", "Neutral"); public static readonly InfantryType C9 = new InfantryType(15, "c9", "TEXT_UNIT_TITLE_CIV9", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType C10 = new InfantryType(16, "c10", "TEXT_UNIT_TITLE_C10", "Neutral"); public static readonly InfantryType C10 = new InfantryType(16, "c10", "TEXT_UNIT_TITLE_C10", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType Moebius = new InfantryType(17, "moebius", "TEXT_UNIT_TITLE_MOEBIUS", "Neutral"); public static readonly InfantryType Moebius = new InfantryType(17, "moebius", "TEXT_UNIT_TITLE_MOEBIUS", "Neutral", UnitTypeFlag.NoRemap);
public static readonly InfantryType Delphi = new InfantryType(18, "delphi", "TEXT_UNIT_TITLE_DELPHI", "Neutral", UnitTypeFlag.IsArmed); public static readonly InfantryType Delphi = new InfantryType(18, "delphi", "TEXT_UNIT_TITLE_DELPHI", "Neutral", UnitTypeFlag.IsArmed | UnitTypeFlag.NoRemap);
public static readonly InfantryType DrChan = new InfantryType(19, "chan", "TEXT_UNIT_TITLE_CHAN", "Neutral"); public static readonly InfantryType DrChan = new InfantryType(19, "chan", "TEXT_UNIT_TITLE_CHAN", "Neutral", UnitTypeFlag.NoRemap);
private static readonly InfantryType[] Types; private static readonly InfantryType[] Types;

View File

@ -40,10 +40,10 @@ namespace MobiusEditor.TiberianDawn
public static readonly UnitType GunBoat = new UnitType(15, "boat", "TEXT_UNIT_TITLE_WAKE", "Goodguy", UnitTypeFlag.IsArmed); public static readonly UnitType GunBoat = new UnitType(15, "boat", "TEXT_UNIT_TITLE_WAKE", "Goodguy", UnitTypeFlag.IsArmed);
public static readonly UnitType MCV = new UnitType(16, "mcv", "TEXT_UNIT_TITLE_GDI_MCV", "Goodguy"); public static readonly UnitType MCV = new UnitType(16, "mcv", "TEXT_UNIT_TITLE_GDI_MCV", "Goodguy");
public static readonly UnitType Bike = new UnitType(17, "bike", "TEXT_UNIT_TITLE_NOD_RECON_BIKE", "Badguy", UnitTypeFlag.IsArmed); public static readonly UnitType Bike = new UnitType(17, "bike", "TEXT_UNIT_TITLE_NOD_RECON_BIKE", "Badguy", UnitTypeFlag.IsArmed);
public static readonly UnitType Tric = new UnitType(18, "tric", "TEXT_UNIT_TITLE_TRIC", "Special", UnitTypeFlag.IsArmed); public static readonly UnitType Tric = new UnitType(18, "tric", "TEXT_UNIT_TITLE_TRIC", "Special", UnitTypeFlag.IsArmed | UnitTypeFlag.NoRemap);
public static readonly UnitType Trex = new UnitType(19, "trex", "TEXT_UNIT_TITLE_TREX", "Special", UnitTypeFlag.IsArmed); public static readonly UnitType Trex = new UnitType(19, "trex", "TEXT_UNIT_TITLE_TREX", "Special", UnitTypeFlag.IsArmed | UnitTypeFlag.NoRemap);
public static readonly UnitType Rapt = new UnitType(20, "rapt", "TEXT_UNIT_TITLE_RAPT", "Special", UnitTypeFlag.IsArmed); public static readonly UnitType Rapt = new UnitType(20, "rapt", "TEXT_UNIT_TITLE_RAPT", "Special", UnitTypeFlag.IsArmed | UnitTypeFlag.NoRemap);
public static readonly UnitType Steg = new UnitType(21, "steg", "TEXT_UNIT_TITLE_STEG", "Special", UnitTypeFlag.IsArmed); public static readonly UnitType Steg = new UnitType(21, "steg", "TEXT_UNIT_TITLE_STEG", "Special", UnitTypeFlag.IsArmed | UnitTypeFlag.NoRemap);
public static readonly UnitType Tran = new UnitType(0 | UnitTypeIDMask.Aircraft, "tran", "TEXT_UNIT_TITLE_GDI_TRANSPORT", "Goodguy", "LROTOR", "RROTOR", 1, -2, UnitTypeFlag.HasTurret | UnitTypeFlag.HasDoubleTurret); public static readonly UnitType Tran = new UnitType(0 | UnitTypeIDMask.Aircraft, "tran", "TEXT_UNIT_TITLE_GDI_TRANSPORT", "Goodguy", "LROTOR", "RROTOR", 1, -2, UnitTypeFlag.HasTurret | UnitTypeFlag.HasDoubleTurret);
public static readonly UnitType A10 = new UnitType(1 | UnitTypeIDMask.Aircraft, "a10", "TEXT_UNIT_TITLE_A10", "Goodguy", UnitTypeFlag.IsArmed | UnitTypeFlag.IsFixedWing); public static readonly UnitType A10 = new UnitType(1 | UnitTypeIDMask.Aircraft, "a10", "TEXT_UNIT_TITLE_A10", "Goodguy", UnitTypeFlag.IsArmed | UnitTypeFlag.IsFixedWing);

View File

@ -759,11 +759,11 @@ namespace MobiusEditor.Tools
MapRenderer.RenderAllOccupierBounds(g, Globals.PreviewTileSize, buildingList); MapRenderer.RenderAllOccupierBounds(g, Globals.PreviewTileSize, buildingList);
if ((Layers & MapLayerFlag.BuildingFakes) == MapLayerFlag.BuildingFakes) if ((Layers & MapLayerFlag.BuildingFakes) == MapLayerFlag.BuildingFakes)
{ {
MapRenderer.RenderFakeBuildingLabel(g, mockBuilding, new Point(0, 0), Globals.PreviewTileSize, Globals.PreviewTileScale, false); MapRenderer.RenderFakeBuildingLabel(g, mockBuilding, new Point(0, 0), Globals.PreviewTileSize, false);
} }
if ((Layers & MapLayerFlag.BuildingRebuild) == MapLayerFlag.BuildingRebuild) if ((Layers & MapLayerFlag.BuildingRebuild) == MapLayerFlag.BuildingRebuild)
{ {
MapRenderer.RenderRebuildPriorityLabel(g, mockBuilding, new Point(0, 0), Globals.PreviewTileSize, Globals.PreviewTileScale, false); MapRenderer.RenderRebuildPriorityLabel(g, mockBuilding, new Point(0, 0), Globals.PreviewTileSize, false);
} }
} }
buildingTypeMapPanel.MapImage = buildingPreview; buildingTypeMapPanel.MapImage = buildingPreview;
@ -858,15 +858,15 @@ namespace MobiusEditor.Tools
} }
if ((Layers & MapLayerFlag.BuildingFakes) == MapLayerFlag.BuildingFakes) if ((Layers & MapLayerFlag.BuildingFakes) == MapLayerFlag.BuildingFakes)
{ {
MapRenderer.RenderAllFakeBuildingLabels(graphics, previewMap, Globals.MapTileSize, Globals.MapTileScale); MapRenderer.RenderAllFakeBuildingLabels(graphics, previewMap, Globals.MapTileSize);
} }
if ((Layers & MapLayerFlag.BuildingRebuild) == MapLayerFlag.BuildingRebuild) if ((Layers & MapLayerFlag.BuildingRebuild) == MapLayerFlag.BuildingRebuild)
{ {
MapRenderer.RenderAllRebuildPriorityLabels(graphics, previewMap, Globals.MapTileSize, Globals.MapTileScale); MapRenderer.RenderAllRebuildPriorityLabels(graphics, previewMap, Globals.MapTileSize);
} }
if ((Layers & MapLayerFlag.TechnoTriggers) == MapLayerFlag.TechnoTriggers) if ((Layers & MapLayerFlag.TechnoTriggers) == MapLayerFlag.TechnoTriggers)
{ {
MapRenderer.RenderAllTechnoTriggers(graphics, previewMap, Globals.MapTileSize, Globals.MapTileScale, Layers); MapRenderer.RenderAllTechnoTriggers(graphics, previewMap, Globals.MapTileSize, Layers);
} }
} }
} }

View File

@ -486,14 +486,14 @@ namespace MobiusEditor.Tools
selected = null; selected = null;
string[] selectedRange = selected != null ? new[] { selected } : new string[] { }; string[] selectedRange = selected != null ? new[] { selected } : new string[] { };
// Normal techno triggers: under cell // Normal techno triggers: under cell
MapRenderer.RenderAllTechnoTriggers(graphics, map, Globals.MapTileSize, Globals.MapTileScale, Layers, Color.LimeGreen, selected, true); MapRenderer.RenderAllTechnoTriggers(graphics, map, Globals.MapTileSize, Layers, Color.LimeGreen, selected, true);
MapRenderer.RenderCellTriggersHard(graphics, map, Globals.MapTileSize, Globals.MapTileScale, selectedRange); MapRenderer.RenderCellTriggersHard(graphics, map, Globals.MapTileSize, selectedRange);
if (selected != null) if (selected != null)
{ {
// Only use preview map if in placement mode. // Only use preview map if in placement mode.
MapRenderer.RenderCellTriggersSelected(graphics, placementMode ? previewMap : map, Globals.MapTileSize, Globals.MapTileScale, selectedRange); MapRenderer.RenderCellTriggersSelected(graphics, placementMode ? previewMap : map, Globals.MapTileSize, selectedRange);
// Selected technos: on top of cell // Selected technos: on top of cell
MapRenderer.RenderAllTechnoTriggers(graphics, map, Globals.MapTileSize, Globals.MapTileScale, Layers, Color.Yellow, selected, false); MapRenderer.RenderAllTechnoTriggers(graphics, map, Globals.MapTileSize, Layers, Color.Yellow, selected, false);
} }
} }

View File

@ -812,7 +812,7 @@ namespace MobiusEditor.Tools
MapRenderer.RenderAllBoundsFromPoint(graphics, Globals.MapTileSize, previewMap.Technos.OfType<InfantryGroup>()); MapRenderer.RenderAllBoundsFromPoint(graphics, Globals.MapTileSize, previewMap.Technos.OfType<InfantryGroup>());
if ((Layers & (MapLayerFlag.Infantry | MapLayerFlag.TechnoTriggers)) == (MapLayerFlag.Infantry | MapLayerFlag.TechnoTriggers)) if ((Layers & (MapLayerFlag.Infantry | MapLayerFlag.TechnoTriggers)) == (MapLayerFlag.Infantry | MapLayerFlag.TechnoTriggers))
{ {
MapRenderer.RenderAllTechnoTriggers(graphics, previewMap, Globals.MapTileSize, Globals.MapTileScale, Layers); MapRenderer.RenderAllTechnoTriggers(graphics, previewMap, Globals.MapTileSize, Layers);
} }
} }

View File

@ -957,7 +957,7 @@ namespace MobiusEditor.Tools
} }
templateTypeMapPanel.MapImage = selected.Thumbnail; templateTypeMapPanel.MapImage = selected.Thumbnail;
var templateTypeMetrics = new CellMetrics(selected.ThumbnailIconWidth, selected.ThumbnailIconHeight); var templateTypeMetrics = new CellMetrics(selected.ThumbnailIconWidth, selected.ThumbnailIconHeight);
templateTypeNavigationWidget = new NavigationWidget(templateTypeMapPanel, templateTypeMetrics, Globals.OriginalTileSize, false); templateTypeNavigationWidget = new NavigationWidget(templateTypeMapPanel, templateTypeMetrics, Globals.PreviewTileSize, false);
templateTypeNavigationWidget.MouseoverSize = Size.Empty; templateTypeNavigationWidget.MouseoverSize = Size.Empty;
templateTypeNavigationWidget.Activate(); templateTypeNavigationWidget.Activate();
} }

View File

@ -580,7 +580,7 @@ namespace MobiusEditor.Tools
MapRenderer.RenderAllOccupierBounds(graphics, Globals.MapTileSize, previewMap.Technos.OfType<Terrain>()); MapRenderer.RenderAllOccupierBounds(graphics, Globals.MapTileSize, previewMap.Technos.OfType<Terrain>());
if ((Layers & MapLayerFlag.TechnoTriggers) == MapLayerFlag.TechnoTriggers) if ((Layers & MapLayerFlag.TechnoTriggers) == MapLayerFlag.TechnoTriggers)
{ {
MapRenderer.RenderAllTechnoTriggers(graphics, previewMap, Globals.MapTileSize, Globals.MapTileScale, Layers); MapRenderer.RenderAllTechnoTriggers(graphics, previewMap, Globals.MapTileSize, Layers);
} }
} }

View File

@ -613,7 +613,7 @@ namespace MobiusEditor.Tools
{ {
if ((Layers & MapLayerFlag.TechnoTriggers) == MapLayerFlag.TechnoTriggers) if ((Layers & MapLayerFlag.TechnoTriggers) == MapLayerFlag.TechnoTriggers)
{ {
MapRenderer.RenderAllTechnoTriggers(graphics, previewMap, Globals.MapTileSize, Globals.MapTileScale, Layers); MapRenderer.RenderAllTechnoTriggers(graphics, previewMap, Globals.MapTileSize, Layers);
} }
if ((Layers & MapLayerFlag.EffectRadius) == MapLayerFlag.EffectRadius) if ((Layers & MapLayerFlag.EffectRadius) == MapLayerFlag.EffectRadius)
{ {

View File

@ -281,7 +281,7 @@ namespace MobiusEditor.Tools
if ((layersToRender & MapLayerFlag.CellTriggers) == MapLayerFlag.CellTriggers if ((layersToRender & MapLayerFlag.CellTriggers) == MapLayerFlag.CellTriggers
&& (manuallyHandledLayers & MapLayerFlag.CellTriggers) == MapLayerFlag.None) && (manuallyHandledLayers & MapLayerFlag.CellTriggers) == MapLayerFlag.None)
{ {
MapRenderer.RenderCellTriggersSoft(graphics, map, tileSize, tileScale); MapRenderer.RenderCellTriggersSoft(graphics, map, tileSize);
} }
if ((layersToRender & (MapLayerFlag.Waypoints | MapLayerFlag.FootballArea)) == (MapLayerFlag.Waypoints | MapLayerFlag.FootballArea) if ((layersToRender & (MapLayerFlag.Waypoints | MapLayerFlag.FootballArea)) == (MapLayerFlag.Waypoints | MapLayerFlag.FootballArea)
&& (manuallyHandledLayers & MapLayerFlag.WaypointsIndic) == MapLayerFlag.None && plugin.GameType == GameType.SoleSurvivor) && (manuallyHandledLayers & MapLayerFlag.WaypointsIndic) == MapLayerFlag.None && plugin.GameType == GameType.SoleSurvivor)
@ -307,22 +307,22 @@ namespace MobiusEditor.Tools
if ((layersToRender & (MapLayerFlag.Waypoints | MapLayerFlag.WaypointsIndic)) == (MapLayerFlag.Waypoints | MapLayerFlag.WaypointsIndic) if ((layersToRender & (MapLayerFlag.Waypoints | MapLayerFlag.WaypointsIndic)) == (MapLayerFlag.Waypoints | MapLayerFlag.WaypointsIndic)
&& (manuallyHandledLayers & MapLayerFlag.WaypointsIndic) == MapLayerFlag.None) && (manuallyHandledLayers & MapLayerFlag.WaypointsIndic) == MapLayerFlag.None)
{ {
MapRenderer.RenderWayPointIndicators(graphics, map, tileSize, tileScale, Color.LightGreen, false, true); MapRenderer.RenderWayPointIndicators(graphics, map, tileSize, Color.LightGreen, false, true);
} }
if ((layersToRender & (MapLayerFlag.Buildings | MapLayerFlag.BuildingFakes)) == (MapLayerFlag.Buildings | MapLayerFlag.BuildingFakes) if ((layersToRender & (MapLayerFlag.Buildings | MapLayerFlag.BuildingFakes)) == (MapLayerFlag.Buildings | MapLayerFlag.BuildingFakes)
&& (manuallyHandledLayers & MapLayerFlag.BuildingFakes) == MapLayerFlag.None) && (manuallyHandledLayers & MapLayerFlag.BuildingFakes) == MapLayerFlag.None)
{ {
MapRenderer.RenderAllFakeBuildingLabels(graphics, map, tileSize, tileScale); MapRenderer.RenderAllFakeBuildingLabels(graphics, map, tileSize);
} }
if ((layersToRender & (MapLayerFlag.Buildings | MapLayerFlag.BuildingRebuild)) == (MapLayerFlag.Buildings | MapLayerFlag.BuildingRebuild) if ((layersToRender & (MapLayerFlag.Buildings | MapLayerFlag.BuildingRebuild)) == (MapLayerFlag.Buildings | MapLayerFlag.BuildingRebuild)
&& (manuallyHandledLayers & MapLayerFlag.BuildingRebuild) == MapLayerFlag.None) && (manuallyHandledLayers & MapLayerFlag.BuildingRebuild) == MapLayerFlag.None)
{ {
MapRenderer.RenderAllRebuildPriorityLabels(graphics, map, tileSize, tileScale); MapRenderer.RenderAllRebuildPriorityLabels(graphics, map, tileSize);
} }
if ((layersToRender & MapLayerFlag.TechnoTriggers) == MapLayerFlag.TechnoTriggers if ((layersToRender & MapLayerFlag.TechnoTriggers) == MapLayerFlag.TechnoTriggers
&& (manuallyHandledLayers & MapLayerFlag.TechnoTriggers) == MapLayerFlag.None) && (manuallyHandledLayers & MapLayerFlag.TechnoTriggers) == MapLayerFlag.None)
{ {
MapRenderer.RenderAllTechnoTriggers(graphics, map, tileSize, tileScale, layersToRender); MapRenderer.RenderAllTechnoTriggers(graphics, map, tileSize, layersToRender);
} }
} }

View File

@ -467,13 +467,13 @@ namespace MobiusEditor.Tools
MapRenderer.RenderWaypoint(plugin.GameType, true, Globals.MapTileSize, map.FlagColors.ToArray(), selected, 1.0f).Item2(graphics); MapRenderer.RenderWaypoint(plugin.GameType, true, Globals.MapTileSize, map.FlagColors.ToArray(), selected, 1.0f).Item2(graphics);
} }
// Render those here to they are put over the opaque redraw of the current waypoint. // Render those here to they are put over the opaque redraw of the current waypoint.
MapRenderer.RenderAllTechnoTriggers(graphics, plugin.Map, Globals.MapTileSize, Globals.MapTileScale, Layers); MapRenderer.RenderAllTechnoTriggers(graphics, plugin.Map, Globals.MapTileSize, Layers);
MapRenderer.RenderAllBoundsFromCell(graphics, Globals.MapTileSize, MapRenderer.RenderAllBoundsFromCell(graphics, Globals.MapTileSize,
map.Waypoints.Where(wp => wp != selected && wp.Cell.HasValue).Select(wp => wp.Cell.Value), map.Metrics, Color.Orange); map.Waypoints.Where(wp => wp != selected && wp.Cell.HasValue).Select(wp => wp.Cell.Value), map.Metrics, Color.Orange);
// For TD, always render reveal waypoint. // For TD, always render reveal waypoint.
bool renderAll = plugin.GameType != GameType.RedAlert || (Layers & MapLayerFlag.WaypointRadius) == MapLayerFlag.WaypointRadius; bool renderAll = plugin.GameType != GameType.RedAlert || (Layers & MapLayerFlag.WaypointRadius) == MapLayerFlag.WaypointRadius;
MapRenderer.RenderAllWayPointRevealRadiuses(graphics, plugin, map, Globals.MapTileSize, selected, !renderAll); MapRenderer.RenderAllWayPointRevealRadiuses(graphics, plugin, map, Globals.MapTileSize, selected, !renderAll);
MapRenderer.RenderWayPointIndicators(graphics, map, Globals.MapTileSize, Globals.MapTileScale, Color.LightGreen, false, true, selectedRange); MapRenderer.RenderWayPointIndicators(graphics, map, Globals.MapTileSize, Color.LightGreen, false, true, selectedRange);
if (selected != null) if (selected != null)
{ {
if (placementMode && selectedIndex >= 0) if (placementMode && selectedIndex >= 0)
@ -484,11 +484,11 @@ namespace MobiusEditor.Tools
if (selected.Cell.HasValue) if (selected.Cell.HasValue)
{ {
MapRenderer.RenderAllBoundsFromCell(graphics, Globals.MapTileSize, new int[] { selected.Cell.Value }, map.Metrics, Color.Yellow); MapRenderer.RenderAllBoundsFromCell(graphics, Globals.MapTileSize, new int[] { selected.Cell.Value }, map.Metrics, Color.Yellow);
MapRenderer.RenderWayPointIndicators(graphics, map, Globals.MapTileSize, Globals.MapTileScale, Color.Yellow, false, false, selectedRange); MapRenderer.RenderWayPointIndicators(graphics, map, Globals.MapTileSize, Color.Yellow, false, false, selectedRange);
} }
if (dummySelected != null && (selected == null || selected.Cell != dummySelected.Cell)) if (dummySelected != null && (selected == null || selected.Cell != dummySelected.Cell))
{ {
MapRenderer.RenderWayPointIndicators(graphics, map, Globals.MapTileSize, Globals.MapTileScale, Color.Yellow, true, false, new[] { dummySelected }); MapRenderer.RenderWayPointIndicators(graphics, map, Globals.MapTileSize, Color.Yellow, true, false, new[] { dummySelected });
// Need to do this manually since it's an extra waypoint not normally on the list, and it uses the radius data of the original waypoint to place. // Need to do this manually since it's an extra waypoint not normally on the list, and it uses the radius data of the original waypoint to place.
int[] wpReveal1 = plugin.GetRevealRadiusForWaypoints(map, false); int[] wpReveal1 = plugin.GetRevealRadiusForWaypoints(map, false);
int[] wpReveal2 = plugin.GetRevealRadiusForWaypoints(map, true); int[] wpReveal2 = plugin.GetRevealRadiusForWaypoints(map, true);

View File

@ -500,7 +500,8 @@ namespace MobiusEditor.Utility
Int32 hdrIconsPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x0C); Int32 hdrIconsPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x0C);
// Offset of start of palette data. Probably always 0. // Offset of start of palette data. Probably always 0.
Int32 hdrPalettesPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x10); Int32 hdrPalettesPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x10);
// Offset of remaps data? Always fixed value "0x0D1AFFFF", which makes no sense as ptr. // Offset of remaps data. Dune II leftover of 4 bit to 8 bit translation tables.
// Always fixed value 0x0D1AFFFF, which makes no sense as ptr.
Int32 hdrRemapsPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x14); Int32 hdrRemapsPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x14);
// Offset of 'transparency flags'? Generally points to an empty array at the end of the file. // Offset of 'transparency flags'? Generally points to an empty array at the end of the file.
Int32 hdrTransFlagPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x18); Int32 hdrTransFlagPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x18);
@ -513,7 +514,85 @@ namespace MobiusEditor.Utility
if (hdrHeight != 24 || hdrWidth != 24) if (hdrHeight != 24 || hdrWidth != 24)
throw new ArgumentException("Only 24×24 pixel tiles are supported.", "fileData"); throw new ArgumentException("Only 24×24 pixel tiles are supported.", "fileData");
// Checking some normally hardcoded values // Checking some normally hardcoded values
if (hdrAllocated != 00 || hdrPalettesPtr != 0 || hdrRemapsPtr != 0x0D1AFFFF) if (hdrAllocated != 0 || hdrPalettesPtr != 0)// || hdrRemapsPtr != 0x0D1AFFFF)
throw new ArgumentException("Invalid values encountered in header.");
if (hdrCount == 0)
throw new ArgumentException("Tileset files with 0 tiles are not supported!", "fileData");
// Checking if data is all inside the file
if (hdrIconsPtr >= fileLen || (hdrMapPtr + hdrCount) > fileLen)
throw new ArgumentException("Invalid header values: indices outside file range.", "fileData");
Int32 tileSize = hdrWidth * hdrHeight;
// Maps the available images onto the full iconset definition
Byte[] map = new Byte[hdrCount];
Array.Copy(fileData, hdrMapPtr, map, 0, hdrCount);
// Get max index plus one for real images count. Nothing in the file header actually specifies this directly.
Int32 actualImages = map.Max(x => x == 0xFF ? -1 : x) + 1;
if (hdrTransFlagPtr + actualImages > fileLen)
throw new ArgumentException("Invalid header values: indices outside file range.", "fileData");
if (hdrIconsPtr + actualImages * tileSize > fileLen)
throw new ArgumentException("Tile image data outside file range.", "fileData");
Byte[] imagesIndex = new Byte[actualImages];
Array.Copy(fileData, hdrTransFlagPtr, imagesIndex, 0, actualImages);
Byte[][] tiles = new Byte[hdrCount][];
widths = new int[hdrCount];
heights = new int[hdrCount];
Boolean[] tileUseList = new Boolean[map.Length];
for (Int32 i = 0; i < map.Length; ++i)
{
Byte dataIndex = map[i];
Boolean used = dataIndex != 0xFF;
tileUseList[i] = used;
Byte[] tileData = new Byte[tileSize];
if (used)
{
Int32 offset = hdrIconsPtr + dataIndex * tileSize;
if ((offset + tileSize) > fileLen)
throw new ArgumentException("Tile data outside file range.", "fileData");
Array.Copy(fileData, offset, tileData, 0, tileSize);
tiles[i] = tileData;
widths[i] = hdrWidth;
heights[i] = hdrHeight;
}
}
return tiles;
}
public static Byte[][] GetRaTmpData(Byte[] fileData, out int[] widths, out int[] heights)
{
Int32 fileLen = fileData.Length;
if (fileLen < 0x28)
throw new ArgumentException("File is not long enough to be a C&C Template file.", "fileData");
Int16 hdrWidth = ArrayUtils.ReadInt16FromByteArrayLe(fileData, 0x00);
Int16 hdrHeight = ArrayUtils.ReadInt16FromByteArrayLe(fileData, 0x02);
// Amount of icons to form the full icon set. Not necessarily the same as the amount of actual icons.
Int16 hdrCount = ArrayUtils.ReadInt16FromByteArrayLe(fileData, 0x04);
// Always 0
Int16 hdrAllocated = ArrayUtils.ReadInt16FromByteArrayLe(fileData, 0x06);
// New in RA
Int16 hdrMapWidth = ArrayUtils.ReadInt16FromByteArrayLe(fileData, 0x08);
Int16 hdrMapHeight = ArrayUtils.ReadInt16FromByteArrayLe(fileData, 0x0A);
Int32 hdrSize = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x0C);
// Offset of start of actual icon data. Generally always 0x20
Int32 hdrIconsPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x10);
// Offset of start of palette data. Probably always 0.
Int32 hdrPalettesPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x14);
// Offset of remaps data. Dune II leftover of 4 bit to 8 bit translation tables.
// Always seems to be 0x2C730FXX (with values differing for the lowest byte), which makes no sense as ptr.
Int32 hdrRemapsPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x18);
// Offset of 'transparency flags'? Generally points to an empty array at the end of the file.
Int32 hdrTransFlagPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x1C);
// Offset of 'color' map, indicating the terrain type for each type. This includes unused cells, which are usually indicated as 0.
Int32 hdrColorMapPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x20);
// Offset of actual icon set definition, defining for each index which icon data to use. FF for none.
Int32 hdrMapPtr = ArrayUtils.ReadInt32FromByteArrayLe(fileData, 0x24);
// File size check
if (hdrSize != fileData.Length)
throw new ArgumentException("File size in header does not match.", "fileData");
// Only allowing standard 24x24 size
if (hdrHeight != 24 || hdrWidth != 24)
throw new ArgumentException("Only 24×24 pixel tiles are supported.", "fileData");
// Checking some normally hardcoded values
if (hdrAllocated != 00 || hdrPalettesPtr != 0)
throw new ArgumentException("Invalid values encountered in header."); throw new ArgumentException("Invalid values encountered in header.");
if (hdrCount == 0) if (hdrCount == 0)
throw new ArgumentException("Tileset files with 0 tiles are not supported!", "fileData"); throw new ArgumentException("Tileset files with 0 tiles are not supported!", "fileData");
@ -556,14 +635,6 @@ namespace MobiusEditor.Utility
return tiles; return tiles;
} }
public static Byte[][] GetRaTmpData(Byte[] fileData, out int width, out int height)
{
width = 24;
height = 24;
// TODO
return null;
}
public static Color[] LoadSixBitPalette(Byte[] fileData, int palStart, int colors) public static Color[] LoadSixBitPalette(Byte[] fileData, int palStart, int colors)
{ {
Color[] palette = Enumerable.Repeat(Color.Black, colors).ToArray(); Color[] palette = Enumerable.Repeat(Color.Black, colors).ToArray();

View File

@ -278,6 +278,45 @@ namespace MobiusEditor.Utility
return GeneralUtils.GetBoundingBoxCenter(image.Width, image.Height, maxWidth, maxHeight); return GeneralUtils.GetBoundingBoxCenter(image.Width, image.Height, maxWidth, maxHeight);
} }
public static void RemoveAlphaOnCurrent(this Bitmap bitmap)
{
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
if ((bitmap.PixelFormat & PixelFormat.Indexed) == PixelFormat.Indexed)
{
ColorPalette pal = bitmap.Palette;
for (int i = 0; i < pal.Entries.Length; i++)
{
pal.Entries[i] = Color.FromArgb(255, pal.Entries[i]);
}
return;
}
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
{
// can't handle.
return;
}
BitmapData sourceData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
Int32 actualDataWidth = rect.Width * 4;
Int32 h = bitmap.Height;
Int32 origStride = sourceData.Stride;
Byte[] imageData = new Byte[actualDataWidth];
Int64 sourcePos = sourceData.Scan0.ToInt64();
// Copy line by line, skipping by stride but copying actual data width
for (Int32 y = 0; y < h; ++y)
{
Marshal.Copy(new IntPtr(sourcePos), imageData, 0, actualDataWidth);
for (int i = 3; i < actualDataWidth; i += 4)
{
// Clear alpha
imageData[i] = 255;
}
Marshal.Copy(imageData, 0, new IntPtr(sourcePos), actualDataWidth);
sourcePos += origStride;
}
bitmap.UnlockBits(sourceData);
return;
}
public static Bitmap RemoveAlpha(this Bitmap bitmap) public static Bitmap RemoveAlpha(this Bitmap bitmap)
{ {
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
@ -285,7 +324,7 @@ namespace MobiusEditor.Utility
targetImage.SetResolution(bitmap.HorizontalResolution, bitmap.VerticalResolution); targetImage.SetResolution(bitmap.HorizontalResolution, bitmap.VerticalResolution);
BitmapData sourceData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData sourceData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
BitmapData targetData = targetImage.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); BitmapData targetData = targetImage.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Int32 actualDataWidth = ((Image.GetPixelFormatSize(bitmap.PixelFormat) * rect.Width) + 7) / 8; Int32 actualDataWidth = ((Image.GetPixelFormatSize(PixelFormat.Format32bppArgb) * rect.Width) + 7) / 8;
Int32 h = bitmap.Height; Int32 h = bitmap.Height;
Int32 origStride = sourceData.Stride; Int32 origStride = sourceData.Stride;
Int32 targetStride = targetData.Stride; Int32 targetStride = targetData.Stride;

View File

@ -16,7 +16,7 @@ namespace MobiusEditor.Utility
private bool isEmbedded = false; private bool isEmbedded = false;
private long fileStart; private long fileStart;
private long fileLength; private long fileLength;
private long dataStart; private uint dataStart;
public Mixfile(string mixPath) public Mixfile(string mixPath)
{ {
@ -42,18 +42,18 @@ namespace MobiusEditor.Utility
this.fileLength = length; this.fileLength = length;
// Copy reference to parent map. The "CreateViewStream" function takes care of reading the right parts from it. // Copy reference to parent map. The "CreateViewStream" function takes care of reading the right parts from it.
this.mixFileMap = container.mixFileMap; this.mixFileMap = container.mixFileMap;
this.ReadMixHeader(mixFileMap, offset, fileLength); this.ReadMixHeader(this.mixFileMap, offset, this.fileLength);
} }
private void ReadMixHeader(MemoryMappedFile mixMap, long mixStart, long mixLength) private void ReadMixHeader(MemoryMappedFile mixMap, long mixStart, long mixLength)
{ {
mixFileContents.Clear(); this.mixFileContents.Clear();
uint readOffset = 0; uint readOffset = 0;
ushort nrOfFiles = 0; ushort nrOfFiles = 0;
bool hasFlags = false; bool hasFlags = false;
bool encrypted = false; bool encrypted = false;
bool checksum = false; bool checksum = false;
using (BinaryReader headerReader = new BinaryReader(CreateViewStream(mixMap, mixStart, mixLength, readOffset, 2))) using (BinaryReader headerReader = new BinaryReader(this.CreateViewStream(mixMap, mixStart, mixLength, readOffset, 2)))
{ {
ushort start = headerReader.ReadUInt16(); ushort start = headerReader.ReadUInt16();
if (start == 0) if (start == 0)
@ -64,9 +64,9 @@ namespace MobiusEditor.Utility
} }
if (hasFlags) if (hasFlags)
{ {
using (BinaryReader headerReader = new BinaryReader(CreateViewStream(mixMap, mixStart, mixLength, readOffset, 2))) using (BinaryReader headerReader = new BinaryReader(this.CreateViewStream(mixMap, mixStart, mixLength, readOffset, 2)))
{ {
var flags = headerReader.ReadUInt16(); ushort flags = headerReader.ReadUInt16();
checksum = (flags & 1) != 0; checksum = (flags & 1) != 0;
encrypted = (flags & 2) != 0; encrypted = (flags & 2) != 0;
readOffset += 2; readOffset += 2;
@ -74,7 +74,7 @@ namespace MobiusEditor.Utility
// Not encrypted; read nr of files. // Not encrypted; read nr of files.
if (!encrypted) if (!encrypted)
{ {
using (BinaryReader headerReader = new BinaryReader(CreateViewStream(mixMap, mixStart, mixLength, readOffset, 2))) using (BinaryReader headerReader = new BinaryReader(this.CreateViewStream(mixMap, mixStart, mixLength, readOffset, 2)))
{ {
nrOfFiles = headerReader.ReadUInt16(); nrOfFiles = headerReader.ReadUInt16();
readOffset += 2; readOffset += 2;
@ -85,7 +85,7 @@ namespace MobiusEditor.Utility
Byte[] header = null; Byte[] header = null;
if (encrypted) if (encrypted)
{ {
using (BinaryReader headerReader = new BinaryReader(CreateViewStream(mixMap, mixStart, mixLength, readOffset, 80))) using (BinaryReader headerReader = new BinaryReader(this.CreateViewStream(mixMap, mixStart, mixLength, readOffset, 80)))
{ {
byte[] blowfishKey = headerReader.ReadAllBytes(); byte[] blowfishKey = headerReader.ReadAllBytes();
readOffset += 80; readOffset += 80;
@ -102,7 +102,7 @@ namespace MobiusEditor.Utility
{ {
throw new ArgumentOutOfRangeException("Not a valid mix file: header length exceeds file length."); throw new ArgumentOutOfRangeException("Not a valid mix file: header length exceeds file length.");
} }
using (BinaryReader headerReader = new BinaryReader(CreateViewStream(mixMap, mixStart, mixLength, readOffset, headerSize))) using (BinaryReader headerReader = new BinaryReader(this.CreateViewStream(mixMap, mixStart, mixLength, readOffset, headerSize)))
{ {
header = headerReader.ReadBytes((Int32)headerSize); header = headerReader.ReadBytes((Int32)headerSize);
// End of header reading; no longer needed. // End of header reading; no longer needed.
@ -123,7 +123,7 @@ namespace MobiusEditor.Utility
{ {
throw new ArgumentOutOfRangeException(String.Format("Not a valid mix file: file #{0} with id {1:X08} exceeds archive length.", i, fileId)); throw new ArgumentOutOfRangeException(String.Format("Not a valid mix file: file #{0} with id {1:X08} exceeds archive length.", i, fileId));
} }
mixFileContents.Add(fileId, (fileOffset, fileLength)); this.mixFileContents.Add(fileId, (fileOffset, fileLength));
} }
} }
} }
@ -132,26 +132,24 @@ namespace MobiusEditor.Utility
{ {
offset = 0; offset = 0;
length = 0; length = 0;
uint fileId = hashRol.GetNameId(filename); uint fileId = this.hashRol.GetNameId(filename);
(uint Offset, uint Length) fileLoc; (uint Offset, uint Length) fileLoc;
if (!mixFileContents.TryGetValue(fileId, out fileLoc)) if (!this.mixFileContents.TryGetValue(fileId, out fileLoc))
{ {
return false; return false;
} }
offset = fileLoc.Offset; offset = fileLoc.Offset + this.dataStart;
length = fileLoc.Length; length = fileLoc.Length;
return true; return true;
} }
public Stream OpenFile(string path) public Stream OpenFile(string path)
{ {
uint fileId = hashRol.GetNameId(path); if (!this.GetFileInfo(path, out uint offset, out uint length))
(uint Offset, uint Length) fileLoc;
if (!mixFileContents.TryGetValue(fileId, out fileLoc))
{ {
return null; return null;
} }
return CreateViewStream(mixFileMap, fileStart, fileLength, this.dataStart + fileLoc.Offset, fileLoc.Length); return this.CreateViewStream(this.mixFileMap, this.fileStart, this.fileLength, offset, length);
} }
/// <summary> /// <summary>
@ -166,7 +164,7 @@ namespace MobiusEditor.Utility
/// <exception cref="IndexOutOfRangeException">The data is not in the bounds of this mix file.</exception> /// <exception cref="IndexOutOfRangeException">The data is not in the bounds of this mix file.</exception>
private Stream CreateViewStream(MemoryMappedFile mixMap, long mixFileStart, long mixFileLength, long dataReadOffset, uint dataReadLength) private Stream CreateViewStream(MemoryMappedFile mixMap, long mixFileStart, long mixFileLength, long dataReadOffset, uint dataReadLength)
{ {
if (disposedValue) if (this.disposedValue)
{ {
throw new ObjectDisposedException("Mixfile"); throw new ObjectDisposedException("Mixfile");
} }
@ -182,22 +180,22 @@ namespace MobiusEditor.Utility
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (!disposedValue) if (!this.disposedValue)
{ {
// Only dispose if not an embedded mix file. // Only dispose if not an embedded mix file.
// If embedded, the mixFileMap is contained in the parent. // If embedded, the mixFileMap is contained in the parent.
if (disposing && !isEmbedded) if (disposing && !this.isEmbedded)
{ {
mixFileMap.Dispose(); this.mixFileMap.Dispose();
} }
mixFileMap = null; this.mixFileMap = null;
disposedValue = true; this.disposedValue = true;
} }
} }
public void Dispose() public void Dispose()
{ {
Dispose(true); this.Dispose(true);
} }
#endregion #endregion
} }

View File

@ -40,7 +40,7 @@ namespace MobiusEditor.Utility
this.Name = name; this.Name = name;
this.UnitRadarColor = unitRadarColor; this.UnitRadarColor = unitRadarColor;
this.BuildingRadarColor = buildingRadarColor; this.BuildingRadarColor = buildingRadarColor;
this.remapTable = Enumerable.Range(0, 0x100).Select(b => (Byte)b).ToArray(); this.remapTable = Enumerable.Range(0, 0x100).Select(b => (byte)b).ToArray();
int max = Math.Min(0x100, remapstart + remapValues.Length) - remapstart; int max = Math.Min(0x100, remapstart + remapValues.Length) - remapstart;
for (int i = 0; i < max; ++i) for (int i = 0; i < max; ++i)
{ {
@ -53,7 +53,7 @@ namespace MobiusEditor.Utility
this.Name = name; this.Name = name;
this.UnitRadarColor = unitRadarColor; this.UnitRadarColor = unitRadarColor;
this.BuildingRadarColor = buildingRadarColor; this.BuildingRadarColor = buildingRadarColor;
this.remapTable = Enumerable.Range(0, 0x100).Cast<byte>().ToArray(); this.remapTable = Enumerable.Range(0, 0x100).Select(b => (byte)b).ToArray();
int max = Math.Max(remapOrigins.Length, remapValues.Length); int max = Math.Max(remapOrigins.Length, remapValues.Length);
for (int i = 0; i < max; ++i) for (int i = 0; i < max; ++i)
{ {
@ -100,6 +100,7 @@ namespace MobiusEditor.Utility
} }
} }
} }
public void ApplyToImage(byte[] bytes, int width, int height, int bytesPerPixel, int stride, Rectangle? opaqueBounds) public void ApplyToImage(byte[] bytes, int width, int height, int bytesPerPixel, int stride, Rectangle? opaqueBounds)
{ {
// Only handle 8bpp data. // Only handle 8bpp data.
@ -110,7 +111,7 @@ namespace MobiusEditor.Utility
Rectangle bounds = opaqueBounds ?? new Rectangle(0, 0, width, height); Rectangle bounds = opaqueBounds ?? new Rectangle(0, 0, width, height);
int boundsBottom = Math.Min(height, bounds.Bottom); int boundsBottom = Math.Min(height, bounds.Bottom);
int boundsWidth = Math.Min(Math.Max(0, width - bounds.Left), bounds.Width); int boundsWidth = Math.Min(Math.Max(0, width - bounds.Left), bounds.Width);
int linePtr = 0; int linePtr = bounds.Top * stride;
for (int y = bounds.Top; y < boundsBottom; y++) for (int y = bounds.Top; y < boundsBottom; y++)
{ {
int ptr = linePtr + bounds.Left; int ptr = linePtr + bounds.Left;

View File

@ -32,7 +32,7 @@ namespace MobiusEditor.Utility
static TeamRemapManager() static TeamRemapManager()
{ {
RemapsTd = (from field in typeof(ITeamColorManager).GetFields(BindingFlags.Static | BindingFlags.Public) RemapsTd = (from field in typeof(TeamRemapManager).GetFields(BindingFlags.Static | BindingFlags.Public)
where field.IsInitOnly && typeof(TeamRemap).IsAssignableFrom(field.FieldType) && field.Name.StartsWith("RemapTd") where field.IsInitOnly && typeof(TeamRemap).IsAssignableFrom(field.FieldType) && field.Name.StartsWith("RemapTd")
select field.GetValue(null) as TeamRemap).ToDictionary(trm => trm.Name); select field.GetValue(null) as TeamRemap).ToDictionary(trm => trm.Name);
} }

View File

@ -139,7 +139,7 @@ namespace MobiusEditor.Utility
{ {
if (generateFallback && tiles.Any(t => t.Image == null)) if (generateFallback && tiles.Any(t => t.Image == null))
{ {
// Tile found, but contains no data. Re-fetch with dummy generation. // Tile not found, or contains no data. Re-fetch with dummy generation.
if (tileset.GetTileData(name, shape, teamColor, out fps, out tiles, true)) if (tileset.GetTileData(name, shape, teamColor, out fps, out tiles, true))
{ {
// Signal in return value that dummy was generated. // Signal in return value that dummy was generated.
@ -151,7 +151,7 @@ namespace MobiusEditor.Utility
} }
} }
// If the tile is not defined at all, and onlyifdefined is not enabled, make a dummy entry anyway. // If the tile is not defined at all, and onlyifdefined is not enabled, make a dummy entry anyway.
if (!onlyIfDefined && generateFallback && first != null && first.GetTileData(name, shape, teamColor, out fps, out tiles, true)) if (generateFallback && !onlyIfDefined && first != null && first.GetTileData(name, shape, teamColor, out fps, out tiles, true))
{ {
// Signal in return value that dummy was generated. // Signal in return value that dummy was generated.
return false; return false;

View File

@ -60,7 +60,7 @@ namespace MobiusEditor.Utility
this.currentlyLoadedPalette = TeamRemapManager.GetPaletteForTheater(this.archiveManager, theater); this.currentlyLoadedPalette = TeamRemapManager.GetPaletteForTheater(this.archiveManager, theater);
} }
public Boolean GetTeamColorTileData(String name, Int32 shape, ITeamColor teamColor, out Tile tile, Boolean generateFallback, Boolean onlyIfDefined) public Boolean GetTeamColorTileData(String name, Int32 shape, ITeamColor teamColor, out Tile tile, Boolean generateFallback, Boolean onlyIfDefined, string remapGraphicsSource, byte[] remapTable)
{ {
tile = null; tile = null;
String teamColorName = teamColor == null ? String.Empty : (teamColor.Name ?? String.Empty); String teamColorName = teamColor == null ? String.Empty : (teamColor.Name ?? String.Empty);
@ -78,7 +78,8 @@ namespace MobiusEditor.Utility
} }
else else
{ {
shapeFile = this.GetShapeFile(name); // If there's a remap graphics source, prefer that.
shapeFile = this.GetShapeFile(remapGraphicsSource ?? name);
if (shapeFile == null) if (shapeFile == null)
{ {
if (!generateFallback) if (!generateFallback)
@ -88,25 +89,44 @@ namespace MobiusEditor.Utility
shapeFile = new Dictionary<int, ShapeFrameData>(); shapeFile = new Dictionary<int, ShapeFrameData>();
} }
tileData[name] = shapeFile; tileData[name] = shapeFile;
// System to fix RA's remapped infantry. Since everything is cached, this only works if the very
// first call to fetch these graphics is guaranteed to pass along the graphics source and remap info.
if (remapTable != null && remapTable.Length >= 0x100)
{
foreach (int key in shapeFile.Keys)
{
ShapeFrameData sfd = shapeFile[key];
Byte[] frameGfx = sfd.FrameData;
for (int i = 0; i < frameGfx.Length; ++i)
{
frameGfx[i] = remapTable[frameGfx[i]];
}
}
}
// Remaps the tile, and takes care of caching it and possibly generating dummies. // Remaps the tile, and takes care of caching it and possibly generating dummies.
tile = this.RemapShapeFile(shapeFile, shape, teamColor, generateFallback); tile = this.RemapShapeFile(shapeFile, shape, teamColor, generateFallback);
} }
return tile != null; return tile != null;
} }
public Boolean GetTeamColorTileData(String name, Int32 shape, ITeamColor teamColor, out Tile tile) public Boolean GetTeamColorTileData(String name, Int32 shape, ITeamColor teamColor, out Tile tile, Boolean generateFallback, Boolean onlyIfDefined)
{ {
return GetTeamColorTileData(name, shape, teamColor, out tile, false, false); return GetTeamColorTileData(name, shape, teamColor, out tile, generateFallback, onlyIfDefined, null, null);
} }
public Boolean GetTileData(String name, Int32 shape, out Tile tile, Boolean generateFallback, Boolean onlyIfDefined) public Boolean GetTileData(String name, Int32 shape, out Tile tile, Boolean generateFallback, Boolean onlyIfDefined)
{ {
return GetTeamColorTileData(name, shape, null, out tile, false, false); return GetTeamColorTileData(name, shape, null, out tile, generateFallback, onlyIfDefined, null, null);
}
public Boolean GetTeamColorTileData(String name, Int32 shape, ITeamColor teamColor, out Tile tile)
{
return GetTeamColorTileData(name, shape, teamColor, out tile, false, false, null, null);
} }
public Boolean GetTileData(String name, Int32 shape, out Tile tile) public Boolean GetTileData(String name, Int32 shape, out Tile tile)
{ {
return GetTeamColorTileData(name, shape, null, out tile, false, false); return GetTeamColorTileData(name, shape, null, out tile, false, false, null, null);
} }
public int GetTileDataLength(string name) public int GetTileDataLength(string name)
@ -117,7 +137,13 @@ namespace MobiusEditor.Utility
} }
if (!this.tileData.TryGetValue(name, out Dictionary<int, ShapeFrameData> shapes)) if (!this.tileData.TryGetValue(name, out Dictionary<int, ShapeFrameData> shapes))
{ {
return -1; // If it's not cached yet, fetch without caching. This avoids issues with the special remap system.
// These ShapeFrameData objects don't need to be disposed since they can't contain Bitmap objects yet.
shapes = GetShapeFile(name);
if (shapes == null)
{
return -1;
}
} }
return shapes.Max(kv => kv.Key) + 1; return shapes.Max(kv => kv.Key) + 1;
} }
@ -125,8 +151,22 @@ namespace MobiusEditor.Utility
private Dictionary<int, ShapeFrameData> GetShapeFile(String name) private Dictionary<int, ShapeFrameData> GetShapeFile(String name)
{ {
bool isShpExt = false; bool isShpExt = false;
Byte[] fileContents = null;
// If it has an extension, force it.
if (Path.HasExtension(name))
{
fileContents = GetFileContents(name);
// Immediately abort; classic file system does not support double extensions.
if (fileContents == null)
{
return null;
}
}
// Try theater extension, then ".shp". // Try theater extension, then ".shp".
Byte[] fileContents = GetFileContents(name + "." + theater.ClassicExtension); if (fileContents == null)
{
fileContents = GetFileContents(name + "." + theater.ClassicExtension);
}
if (fileContents == null) if (fileContents == null)
{ {
isShpExt = true; isShpExt = true;
@ -168,15 +208,7 @@ namespace MobiusEditor.Utility
try try
{ {
// RA map template tileset // RA map template tileset
int width; shpData = ClassicSpriteLoader.GetRaTmpData(fileContents, out widths, out heights);
int height;
shpData = ClassicSpriteLoader.GetRaTmpData(fileContents, out width, out height);
if (shpData != null)
{
int len = shpData.Length;
widths = Enumerable.Repeat(width, len).ToArray();
heights = Enumerable.Repeat(height, len).ToArray();
}
} }
catch (ArgumentException) { /* ignore */ } catch (ArgumentException) { /* ignore */ }
} }
@ -228,10 +260,11 @@ namespace MobiusEditor.Utility
return null; return null;
} }
// Make average-sized dummy. // Make average-sized dummy.
int minWidth = shapeFile.Values.Where(v => v.Width != 0).Min(v => v.Width); bool noValues = shapeFile.Values.Count == 0;
int maxWidth = shapeFile.Values.Where(v => v.Width != 0).Max(v => v.Width); int minWidth = noValues? 24 : shapeFile.Values.Where(v => v.Width != 0).Min(v => v.Width);
int minHeight = shapeFile.Values.Where(v => v.Height != 0).Min(v => v.Height); int maxWidth = noValues? 24 : shapeFile.Values.Where(v => v.Width != 0).Max(v => v.Width);
int maxHeight = shapeFile.Values.Where(v => v.Height != 0).Max(v => v.Height); int minHeight = noValues? 24 : shapeFile.Values.Where(v => v.Height != 0).Min(v => v.Height);
int maxHeight = noValues? 24 : shapeFile.Values.Where(v => v.Height != 0).Max(v => v.Height);
int dummyWidth = minWidth + (maxWidth - minWidth) / 2; int dummyWidth = minWidth + (maxWidth - minWidth) / 2;
int dummyHeight = minHeight + (maxHeight - minHeight) / 2; int dummyHeight = minHeight + (maxHeight - minHeight) / 2;
frameData = GenerateDummy(dummyWidth, dummyHeight); frameData = GenerateDummy(dummyWidth, dummyHeight);
@ -249,9 +282,20 @@ namespace MobiusEditor.Utility
if (teamColor != null && !String.IsNullOrEmpty(teamColorName) && !frameData.IsDummy) if (teamColor != null && !String.IsNullOrEmpty(teamColorName) && !frameData.IsDummy)
{ {
// Finally, the actual remapping! // Finally, the actual remapping!
teamColor.ApplyToImage(data, width, height, 1, width, opaqueBounds); byte[] dataRemap = new byte[data.Length];
Array.Copy(data, 0, dataRemap, 0, data.Length);
teamColor.ApplyToImage(dataRemap, width, height, 1, width, opaqueBounds);
data = dataRemap;
} }
Bitmap bm = ImageUtils.BuildImage(data, width, height, width, PixelFormat.Format8bppIndexed, currentlyLoadedPalette, null); Color[] pal = currentlyLoadedPalette;
if (frameData.IsDummy)
{
// Make gray colour semitransparent on dummy graphics.
pal = new Color[currentlyLoadedPalette.Length];
Array.Copy(currentlyLoadedPalette, 0, pal, 0, pal.Length);
pal[14] = Color.FromArgb(0x80, pal[14]);
}
Bitmap bm = ImageUtils.BuildImage(data, width, height, width, PixelFormat.Format8bppIndexed, pal, null);
tile = new Tile(bm, opaqueBounds); tile = new Tile(bm, opaqueBounds);
frameData.TeamColorTiles.Add(teamColorName, tile); frameData.TeamColorTiles.Add(teamColorName, tile);
return tile; return tile;