diff --git a/CnCTDRAMapEditor/Controls/ObjectProperties.cs b/CnCTDRAMapEditor/Controls/ObjectProperties.cs index 4ab1767..4299ea1 100644 --- a/CnCTDRAMapEditor/Controls/ObjectProperties.cs +++ b/CnCTDRAMapEditor/Controls/ObjectProperties.cs @@ -151,7 +151,6 @@ namespace MobiusEditor.Controls captureUnknownImage = ToolStripRenderer.CreateDisabledImage(captureImage); houseComboBox.DataSource = plugin.Map.Houses.Select(t => new TypeItem(t.Type.Name, t.Type)).ToArray(); missionComboBox.DataSource = plugin.Map.MissionTypes; - UpdateDataSource(); Disposed += (sender, e) => { Object = null; @@ -166,14 +165,22 @@ namespace MobiusEditor.Controls private void UpdateDataSource() { + if (obj == null) + { + return; + } string selected = triggerComboBox.SelectedItem as string; triggerComboBox.DataBindings.Clear(); triggerComboBox.SelectedIndexChanged -= this.TriggerComboBox_SelectedIndexChanged; triggerComboBox.DataSource = null; triggerComboBox.Items.Clear(); string[] items; - Boolean isAircraft = obj is Unit un && un.Type.IsAircraft; - Boolean isOnMap = true; + bool isAircraft = obj is Unit un && un.Type.IsAircraft; + bool isOnMap = true; + if (selected == null && obj is ITechno tch) + { + selected = tch.Trigger; + } switch (obj) { case Infantry infantry: @@ -206,7 +213,6 @@ namespace MobiusEditor.Controls int sel = triggerComboBox.SelectedIndex; triggerComboBox.SelectedIndexChanged += this.TriggerComboBox_SelectedIndexChanged; triggerComboBox.SelectedItem = items[selectIndex]; - TriggerComboBox_SelectedIndexChanged(triggerComboBox, new EventArgs()); if (sel == selectIndex) { TriggerComboBox_SelectedIndexChanged(triggerComboBox, new EventArgs()); diff --git a/CnCTDRAMapEditor/GameInstallationPathForm.Designer.cs b/CnCTDRAMapEditor/GameInstallationPathForm.Designer.cs index bbe8efb..e896385 100644 --- a/CnCTDRAMapEditor/GameInstallationPathForm.Designer.cs +++ b/CnCTDRAMapEditor/GameInstallationPathForm.Designer.cs @@ -12,7 +12,8 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with this program. If not, see . namespace MobiusEditor +// along with this program. If not, see . +namespace MobiusEditor { partial class GameInstallationPathForm { diff --git a/CnCTDRAMapEditor/Model/GameInfo.cs b/CnCTDRAMapEditor/Model/GameInfo.cs index cbe1de3..2e5c2c2 100644 --- a/CnCTDRAMapEditor/Model/GameInfo.cs +++ b/CnCTDRAMapEditor/Model/GameInfo.cs @@ -260,16 +260,16 @@ namespace MobiusEditor.Model public enum ClassicFont { - /// Font used for Waypoints + /// Font used for Waypoints. Waypoints, /// Font used for waypoints with longer names. Separate because it needs a smaller font to fit inside one cell. WaypointsLong, - /// Font used for cell triggers + /// Font used for cell triggers. CellTriggers, - /// Font used for techno triggers, except infantry + /// Font used for techno triggers on multi-cell objects. TechnoTriggers, - /// Font used for infantry techno triggers. Separate because it might need to be smaller. - InfantryTriggers, + /// Font used for one-cell techno triggers. Separate because it might need to be smaller. + TechnoTriggersSmall, /// Font used for rebuild priority numbers on buildings. RebuildPriority, /// Font used for "FAKE" labels on buildings. diff --git a/CnCTDRAMapEditor/RedAlert/GameInfoRedAlert.cs b/CnCTDRAMapEditor/RedAlert/GameInfoRedAlert.cs index 8e90a67..6e6c85d 100644 --- a/CnCTDRAMapEditor/RedAlert/GameInfoRedAlert.cs +++ b/CnCTDRAMapEditor/RedAlert/GameInfoRedAlert.cs @@ -252,7 +252,7 @@ namespace MobiusEditor.RedAlert break; case ClassicFont.WaypointsLong: crop = true; - fontName = "6point.fnt"; + fontName = "editfnt.fnt"; remap = GetClassicFontRemapSimple(fontName, tsmc, trm, textColor, 2, 3); break; case ClassicFont.CellTriggers: @@ -266,14 +266,18 @@ namespace MobiusEditor.RedAlert remap = GetClassicFontRemapSimple(fontName, tsmc, trm, textColor); break; case ClassicFont.TechnoTriggers: - case ClassicFont.InfantryTriggers: + crop = true; + fontName = "editfnt.fnt"; + remap = GetClassicFontRemapSimple(fontName, tsmc, trm, textColor, 2, 3); + break; + case ClassicFont.TechnoTriggersSmall: crop = true; fontName = "3point.fnt"; remap = GetClassicFontRemapSimple(fontName, tsmc, trm, textColor); break; case ClassicFont.FakeLabels: crop = true; - fontName = "6point.fnt"; + fontName = "editfnt.fnt"; remap = GetClassicFontRemapSimple(fontName, tsmc, trm, textColor, 2, 3); break; } diff --git a/CnCTDRAMapEditor/RedAlert/GamePluginRA.cs b/CnCTDRAMapEditor/RedAlert/GamePluginRA.cs index 12b1f2d..0944314 100644 --- a/CnCTDRAMapEditor/RedAlert/GamePluginRA.cs +++ b/CnCTDRAMapEditor/RedAlert/GamePluginRA.cs @@ -2476,7 +2476,7 @@ namespace MobiusEditor.RedAlert modified = true; continue; } - if ((overlayType.IsWall || overlayType.IsSolid) && Map.Technos.ObjectAt(i, out ICellOccupier techno)) + if ((overlayType.IsWall || overlayType.IsSolid) && Map.Buildings.ObjectAt(i, out ICellOccupier techno)) { string desc = overlayType.IsWall ? "Wall" : "Solid overlay"; if (techno is Building building) @@ -2484,21 +2484,6 @@ namespace MobiusEditor.RedAlert errors.Add(string.Format("{0} '{1}' overlaps structure '{2}' at cell {3}; skipping.", desc, overlayType.Name, building.Type.Name, i)); modified = true; } - else if (techno is Terrain terrain) - { - errors.Add(string.Format("{0} '{1}' overlaps terrain '{2}' at cell {3}; skipping.", desc, overlayType.Name, terrain.Type.Name, i)); - modified = true; - } - else if (techno is Unit unit) - { - errors.Add(string.Format("{0} '{1}' overlaps unit '{2}' at cell {3}; skipping.", desc, overlayType.Name, unit.Type.Name, i)); - modified = true; - } - else if (techno is InfantryGroup) - { - errors.Add(string.Format("{0} '{1}' overlaps infantry at cell {2}; skipping.", desc, overlayType.Name, i)); - modified = true; - } else { errors.Add(string.Format("{0} '{1}' overlaps unknown techno in cell {2}; skipping.", desc, overlayType.Name, i)); diff --git a/CnCTDRAMapEditor/Render/MapRenderer.cs b/CnCTDRAMapEditor/Render/MapRenderer.cs index f975a2f..7c1c0f7 100644 --- a/CnCTDRAMapEditor/Render/MapRenderer.cs +++ b/CnCTDRAMapEditor/Render/MapRenderer.cs @@ -2025,16 +2025,16 @@ namespace MobiusEditor.Render public static void RenderAllTechnoTriggers(Graphics graphics, GameInfo gameInfo, OccupierSet mapTechnos, OccupierSet mapBuildings, Rectangle visibleCells, Size tileSize, MapLayerFlag layersToRender, Color color, string toPick, bool excludePick) { - string classicFont = null; - bool cropClassicFont = false; - string classicFontInf = null; - bool cropClassicFontInf = false; - TeamRemap remapClassicFont = null; - TeamRemap remapClassicFontInf = null; + string classicFontLarge = null; + bool cropClassicFontLarge = false; + string classicFontSmall = null; + bool cropClassicFontSmall = false; + TeamRemap remapClassicFontLarge = null; + TeamRemap remapClassicFontSmall = null; if (Globals.TheTilesetManager is TilesetManagerClassic tsmc && Globals.TheTeamColorManager is TeamRemapManager trm) { - classicFont = gameInfo.GetClassicFontInfo(ClassicFont.TechnoTriggers, tsmc, trm, color, out cropClassicFont, out remapClassicFont); - classicFontInf = gameInfo.GetClassicFontInfo(ClassicFont.InfantryTriggers, tsmc, trm, color, out cropClassicFontInf, out remapClassicFontInf); + classicFontLarge = gameInfo.GetClassicFontInfo(ClassicFont.TechnoTriggers, tsmc, trm, color, out cropClassicFontLarge, out remapClassicFontLarge); + classicFontSmall = gameInfo.GetClassicFontInfo(ClassicFont.TechnoTriggersSmall, tsmc, trm, color, out cropClassicFontSmall, out remapClassicFontSmall); } double tileScaleHor = tileSize.Width / 128.0; float borderSize = Math.Max(0.5f, tileSize.Width / 60.0f); @@ -2051,8 +2051,9 @@ namespace MobiusEditor.Render { if (visibleCells.IntersectsWith(new Rectangle(topLeft, terrain.Type.Size))) { - Size size = new Size(terrain.Type.Size.Width * tileSize.Width, terrain.Type.Size.Height * tileSize.Height); - triggers = new (string, Rectangle, int)[] { (terrain.Trigger, new Rectangle(location, size), terrain.IsPreview ? Globals.PreviewAlphaInt : 255) }; + Size size = new Size(terrain.Type.Size.Width * Globals.OriginalTileWidth, terrain.Type.Size.Height * Globals.OriginalTileHeight); + triggers = new (string, Rectangle, int)[] { (terrain.Trigger, new Rectangle(location, size), + terrain.IsPreview ? Globals.PreviewAlphaInt : 256) }; } } } @@ -2062,7 +2063,8 @@ namespace MobiusEditor.Render { if (visibleCells.Contains(topLeft)) { - triggers = new (string, Rectangle, int)[] { (unit.Trigger, new Rectangle(location, tileSize), unit.IsPreview ? Globals.PreviewAlphaInt : 255) }; + triggers = new (string, Rectangle, int)[] { (unit.Trigger, new Rectangle(location, Globals.OriginalTileSize), + unit.IsPreview ? Globals.PreviewAlphaInt : 256) }; } } } @@ -2082,7 +2084,7 @@ namespace MobiusEditor.Render { continue; } - Size size = tileSize; + Size size = Globals.OriginalTileSize; Size offset = Size.Empty; switch ((InfantryStoppingType)i) { @@ -2104,7 +2106,7 @@ namespace MobiusEditor.Render break; } Rectangle bounds = new Rectangle(location + offset, size); - infantryTriggers.Add((infantry.Trigger, bounds, infantry.IsPreview ? Globals.PreviewAlphaInt : 255)); + infantryTriggers.Add((infantry.Trigger, bounds, infantry.IsPreview ? Globals.PreviewAlphaInt : 256)); } triggers = infantryTriggers.ToArray(); } @@ -2126,8 +2128,9 @@ namespace MobiusEditor.Render { if (visibleCells.IntersectsWith(new Rectangle(topLeft, building.Type.Size))) { - Size size = new Size(building.Type.Size.Width * tileSize.Width, building.Type.Size.Height * tileSize.Height); - allTriggers.Add((building.Trigger, new Rectangle(location, size), building.IsPreview ? Globals.PreviewAlphaInt : 255)); + Size size = new Size(building.Type.Size.Width * Globals.OriginalTileWidth, building.Type.Size.Height * Globals.OriginalTileHeight); + allTriggers.Add((building.Trigger, new Rectangle(location, size), + building.IsPreview ? Globals.PreviewAlphaInt : 256)); } } } @@ -2142,19 +2145,56 @@ namespace MobiusEditor.Render || (excludePick && !x.trigger.Equals(toPick, StringComparison.OrdinalIgnoreCase)) || (!excludePick && x.trigger.Equals(toPick, StringComparison.OrdinalIgnoreCase)))) { - Color alphaColor = Color.FromArgb(alpha, color); - using (SolidBrush technoTriggerBackgroundBrush = new SolidBrush(Color.FromArgb(96 * alpha / 256, Color.Black))) - using (SolidBrush technoTriggerBrush = new SolidBrush(alphaColor)) - using (Pen technoTriggerPen = new Pen(alphaColor, borderSize)) - using (Font font = graphics.GetAdjustedFont(trigger, SystemFonts.DefaultFont, bounds.Width, bounds.Height, - Math.Max(1, (int)Math.Round(12 * tileScaleHor)), Math.Max(1, (int)Math.Round(24 * tileScaleHor)), stringFormat, true)) + // Larger than a single cell. + bool isLarge = bounds.Width > Globals.OriginalTileWidth; + string classicFont = isLarge ? classicFontLarge : classicFontSmall; + bool cropClassicFont = isLarge ? cropClassicFontLarge : cropClassicFontSmall; + TeamRemap remapClassicFont = isLarge ? remapClassicFontLarge : remapClassicFontSmall; + Color alphaColor = Color.FromArgb(alpha.Restrict(0,255), color); + if (classicFont == null) { - SizeF textBounds = graphics.MeasureString(trigger, font, bounds.Width, stringFormat); - RectangleF backgroundBounds = new RectangleF(bounds.Location, textBounds); - backgroundBounds.Offset((bounds.Width - textBounds.Width) / 2.0f, (bounds.Height - textBounds.Height) / 2.0f); - graphics.FillRectangle(technoTriggerBackgroundBrush, backgroundBounds); - graphics.DrawRectangle(technoTriggerPen, Rectangle.Round(backgroundBounds)); - graphics.DrawString(trigger, font, technoTriggerBrush, bounds, stringFormat); + int width = bounds.Width * tileSize.Width / Globals.OriginalTileWidth; + int height = bounds.Height * tileSize.Height / Globals.OriginalTileHeight; + Rectangle realBounds = new Rectangle(bounds.Location, new Size(width, height)); + using (SolidBrush technoTriggerBackgroundBrush = new SolidBrush(Color.FromArgb((96 * alpha / 256).Restrict(0, 255), Color.Black))) + using (SolidBrush technoTriggerBrush = new SolidBrush(alphaColor)) + using (Pen technoTriggerPen = new Pen(alphaColor, borderSize)) + using (Font font = graphics.GetAdjustedFont(trigger, SystemFonts.DefaultFont, width, height, + Math.Max(1, (int)Math.Round(12 * tileScaleHor)), Math.Max(1, (int)Math.Round(24 * tileScaleHor)), stringFormat, true)) + { + SizeF textBounds = graphics.MeasureString(trigger, font, width, stringFormat); + RectangleF backgroundBounds = new RectangleF(bounds.Location, textBounds); + backgroundBounds.Offset((width - textBounds.Width) / 2.0f, (height - textBounds.Height) / 2.0f); + graphics.FillRectangle(technoTriggerBackgroundBrush, backgroundBounds); + graphics.DrawRectangle(technoTriggerPen, Rectangle.Round(backgroundBounds)); + graphics.DrawString(trigger, font, technoTriggerBrush, realBounds, stringFormat); + } + } + else + { + int[] indices = Encoding.ASCII.GetBytes(trigger).Select(x => (int)x).ToArray(); + using (SolidBrush technoTriggerBackgroundBrush = new SolidBrush(Color.FromArgb(96, Color.Black))) + using (Pen technoTriggerPen = new Pen(color, 1)) + using (Bitmap txt = RenderTextFromSprite(classicFont, remapClassicFont, Size.Empty, indices, false, cropClassicFont)) + using (Bitmap txt2 = new Bitmap(txt.Width + 4, txt.Height + 4)) + using (ImageAttributes imageAttributes = new ImageAttributes()) + { + txt2.SetResolution(96, 96); + using (Graphics txt2g = Graphics.FromImage(txt2)) + { + txt2g.FillRectangle(technoTriggerBackgroundBrush, new Rectangle(1, 1, txt2.Width - 2, txt2.Height - 2)); + txt2g.DrawRectangle(technoTriggerPen, new Rectangle(0, 0, txt2.Width - 1, txt2.Height - 1)); + txt2g.DrawImage(txt, new Rectangle(2, 2, txt.Width, txt.Height)); + } + imageAttributes.SetColorMatrix(GetColorMatrix(Color.White, 1.0f, alpha / 256.0f)); + int paintOffsX = (bounds.Width - txt2.Width) / 2 * tileSize.Width / Globals.OriginalTileWidth; + int paintOffsY = (bounds.Height - txt2.Height) / 2 * tileSize.Width / Globals.OriginalTileWidth; + int textWidth = txt2.Width * tileSize.Width / Globals.OriginalTileWidth; + int textHeight = txt2.Height * tileSize.Width / Globals.OriginalTileWidth; + Rectangle paintBounds = new Rectangle(bounds.Location, new Size(textWidth, textHeight)); + paintBounds.Offset(new Point(paintOffsX, paintOffsY)); + graphics.DrawImage(txt2, paintBounds, 0, 0, txt2.Width, txt2.Height, GraphicsUnit.Pixel, imageAttributes); + } } } } @@ -2244,7 +2284,6 @@ namespace MobiusEditor.Render Globals.TheShapeCacheManager.AddImage(wpId, wpBm); Rectangle paintRect = new Rectangle(paintBounds.Location.X, paintBounds.Location.Y, wpBm.Width, wpBm.Height); graphics.DrawImage(wpBm, paintRect, 0, 0, wpBm.Width, wpBm.Height, GraphicsUnit.Pixel, imageAttributes); - } } } @@ -2883,12 +2922,13 @@ namespace MobiusEditor.Render } else { + // Solid overlays in the buildings list. isBuilding = building != null; } bool isTechno = techno != null || isBuilding; - // Skip if it's the techno-loop and there's no techno, - // or if it's not the techno-loop and there is a techno (to avoid overlap). - if ((isTechno && !forTechnos) || (!isTechno && forTechnos)) + // Skip if it's a techno-loop and there's no techno, + // or if it's not a techno-loop and there is a techno (to avoid overlap). + if ((forTechnos && !isTechno) || (!forTechnos && isTechno)) { continue; } @@ -3165,9 +3205,12 @@ namespace MobiusEditor.Render int curWidth = 0; if (lineLength == 0 || maxHeight - minTop == 0) { - return new Bitmap(2, 2); + Bitmap bm = new Bitmap(2, 2); + bm.SetResolution(96, 96); + return bm; } Bitmap bitmap = new Bitmap(lineLength, maxHeight - minTop, PixelFormat.Format32bppArgb); + bitmap.SetResolution(96, 96); using (Graphics g = Graphics.FromImage(bitmap)) { for (int i = 0; i < nrOfChars; ++i) diff --git a/CnCTDRAMapEditor/TiberianDawn/GameInfoTibDawn.cs b/CnCTDRAMapEditor/TiberianDawn/GameInfoTibDawn.cs index 16b9335..974d9e0 100644 --- a/CnCTDRAMapEditor/TiberianDawn/GameInfoTibDawn.cs +++ b/CnCTDRAMapEditor/TiberianDawn/GameInfoTibDawn.cs @@ -179,7 +179,11 @@ namespace MobiusEditor.TiberianDawn remap = GetClassicFontRemapSimple(fontName, tsmc, trm, textColor); break; case ClassicFont.TechnoTriggers: - case ClassicFont.InfantryTriggers: + crop = true; + fontName = "scorefnt.fnt"; + remap = GetClassicFontRemapSimple(fontName, tsmc, trm, textColor); + break; + case ClassicFont.TechnoTriggersSmall: crop = true; fontName = "3point.fnt"; remap = GetClassicFontRemapSimple(fontName, tsmc, trm, textColor); diff --git a/CnCTDRAMapEditor/TiberianDawn/GamePluginTD.cs b/CnCTDRAMapEditor/TiberianDawn/GamePluginTD.cs index 5ba4f39..005c39a 100644 --- a/CnCTDRAMapEditor/TiberianDawn/GamePluginTD.cs +++ b/CnCTDRAMapEditor/TiberianDawn/GamePluginTD.cs @@ -2117,7 +2117,7 @@ namespace MobiusEditor.TiberianDawn modified = true; continue; } - if ((overlayType.IsWall || overlayType.IsSolid) && Map.Technos.ObjectAt(cell, out ICellOccupier techno)) + if ((overlayType.IsWall || overlayType.IsSolid) && Map.Buildings.ObjectAt(cell, out ICellOccupier techno)) { string desc = overlayType.IsWall ? "Wall" : "Solid overlay"; if (techno is Building building) @@ -2125,19 +2125,9 @@ namespace MobiusEditor.TiberianDawn errors.Add(string.Format("{0} '{1}' overlaps structure '{2}' at cell {3}; skipping.", desc, overlayType.Name, building.Type.Name, cell)); modified = true; } - else if (techno is Terrain terrain) + else if (techno is Overlay ovl) { - errors.Add(string.Format("{0} '{1}' overlaps terrain '{2}' at cell {3}; skipping.", desc, overlayType.Name, terrain.Type.Name, cell)); - modified = true; - } - else if (techno is Unit unit) - { - errors.Add(string.Format("{0} '{1}' overlaps unit '{2}' at cell {3}; skipping.", desc, overlayType.Name, unit.Type.Name, cell)); - modified = true; - } - else if (techno is InfantryGroup) - { - errors.Add(string.Format("{0} '{1}' overlaps infantry at cell {2}; skipping.", desc, overlayType.Name, cell)); + errors.Add(string.Format("{0} '{1}' overlaps overlay '{2}' at cell {3}; skipping.", desc, overlayType.Name, ovl.Type.Name, cell)); modified = true; } else