custom ini content support, encoding stuff and celltriggers preview.
This commit is contained in:
parent
ad7f86843d
commit
9fb1d69ac0
@ -365,14 +365,17 @@ Released on 14 Nov 2022 at 22:25 GMT
|
|||||||
--Unreleased--
|
--Unreleased--
|
||||||
|
|
||||||
* Added igloos (haystacks) to the Overlay in Sole Survivor's Winter theater.
|
* Added igloos (haystacks) to the Overlay in Sole Survivor's Winter theater.
|
||||||
* Fixed refresh bug where a ghost image of the label indicating a heavy operation remained while repainting the map. The label is now only removed after the repaint.
|
* Fixed refresh bug where a ghost image of the label indicating a heavy operation remained while repainting the map. The label is now only removed after the following map repaint.
|
||||||
* Fixed issues with the editor not loading old missions with DOS special characters in them. Specific ini sections are now loaded and saved in specific text encodings; the maps are normally DOS-437, but its remaster-specific content supports UTF-8.
|
* Fixed issues with the editor not loading old missions with DOS special characters in them. Specific ini sections are now loaded and saved in specific text encodings; the maps are normally DOS-437, but their remaster-specific contents support UTF-8.
|
||||||
* Fixed an issue with TD triggers not linking to teamtypes if the teamtype reference has case differences compared to the actual Teamtype name.
|
* Fixed an issue with TD triggers not linking to teamtypes if the teamtype reference has case differences compared to the actual Teamtype name.
|
||||||
* Added turrets to RA ships, and rotors to helicopters.
|
* Added turrets to RA ships, and rotors to helicopters.
|
||||||
* When air units are enabled to be placed down, this no longer excludes winged airplanes.
|
* When air units are enabled to be placed down, this no longer excludes winged airplanes. They'll just fly off the map, but that could be used for its cinematic effect in missions.
|
||||||
* Added the ability to open .pgm archives, to easily check the contents of packed workshop maps. Export to this format is not supported, though.
|
* Added the ability to open .pgm archives, to easily check the contents of packed workshop maps. Export to this format is not supported, though.
|
||||||
* Restored some of the "useless" orders possible to set on preplaced units; it turns out "Unload" on air units is the only order that makes them land on the intended spot.
|
* Restored some of the "useless" orders possible to set on preplaced units; it turns out "Unload" on air units is the only order that makes them land on the intended spot.
|
||||||
* The drawing order of overlapping objects is now based on the center of the graphics, rather than the bottom, which means buildings or trees will no longer overlap objects placed on their lower but unoccupied cells.
|
* The drawing order of overlapping objects is now based on the center of the graphics, rather than the bottom, which means buildings or trees will no longer overlap objects placed on their lower but unoccupied cells.
|
||||||
* Repair Facilities are now treated as flat buildings, meaning they won't overlap things placed on their top cells.
|
* Repair Facilities are now treated as flat buildings, meaning they won't overlap things placed on their top cells.
|
||||||
* Increased the size of waypoint labels.
|
* Increased the size of waypoint labels.
|
||||||
* When holding the mouse over a bib, the status bar will now also show if it is attached to a building.
|
* When holding the mouse over a bib, the status bar will now also show if it is attached to a building.
|
||||||
|
* The "Rules" section in the map settings has been renamed to "INI Rules & Tweaks", and is now also available for TD.
|
||||||
|
* Custom ini keys that are added to the [Basic] and [Map] sections, and to any of the House sections, are now preserved, and editable in the "INI Rules & Tweaks" section. This will allow passive support for modded features.
|
||||||
|
* Added a preview mode to Celltriggers.
|
||||||
|
@ -581,6 +581,7 @@
|
|||||||
<Compile Include="Utility\GeneralUtils.cs" />
|
<Compile Include="Utility\GeneralUtils.cs" />
|
||||||
<Compile Include="Utility\GenericBooleanTypeConverter.cs" />
|
<Compile Include="Utility\GenericBooleanTypeConverter.cs" />
|
||||||
<Compile Include="Utility\INI.cs" />
|
<Compile Include="Utility\INI.cs" />
|
||||||
|
<Compile Include="Utility\INITools.cs" />
|
||||||
<Compile Include="Utility\Keyboard.cs" />
|
<Compile Include="Utility\Keyboard.cs" />
|
||||||
<Compile Include="Utility\ListItem.cs" />
|
<Compile Include="Utility\ListItem.cs" />
|
||||||
<Compile Include="Utility\Megafile.cs" />
|
<Compile Include="Utility\Megafile.cs" />
|
||||||
|
@ -30,15 +30,17 @@ namespace MobiusEditor.Controls
|
|||||||
playerComboBox.DataSource = plugin.Map.Houses.Select(h => h.Type.Name).ToArray();
|
playerComboBox.DataSource = plugin.Map.Houses.Select(h => h.Type.Name).ToArray();
|
||||||
baseComboBox.DataSource = plugin.Map.Houses.Select(h => h.Type.Name).ToArray();
|
baseComboBox.DataSource = plugin.Map.Houses.Select(h => h.Type.Name).ToArray();
|
||||||
var themeData = plugin.Map.ThemeTypes.ToList();
|
var themeData = plugin.Map.ThemeTypes.ToList();
|
||||||
|
string noTheme = plugin.Map.ThemeEmpty;
|
||||||
themeData.Sort(new ExplorerComparer());
|
themeData.Sort(new ExplorerComparer());
|
||||||
themeData.RemoveAll(v => "No Theme".Equals(v, StringComparison.InvariantCultureIgnoreCase));
|
themeData.RemoveAll(v => noTheme.Equals(v, StringComparison.OrdinalIgnoreCase));
|
||||||
themeData.Insert(0, "No Theme");
|
themeData.Insert(0, noTheme);
|
||||||
themeComboBox.DataSource = themeData;
|
themeComboBox.DataSource = themeData;
|
||||||
// No need for matching to index here; [Basic] saves it by name, not index.
|
// No need for matching to index here; [Basic] saves it by name, not index.
|
||||||
var movData = plugin.Map.MovieTypes.ToList();
|
var movData = plugin.Map.MovieTypes.ToList();
|
||||||
|
string noMovie = plugin.Map.MovieEmpty;
|
||||||
movData.Sort(new ExplorerComparer());
|
movData.Sort(new ExplorerComparer());
|
||||||
movData.RemoveAll(v => "x".Equals(v, StringComparison.InvariantCultureIgnoreCase));
|
movData.RemoveAll(v => noMovie.Equals(v, StringComparison.OrdinalIgnoreCase));
|
||||||
movData.Insert(0, "x");
|
movData.Insert(0, noMovie);
|
||||||
introComboBox.DataSource = movData.ToArray();
|
introComboBox.DataSource = movData.ToArray();
|
||||||
briefComboBox.DataSource = movData.ToArray();
|
briefComboBox.DataSource = movData.ToArray();
|
||||||
actionComboBox.DataSource = movData.ToArray();
|
actionComboBox.DataSource = movData.ToArray();
|
||||||
|
@ -132,7 +132,7 @@ namespace MobiusEditor.Controls
|
|||||||
}
|
}
|
||||||
HashSet<string> allowedTriggers = new HashSet<string>(items);
|
HashSet<string> allowedTriggers = new HashSet<string>(items);
|
||||||
items = Trigger.None.Yield().Concat(Plugin.Map.Triggers.Select(t => t.Name).Where(t => allowedTriggers.Contains(t)).Distinct()).ToArray();
|
items = Trigger.None.Yield().Concat(Plugin.Map.Triggers.Select(t => t.Name).Where(t => allowedTriggers.Contains(t)).Distinct()).ToArray();
|
||||||
int selectIndex = selected == null ? 0 : Enumerable.Range(0, items.Length).FirstOrDefault(x => String.Equals(items[x], selected, StringComparison.InvariantCultureIgnoreCase));
|
int selectIndex = selected == null ? 0 : Enumerable.Range(0, items.Length).FirstOrDefault(x => String.Equals(items[x], selected, StringComparison.OrdinalIgnoreCase));
|
||||||
triggerComboBox.DataSource = items;
|
triggerComboBox.DataSource = items;
|
||||||
triggerComboBox.Enabled = !isAircraft && isOnMap;
|
triggerComboBox.Enabled = !isAircraft && isOnMap;
|
||||||
triggerToolTip = Map.MakeAllowedTriggersToolTip(filteredEvents, filteredActions);
|
triggerToolTip = Map.MakeAllowedTriggersToolTip(filteredEvents, filteredActions);
|
||||||
|
82
CnCTDRAMapEditor/Controls/RulesSettings.Designer.cs
generated
82
CnCTDRAMapEditor/Controls/RulesSettings.Designer.cs
generated
@ -43,43 +43,20 @@ namespace MobiusEditor.Controls
|
|||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RulesSettings));
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RulesSettings));
|
||||||
this.txtRules = new System.Windows.Forms.TextBox();
|
|
||||||
this.lblRules = new System.Windows.Forms.Label();
|
|
||||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||||
this.lblTextEncoding = new System.Windows.Forms.Label();
|
this.lblRaRules = new System.Windows.Forms.Label();
|
||||||
|
this.txtRules = new System.Windows.Forms.TextBox();
|
||||||
|
this.lblDosContent = new System.Windows.Forms.Label();
|
||||||
this.tableLayoutPanel1.SuspendLayout();
|
this.tableLayoutPanel1.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
// txtRules
|
|
||||||
//
|
|
||||||
this.txtRules.Dock = System.Windows.Forms.DockStyle.Fill;
|
|
||||||
this.txtRules.Location = new System.Drawing.Point(2, 97);
|
|
||||||
this.txtRules.Margin = new System.Windows.Forms.Padding(2);
|
|
||||||
this.txtRules.Multiline = true;
|
|
||||||
this.txtRules.Name = "txtRules";
|
|
||||||
this.txtRules.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
|
||||||
this.txtRules.Size = new System.Drawing.Size(396, 325);
|
|
||||||
this.txtRules.TabIndex = 1;
|
|
||||||
this.txtRules.Leave += new System.EventHandler(this.txtRules_Leave);
|
|
||||||
//
|
|
||||||
// lblRules
|
|
||||||
//
|
|
||||||
this.lblRules.AutoSize = true;
|
|
||||||
this.lblRules.Dock = System.Windows.Forms.DockStyle.Fill;
|
|
||||||
this.lblRules.Location = new System.Drawing.Point(3, 0);
|
|
||||||
this.lblRules.Name = "lblRules";
|
|
||||||
this.lblRules.Padding = new System.Windows.Forms.Padding(0, 0, 0, 2);
|
|
||||||
this.lblRules.Size = new System.Drawing.Size(394, 67);
|
|
||||||
this.lblRules.TabIndex = 0;
|
|
||||||
this.lblRules.Text = resources.GetString("lblRules.Text");
|
|
||||||
//
|
|
||||||
// tableLayoutPanel1
|
// tableLayoutPanel1
|
||||||
//
|
//
|
||||||
this.tableLayoutPanel1.ColumnCount = 1;
|
this.tableLayoutPanel1.ColumnCount = 1;
|
||||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||||
this.tableLayoutPanel1.Controls.Add(this.lblRules, 0, 0);
|
this.tableLayoutPanel1.Controls.Add(this.lblRaRules, 0, 1);
|
||||||
this.tableLayoutPanel1.Controls.Add(this.txtRules, 0, 2);
|
this.tableLayoutPanel1.Controls.Add(this.txtRules, 0, 2);
|
||||||
this.tableLayoutPanel1.Controls.Add(this.lblTextEncoding, 0, 1);
|
this.tableLayoutPanel1.Controls.Add(this.lblDosContent, 0, 0);
|
||||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||||
@ -87,19 +64,44 @@ namespace MobiusEditor.Controls
|
|||||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||||
|
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(400, 424);
|
this.tableLayoutPanel1.Size = new System.Drawing.Size(400, 424);
|
||||||
this.tableLayoutPanel1.TabIndex = 2;
|
this.tableLayoutPanel1.TabIndex = 2;
|
||||||
//
|
//
|
||||||
// lblTextEncoding
|
// lblRaRules
|
||||||
//
|
//
|
||||||
this.lblTextEncoding.AutoSize = true;
|
this.lblRaRules.AutoSize = true;
|
||||||
this.lblTextEncoding.Location = new System.Drawing.Point(3, 67);
|
this.lblRaRules.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
this.lblTextEncoding.Name = "lblTextEncoding";
|
this.lblRaRules.Location = new System.Drawing.Point(3, 67);
|
||||||
this.lblTextEncoding.Padding = new System.Windows.Forms.Padding(0, 0, 0, 2);
|
this.lblRaRules.Name = "lblRaRules";
|
||||||
this.lblTextEncoding.Size = new System.Drawing.Size(378, 28);
|
this.lblRaRules.Padding = new System.Windows.Forms.Padding(0, 0, 0, 2);
|
||||||
this.lblTextEncoding.TabIndex = 2;
|
this.lblRaRules.Size = new System.Drawing.Size(394, 15);
|
||||||
this.lblTextEncoding.Text = "Note that all text here is treated as DOS content, meaning it will be loaded and " +
|
this.lblRaRules.TabIndex = 0;
|
||||||
"saved using DOS-437 text encoding.";
|
this.lblRaRules.Text = "Rule changes concerning bibs, power and silo storage will be applied in the edito" +
|
||||||
|
"r.";
|
||||||
|
//
|
||||||
|
// txtRules
|
||||||
|
//
|
||||||
|
this.txtRules.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.txtRules.Location = new System.Drawing.Point(2, 84);
|
||||||
|
this.txtRules.Margin = new System.Windows.Forms.Padding(2);
|
||||||
|
this.txtRules.Multiline = true;
|
||||||
|
this.txtRules.Name = "txtRules";
|
||||||
|
this.txtRules.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||||
|
this.txtRules.Size = new System.Drawing.Size(396, 338);
|
||||||
|
this.txtRules.TabIndex = 1;
|
||||||
|
this.txtRules.Leave += new System.EventHandler(this.txtRules_Leave);
|
||||||
|
//
|
||||||
|
// lblDosContent
|
||||||
|
//
|
||||||
|
this.lblDosContent.AutoSize = true;
|
||||||
|
this.lblDosContent.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.lblDosContent.Location = new System.Drawing.Point(3, 0);
|
||||||
|
this.lblDosContent.Name = "lblDosContent";
|
||||||
|
this.lblDosContent.Padding = new System.Windows.Forms.Padding(0, 0, 0, 2);
|
||||||
|
this.lblDosContent.Size = new System.Drawing.Size(394, 67);
|
||||||
|
this.lblDosContent.TabIndex = 2;
|
||||||
|
this.lblDosContent.Text = resources.GetString("lblDosContent.Text");
|
||||||
//
|
//
|
||||||
// RulesSettings
|
// RulesSettings
|
||||||
//
|
//
|
||||||
@ -116,9 +118,9 @@ namespace MobiusEditor.Controls
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
private System.Windows.Forms.TextBox txtRules;
|
|
||||||
private System.Windows.Forms.Label lblRules;
|
|
||||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||||
private System.Windows.Forms.Label lblTextEncoding;
|
private System.Windows.Forms.Label lblDosContent;
|
||||||
|
private System.Windows.Forms.Label lblRaRules;
|
||||||
|
private System.Windows.Forms.TextBox txtRules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ namespace MobiusEditor.Controls
|
|||||||
txtRules.Text = iniText;
|
txtRules.Text = iniText;
|
||||||
if (!showRulesWarning)
|
if (!showRulesWarning)
|
||||||
{
|
{
|
||||||
lblRules.Visible = false;
|
lblRaRules.Visible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="lblRules.Text" xml:space="preserve">
|
<data name="lblDosContent.Text" xml:space="preserve">
|
||||||
<value>The text below shows all INI sections not managed by the editor. Add any rule changes you need. Sections managed by the editor ([Basic], [Units], [Trigs] etc.) will be ignored. Rule changes will be applied in the editor. [Aftermath] can be added, but its "NewUnitsEnabled" option is managed by the editor (in "Basic") and will be ignored here.</value>
|
<value>The text below shows all INI content not managed by the editor. Sections that contain lists of data, like units, triggers, waypoints etc will be ignored when added here, as will any specific ini keys managed by the editor. Note that this text is treated as DOS content; special characters will be loaded and saved using DOS-437 text encoding.</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
@ -93,7 +93,7 @@ namespace MobiusEditor.Controls
|
|||||||
string[] filteredActions = Plugin.Map.ActionTypes.Where(ev => Plugin.Map.TerrainActionTypes.Contains(ev)).Distinct().ToArray();
|
string[] filteredActions = Plugin.Map.ActionTypes.Where(ev => Plugin.Map.TerrainActionTypes.Contains(ev)).Distinct().ToArray();
|
||||||
HashSet<string> allowedTriggers = new HashSet<string>(items);
|
HashSet<string> allowedTriggers = new HashSet<string>(items);
|
||||||
items = Trigger.None.Yield().Concat(Plugin.Map.Triggers.Select(t => t.Name).Where(t => allowedTriggers.Contains(t)).Distinct()).ToArray();
|
items = Trigger.None.Yield().Concat(Plugin.Map.Triggers.Select(t => t.Name).Where(t => allowedTriggers.Contains(t)).Distinct()).ToArray();
|
||||||
int selectIndex = selected == null ? 0 : Enumerable.Range(0, items.Length).FirstOrDefault(x => String.Equals(items[x], selected, StringComparison.InvariantCultureIgnoreCase));
|
int selectIndex = selected == null ? 0 : Enumerable.Range(0, items.Length).FirstOrDefault(x => String.Equals(items[x], selected, StringComparison.OrdinalIgnoreCase));
|
||||||
triggerComboBox.DataSource = items;
|
triggerComboBox.DataSource = items;
|
||||||
triggerComboBox.SelectedIndex = selectIndex;
|
triggerComboBox.SelectedIndex = selectIndex;
|
||||||
triggerToolTip = Map.MakeAllowedTriggersToolTip(filteredEvents, filteredActions);
|
triggerToolTip = Map.MakeAllowedTriggersToolTip(filteredEvents, filteredActions);
|
||||||
|
@ -24,6 +24,7 @@ using System.Drawing;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace MobiusEditor.Dialogs
|
namespace MobiusEditor.Dialogs
|
||||||
@ -108,7 +109,7 @@ namespace MobiusEditor.Dialogs
|
|||||||
{
|
{
|
||||||
settingsTreeView.Nodes.Add("CRATES", "Crates");
|
settingsTreeView.Nodes.Add("CRATES", "Crates");
|
||||||
}
|
}
|
||||||
settingsTreeView.Nodes.Add("RULES", this.plugin.GameType == GameType.RedAlert ? "Rules" : "Unmanaged INI");
|
settingsTreeView.Nodes.Add("RULES", "INI Rules && Tweaks");
|
||||||
if (this.plugin.GameType != GameType.SoleSurvivor)
|
if (this.plugin.GameType != GameType.SoleSurvivor)
|
||||||
{
|
{
|
||||||
settingsTreeView.Nodes.Add("BRIEFING", "Briefing");
|
settingsTreeView.Nodes.Add("BRIEFING", "Briefing");
|
||||||
@ -317,8 +318,16 @@ namespace MobiusEditor.Dialogs
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check if RA rules were changed.
|
// Combine diacritics into their characters, and remove characters not included in DOS-437.
|
||||||
bool rulesChanged = plugin.GameType == GameType.RedAlert && !(this.ExtraIniText ?? String.Empty).Equals(originalExtraIniText);
|
string normalised = (this.ExtraIniText ?? String.Empty).Normalize(NormalizationForm.FormC);
|
||||||
|
Encoding dos437 = Encoding.GetEncoding(437);
|
||||||
|
// DOS chars excluding specials at the start and end. Explicitly add tab, then the normal range from 32 to 254.
|
||||||
|
HashSet<Char> dos437chars = String.Concat("\t".Yield().Concat(Enumerable.Range(32, 256 - 32 - 1).Select(i => dos437.GetString(new Byte[] { (byte)i })))).ToHashSet();
|
||||||
|
normalised = new String(normalised.Where(ch => dos437chars.Contains(ch)).ToArray());
|
||||||
|
// Check if RA rules were changed. Ignore trivial line changes. This will not detect any irrelevant but non-trivial changes like swapping lines, though.
|
||||||
|
String checkTextNew = Regex.Replace(normalised, "[\\r\\n]+", "\n").Trim('\n');
|
||||||
|
String checkTextOrig = Regex.Replace(originalExtraIniText ?? String.Empty, "[\\r\\n]+", "\n").Trim('\n');
|
||||||
|
bool rulesChanged = plugin.GameType == GameType.RedAlert && !checkTextOrig.Equals(checkTextNew, StringComparison.OrdinalIgnoreCase);
|
||||||
// Check if RA expansion units were disabled.
|
// Check if RA expansion units were disabled.
|
||||||
bool expansionWarn = plugin.GameType == GameType.RedAlert && expansionWasEnabled
|
bool expansionWarn = plugin.GameType == GameType.RedAlert && expansionWasEnabled
|
||||||
&& basicSettingsTracker.TryGetMember("ExpansionEnabled", out object res) && (res is bool expOn) && !expOn;
|
&& basicSettingsTracker.TryGetMember("ExpansionEnabled", out object res) && (res is bool expOn) && !expOn;
|
||||||
|
@ -317,7 +317,7 @@ namespace MobiusEditor.Dialogs
|
|||||||
}
|
}
|
||||||
if (hasChanges)
|
if (hasChanges)
|
||||||
{
|
{
|
||||||
DialogResult dr = MessageBox.Show("Teams have been changed! Are you sure you want to cancel?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
DialogResult dr = MessageBox.Show(this, "Teams have been changed! Are you sure you want to cancel?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||||
if (dr == DialogResult.Yes)
|
if (dr == DialogResult.Yes)
|
||||||
return;
|
return;
|
||||||
this.DialogResult = DialogResult.None;
|
this.DialogResult = DialogResult.None;
|
||||||
@ -499,22 +499,22 @@ namespace MobiusEditor.Dialogs
|
|||||||
else if (curName.Length > maxLength)
|
else if (curName.Length > maxLength)
|
||||||
{
|
{
|
||||||
e.CancelEdit = true;
|
e.CancelEdit = true;
|
||||||
MessageBox.Show(string.Format("Team name is longer than {0} characters.", maxLength), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show(this, string.Format("Team name is longer than {0} characters.", maxLength), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
else if (TeamType.None.Equals(curName, StringComparison.InvariantCultureIgnoreCase))
|
else if (TeamType.IsEmpty(curName))
|
||||||
{
|
{
|
||||||
e.CancelEdit = true;
|
e.CancelEdit = true;
|
||||||
MessageBox.Show(string.Format("Team name 'None' is reserved and cannot be used."), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show(this, string.Format("Team name '{0}' is reserved and cannot be used.", TeamType.None), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
else if (!INIHelpers.IsValidKey(curName))
|
else if (!INITools.IsValidKey(curName))
|
||||||
{
|
{
|
||||||
e.CancelEdit = true;
|
e.CancelEdit = true;
|
||||||
MessageBox.Show(string.Format("Team name '{0}' contains illegal characters. This format only supports simple ASCII, and cannot contain '=', '[' or ']'.", curName), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show(this, string.Format("Team name '{0}' contains illegal characters. This format only supports simple ASCII, and cannot contain '=', '[' or ']'.", curName.ToUpperInvariant()), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
else if (teamTypes.Where(t => (t != SelectedTeamType) && t.Name.Equals(curName, StringComparison.InvariantCultureIgnoreCase)).Any())
|
else if (teamTypes.Where(t => (t != SelectedTeamType) && t.Name.Equals(curName, StringComparison.OrdinalIgnoreCase)).Any())
|
||||||
{
|
{
|
||||||
e.CancelEdit = true;
|
e.CancelEdit = true;
|
||||||
MessageBox.Show(string.Format("Team with name '{0}' already exists.", curName.ToUpperInvariant()), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show(this, string.Format("Team with name '{0}' already exists.", curName.ToUpperInvariant()), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -274,7 +274,7 @@ namespace MobiusEditor.Dialogs
|
|||||||
}
|
}
|
||||||
if (hasChanges)
|
if (hasChanges)
|
||||||
{
|
{
|
||||||
DialogResult dr = MessageBox.Show("Triggers have been changed! Are you sure you want to cancel?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
DialogResult dr = MessageBox.Show(this, "Triggers have been changed! Are you sure you want to cancel?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||||
if (dr == DialogResult.Yes)
|
if (dr == DialogResult.Yes)
|
||||||
return;
|
return;
|
||||||
this.DialogResult = DialogResult.None;
|
this.DialogResult = DialogResult.None;
|
||||||
@ -443,22 +443,22 @@ namespace MobiusEditor.Dialogs
|
|||||||
else if (curName.Length > maxLength)
|
else if (curName.Length > maxLength)
|
||||||
{
|
{
|
||||||
e.CancelEdit = true;
|
e.CancelEdit = true;
|
||||||
MessageBox.Show(string.Format("Trigger name is longer than {0} characters.", maxLength), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show(this, string.Format("Trigger name is longer than {0} characters.", maxLength), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
else if (Trigger.IsEmpty(curName))
|
else if (Trigger.IsEmpty(curName))
|
||||||
{
|
{
|
||||||
e.CancelEdit = true;
|
e.CancelEdit = true;
|
||||||
MessageBox.Show(string.Format("Trigger name 'None' is reserved and cannot be used."), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show(this, string.Format("Trigger name '{0}' is reserved and cannot be used.", Trigger.None), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
else if (!INIHelpers.IsValidKey(curName))
|
else if (!INITools.IsValidKey(curName))
|
||||||
{
|
{
|
||||||
e.CancelEdit = true;
|
e.CancelEdit = true;
|
||||||
MessageBox.Show(string.Format("Trigger name '{0}' contains illegal characters. This format only supports simple ASCII, and cannot contain '=', '[' or ']'.", curName), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show(this, string.Format("Trigger name '{0}' contains illegal characters. This format only supports simple ASCII, and cannot contain '=', '[' or ']'.", curName), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
else if (triggers.Where(t => (t != SelectedTrigger) && t.Name.Equals(curName, StringComparison.InvariantCultureIgnoreCase)).Any())
|
else if (triggers.Where(t => (t != SelectedTrigger) && t.Name.Equals(curName, StringComparison.OrdinalIgnoreCase)).Any())
|
||||||
{
|
{
|
||||||
e.CancelEdit = true;
|
e.CancelEdit = true;
|
||||||
MessageBox.Show(string.Format("Trigger with name '{0}' already exists.", curName.ToUpperInvariant()), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show(this, string.Format("Trigger with name '{0}' already exists.", curName.ToUpperInvariant()), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -830,8 +830,9 @@ namespace MobiusEditor.Dialogs
|
|||||||
actionValueComboBox.Visible = true;
|
actionValueComboBox.Visible = true;
|
||||||
actionValueComboBox.DisplayMember = "Label";
|
actionValueComboBox.DisplayMember = "Label";
|
||||||
actionValueComboBox.ValueMember = "Value";
|
actionValueComboBox.ValueMember = "Value";
|
||||||
|
ExplorerComparer sorter = new ExplorerComparer();
|
||||||
// First video is the "None" entry; expose as -1.
|
// First video is the "None" entry; expose as -1.
|
||||||
var movData = plugin.Map.MovieTypes.Select((t, i) => new ListItem<long>(i - 1, t)).OrderBy(t => t.Label, new ExplorerComparer()).ToList();
|
var movData = plugin.Map.MovieTypes.Select((t, i) => new ListItem<long>(i - 1, t)).OrderBy(t => t.Label, sorter).ToList();
|
||||||
var movDefItem = movData.Where(t => t.Value == -1).FirstOrDefault();
|
var movDefItem = movData.Where(t => t.Value == -1).FirstOrDefault();
|
||||||
if (movDefItem != null)
|
if (movDefItem != null)
|
||||||
{
|
{
|
||||||
@ -848,7 +849,7 @@ namespace MobiusEditor.Dialogs
|
|||||||
actionValueComboBox.ValueMember = "Value";
|
actionValueComboBox.ValueMember = "Value";
|
||||||
var vocData = new ListItem<long>(-1, "None").Yield().Concat(
|
var vocData = new ListItem<long>(-1, "None").Yield().Concat(
|
||||||
RedAlert.ActionDataTypes.VocDesc.Select((t, i) => new ListItem<long>(i, t + " (" + RedAlert.ActionDataTypes.VocNames[i] + ")"))
|
RedAlert.ActionDataTypes.VocDesc.Select((t, i) => new ListItem<long>(i, t + " (" + RedAlert.ActionDataTypes.VocNames[i] + ")"))
|
||||||
.Where(t => !String.Equals(RedAlert.ActionDataTypes.VocNames[t.Value], "x", StringComparison.InvariantCultureIgnoreCase))).ToArray();
|
.Where(t => !String.Equals(RedAlert.ActionDataTypes.VocNames[t.Value], "x", StringComparison.OrdinalIgnoreCase))).ToArray();
|
||||||
actionValueComboBox.DataSource = vocData;
|
actionValueComboBox.DataSource = vocData;
|
||||||
actionValueComboBox.DataBindings.Add("SelectedValue", triggerAction, "Data");
|
actionValueComboBox.DataBindings.Add("SelectedValue", triggerAction, "Data");
|
||||||
actionValueComboBox.SelectedValue = ListItem.CheckInList(data, vocData);
|
actionValueComboBox.SelectedValue = ListItem.CheckInList(data, vocData);
|
||||||
@ -859,7 +860,7 @@ namespace MobiusEditor.Dialogs
|
|||||||
actionValueComboBox.ValueMember = "Value";
|
actionValueComboBox.ValueMember = "Value";
|
||||||
var voxData = new ListItem<long>(-1, "None").Yield().Concat(
|
var voxData = new ListItem<long>(-1, "None").Yield().Concat(
|
||||||
RedAlert.ActionDataTypes.VoxDesc.Select((t, i) => new ListItem<long>(i, t + " (" + RedAlert.ActionDataTypes.VoxNames[i] + ")"))
|
RedAlert.ActionDataTypes.VoxDesc.Select((t, i) => new ListItem<long>(i, t + " (" + RedAlert.ActionDataTypes.VoxNames[i] + ")"))
|
||||||
.Where(t => !String.Equals(RedAlert.ActionDataTypes.VoxNames[t.Value], "none", StringComparison.InvariantCultureIgnoreCase))).ToArray();
|
.Where(t => !String.Equals(RedAlert.ActionDataTypes.VoxNames[t.Value], "none", StringComparison.OrdinalIgnoreCase))).ToArray();
|
||||||
actionValueComboBox.DataSource = voxData;
|
actionValueComboBox.DataSource = voxData;
|
||||||
actionValueComboBox.DataBindings.Add("SelectedValue", triggerAction, "Data");
|
actionValueComboBox.DataBindings.Add("SelectedValue", triggerAction, "Data");
|
||||||
actionValueComboBox.SelectedValue = ListItem.CheckInList(data, voxData);
|
actionValueComboBox.SelectedValue = ListItem.CheckInList(data, voxData);
|
||||||
@ -918,7 +919,7 @@ namespace MobiusEditor.Dialogs
|
|||||||
{
|
{
|
||||||
if (Trigger.CheckForChanges(triggers, backupTriggers))
|
if (Trigger.CheckForChanges(triggers, backupTriggers))
|
||||||
{
|
{
|
||||||
DialogResult dr = MessageBox.Show("Warning! There are changes in the triggers. This function works best if the triggers match the state of the currently edited map. Are you sure you want to continue?", "Triggers check", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
DialogResult dr = MessageBox.Show(this, "Warning! There are changes in the triggers. This function works best if the triggers match the state of the currently edited map. Are you sure you want to continue?", "Triggers check", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||||
if (dr == DialogResult.No)
|
if (dr == DialogResult.No)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -927,7 +928,7 @@ namespace MobiusEditor.Dialogs
|
|||||||
string[] errors = plugin.CheckTriggers(this.triggers, true, false, false, out _, false, out _)?.ToArray();
|
string[] errors = plugin.CheckTriggers(this.triggers, true, false, false, out _, false, out _)?.ToArray();
|
||||||
if (errors == null || errors.Length == 0)
|
if (errors == null || errors.Length == 0)
|
||||||
{
|
{
|
||||||
MessageBox.Show("No issues were encountered.", "Triggers check", MessageBoxButtons.OK);
|
MessageBox.Show(this, "No issues were encountered.", "Triggers check", MessageBoxButtons.OK);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
using (ErrorMessageBox emb = new ErrorMessageBox())
|
using (ErrorMessageBox emb = new ErrorMessageBox())
|
||||||
|
@ -30,6 +30,7 @@ using System.Linq;
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using static MobiusEditor.Utility.SimpleMultiThreading;
|
using static MobiusEditor.Utility.SimpleMultiThreading;
|
||||||
|
|
||||||
@ -526,11 +527,13 @@ namespace MobiusEditor
|
|||||||
PropertyTracker<BasicSection> basicSettings = new PropertyTracker<BasicSection>(plugin.Map.BasicSection);
|
PropertyTracker<BasicSection> basicSettings = new PropertyTracker<BasicSection>(plugin.Map.BasicSection);
|
||||||
PropertyTracker<BriefingSection> briefingSettings = new PropertyTracker<BriefingSection>(plugin.Map.BriefingSection);
|
PropertyTracker<BriefingSection> briefingSettings = new PropertyTracker<BriefingSection>(plugin.Map.BriefingSection);
|
||||||
PropertyTracker<SoleSurvivor.CratesSection> cratesSettings = null;
|
PropertyTracker<SoleSurvivor.CratesSection> cratesSettings = null;
|
||||||
if (plugin is SoleSurvivor.GamePlugin ssPlugin)
|
if (plugin.GameType == GameType.SoleSurvivor && plugin is SoleSurvivor.GamePlugin ssPlugin)
|
||||||
{
|
{
|
||||||
cratesSettings = new PropertyTracker<SoleSurvivor.CratesSection>(ssPlugin.CratesSection);
|
cratesSettings = new PropertyTracker<SoleSurvivor.CratesSection>(ssPlugin.CratesSection);
|
||||||
}
|
}
|
||||||
string extraIniText = plugin.ExtraIniText;
|
string extraIniText = plugin.ExtraIniText;
|
||||||
|
if (extraIniText.Trim('\r', '\n').Length == 0)
|
||||||
|
extraIniText = String.Empty;
|
||||||
Dictionary<House, PropertyTracker<House>> houseSettingsTrackers = plugin.Map.Houses.ToDictionary(h => h, h => new PropertyTracker<House>(h));
|
Dictionary<House, PropertyTracker<House>> houseSettingsTrackers = plugin.Map.Houses.ToDictionary(h => h, h => new PropertyTracker<House>(h));
|
||||||
using (MapSettingsDialog msd = new MapSettingsDialog(plugin, basicSettings, briefingSettings, cratesSettings, houseSettingsTrackers, extraIniText))
|
using (MapSettingsDialog msd = new MapSettingsDialog(plugin, basicSettings, briefingSettings, cratesSettings, houseSettingsTrackers, extraIniText))
|
||||||
{
|
{
|
||||||
@ -550,17 +553,26 @@ namespace MobiusEditor
|
|||||||
hasChanges = true;
|
hasChanges = true;
|
||||||
houseSettingsTracker.Commit();
|
houseSettingsTracker.Commit();
|
||||||
}
|
}
|
||||||
if (!extraIniText.Equals(msd.ExtraIniText, StringComparison.InvariantCultureIgnoreCase))
|
// Combine diacritics into their characters, and remove characters not included in DOS-437.
|
||||||
|
string normalised = (msd.ExtraIniText ?? String.Empty).Normalize(NormalizationForm.FormC);
|
||||||
|
Encoding dos437 = Encoding.GetEncoding(437);
|
||||||
|
// DOS chars excluding specials at the start and end. Explicitly add tab, then the normal range from 32 to 254.
|
||||||
|
HashSet<Char> dos437chars = String.Concat("\t".Yield().Concat(Enumerable.Range(32, 256 - 32 - 1).Select(i => dos437.GetString(new Byte[] { (byte)i })))).ToHashSet();
|
||||||
|
normalised = new String(normalised.Where(ch => dos437chars.Contains(ch)).ToArray());
|
||||||
|
// Ignore trivial line changes. This will not detect any irrelevant but non-trivial changes like swapping lines, though.
|
||||||
|
String checkTextNew = Regex.Replace(normalised, "[\\r\\n]+", "\n").Trim('\n');
|
||||||
|
String checkTextOrig = Regex.Replace(extraIniText ?? String.Empty, "[\\r\\n]+", "\n").Trim('\n');
|
||||||
|
if (!checkTextOrig.Equals(checkTextNew, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
plugin.ExtraIniText = msd.ExtraIniText;
|
plugin.ExtraIniText = normalised;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
MessageBox.Show("Errors occurred when applying rule changes:\n\n" + ex.Message, GetProgramVersionTitle());
|
MessageBox.Show("Errors occurred when applying rule changes:\n\n" + ex.Message, GetProgramVersionTitle());
|
||||||
}
|
}
|
||||||
rulesChanged = true;
|
rulesChanged = plugin.GameType == GameType.RedAlert;
|
||||||
hasChanges = true;
|
hasChanges = true;
|
||||||
}
|
}
|
||||||
plugin.Dirty = hasChanges;
|
plugin.Dirty = hasChanges;
|
||||||
@ -1009,7 +1021,7 @@ namespace MobiusEditor
|
|||||||
{
|
{
|
||||||
iniContents = GeneralUtils.GetIniContents(iniFile, fileType);
|
iniContents = GeneralUtils.GetIniContents(iniFile, fileType);
|
||||||
}
|
}
|
||||||
if (iniContents == null || !GeneralUtils.CheckForIniInfo(iniContents, "Map") || !GeneralUtils.CheckForIniInfo(iniContents, "Basic"))
|
if (iniContents == null || !INITools.CheckForIniInfo(iniContents, "Map") || !INITools.CheckForIniInfo(iniContents, "Basic"))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,16 @@
|
|||||||
// distributed with this program. You should have received a copy of the
|
// distributed with this program. You should have received a copy of the
|
||||||
// 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
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
namespace MobiusEditor.Model
|
namespace MobiusEditor.Model
|
||||||
{
|
{
|
||||||
public class CellTrigger
|
public class CellTrigger
|
||||||
{
|
{
|
||||||
public string Trigger { get; set; } = Model.Trigger.None;
|
public string Trigger { get; set; } = Model.Trigger.None;
|
||||||
|
|
||||||
|
public Color Tint { get; set; } = Color.White;
|
||||||
|
|
||||||
public CellTrigger(string trigger)
|
public CellTrigger(string trigger)
|
||||||
{
|
{
|
||||||
Trigger = trigger;
|
Trigger = trigger;
|
||||||
|
@ -169,12 +169,15 @@ namespace MobiusEditor.Model
|
|||||||
|
|
||||||
public readonly string[] MissionTypes;
|
public readonly string[] MissionTypes;
|
||||||
|
|
||||||
|
private const string defaultMission = "Guard";
|
||||||
|
private readonly string inputMissionArmed;
|
||||||
|
private readonly string inputMissionUnarmed;
|
||||||
|
private readonly string inputMissionAircraft;
|
||||||
|
private readonly string inputMissionHarvest;
|
||||||
|
|
||||||
public readonly string DefaultMissionArmed;
|
public readonly string DefaultMissionArmed;
|
||||||
|
|
||||||
public readonly string DefaultMissionUnarmed;
|
public readonly string DefaultMissionUnarmed;
|
||||||
|
|
||||||
public readonly string DefaultMissionAircraft;
|
public readonly string DefaultMissionAircraft;
|
||||||
|
|
||||||
public readonly string DefaultMissionHarvest;
|
public readonly string DefaultMissionHarvest;
|
||||||
|
|
||||||
public readonly List<DirectionType> BuildingDirectionTypes;
|
public readonly List<DirectionType> BuildingDirectionTypes;
|
||||||
@ -279,8 +282,9 @@ namespace MobiusEditor.Model
|
|||||||
|
|
||||||
public House[] HousesIncludingNone;
|
public House[] HousesIncludingNone;
|
||||||
|
|
||||||
|
public string MovieEmpty;
|
||||||
public readonly List<string> MovieTypes;
|
public readonly List<string> MovieTypes;
|
||||||
|
public readonly string ThemeEmpty;
|
||||||
public readonly List<string> ThemeTypes;
|
public readonly List<string> ThemeTypes;
|
||||||
|
|
||||||
public int TiberiumOrGoldValue { get; set; }
|
public int TiberiumOrGoldValue { get; set; }
|
||||||
@ -308,9 +312,10 @@ namespace MobiusEditor.Model
|
|||||||
IEnumerable<TerrainType> terrainTypes, IEnumerable<OverlayType> overlayTypes, IEnumerable<SmudgeType> smudgeTypes,
|
IEnumerable<TerrainType> terrainTypes, IEnumerable<OverlayType> overlayTypes, IEnumerable<SmudgeType> smudgeTypes,
|
||||||
IEnumerable<string> eventTypes, IEnumerable<string> cellEventTypes, IEnumerable<string> unitEventTypes, IEnumerable<string> structureEventTypes, IEnumerable<string> terrainEventTypes,
|
IEnumerable<string> eventTypes, IEnumerable<string> cellEventTypes, IEnumerable<string> unitEventTypes, IEnumerable<string> structureEventTypes, IEnumerable<string> terrainEventTypes,
|
||||||
IEnumerable<string> actionTypes, IEnumerable<string> cellActionTypes, IEnumerable<string> unitActionTypes, IEnumerable<string> structureActionTypes, IEnumerable<string> terrainActionTypes,
|
IEnumerable<string> actionTypes, IEnumerable<string> cellActionTypes, IEnumerable<string> unitActionTypes, IEnumerable<string> structureActionTypes, IEnumerable<string> terrainActionTypes,
|
||||||
IEnumerable<string> missionTypes, IEnumerable<DirectionType> unitDirectionTypes, IEnumerable<DirectionType> buildingDirectionTypes, IEnumerable<InfantryType> infantryTypes,
|
IEnumerable<string> missionTypes, string armedMission, string unarmedMission, string harvestMission, string aircraftMission,
|
||||||
IEnumerable<UnitType> unitTypes, IEnumerable<BuildingType> buildingTypes, IEnumerable<TeamMission> teamMissionTypes,
|
IEnumerable<DirectionType> unitDirectionTypes, IEnumerable<DirectionType> buildingDirectionTypes, IEnumerable<InfantryType> infantryTypes,
|
||||||
IEnumerable<ITechnoType> teamTechnoTypes, IEnumerable<Waypoint> waypoints, IEnumerable<string> movieTypes, IEnumerable<string> themeTypes)
|
IEnumerable<UnitType> unitTypes, IEnumerable<BuildingType> buildingTypes, IEnumerable<TeamMission> teamMissionTypes,IEnumerable<ITechnoType> teamTechnoTypes,
|
||||||
|
IEnumerable<Waypoint> waypoints, IEnumerable<string> movieTypes, string emptyMovie, IEnumerable<string> themeTypes, string emptyTheme)
|
||||||
{
|
{
|
||||||
MapSection = new MapSection(cellSize);
|
MapSection = new MapSection(cellSize);
|
||||||
BasicSection = basicSection;
|
BasicSection = basicSection;
|
||||||
@ -324,23 +329,28 @@ namespace MobiusEditor.Model
|
|||||||
OverlayTypes = new List<OverlayType>(overlayTypes);
|
OverlayTypes = new List<OverlayType>(overlayTypes);
|
||||||
SmudgeTypes = new List<SmudgeType>(smudgeTypes);
|
SmudgeTypes = new List<SmudgeType>(smudgeTypes);
|
||||||
EventTypes = eventTypes.ToArray();
|
EventTypes = eventTypes.ToArray();
|
||||||
CellEventTypes = cellEventTypes.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
CellEventTypes = cellEventTypes.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
UnitEventTypes = unitEventTypes.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
UnitEventTypes = unitEventTypes.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
StructureEventTypes = structureEventTypes.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
StructureEventTypes = structureEventTypes.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
TerrainEventTypes = terrainEventTypes.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
TerrainEventTypes = terrainEventTypes.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
CellActionTypes = cellActionTypes.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
CellActionTypes = cellActionTypes.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
UnitActionTypes = unitActionTypes.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
UnitActionTypes = unitActionTypes.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
StructureActionTypes = structureActionTypes.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
StructureActionTypes = structureActionTypes.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
TerrainActionTypes = terrainActionTypes.ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
TerrainActionTypes = terrainActionTypes.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
ActionTypes = actionTypes.ToArray();
|
ActionTypes = actionTypes.ToArray();
|
||||||
MissionTypes = missionTypes.ToArray();
|
MissionTypes = missionTypes.ToArray();
|
||||||
DefaultMissionArmed = MissionTypes.Where(m => m.Equals("Guard")).FirstOrDefault() ?? MissionTypes.First();
|
string defMission = MissionTypes.Where(m => m.Equals(defaultMission, StringComparison.OrdinalIgnoreCase)).FirstOrDefault() ?? MissionTypes.First();
|
||||||
DefaultMissionUnarmed = MissionTypes.Where(m => m.Equals("Stop")).FirstOrDefault() ?? MissionTypes.First();
|
inputMissionArmed = armedMission;
|
||||||
// Reverts to "stop" if there are no resources (RA indoor)
|
inputMissionUnarmed = unarmedMission;
|
||||||
DefaultMissionHarvest = OverlayTypes.Any(ov => ov.IsResource) ? MissionTypes.Where(m => m.Equals("Harvest")).FirstOrDefault() ?? DefaultMissionUnarmed : DefaultMissionUnarmed;
|
inputMissionAircraft = harvestMission;
|
||||||
// In TD, at lease, only Unload will make them stay on the spot as expected.
|
inputMissionHarvest = aircraftMission;
|
||||||
DefaultMissionAircraft = MissionTypes.Where(m => m.Equals("Unload")).FirstOrDefault() ?? MissionTypes.First();
|
DefaultMissionArmed = MissionTypes.Where(m => m.Equals(armedMission, StringComparison.OrdinalIgnoreCase)).FirstOrDefault() ?? defMission;
|
||||||
|
DefaultMissionUnarmed = MissionTypes.Where(m => m.Equals(unarmedMission, StringComparison.OrdinalIgnoreCase)).FirstOrDefault() ?? defMission;
|
||||||
|
// Reverts to "Stop" if there are no resources (RA indoor)
|
||||||
|
DefaultMissionHarvest = OverlayTypes.Any(ov => ov.IsResource) ? MissionTypes.Where(m => m.Equals(harvestMission, StringComparison.OrdinalIgnoreCase)).FirstOrDefault() ?? DefaultMissionUnarmed : DefaultMissionUnarmed;
|
||||||
|
// Only "Unload" will make them stay on the spot as expected.
|
||||||
|
DefaultMissionAircraft = MissionTypes.Where(m => m.Equals(aircraftMission, StringComparison.OrdinalIgnoreCase)).FirstOrDefault() ?? defMission;
|
||||||
UnitDirectionTypes = new List<DirectionType>(unitDirectionTypes);
|
UnitDirectionTypes = new List<DirectionType>(unitDirectionTypes);
|
||||||
BuildingDirectionTypes = new List<DirectionType>(buildingDirectionTypes);
|
BuildingDirectionTypes = new List<DirectionType>(buildingDirectionTypes);
|
||||||
AllInfantryTypes = new List<InfantryType>(infantryTypes);
|
AllInfantryTypes = new List<InfantryType>(infantryTypes);
|
||||||
@ -348,7 +358,9 @@ namespace MobiusEditor.Model
|
|||||||
BuildingTypes = new List<BuildingType>(buildingTypes);
|
BuildingTypes = new List<BuildingType>(buildingTypes);
|
||||||
TeamMissionTypes = teamMissionTypes.ToArray();
|
TeamMissionTypes = teamMissionTypes.ToArray();
|
||||||
AllTeamTechnoTypes = new List<ITechnoType>(teamTechnoTypes);
|
AllTeamTechnoTypes = new List<ITechnoType>(teamTechnoTypes);
|
||||||
|
MovieEmpty = emptyMovie;
|
||||||
MovieTypes = new List<string>(movieTypes);
|
MovieTypes = new List<string>(movieTypes);
|
||||||
|
ThemeEmpty = emptyTheme;
|
||||||
ThemeTypes = new List<string>(themeTypes);
|
ThemeTypes = new List<string>(themeTypes);
|
||||||
|
|
||||||
Metrics = new CellMetrics(cellSize);
|
Metrics = new CellMetrics(cellSize);
|
||||||
@ -803,14 +815,15 @@ namespace MobiusEditor.Model
|
|||||||
Waypoint[] wpPreview = new Waypoint[Waypoints.Length + 1];
|
Waypoint[] wpPreview = new Waypoint[Waypoints.Length + 1];
|
||||||
Array.Copy(Waypoints, wpPreview, Waypoints.Length);
|
Array.Copy(Waypoints, wpPreview, Waypoints.Length);
|
||||||
wpPreview[Waypoints.Length] = new Waypoint("", null);
|
wpPreview[Waypoints.Length] = new Waypoint("", null);
|
||||||
// This is a shallow clone; the map is new, but the placed content all still reference the original objects.
|
// This is a shallow clone; the map is new, but the placed contents all still reference the original objects.
|
||||||
// These shallow copies are used for map preview during editing, where dummy objects can be added without any issue.
|
// These shallow copies are used for map preview during editing, where dummy objects can be added without any issue.
|
||||||
var map = new Map(BasicSection, Theater, Metrics.Size, HouseType, HouseTypesIncludingNone,
|
var map = new Map(BasicSection, Theater, Metrics.Size, HouseType, HouseTypesIncludingNone,
|
||||||
FlagColors, TheaterTypes, TemplateTypes, TerrainTypes, OverlayTypes, SmudgeTypes,
|
FlagColors, TheaterTypes, TemplateTypes, TerrainTypes, OverlayTypes, SmudgeTypes,
|
||||||
EventTypes, CellEventTypes, UnitEventTypes, StructureEventTypes, TerrainEventTypes,
|
EventTypes, CellEventTypes, UnitEventTypes, StructureEventTypes, TerrainEventTypes,
|
||||||
ActionTypes, CellActionTypes, UnitActionTypes, StructureActionTypes, TerrainActionTypes,
|
ActionTypes, CellActionTypes, UnitActionTypes, StructureActionTypes, TerrainActionTypes,
|
||||||
MissionTypes, UnitDirectionTypes, BuildingDirectionTypes, AllInfantryTypes, AllUnitTypes, BuildingTypes, TeamMissionTypes,
|
MissionTypes, inputMissionArmed, inputMissionUnarmed, inputMissionHarvest, inputMissionAircraft,
|
||||||
AllTeamTechnoTypes, wpPreview, MovieTypes, ThemeTypes)
|
UnitDirectionTypes, BuildingDirectionTypes, AllInfantryTypes, AllUnitTypes, BuildingTypes, TeamMissionTypes,
|
||||||
|
AllTeamTechnoTypes, wpPreview, MovieTypes, MovieEmpty, ThemeTypes, ThemeEmpty)
|
||||||
{
|
{
|
||||||
TopLeft = TopLeft,
|
TopLeft = TopLeft,
|
||||||
Size = Size
|
Size = Size
|
||||||
@ -1387,10 +1400,10 @@ namespace MobiusEditor.Model
|
|||||||
private void CleanUpTriggers(List<Trigger> triggers, Dictionary<object, string> undoList, Dictionary<object, string> redoList, Dictionary<CellTrigger, int> cellTriggerLocations)
|
private void CleanUpTriggers(List<Trigger> triggers, Dictionary<object, string> undoList, Dictionary<object, string> redoList, Dictionary<CellTrigger, int> cellTriggerLocations)
|
||||||
{
|
{
|
||||||
// Clean techno types
|
// Clean techno types
|
||||||
HashSet<string> availableTriggers = triggers.Select(t => t.Name).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> availableTriggers = triggers.Select(t => t.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<string> availableUnitTriggers = FilterUnitTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> availableUnitTriggers = FilterUnitTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<string> availableBuildingTriggers = FilterStructureTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> availableBuildingTriggers = FilterStructureTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<string> availableTerrainTriggers = FilterTerrainTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> availableTerrainTriggers = FilterTerrainTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
foreach (ITechno techno in GetAllTechnos())
|
foreach (ITechno techno in GetAllTechnos())
|
||||||
{
|
{
|
||||||
if (techno is Infantry infantry)
|
if (techno is Infantry infantry)
|
||||||
@ -1465,7 +1478,7 @@ namespace MobiusEditor.Model
|
|||||||
|
|
||||||
private void CleanUpCellTriggers(List<Trigger> triggers, Dictionary<object, string> undoList, Dictionary<object, string> redoList, Dictionary<CellTrigger, int> cellTriggerLocations)
|
private void CleanUpCellTriggers(List<Trigger> triggers, Dictionary<object, string> undoList, Dictionary<object, string> redoList, Dictionary<CellTrigger, int> cellTriggerLocations)
|
||||||
{
|
{
|
||||||
HashSet<string> placeableTrigs = FilterCellTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> placeableTrigs = FilterCellTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
List<int> cellsToClear = new List<int>();
|
List<int> cellsToClear = new List<int>();
|
||||||
foreach ((int cell, CellTrigger value) in CellTriggers)
|
foreach ((int cell, CellTrigger value) in CellTriggers)
|
||||||
{
|
{
|
||||||
|
@ -92,7 +92,7 @@ namespace MobiusEditor.Model
|
|||||||
ThumbnailHeight = IconHeight;
|
ThumbnailHeight = IconHeight;
|
||||||
Theaters = theaters;
|
Theaters = theaters;
|
||||||
Flag = flag;
|
Flag = flag;
|
||||||
MaskOverrides = new Dictionary<string, bool[,]>(StringComparer.InvariantCultureIgnoreCase);
|
MaskOverrides = new Dictionary<string, bool[,]>(StringComparer.OrdinalIgnoreCase);
|
||||||
GroupTiles = new string[0];
|
GroupTiles = new string[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,5 +79,9 @@ namespace MobiusEditor.RedAlert
|
|||||||
[DefaultValue(false)]
|
[DefaultValue(false)]
|
||||||
public bool TruckCrate { get => truckCrate; set => SetField(ref truckCrate, value); }
|
public bool TruckCrate { get => truckCrate; set => SetField(ref truckCrate, value); }
|
||||||
|
|
||||||
|
private int newINIFormat;
|
||||||
|
[DefaultValue(3)]
|
||||||
|
public int NewINIFormat { get => newINIFormat; set => SetField(ref newINIFormat, value); }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ namespace MobiusEditor.RedAlert
|
|||||||
|
|
||||||
private static readonly Regex SinglePlayRegex = new Regex("^SC[A-LN-Z]\\d{2}[EWX][A-EL]$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
private static readonly Regex SinglePlayRegex = new Regex("^SC[A-LN-Z]\\d{2}[EWX][A-EL]$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
private const string defVidVal = "<none>";
|
private const string movieEmpty = "<none>";
|
||||||
private const string RemarkOld = " (Classic only)";
|
private const string RemarkOld = " (Classic only)";
|
||||||
|
|
||||||
private static readonly IEnumerable<string> movieTypesRemarksOld = new string[]
|
private static readonly IEnumerable<string> movieTypesRemarksOld = new string[]
|
||||||
@ -76,6 +76,7 @@ namespace MobiusEditor.RedAlert
|
|||||||
"RETALIATION_WINS",
|
"RETALIATION_WINS",
|
||||||
"RETALIATION_ANTS"
|
"RETALIATION_ANTS"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly IEnumerable<string> movieTypesRa = new string[]
|
private static readonly IEnumerable<string> movieTypesRa = new string[]
|
||||||
{
|
{
|
||||||
"AAGUN",
|
"AAGUN",
|
||||||
@ -205,6 +206,8 @@ namespace MobiusEditor.RedAlert
|
|||||||
"RETALIATION_ANTS"
|
"RETALIATION_ANTS"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private const string themeEmpty = "No Theme";
|
||||||
|
|
||||||
private static readonly IEnumerable<string> themeTypes = new string[]
|
private static readonly IEnumerable<string> themeTypes = new string[]
|
||||||
{
|
{
|
||||||
"No Theme",
|
"No Theme",
|
||||||
@ -310,8 +313,8 @@ namespace MobiusEditor.RedAlert
|
|||||||
}
|
}
|
||||||
// Remove any sections known and handled / disallowed by the editor.
|
// Remove any sections known and handled / disallowed by the editor.
|
||||||
ini.Sections.Remove("Digest");
|
ini.Sections.Remove("Digest");
|
||||||
ini.Sections.Remove("Basic");
|
INITools.ClearDataFrom(ini, "Basic", (BasicSection)Map.BasicSection);
|
||||||
ini.Sections.Remove("Map");
|
INITools.ClearDataFrom(ini, "Map", Map.MapSection);
|
||||||
ini.Sections.Remove("Steam");
|
ini.Sections.Remove("Steam");
|
||||||
ini.Sections.Remove("TeamTypes");
|
ini.Sections.Remove("TeamTypes");
|
||||||
ini.Sections.Remove("Trigs");
|
ini.Sections.Remove("Trigs");
|
||||||
@ -330,7 +333,7 @@ namespace MobiusEditor.RedAlert
|
|||||||
ini.Sections.Remove("Briefing");
|
ini.Sections.Remove("Briefing");
|
||||||
foreach (var house in Map.Houses)
|
foreach (var house in Map.Houses)
|
||||||
{
|
{
|
||||||
ini.Sections.Remove(house.Type.Name);
|
INITools.ClearDataFrom(ini, house.Type.Name, (House)house);
|
||||||
}
|
}
|
||||||
extraSections = ini.Sections.Count == 0 ? null : ini.Sections;
|
extraSections = ini.Sections.Count == 0 ? null : ini.Sections;
|
||||||
IEnumerable<string> errors = UpdateBuildingRules(ini, this.Map);
|
IEnumerable<string> errors = UpdateBuildingRules(ini, this.Map);
|
||||||
@ -342,7 +345,7 @@ namespace MobiusEditor.RedAlert
|
|||||||
}
|
}
|
||||||
public static bool CheckForRAMap(INI contents)
|
public static bool CheckForRAMap(INI contents)
|
||||||
{
|
{
|
||||||
return GeneralUtils.CheckForIniInfo(contents, "MapPack");
|
return INITools.CheckForIniInfo(contents, "MapPack");
|
||||||
}
|
}
|
||||||
|
|
||||||
static GamePlugin()
|
static GamePlugin()
|
||||||
@ -364,10 +367,10 @@ namespace MobiusEditor.RedAlert
|
|||||||
var movies = new List<string>(movieTypesRa);
|
var movies = new List<string>(movieTypesRa);
|
||||||
for (int i = 0; i < movies.Count; ++i)
|
for (int i = 0; i < movies.Count; ++i)
|
||||||
{
|
{
|
||||||
string vidName = GeneralUtils.AddRemarks(movies[i], defVidVal, true, movieTypesRemarksOld, RemarkOld);
|
string vidName = GeneralUtils.AddRemarks(movies[i], movieEmpty, true, movieTypesRemarksOld, RemarkOld);
|
||||||
movies[i] = GeneralUtils.AddRemarks(vidName, defVidVal, true, movieTypesRemarksNew, RemarkNew);
|
movies[i] = GeneralUtils.AddRemarks(vidName, movieEmpty, true, movieTypesRemarksNew, RemarkNew);
|
||||||
}
|
}
|
||||||
movies.Insert(0, defVidVal);
|
movies.Insert(0, movieEmpty);
|
||||||
movieTypes = movies.ToArray();
|
movieTypes = movies.ToArray();
|
||||||
var basicSection = new BasicSection();
|
var basicSection = new BasicSection();
|
||||||
basicSection.SetDefault();
|
basicSection.SetDefault();
|
||||||
@ -418,8 +421,10 @@ namespace MobiusEditor.RedAlert
|
|||||||
TerrainTypes.GetTypes(), OverlayTypes.GetTypes(), SmudgeTypes.GetTypes(Globals.ConvertCraters),
|
TerrainTypes.GetTypes(), OverlayTypes.GetTypes(), SmudgeTypes.GetTypes(Globals.ConvertCraters),
|
||||||
EventTypes.GetTypes(), cellEventTypes, unitEventTypes, structureEventTypes, terrainEventTypes,
|
EventTypes.GetTypes(), cellEventTypes, unitEventTypes, structureEventTypes, terrainEventTypes,
|
||||||
ActionTypes.GetTypes(), cellActionTypes, unitActionTypes, structureActionTypes, terrainActionTypes,
|
ActionTypes.GetTypes(), cellActionTypes, unitActionTypes, structureActionTypes, terrainActionTypes,
|
||||||
MissionTypes.GetTypes(), DirectionTypes.GetMainTypes(), DirectionTypes.GetAllTypes(), InfantryTypes.GetTypes(), UnitTypes.GetTypes(Globals.DisableAirUnits),
|
MissionTypes.GetTypes(), MissionTypes.MISSION_GUARD, MissionTypes.MISSION_STOP, MissionTypes.MISSION_HARVEST,
|
||||||
BuildingTypes.GetTypes(), TeamMissionTypes.GetTypes(), fullTechnoTypes, waypoints, movieTypes, themeTypes)
|
MissionTypes.MISSION_UNLOAD, DirectionTypes.GetMainTypes(), DirectionTypes.GetAllTypes(), InfantryTypes.GetTypes(),
|
||||||
|
UnitTypes.GetTypes(Globals.DisableAirUnits), BuildingTypes.GetTypes(), TeamMissionTypes.GetTypes(),
|
||||||
|
fullTechnoTypes, waypoints, movieTypes, movieEmpty, themeTypes, themeEmpty)
|
||||||
{
|
{
|
||||||
TiberiumOrGoldValue = 35,
|
TiberiumOrGoldValue = 35,
|
||||||
GemValue = 110
|
GemValue = 110
|
||||||
@ -466,10 +471,6 @@ namespace MobiusEditor.RedAlert
|
|||||||
var ini = new INI();
|
var ini = new INI();
|
||||||
iniBytes = File.ReadAllBytes(path);
|
iniBytes = File.ReadAllBytes(path);
|
||||||
ParseIniContent(ini, iniBytes);
|
ParseIniContent(ini, iniBytes);
|
||||||
using (var reader = new StreamReader(path))
|
|
||||||
{
|
|
||||||
ini.Parse(reader);
|
|
||||||
}
|
|
||||||
forceSingle = SinglePlayRegex.IsMatch(Path.GetFileNameWithoutExtension(path));
|
forceSingle = SinglePlayRegex.IsMatch(Path.GetFileNameWithoutExtension(path));
|
||||||
errors.AddRange(LoadINI(ini, forceSingle, ref modified));
|
errors.AddRange(LoadINI(ini, forceSingle, ref modified));
|
||||||
}
|
}
|
||||||
@ -511,9 +512,9 @@ namespace MobiusEditor.RedAlert
|
|||||||
|
|
||||||
private void ParseIniContent(INI ini, Byte[] iniBytes)
|
private void ParseIniContent(INI ini, Byte[] iniBytes)
|
||||||
{
|
{
|
||||||
Encoding encUtf8 = new UTF8Encoding(false, false);
|
|
||||||
Encoding encDOS = Encoding.GetEncoding(437);
|
Encoding encDOS = Encoding.GetEncoding(437);
|
||||||
String iniText = encDOS.GetString(iniBytes);
|
String iniText = encDOS.GetString(iniBytes);
|
||||||
|
Encoding encUtf8 = new UTF8Encoding(false, false);
|
||||||
String iniTextUtf8 = encUtf8.GetString(iniBytes);
|
String iniTextUtf8 = encUtf8.GetString(iniBytes);
|
||||||
ini.Parse(iniText);
|
ini.Parse(iniText);
|
||||||
// Specific support for DOS-437 file but with some specific sections in UTF-8.
|
// Specific support for DOS-437 file but with some specific sections in UTF-8.
|
||||||
@ -522,34 +523,34 @@ namespace MobiusEditor.RedAlert
|
|||||||
INI utf8Ini = new INI();
|
INI utf8Ini = new INI();
|
||||||
utf8Ini.Parse(iniTextUtf8);
|
utf8Ini.Parse(iniTextUtf8);
|
||||||
// Steam section
|
// Steam section
|
||||||
INISection steamSectionUtf = utf8Ini.Sections["Steam"];
|
INISection steamSectionUtf8 = utf8Ini.Sections["Steam"];
|
||||||
if (steamSectionUtf != null)
|
if (steamSectionUtf8 != null)
|
||||||
{
|
{
|
||||||
if (!ini.Sections.Replace(steamSectionUtf))
|
if (!ini.Sections.Replace(steamSectionUtf8))
|
||||||
{
|
{
|
||||||
ini.Sections.Add(steamSectionUtf);
|
ini.Sections.Add(steamSectionUtf8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Name and author from Basic section
|
// Name and author from Basic section
|
||||||
INISection basicSectionUtf = utf8Ini.Sections["Basic"];
|
INISection basicSectionUtf8 = utf8Ini.Sections["Basic"];
|
||||||
INISection basicSectionDos = ini.Sections["Basic"];
|
INISection basicSectionDos = ini.Sections["Basic"];
|
||||||
if (basicSectionUtf != null && basicSectionDos != null)
|
if (basicSectionUtf8 != null && basicSectionDos != null)
|
||||||
{
|
{
|
||||||
if (basicSectionUtf.Keys.Contains("Name") && !basicSectionUtf.Keys["Name"].Contains('\uFFFD'))
|
if (basicSectionUtf8.Keys.Contains("Name") && !basicSectionUtf8.Keys["Name"].Contains('\uFFFD'))
|
||||||
{
|
{
|
||||||
basicSectionDos.Keys["Name"] = basicSectionUtf.Keys["Name"];
|
basicSectionDos.Keys["Name"] = basicSectionUtf8.Keys["Name"];
|
||||||
}
|
}
|
||||||
if (basicSectionUtf.Keys.Contains("Author") && !basicSectionUtf.Keys["Author"].Contains('\uFFFD'))
|
if (basicSectionUtf8.Keys.Contains("Author") && !basicSectionUtf8.Keys["Author"].Contains('\uFFFD'))
|
||||||
{
|
{
|
||||||
basicSectionDos.Keys["Author"] = basicSectionUtf.Keys["Author"];
|
basicSectionDos.Keys["Author"] = basicSectionUtf8.Keys["Author"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remastered one-line "Text" briefing from [Briefing] section
|
// Remastered one-line "Text" briefing from [Briefing] section
|
||||||
INISection briefSectionUtf = utf8Ini.Sections["Briefing"];
|
INISection briefSectionUtf8 = utf8Ini.Sections["Briefing"];
|
||||||
INISection briefSectionDos = ini.Sections["Briefing"];
|
INISection briefSectionDos = ini.Sections["Briefing"];
|
||||||
if (briefSectionUtf != null && briefSectionDos != null && briefSectionUtf.Keys.Contains("Text"))
|
if (briefSectionUtf8 != null && briefSectionDos != null && briefSectionUtf8.Keys.Contains("Text"))
|
||||||
{
|
{
|
||||||
briefSectionDos.Keys["Text"] = briefSectionUtf.Keys["Text"];
|
briefSectionDos.Keys["Text"] = briefSectionUtf8.Keys["Text"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -563,27 +564,27 @@ namespace MobiusEditor.RedAlert
|
|||||||
// Just gonna remove this; I assume it'll be invalid after a re-save anyway.
|
// Just gonna remove this; I assume it'll be invalid after a re-save anyway.
|
||||||
ini.Sections.Extract("Digest");
|
ini.Sections.Extract("Digest");
|
||||||
// Basic info
|
// Basic info
|
||||||
var basicSection = ini.Sections.Extract("Basic");
|
BasicSection basic = (BasicSection)Map.BasicSection;
|
||||||
|
INISection basicSection = INITools.ParseAndLeaveRemainder(ini, "Basic", basic, new MapContext(Map, true));
|
||||||
if (basicSection != null)
|
if (basicSection != null)
|
||||||
{
|
{
|
||||||
INI.ParseSection(new MapContext(Map, true), basicSection, Map.BasicSection);
|
|
||||||
Model.BasicSection basic = Map.BasicSection;
|
basic.Intro = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Intro, movieEmpty, true, movieTypesRemarksOld, RemarkOld), movieEmpty, true, movieTypesRemarksNew, RemarkNew);
|
||||||
basic.Intro = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Intro, defVidVal, true, movieTypesRemarksOld, RemarkOld), defVidVal, true, movieTypesRemarksNew, RemarkNew);
|
basic.Intro = GeneralUtils.FilterToExisting(basic.Intro, movieEmpty, true, movieTypesRa);
|
||||||
basic.Intro = GeneralUtils.FilterToExisting(basic.Intro, defVidVal, true, movieTypesRa);
|
basic.Brief = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Brief, movieEmpty, true, movieTypesRemarksOld, RemarkOld), movieEmpty, true, movieTypesRemarksNew, RemarkNew);
|
||||||
basic.Brief = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Brief, defVidVal, true, movieTypesRemarksOld, RemarkOld), defVidVal, true, movieTypesRemarksNew, RemarkNew);
|
basic.Brief = GeneralUtils.FilterToExisting(basic.Brief, movieEmpty, true, movieTypesRa);
|
||||||
basic.Brief = GeneralUtils.FilterToExisting(basic.Brief, defVidVal, true, movieTypesRa);
|
basic.Action = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Action, movieEmpty, true, movieTypesRemarksOld, RemarkOld), movieEmpty, true, movieTypesRemarksNew, RemarkNew);
|
||||||
basic.Action = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Action, defVidVal, true, movieTypesRemarksOld, RemarkOld), defVidVal, true, movieTypesRemarksNew, RemarkNew);
|
basic.Action = GeneralUtils.FilterToExisting(basic.Action, movieEmpty, true, movieTypesRa);
|
||||||
basic.Action = GeneralUtils.FilterToExisting(basic.Action, defVidVal, true, movieTypesRa);
|
basic.Win = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Win, movieEmpty, true, movieTypesRemarksOld, RemarkOld), movieEmpty, true, movieTypesRemarksNew, RemarkNew);
|
||||||
basic.Win = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Win, defVidVal, true, movieTypesRemarksOld, RemarkOld), defVidVal, true, movieTypesRemarksNew, RemarkNew);
|
basic.Win = GeneralUtils.FilterToExisting(basic.Win, movieEmpty, true, movieTypesRa);
|
||||||
basic.Win = GeneralUtils.FilterToExisting(basic.Win, defVidVal, true, movieTypesRa);
|
basic.Win2 = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Win2, movieEmpty, true, movieTypesRemarksOld, RemarkOld), movieEmpty, true, movieTypesRemarksNew, RemarkNew);
|
||||||
basic.Win2 = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Win2, defVidVal, true, movieTypesRemarksOld, RemarkOld), defVidVal, true, movieTypesRemarksNew, RemarkNew);
|
basic.Win2 = GeneralUtils.FilterToExisting(basic.Win2, movieEmpty, true, movieTypesRa);
|
||||||
basic.Win2 = GeneralUtils.FilterToExisting(basic.Win2, defVidVal, true, movieTypesRa);
|
basic.Win3 = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Win3, movieEmpty, true, movieTypesRemarksOld, RemarkOld), movieEmpty, true, movieTypesRemarksNew, RemarkNew);
|
||||||
basic.Win3 = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Win3, defVidVal, true, movieTypesRemarksOld, RemarkOld), defVidVal, true, movieTypesRemarksNew, RemarkNew);
|
basic.Win3 = GeneralUtils.FilterToExisting(basic.Win3, movieEmpty, true, movieTypesRa);
|
||||||
basic.Win3 = GeneralUtils.FilterToExisting(basic.Win3, defVidVal, true, movieTypesRa);
|
basic.Win4 = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Win4, movieEmpty, true, movieTypesRemarksOld, RemarkOld), movieEmpty, true, movieTypesRemarksNew, RemarkNew);
|
||||||
basic.Win4 = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Win4, defVidVal, true, movieTypesRemarksOld, RemarkOld), defVidVal, true, movieTypesRemarksNew, RemarkNew);
|
basic.Win4 = GeneralUtils.FilterToExisting(basic.Win4, movieEmpty, true, movieTypesRa);
|
||||||
basic.Win4 = GeneralUtils.FilterToExisting(basic.Win4, defVidVal, true, movieTypesRa);
|
basic.Lose = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Lose, movieEmpty, true, movieTypesRemarksOld, RemarkOld), movieEmpty, true, movieTypesRemarksNew, RemarkNew);
|
||||||
basic.Lose = GeneralUtils.AddRemarks(GeneralUtils.AddRemarks(basic.Lose, defVidVal, true, movieTypesRemarksOld, RemarkOld), defVidVal, true, movieTypesRemarksNew, RemarkNew);
|
basic.Lose = GeneralUtils.FilterToExisting(basic.Lose, movieEmpty, true, movieTypesRa);
|
||||||
basic.Lose = GeneralUtils.FilterToExisting(basic.Lose, defVidVal, true, movieTypesRa);
|
|
||||||
}
|
}
|
||||||
String plName = Map.BasicSection.Player;
|
String plName = Map.BasicSection.Player;
|
||||||
HouseType player = Map.HouseTypes.Where(t => t.Equals(plName)).FirstOrDefault() ?? Map.HouseTypes.First();
|
HouseType player = Map.HouseTypes.Where(t => t.Equals(plName)).FirstOrDefault() ?? Map.HouseTypes.First();
|
||||||
@ -605,11 +606,7 @@ namespace MobiusEditor.RedAlert
|
|||||||
// Needs to be enabled in advance; it determines which units are valid to have placed on the map.
|
// Needs to be enabled in advance; it determines which units are valid to have placed on the map.
|
||||||
Map.BasicSection.ExpansionEnabled = aftermathEnabled;
|
Map.BasicSection.ExpansionEnabled = aftermathEnabled;
|
||||||
// Map info
|
// Map info
|
||||||
var mapSection = ini.Sections.Extract("Map");
|
INISection mapSection = INITools.ParseAndLeaveRemainder(ini, "Map", Map.MapSection, new MapContext(Map, true));
|
||||||
if (mapSection != null)
|
|
||||||
{
|
|
||||||
INI.ParseSection(new MapContext(Map, true), mapSection, Map.MapSection);
|
|
||||||
}
|
|
||||||
Map.MapSection.FixBounds();
|
Map.MapSection.FixBounds();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//MessageBox.Show("Graphics loaded");
|
//MessageBox.Show("Graphics loaded");
|
||||||
@ -720,7 +717,7 @@ namespace MobiusEditor.RedAlert
|
|||||||
}
|
}
|
||||||
var trigger = new Trigger { Name = Key };
|
var trigger = new Trigger { Name = Key };
|
||||||
trigger.PersistentType = (TriggerPersistentType)int.Parse(tokens[0]);
|
trigger.PersistentType = (TriggerPersistentType)int.Parse(tokens[0]);
|
||||||
trigger.House = Map.HouseTypes.Where(t => t.Equals(sbyte.Parse(tokens[1]))).FirstOrDefault()?.Name ?? "None";
|
trigger.House = Map.HouseTypes.Where(t => t.Equals(sbyte.Parse(tokens[1]))).FirstOrDefault()?.Name ?? House.None;
|
||||||
trigger.EventControl = (TriggerMultiStyleType)int.Parse(tokens[2]);
|
trigger.EventControl = (TriggerMultiStyleType)int.Parse(tokens[2]);
|
||||||
trigger.Event1.EventType = indexToType(Map.EventTypes, tokens[4]);
|
trigger.Event1.EventType = indexToType(Map.EventTypes, tokens[4]);
|
||||||
trigger.Event1.Team = tokens[5];
|
trigger.Event1.Team = tokens[5];
|
||||||
@ -819,12 +816,12 @@ namespace MobiusEditor.RedAlert
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//MessageBox.Show("at triggers");
|
//MessageBox.Show("at triggers");
|
||||||
HashSet<string> checkTrigs = Trigger.None.Yield().Concat(triggers.Select(t => t.Name)).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> checkTrigs = Trigger.None.Yield().Concat(triggers.Select(t => t.Name)).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<string> checkCellTrigs = Map.FilterCellTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> checkCellTrigs = Map.FilterCellTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<string> checkUnitTrigs = Trigger.None.Yield().Concat(Map.FilterUnitTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> checkUnitTrigs = Trigger.None.Yield().Concat(Map.FilterUnitTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<string> checkStrcTrigs = Trigger.None.Yield().Concat(Map.FilterStructureTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> checkStrcTrigs = Trigger.None.Yield().Concat(Map.FilterStructureTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
// Terrain objects in RA have no triggers
|
// Terrain objects in RA have no triggers
|
||||||
//HashSet<string> checkTerrTrigs = Trigger.None.Yield().Concat(Map.FilterTerrainTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
//HashSet<string> checkTerrTrigs = Trigger.None.Yield().Concat(Map.FilterTerrainTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
//MessageBox.Show("MapPack");
|
//MessageBox.Show("MapPack");
|
||||||
var mapPackSection = ini.Sections.Extract("MapPack");
|
var mapPackSection = ini.Sections.Extract("MapPack");
|
||||||
if (mapPackSection != null)
|
if (mapPackSection != null)
|
||||||
@ -1921,16 +1918,9 @@ namespace MobiusEditor.RedAlert
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var houseSection = ini.Sections.Extract(house.Type.Name);
|
House gameHouse = (House)house;
|
||||||
if (houseSection != null)
|
INISection houseSection = INITools.ParseAndLeaveRemainder(ini, gameHouse.Type.Name, gameHouse, new MapContext(Map, true));
|
||||||
{
|
house.Enabled = houseSection != null;
|
||||||
INI.ParseSection(new MapContext(Map, true), houseSection, house);
|
|
||||||
house.Enabled = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
house.Enabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
string indexToName<T>(IList<T> list, string index, string defaultValue) where T : INamedType
|
string indexToName<T>(IList<T> list, string index, string defaultValue) where T : INamedType
|
||||||
{
|
{
|
||||||
@ -1975,7 +1965,7 @@ namespace MobiusEditor.RedAlert
|
|||||||
Map.Triggers.AddRange(triggers);
|
Map.Triggers.AddRange(triggers);
|
||||||
extraSections = ini.Sections;
|
extraSections = ini.Sections;
|
||||||
bool switchedToSolo = false;
|
bool switchedToSolo = false;
|
||||||
if (forceSoloMission)
|
if (forceSoloMission && !basic.SoloMission)
|
||||||
{
|
{
|
||||||
int playerId = player.ID;
|
int playerId = player.ID;
|
||||||
bool hasWinTrigger =
|
bool hasWinTrigger =
|
||||||
@ -2002,7 +1992,7 @@ namespace MobiusEditor.RedAlert
|
|||||||
private IEnumerable<string> UpdateBuildingRules(INI ini, Map map)
|
private IEnumerable<string> UpdateBuildingRules(INI ini, Map map)
|
||||||
{
|
{
|
||||||
List<string> errors = new List<string>();
|
List<string> errors = new List<string>();
|
||||||
Dictionary<string, BuildingType> originals = BuildingTypes.GetTypes().ToDictionary(b => b.Name, StringComparer.InvariantCultureIgnoreCase);
|
Dictionary<string, BuildingType> originals = BuildingTypes.GetTypes().ToDictionary(b => b.Name, StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<Point> refreshPoints = new HashSet<Point>();
|
HashSet<Point> refreshPoints = new HashSet<Point>();
|
||||||
List<(Point Location, Building Occupier)> buildings = map.Buildings.OfType<Building>()
|
List<(Point Location, Building Occupier)> buildings = map.Buildings.OfType<Building>()
|
||||||
.OrderBy(pb => pb.Location.Y * map.Metrics.Width + pb.Location.X).ToList();
|
.OrderBy(pb => pb.Location.Y * map.Metrics.Width + pb.Location.X).ToList();
|
||||||
@ -2209,7 +2199,7 @@ namespace MobiusEditor.RedAlert
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Model.BasicSection basic = Map.BasicSection;
|
BasicSection basic = (BasicSection)Map.BasicSection;
|
||||||
// Make new Aftermath section
|
// Make new Aftermath section
|
||||||
INISection newAftermathSection = new INISection("Aftermath");
|
INISection newAftermathSection = new INISection("Aftermath");
|
||||||
newAftermathSection["NewUnitsEnabled"] = basic.ExpansionEnabled ? "1" : "0";
|
newAftermathSection["NewUnitsEnabled"] = basic.ExpansionEnabled ? "1" : "0";
|
||||||
@ -2250,14 +2240,13 @@ namespace MobiusEditor.RedAlert
|
|||||||
}
|
}
|
||||||
basic.Name = String.Join(" ", name);
|
basic.Name = String.Join(" ", name);
|
||||||
}
|
}
|
||||||
INI.WriteSection(new MapContext(Map, false), ini.Sections.Add("Basic"), Map.BasicSection);
|
INITools.FillAndReAdd(ini, "Basic", basic, new MapContext(Map, false), true);
|
||||||
Map.MapSection.FixBounds();
|
Map.MapSection.FixBounds();
|
||||||
INI.WriteSection(new MapContext(Map, false), ini.Sections.Add("Map"), Map.MapSection);
|
INITools.FillAndReAdd(ini, "Map", Map.MapSection, new MapContext(Map, false), true);
|
||||||
if (fileType != FileType.PGM)
|
if (fileType != FileType.PGM)
|
||||||
{
|
{
|
||||||
INI.WriteSection(new MapContext(Map, false), ini.Sections.Add("Steam"), Map.SteamSection);
|
INI.WriteSection(new MapContext(Map, false), ini.Sections.Add("Steam"), Map.SteamSection);
|
||||||
}
|
}
|
||||||
ini["Basic"]["NewINIFormat"] = "3";
|
|
||||||
var smudgeSection = ini.Sections.Add("SMUDGE");
|
var smudgeSection = ini.Sections.Add("SMUDGE");
|
||||||
// Flatten multi-cell bibs
|
// Flatten multi-cell bibs
|
||||||
Dictionary<int, Smudge> resolvedSmudge = new Dictionary<int, Smudge>();
|
Dictionary<int, Smudge> resolvedSmudge = new Dictionary<int, Smudge>();
|
||||||
@ -2441,7 +2430,6 @@ namespace MobiusEditor.RedAlert
|
|||||||
ship.Trigger
|
ship.Trigger
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var triggersSection = ini.Sections.Add("Trigs");
|
var triggersSection = ini.Sections.Add("Trigs");
|
||||||
foreach (var trigger in Map.Triggers)
|
foreach (var trigger in Map.Triggers)
|
||||||
{
|
{
|
||||||
@ -2477,7 +2465,6 @@ namespace MobiusEditor.RedAlert
|
|||||||
|
|
||||||
triggersSection[trigger.Name] = string.Join(",", tokens);
|
triggersSection[trigger.Name] = string.Join(",", tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
var waypointsSection = ini.Sections.Add("Waypoints");
|
var waypointsSection = ini.Sections.Add("Waypoints");
|
||||||
for (var i = 0; i < Map.Waypoints.Length; ++i)
|
for (var i = 0; i < Map.Waypoints.Length; ++i)
|
||||||
{
|
{
|
||||||
@ -2487,23 +2474,22 @@ namespace MobiusEditor.RedAlert
|
|||||||
waypointsSection[i.ToString()] = waypoint.Cell.Value.ToString();
|
waypointsSection[i.ToString()] = waypoint.Cell.Value.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var house in Map.Houses)
|
foreach (var house in Map.Houses)
|
||||||
{
|
{
|
||||||
if ((house.Type.ID < 0) || !house.Enabled)
|
if (house.Type.ID < 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
INI.WriteSection(new MapContext(Map, true), ini.Sections.Add(house.Type.Name), house);
|
House gameHouse = (House)house;
|
||||||
|
bool enabled = house.Enabled;
|
||||||
|
INITools.FillAndReAdd(ini, gameHouse.Type.Name, gameHouse, new MapContext(Map, false), enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
ini.Sections.Remove("Briefing");
|
ini.Sections.Remove("Briefing");
|
||||||
if (!string.IsNullOrEmpty(Map.BriefingSection.Briefing))
|
if (!string.IsNullOrEmpty(Map.BriefingSection.Briefing))
|
||||||
{
|
{
|
||||||
//var briefingSection = SaveIniBriefing(ini);
|
//var briefingSection = SaveIniBriefing(ini);
|
||||||
SaveIniBriefing(ini);
|
SaveIniBriefing(ini);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var stream = new MemoryStream())
|
using (var stream = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (var writer = new BinaryWriter(stream))
|
using (var writer = new BinaryWriter(stream))
|
||||||
@ -2540,11 +2526,9 @@ namespace MobiusEditor.RedAlert
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ini.Sections.Remove("MapPack");
|
ini.Sections.Remove("MapPack");
|
||||||
CompressLCWSection(ini.Sections.Add("MapPack"), stream.ToArray());
|
CompressLCWSection(ini.Sections.Add("MapPack"), stream.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var stream = new MemoryStream())
|
using (var stream = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (var writer = new BinaryWriter(stream))
|
using (var writer = new BinaryWriter(stream))
|
||||||
|
@ -18,33 +18,57 @@ namespace MobiusEditor.RedAlert
|
|||||||
{
|
{
|
||||||
public static class MissionTypes
|
public static class MissionTypes
|
||||||
{
|
{
|
||||||
|
public const string MISSION_SLEEP = "Sleep";
|
||||||
|
public const string MISSION_ATTACK = "Attack";
|
||||||
|
public const string MISSION_MOVE = "Move";
|
||||||
|
public const string MISSION_QMOVE = "QMove";
|
||||||
|
public const string MISSION_RETREAT = "Retreat";
|
||||||
|
public const string MISSION_STICKY = "Sticky";
|
||||||
|
public const string MISSION_GUARD = "Guard";
|
||||||
|
public const string MISSION_ENTER = "Enter";
|
||||||
|
public const string MISSION_CAPTURE = "Capture";
|
||||||
|
public const string MISSION_HARVEST = "Harvest";
|
||||||
|
public const string MISSION_AREAGUARD = "Area Guard";
|
||||||
|
public const string MISSION_RETURN = "Return";
|
||||||
|
public const string MISSION_STOP = "Stop";
|
||||||
|
public const string MISSION_AMBUSH = "Ambush";
|
||||||
|
public const string MISSION_HUNT = "Hunt";
|
||||||
|
public const string MISSION_UNLOAD = "Unload";
|
||||||
|
public const string MISSION_SABOTAGE = "Sabotage";
|
||||||
|
public const string MISSION_CONSTRUCTION = "Construction";
|
||||||
|
public const string MISSION_SELLING = "Selling";
|
||||||
|
public const string MISSION_REPAIR = "Repair";
|
||||||
|
public const string MISSION_RESCUE = "Rescue";
|
||||||
|
public const string MISSION_MISSILE = "Missile";
|
||||||
|
public const string MISSION_HARMLESS = "Harmless";
|
||||||
|
|
||||||
private static readonly string[] Types = new string[]
|
private static readonly string[] Types = new string[]
|
||||||
{
|
{
|
||||||
// Nyerguds upgrade: Removed irrelevant types for preplaced units.
|
// Nyerguds upgrade: Removed irrelevant types for preplaced units.
|
||||||
// Note that TeamTypes use a separate list, defined in the TeamMissionTypes class.
|
// Note that TeamTypes use a separate list, defined in the TeamMissionTypes class.
|
||||||
"Sleep",
|
MISSION_SLEEP,
|
||||||
//"Attack",
|
//MISSION_ATTACK,
|
||||||
//"Move",
|
//MISSION_MOVE,
|
||||||
//"QMove",
|
//MISSION_QMOVE,
|
||||||
//"Retreat",
|
//MISSION_RETREAT,
|
||||||
"Sticky",
|
MISSION_STICKY,
|
||||||
"Guard",
|
MISSION_GUARD,
|
||||||
//"Enter",
|
//MISSION_ENTER,
|
||||||
//"Capture",
|
//MISSION_CAPTURE,
|
||||||
"Harvest",
|
MISSION_HARVEST,
|
||||||
"Area Guard",
|
MISSION_AREAGUARD,
|
||||||
"Return",
|
MISSION_RETURN,
|
||||||
"Stop",
|
MISSION_STOP,
|
||||||
//"Ambush",
|
MISSION_AMBUSH,
|
||||||
"Hunt",
|
MISSION_HUNT,
|
||||||
"Unload",
|
MISSION_UNLOAD,
|
||||||
//"Sabotage",
|
//MISSION_SABOTAGE,
|
||||||
//"Construction",
|
//MISSION_CONSTRUCTION,
|
||||||
//"Selling",
|
//MISSION_SELLING,
|
||||||
//"Repair",
|
//MISSION_REPAIR,
|
||||||
//"Rescue",
|
//MISSION_RESCUE,
|
||||||
//"Missile",
|
//MISSION_MISSILE,
|
||||||
"Harmless"
|
MISSION_HARMLESS,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static IEnumerable<string> GetTypes()
|
public static IEnumerable<string> GetTypes()
|
||||||
|
@ -1378,10 +1378,13 @@ namespace MobiusEditor.Render
|
|||||||
{
|
{
|
||||||
float borderSize = Math.Max(0.5f, tileSize.Width / 60.0f);
|
float borderSize = Math.Max(0.5f, tileSize.Width / 60.0f);
|
||||||
float thickBorderSize = Math.Max(1f, tileSize.Width / 20.0f);
|
float thickBorderSize = Math.Max(1f, tileSize.Width / 20.0f);
|
||||||
HashSet<String> specifiedSet = new HashSet<String>(specified, StringComparer.InvariantCultureIgnoreCase);
|
HashSet<String> specifiedSet = new HashSet<String>(specified, StringComparer.OrdinalIgnoreCase);
|
||||||
using (var cellTriggersBackgroundBrush = new SolidBrush(Color.FromArgb(96, fillColor)))
|
using (SolidBrush prevCellTriggersBackgroundBrush = new SolidBrush(Color.FromArgb(48, fillColor)))
|
||||||
using (var cellTriggersBrush = new SolidBrush(Color.FromArgb(128, textColor)))
|
using (SolidBrush prevCellTriggersBrush = new SolidBrush(Color.FromArgb(64, textColor)))
|
||||||
using (var cellTriggerPen = new Pen(borderColor, thickborder ? thickBorderSize : borderSize))
|
using (Pen prevCellTriggerPen = new Pen(Color.FromArgb(128, borderColor), thickborder ? thickBorderSize : borderSize))
|
||||||
|
using (SolidBrush cellTriggersBackgroundBrush = new SolidBrush(Color.FromArgb(96, fillColor)))
|
||||||
|
using (SolidBrush cellTriggersBrush = new SolidBrush(Color.FromArgb(128, textColor)))
|
||||||
|
using (Pen cellTriggerPen = new Pen(borderColor, thickborder ? thickBorderSize : borderSize))
|
||||||
{
|
{
|
||||||
foreach (var (cell, cellTrigger) in map.CellTriggers)
|
foreach (var (cell, cellTrigger) in map.CellTriggers)
|
||||||
{
|
{
|
||||||
@ -1394,8 +1397,9 @@ namespace MobiusEditor.Render
|
|||||||
var y = cell / map.Metrics.Width;
|
var y = cell / map.Metrics.Width;
|
||||||
var location = new Point(x * tileSize.Width, y * tileSize.Height);
|
var location = new Point(x * tileSize.Width, y * tileSize.Height);
|
||||||
var textBounds = new Rectangle(location, tileSize);
|
var textBounds = new Rectangle(location, tileSize);
|
||||||
graphics.FillRectangle(cellTriggersBackgroundBrush, textBounds);
|
bool isPreview = cellTrigger.Tint.A != 255;
|
||||||
graphics.DrawRectangle(cellTriggerPen, textBounds);
|
graphics.FillRectangle(isPreview ? prevCellTriggersBackgroundBrush : cellTriggersBackgroundBrush, textBounds);
|
||||||
|
graphics.DrawRectangle(isPreview ? prevCellTriggerPen : cellTriggerPen, textBounds);
|
||||||
StringFormat stringFormat = new StringFormat
|
StringFormat stringFormat = new StringFormat
|
||||||
{
|
{
|
||||||
Alignment = StringAlignment.Center,
|
Alignment = StringAlignment.Center,
|
||||||
@ -1405,7 +1409,7 @@ namespace MobiusEditor.Render
|
|||||||
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 * tileScale)), Math.Max(1, (int)(48 * tileScale)), stringFormat, true))
|
||||||
{
|
{
|
||||||
graphics.DrawString(text.ToString(), font, cellTriggersBrush, textBounds, stringFormat);
|
graphics.DrawString(text.ToString(), font, isPreview ? prevCellTriggersBrush : cellTriggersBrush, textBounds, stringFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,8 @@ using MobiusEditor.Utility;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MobiusEditor.SoleSurvivor
|
namespace MobiusEditor.SoleSurvivor
|
||||||
{
|
{
|
||||||
@ -17,13 +14,34 @@ namespace MobiusEditor.SoleSurvivor
|
|||||||
|
|
||||||
protected const int cratePoints = 4;
|
protected const int cratePoints = 4;
|
||||||
protected const int teamStartPoints = 8;
|
protected const int teamStartPoints = 8;
|
||||||
|
|
||||||
|
protected static readonly IEnumerable<string> movieTypesSole = new string[]
|
||||||
|
{
|
||||||
|
"WESTLOGO",
|
||||||
|
};
|
||||||
|
|
||||||
|
protected static readonly IEnumerable<string> themeTypesSole = new string[]
|
||||||
|
{
|
||||||
|
"No Theme",
|
||||||
|
"WORKREMX",
|
||||||
|
"CRSHNVOX",
|
||||||
|
"DEPTHCHG",
|
||||||
|
"DRILL",
|
||||||
|
"HELLNVOX",
|
||||||
|
"IRONFIST",
|
||||||
|
"MERCY98",
|
||||||
|
"MUDREMX",
|
||||||
|
"CREEPING",
|
||||||
|
"MAP1",
|
||||||
|
};
|
||||||
|
|
||||||
public override String Name => "Sole Survivor";
|
public override String Name => "Sole Survivor";
|
||||||
public override GameType GameType => GameType.SoleSurvivor;
|
public override GameType GameType => GameType.SoleSurvivor;
|
||||||
public override bool IsMegaMap => true;
|
public override bool IsMegaMap => true;
|
||||||
|
|
||||||
public static bool CheckForSSmap(INI iniContents)
|
public static bool CheckForSSmap(INI iniContents)
|
||||||
{
|
{
|
||||||
return GeneralUtils.CheckForIniInfo(iniContents, "Crates");
|
return INITools.CheckForIniInfo(iniContents, "Crates");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CratesSection cratesSection;
|
protected CratesSection cratesSection;
|
||||||
@ -100,14 +118,19 @@ namespace MobiusEditor.SoleSurvivor
|
|||||||
flagColors[6] = Globals.TheTeamColorManager["MULTI2"];
|
flagColors[6] = Globals.TheTeamColorManager["MULTI2"];
|
||||||
// Multi8: RA Purple
|
// Multi8: RA Purple
|
||||||
flagColors[7] = new TeamColor(Globals.TheTeamColorManager, flagColors[0], "MULTI8", new Vector3(0.410f, 0.100f, 0.000f));
|
flagColors[7] = new TeamColor(Globals.TheTeamColorManager, flagColors[0], "MULTI8", new Vector3(0.410f, 0.100f, 0.000f));
|
||||||
|
List<String> movies = movieTypesTD.Concat(movieTypesSole).ToList();
|
||||||
|
ExplorerComparer sorter = new ExplorerComparer();
|
||||||
|
movies.Sort(sorter);
|
||||||
Size mapSize = !megaMap ? TiberianDawn.Constants.MaxSize : TiberianDawn.Constants.MaxSizeMega;
|
Size mapSize = !megaMap ? TiberianDawn.Constants.MaxSize : TiberianDawn.Constants.MaxSizeMega;
|
||||||
Map = new Map(basicSection, null, mapSize, typeof(House), houseTypes,
|
Map = new Map(basicSection, null, mapSize, typeof(House), houseTypes,
|
||||||
flagColors, TiberianDawn.TheaterTypes.GetTypes(), TiberianDawn.TemplateTypes.GetTypes(),
|
flagColors, TiberianDawn.TheaterTypes.GetTypes(), TiberianDawn.TemplateTypes.GetTypes(),
|
||||||
TiberianDawn.TerrainTypes.GetTypes(), OverlayTypes.GetTypes(), TiberianDawn.SmudgeTypes.GetTypes(Globals.ConvertCraters),
|
TiberianDawn.TerrainTypes.GetTypes(), OverlayTypes.GetTypes(), TiberianDawn.SmudgeTypes.GetTypes(Globals.ConvertCraters),
|
||||||
TiberianDawn.EventTypes.GetTypes(), cellEventTypes, unitEventTypes, structureEventTypes, terrainEventTypes,
|
TiberianDawn.EventTypes.GetTypes(), cellEventTypes, unitEventTypes, structureEventTypes, terrainEventTypes,
|
||||||
TiberianDawn.ActionTypes.GetTypes(), cellActionTypes, unitActionTypes, structureActionTypes, terrainActionTypes,
|
TiberianDawn.ActionTypes.GetTypes(), cellActionTypes, unitActionTypes, structureActionTypes, terrainActionTypes,
|
||||||
TiberianDawn.MissionTypes.GetTypes(), DirectionTypes.GetMainTypes(), DirectionTypes.GetAllTypes(), infantry, units,
|
TiberianDawn.MissionTypes.GetTypes(), TiberianDawn.MissionTypes.MISSION_GUARD, TiberianDawn.MissionTypes.MISSION_STOP,
|
||||||
buildings, TiberianDawn.TeamMissionTypes.GetTypes(), fullTechnoTypes, waypoints, movieTypes, themeTypes)
|
TiberianDawn.MissionTypes.MISSION_HARVEST, TiberianDawn.MissionTypes.MISSION_UNLOAD, DirectionTypes.GetMainTypes(),
|
||||||
|
DirectionTypes.GetAllTypes(), infantry, units, buildings, TiberianDawn.TeamMissionTypes.GetTypes(), fullTechnoTypes,
|
||||||
|
waypoints, movies, movieEmpty, themeTypesSole, themeEmpty)
|
||||||
{
|
{
|
||||||
TiberiumOrGoldValue = 25
|
TiberiumOrGoldValue = 25
|
||||||
};
|
};
|
||||||
@ -137,7 +160,14 @@ namespace MobiusEditor.SoleSurvivor
|
|||||||
var cratesIniSection = extraSections.Extract("Crates");
|
var cratesIniSection = extraSections.Extract("Crates");
|
||||||
if (cratesIniSection != null)
|
if (cratesIniSection != null)
|
||||||
{
|
{
|
||||||
INI.ParseSection(new MapContext(Map, false), cratesIniSection, this.cratesSection);
|
try
|
||||||
|
{
|
||||||
|
INI.ParseSection(new MapContext(Map, false), cratesIniSection, this.cratesSection);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
errors.Add("Parsing of [Crates] section failed: " + ex.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
@ -192,7 +222,7 @@ namespace MobiusEditor.SoleSurvivor
|
|||||||
public override HashSet<string> GetHousesWithProduction()
|
public override HashSet<string> GetHousesWithProduction()
|
||||||
{
|
{
|
||||||
// Not applicable. Return empty set.
|
// Not applicable. Return empty set.
|
||||||
return new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
|
return new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,125 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
|
|
||||||
protected static readonly IEnumerable<ITechnoType> fullTechnoTypes;
|
protected static readonly IEnumerable<ITechnoType> fullTechnoTypes;
|
||||||
|
|
||||||
protected const string defVidVal = "x";
|
protected const string movieEmpty = "x";
|
||||||
protected readonly IEnumerable<string> movieTypes;
|
protected readonly IEnumerable<string> movieTypes;
|
||||||
|
|
||||||
|
protected static readonly IEnumerable<string> movieTypesTD = new string[]
|
||||||
|
{
|
||||||
|
"AIRSTRK",
|
||||||
|
"AKIRA",
|
||||||
|
"BANNER",
|
||||||
|
"BANR_NOD",
|
||||||
|
"BCANYON",
|
||||||
|
"BKGROUND",
|
||||||
|
"BLACKOUT",
|
||||||
|
"BODYBAGS",
|
||||||
|
"BOMBAWAY",
|
||||||
|
"BOMBFLEE",
|
||||||
|
"BURDET1",
|
||||||
|
"BURDET2",
|
||||||
|
"CC2TEASE",
|
||||||
|
"CONSYARD",
|
||||||
|
"DESFLEES",
|
||||||
|
"DESKILL",
|
||||||
|
"DESOLAT",
|
||||||
|
"DESSWEEP",
|
||||||
|
"DINO",
|
||||||
|
"FLAG",
|
||||||
|
"FLYY",
|
||||||
|
"FORESTKL",
|
||||||
|
"GAMEOVER",
|
||||||
|
"GDI1",
|
||||||
|
"GDI2",
|
||||||
|
"GDI3",
|
||||||
|
"GDI4A",
|
||||||
|
"GDI4B",
|
||||||
|
"GDI5",
|
||||||
|
"GDI6",
|
||||||
|
"GDI7",
|
||||||
|
"GDI8A",
|
||||||
|
"GDI8B",
|
||||||
|
"GDI9",
|
||||||
|
"GDI10",
|
||||||
|
"GDI11",
|
||||||
|
"GDI12",
|
||||||
|
"GDI13",
|
||||||
|
"GDI14",
|
||||||
|
"GDI15",
|
||||||
|
"GDI3LOSE",
|
||||||
|
"GDIEND1",
|
||||||
|
"GDIEND2",
|
||||||
|
"GDIFINA",
|
||||||
|
"GDIFINB",
|
||||||
|
"GDILOSE",
|
||||||
|
"GENERIC",
|
||||||
|
"GUNBOAT",
|
||||||
|
"HELLVALY",
|
||||||
|
"INFERNO",
|
||||||
|
"INSITES",
|
||||||
|
"INTRO2",
|
||||||
|
"IONTEST",
|
||||||
|
"KANEPRE",
|
||||||
|
"LANDING",
|
||||||
|
"LOGO",
|
||||||
|
"NAPALM",
|
||||||
|
"NITEJUMP",
|
||||||
|
"NOD1",
|
||||||
|
"NOD2",
|
||||||
|
"NOD3",
|
||||||
|
"NOD4A",
|
||||||
|
"NOD4B",
|
||||||
|
"NOD5",
|
||||||
|
"NOD6",
|
||||||
|
"NOD7A",
|
||||||
|
"NOD7B",
|
||||||
|
"NOD8",
|
||||||
|
"NOD9",
|
||||||
|
"NOD10A",
|
||||||
|
"NOD10B",
|
||||||
|
"NOD11",
|
||||||
|
"NOD12",
|
||||||
|
"NOD13",
|
||||||
|
"NOD1PRE",
|
||||||
|
"NODEND1",
|
||||||
|
"NODEND2",
|
||||||
|
"NODEND3",
|
||||||
|
"NODEND4",
|
||||||
|
"NODFINAL",
|
||||||
|
"NODFLEES",
|
||||||
|
"NODLOSE",
|
||||||
|
"NODSWEEP",
|
||||||
|
"NUKE",
|
||||||
|
"OBEL",
|
||||||
|
"PARATROP",
|
||||||
|
"PINTLE",
|
||||||
|
"PLANECRA",
|
||||||
|
"PODIUM",
|
||||||
|
"REFINT",
|
||||||
|
"REFINERY",
|
||||||
|
"RETRO",
|
||||||
|
"SABOTAGE",
|
||||||
|
"SAMDIE",
|
||||||
|
"SAMSITE",
|
||||||
|
"SEIGE",
|
||||||
|
"SETHPRE",
|
||||||
|
"SIZZLE",
|
||||||
|
"SIZZLE2",
|
||||||
|
"SPYCRASH",
|
||||||
|
"STEALTH",
|
||||||
|
"SUNDIAL",
|
||||||
|
"TANKGO",
|
||||||
|
"TANKKILL",
|
||||||
|
"TBRINFO1",
|
||||||
|
"TBRINFO2",
|
||||||
|
"TBRINFO3",
|
||||||
|
"TIBERFX",
|
||||||
|
"TRAILER",
|
||||||
|
"TRTKIL_D",
|
||||||
|
"TURTKILL",
|
||||||
|
"VISOR",
|
||||||
|
};
|
||||||
|
|
||||||
protected static readonly IEnumerable<string> movieTypesAdditional = new string[]
|
protected static readonly IEnumerable<string> movieTypesAdditional = new string[]
|
||||||
{
|
{
|
||||||
"BODYBAGS (Classic only)",
|
"BODYBAGS (Classic only)",
|
||||||
@ -54,6 +170,8 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
"TRTKIL_D (Classic only)",
|
"TRTKIL_D (Classic only)",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected const string themeEmpty = "No Theme";
|
||||||
|
|
||||||
protected static readonly IEnumerable<string> themeTypes = new string[]
|
protected static readonly IEnumerable<string> themeTypes = new string[]
|
||||||
{
|
{
|
||||||
"No Theme",
|
"No Theme",
|
||||||
@ -98,6 +216,7 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
"NOD_MAP1",
|
"NOD_MAP1",
|
||||||
"OUTTAKES"
|
"OUTTAKES"
|
||||||
};
|
};
|
||||||
|
|
||||||
public virtual string Name => "Tiberian Dawn";
|
public virtual string Name => "Tiberian Dawn";
|
||||||
|
|
||||||
public virtual GameType GameType => GameType.TiberianDawn;
|
public virtual GameType GameType => GameType.TiberianDawn;
|
||||||
@ -145,8 +264,8 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Remove any sections known and handled / disallowed by the editor.
|
// Remove any sections known and handled / disallowed by the editor.
|
||||||
ini.Sections.Remove("Basic");
|
INITools.ClearDataFrom(ini, "Basic", (BasicSection)Map.BasicSection);
|
||||||
ini.Sections.Remove("Map");
|
INITools.ClearDataFrom(ini, "Map", Map.MapSection);
|
||||||
ini.Sections.Remove("Briefing");
|
ini.Sections.Remove("Briefing");
|
||||||
ini.Sections.Remove("Steam");
|
ini.Sections.Remove("Steam");
|
||||||
ini.Sections.Remove("TeamTypes");
|
ini.Sections.Remove("TeamTypes");
|
||||||
@ -163,7 +282,7 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
ini.Sections.Remove("CellTriggers");
|
ini.Sections.Remove("CellTriggers");
|
||||||
foreach (var house in Map.Houses)
|
foreach (var house in Map.Houses)
|
||||||
{
|
{
|
||||||
ini.Sections.Remove(house.Type.Name);
|
INITools.ClearDataFrom(ini, house.Type.Name, (House)house);
|
||||||
}
|
}
|
||||||
extraSections = ini.Sections.Count == 0 ? null : ini.Sections;
|
extraSections = ini.Sections.Count == 0 ? null : ini.Sections;
|
||||||
}
|
}
|
||||||
@ -171,7 +290,7 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
|
|
||||||
public static bool CheckForMegamap(INI iniContents)
|
public static bool CheckForMegamap(INI iniContents)
|
||||||
{
|
{
|
||||||
return GeneralUtils.CheckForIniInfo(iniContents, "Map", "Version", "1");
|
return INITools.CheckForIniInfo(iniContents, "Map", "Version", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
static GamePlugin()
|
static GamePlugin()
|
||||||
@ -194,10 +313,22 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
movies.AddRange(movieTypesAdditional);
|
// Preparation for decoupling from remaster files.
|
||||||
|
if (movies.Count == 0)
|
||||||
|
{
|
||||||
|
movies.AddRange(movieTypesTD);
|
||||||
|
}
|
||||||
|
foreach (string mov in movieTypesAdditional)
|
||||||
|
{
|
||||||
|
string movName = GeneralUtils.TrimRemarks(mov, true, ';', '(');
|
||||||
|
if (movies.FirstOrDefault(m => m.Equals(movName, StringComparison.OrdinalIgnoreCase)) == null)
|
||||||
|
{
|
||||||
|
movies.Add(mov);
|
||||||
|
}
|
||||||
|
}
|
||||||
movies = movies.Distinct().ToList();
|
movies = movies.Distinct().ToList();
|
||||||
movies.Sort(new ExplorerComparer());
|
movies.Sort(new ExplorerComparer());
|
||||||
movies.Insert(0, defVidVal);
|
movies.Insert(0, movieEmpty);
|
||||||
movieTypes = movies.ToArray();
|
movieTypes = movies.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,8 +394,10 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
TerrainTypes.GetTypes(), OverlayTypes.GetTypes(), SmudgeTypes.GetTypes(Globals.ConvertCraters),
|
TerrainTypes.GetTypes(), OverlayTypes.GetTypes(), SmudgeTypes.GetTypes(Globals.ConvertCraters),
|
||||||
EventTypes.GetTypes(), cellEventTypes, unitEventTypes, structureEventTypes, terrainEventTypes,
|
EventTypes.GetTypes(), cellEventTypes, unitEventTypes, structureEventTypes, terrainEventTypes,
|
||||||
ActionTypes.GetTypes(), cellActionTypes, unitActionTypes, structureActionTypes, terrainActionTypes,
|
ActionTypes.GetTypes(), cellActionTypes, unitActionTypes, structureActionTypes, terrainActionTypes,
|
||||||
MissionTypes.GetTypes(), DirectionTypes.GetMainTypes(), DirectionTypes.GetAllTypes(), InfantryTypes.GetTypes(), UnitTypes.GetTypes(Globals.DisableAirUnits),
|
MissionTypes.GetTypes(), MissionTypes.MISSION_GUARD, MissionTypes.MISSION_STOP, MissionTypes.MISSION_HARVEST,
|
||||||
BuildingTypes.GetTypes(), TeamMissionTypes.GetTypes(), fullTechnoTypes, waypoints, movieTypes, themeTypes)
|
MissionTypes.MISSION_UNLOAD, DirectionTypes.GetMainTypes(), DirectionTypes.GetAllTypes(), InfantryTypes.GetTypes(),
|
||||||
|
UnitTypes.GetTypes(Globals.DisableAirUnits), BuildingTypes.GetTypes(), TeamMissionTypes.GetTypes(),
|
||||||
|
fullTechnoTypes, waypoints, movieTypes, movieEmpty, themeTypes, themeEmpty)
|
||||||
{
|
{
|
||||||
TiberiumOrGoldValue = 25
|
TiberiumOrGoldValue = 25
|
||||||
};
|
};
|
||||||
@ -377,9 +510,9 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
|
|
||||||
private void ParseIniContent(INI ini, Byte[] iniBytes, Boolean forSole)
|
private void ParseIniContent(INI ini, Byte[] iniBytes, Boolean forSole)
|
||||||
{
|
{
|
||||||
Encoding encUtf8 = new UTF8Encoding(false, false);
|
|
||||||
Encoding encDOS = Encoding.GetEncoding(437);
|
Encoding encDOS = Encoding.GetEncoding(437);
|
||||||
String iniText = encDOS.GetString(iniBytes);
|
String iniText = encDOS.GetString(iniBytes);
|
||||||
|
Encoding encUtf8 = new UTF8Encoding(false, false);
|
||||||
String iniTextUtf8 = encUtf8.GetString(iniBytes);
|
String iniTextUtf8 = encUtf8.GetString(iniBytes);
|
||||||
if (!forSole)
|
if (!forSole)
|
||||||
{
|
{
|
||||||
@ -480,7 +613,7 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
}
|
}
|
||||||
// Only process the ini if any of the detected lines have a found amount of more than one. If references to literal ROAD2 are found,
|
// Only process the ini if any of the detected lines have a found amount of more than one. If references to literal ROAD2 are found,
|
||||||
// also process the ini so they can be removed; we do not want those to be accepted as valid type by the editor.
|
// also process the ini so they can be removed; we do not want those to be accepted as valid type by the editor.
|
||||||
if (foundAmounts.All(k => k.Value == 1) && !cellTypes.Values.Contains(OverlayTypes.Road2.Name, StringComparer.InvariantCultureIgnoreCase))
|
if (foundAmounts.All(k => k.Value == 1) && !cellTypes.Values.Contains(OverlayTypes.Road2.Name, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return iniText;
|
return iniText;
|
||||||
}
|
}
|
||||||
@ -549,29 +682,27 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
{
|
{
|
||||||
var errors = new List<string>();
|
var errors = new List<string>();
|
||||||
Map.BeginUpdate();
|
Map.BeginUpdate();
|
||||||
var basicSection = ini.Sections.Extract("Basic");
|
BasicSection basic = (BasicSection)Map.BasicSection;
|
||||||
|
INISection basicSection = INITools.ParseAndLeaveRemainder(ini, "Basic", Map.BasicSection, new MapContext(Map, false));
|
||||||
if (basicSection != null)
|
if (basicSection != null)
|
||||||
{
|
{
|
||||||
INI.ParseSection(new MapContext(Map, false), basicSection, Map.BasicSection);
|
|
||||||
char[] cutfrom = { ';', '(' };
|
char[] cutfrom = { ';', '(' };
|
||||||
string[] toAddRem = movieTypesAdditional.Select(vid => GeneralUtils.TrimRemarks(vid, true, cutfrom)).ToArray();
|
string[] toAddRem = movieTypesAdditional.Select(vid => GeneralUtils.TrimRemarks(vid, true, cutfrom)).ToArray();
|
||||||
Model.BasicSection basic = Map.BasicSection;
|
|
||||||
const string remark = " (Classic only)";
|
const string remark = " (Classic only)";
|
||||||
basic.Intro = GeneralUtils.AddRemarks(basic.Intro, defVidVal, true, toAddRem, remark);
|
basic.Intro = GeneralUtils.AddRemarks(basic.Intro, movieEmpty, true, toAddRem, remark);
|
||||||
basic.Brief = GeneralUtils.AddRemarks(basic.Brief, defVidVal, true, toAddRem, remark);
|
basic.Brief = GeneralUtils.AddRemarks(basic.Brief, movieEmpty, true, toAddRem, remark);
|
||||||
basic.Action = GeneralUtils.AddRemarks(basic.Action, defVidVal, true, toAddRem, remark);
|
basic.Action = GeneralUtils.AddRemarks(basic.Action, movieEmpty, true, toAddRem, remark);
|
||||||
basic.Win = GeneralUtils.AddRemarks(basic.Win, defVidVal, true, toAddRem, remark);
|
basic.Win = GeneralUtils.AddRemarks(basic.Win, movieEmpty, true, toAddRem, remark);
|
||||||
basic.Win2 = GeneralUtils.AddRemarks(basic.Win2, defVidVal, true, toAddRem, remark);
|
basic.Win2 = GeneralUtils.AddRemarks(basic.Win2, movieEmpty, true, toAddRem, remark);
|
||||||
basic.Win3 = GeneralUtils.AddRemarks(basic.Win3, defVidVal, true, toAddRem, remark);
|
basic.Win3 = GeneralUtils.AddRemarks(basic.Win3, movieEmpty, true, toAddRem, remark);
|
||||||
basic.Win4 = GeneralUtils.AddRemarks(basic.Win4, defVidVal, true, toAddRem, remark);
|
basic.Win4 = GeneralUtils.AddRemarks(basic.Win4, movieEmpty, true, toAddRem, remark);
|
||||||
basic.Lose = GeneralUtils.AddRemarks(basic.Lose, defVidVal, true, toAddRem, remark);
|
basic.Lose = GeneralUtils.AddRemarks(basic.Lose, movieEmpty, true, toAddRem, remark);
|
||||||
}
|
}
|
||||||
Map.BasicSection.Player = Map.HouseTypes.Where(t => t.Equals(Map.BasicSection.Player)).FirstOrDefault()?.Name ?? Map.HouseTypes.First().Name;
|
Map.BasicSection.Player = Map.HouseTypes.Where(t => t.Equals(Map.BasicSection.Player)).FirstOrDefault()?.Name ?? Map.HouseTypes.First().Name;
|
||||||
var mapSection = ini.Sections.Extract("Map");
|
INISection mapSection = INITools.ParseAndLeaveRemainder(ini, "Map", Map.MapSection, new MapContext(Map, false));
|
||||||
if (mapSection != null)
|
// Also clear megamap indicator.
|
||||||
{
|
if (mapSection.Keys.Remove("Version") && mapSection.Keys.Count == 0)
|
||||||
INI.ParseSection(new MapContext(Map, false), mapSection, Map.MapSection);
|
ini.Sections.Remove(mapSection.Name);
|
||||||
}
|
|
||||||
Map.MapSection.FixBounds();
|
Map.MapSection.FixBounds();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//MessageBox.Show("Graphics loaded");
|
//MessageBox.Show("Graphics loaded");
|
||||||
@ -591,7 +722,7 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
bool addSpace = false;
|
bool addSpace = false;
|
||||||
while (briefingSection.Keys.Contains(lineStr = line.ToString()))
|
while (briefingSection.Keys.Contains(lineStr = line.ToString()))
|
||||||
{
|
{
|
||||||
String briefLine = briefingSection[lineStr].Trim();
|
String briefLine = briefingSection[lineStr].TrimStart();
|
||||||
// C&C95 v1.06 line break format.
|
// C&C95 v1.06 line break format.
|
||||||
bool hasBreak = briefLine.EndsWith("##");
|
bool hasBreak = briefLine.EndsWith("##");
|
||||||
if (hasBreak)
|
if (hasBreak)
|
||||||
@ -602,7 +733,7 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
{
|
{
|
||||||
briefLines.Append(" ");
|
briefLines.Append(" ");
|
||||||
}
|
}
|
||||||
briefLines.Append(briefLine);
|
briefLines.Append(briefLine.TrimEnd());
|
||||||
if (hasBreak)
|
if (hasBreak)
|
||||||
{
|
{
|
||||||
briefLines.AppendLine();
|
briefLines.AppendLine();
|
||||||
@ -611,7 +742,6 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
Map.BriefingSection.Briefing = briefLines.ToString();
|
Map.BriefingSection.Briefing = briefLines.ToString();
|
||||||
//Map.BriefingSection.Briefing = string.Join(" ", briefingSection.Keys.Select(k => k.Value)).Replace("@", Environment.NewLine);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var steamSection = ini.Sections.Extract("Steam");
|
var steamSection = ini.Sections.Extract("Steam");
|
||||||
@ -815,11 +945,11 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
// Sort
|
// Sort
|
||||||
var comparer = new ExplorerComparer();
|
var comparer = new ExplorerComparer();
|
||||||
triggers.Sort((x, y) => comparer.Compare(x.Name, y.Name));
|
triggers.Sort((x, y) => comparer.Compare(x.Name, y.Name));
|
||||||
Dictionary<string, string> checkTrigs = Trigger.None.Yield().Concat(triggers.Select(t => t.Name)).ToDictionary(t => t, t => t, StringComparer.InvariantCultureIgnoreCase);
|
Dictionary<string, string> checkTrigs = Trigger.None.Yield().Concat(triggers.Select(t => t.Name)).ToDictionary(t => t, t => t, StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<string> checkCellTrigs = Map.FilterCellTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> checkCellTrigs = Map.FilterCellTriggers(triggers).Select(t => t.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<string> checkUnitTrigs = Trigger.None.Yield().Concat(Map.FilterUnitTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> checkUnitTrigs = Trigger.None.Yield().Concat(Map.FilterUnitTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<string> checkStrcTrigs = Trigger.None.Yield().Concat(Map.FilterStructureTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> checkStrcTrigs = Trigger.None.Yield().Concat(Map.FilterStructureTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
HashSet<string> checkTerrTrigs = Trigger.None.Yield().Concat(Map.FilterTerrainTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
|
HashSet<string> checkTerrTrigs = Trigger.None.Yield().Concat(Map.FilterTerrainTriggers(triggers).Select(t => t.Name)).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
var smudgeSection = ini.Sections.Extract("Smudge");
|
var smudgeSection = ini.Sections.Extract("Smudge");
|
||||||
if (smudgeSection != null)
|
if (smudgeSection != null)
|
||||||
{
|
{
|
||||||
@ -1069,7 +1199,7 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
House = Map.HouseTypes.Where(t => t.Equals(tokens[0])).FirstOrDefault(),
|
House = Map.HouseTypes.Where(t => t.Equals(tokens[0])).FirstOrDefault(),
|
||||||
Strength = strength,
|
Strength = strength,
|
||||||
Direction = DirectionType.GetDirectionType(dirValue, Map.UnitDirectionTypes),
|
Direction = DirectionType.GetDirectionType(dirValue, Map.UnitDirectionTypes),
|
||||||
Mission = Map.MissionTypes.Where(t => t.Equals(tokens[5])).FirstOrDefault() ?? Map.GetDefaultMission(unitType),
|
Mission = Map.MissionTypes.Where(t => t.Equals(tokens[5], StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault() ?? Map.GetDefaultMission(unitType),
|
||||||
};
|
};
|
||||||
// "Rescue" and "Unload" both make the MCV deploy, but "Rescue" looks very strange in the editor, so we keep only one of them and convert the other.
|
// "Rescue" and "Unload" both make the MCV deploy, but "Rescue" looks very strange in the editor, so we keep only one of them and convert the other.
|
||||||
if (MissionTypes.MISSION_RESCUE.Equals(tokens[5], StringComparison.InvariantCultureIgnoreCase) && newUnit.Type.Equals(UnitTypes.MCV))
|
if (MissionTypes.MISSION_RESCUE.Equals(tokens[5], StringComparison.InvariantCultureIgnoreCase) && newUnit.Type.Equals(UnitTypes.MCV))
|
||||||
@ -1685,20 +1815,9 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var houseSection = ini.Sections.Extract(house.Type.Name);
|
House gameHouse = (House)house;
|
||||||
if (houseSection != null)
|
INISection houseSection = INITools.ParseAndLeaveRemainder(ini, gameHouse.Type.Name, gameHouse, new MapContext(Map, false));
|
||||||
{
|
gameHouse.Enabled = houseSection != null;
|
||||||
INI.ParseSection(new MapContext(Map, false), houseSection, house);
|
|
||||||
house.Enabled = true;
|
|
||||||
string correctedEdge;
|
|
||||||
if (!correctedEdges.TryGetValue(house.Edge, out correctedEdge))
|
|
||||||
correctedEdge = defaultEdge;
|
|
||||||
house.Edge = correctedEdge;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
house.Enabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
UpdateBasePlayerHouse();
|
UpdateBasePlayerHouse();
|
||||||
errors.AddRange(CheckTriggers(triggers, true, true, false, out _, false, out _));
|
errors.AddRange(CheckTriggers(triggers, true, true, false, out _, false, out _));
|
||||||
@ -1707,7 +1826,7 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
Map.Triggers.AddRange(triggers);
|
Map.Triggers.AddRange(triggers);
|
||||||
Map.TeamTypes.Sort((x, y) => comparer.Compare(x.Name, y.Name));
|
Map.TeamTypes.Sort((x, y) => comparer.Compare(x.Name, y.Name));
|
||||||
extraSections = ini.Sections;
|
extraSections = ini.Sections;
|
||||||
bool switchedToSolo = !forSole && forceSoloMission && !Map.BasicSection.SoloMission
|
bool switchedToSolo = !forSole && forceSoloMission && !basic.SoloMission
|
||||||
&& ((triggers.Any(t => t.Action1.ActionType == ActionTypes.ACTION_WIN) && triggers.Any(t => t.Action1.ActionType == ActionTypes.ACTION_LOSE))
|
&& ((triggers.Any(t => t.Action1.ActionType == ActionTypes.ACTION_WIN) && triggers.Any(t => t.Action1.ActionType == ActionTypes.ACTION_LOSE))
|
||||||
|| triggers.Any(t => t.Event1.EventType == EventTypes.EVENT_ANY && t.Action1.ActionType == ActionTypes.ACTION_WINLOSE));
|
|| triggers.Any(t => t.Event1.EventType == EventTypes.EVENT_ANY && t.Action1.ActionType == ActionTypes.ACTION_WINLOSE));
|
||||||
if (switchedToSolo)
|
if (switchedToSolo)
|
||||||
@ -2009,7 +2128,7 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
|
|
||||||
protected INISection SaveIniBasic(INI ini, string fileName)
|
protected INISection SaveIniBasic(INI ini, string fileName)
|
||||||
{
|
{
|
||||||
Model.BasicSection basic = Map.BasicSection;
|
BasicSection basic = (BasicSection)Map.BasicSection;
|
||||||
char[] cutfrom = { ';', '(' };
|
char[] cutfrom = { ';', '(' };
|
||||||
basic.Intro = GeneralUtils.TrimRemarks(basic.Intro, true, cutfrom);
|
basic.Intro = GeneralUtils.TrimRemarks(basic.Intro, true, cutfrom);
|
||||||
basic.Brief = GeneralUtils.TrimRemarks(basic.Brief, true, cutfrom);
|
basic.Brief = GeneralUtils.TrimRemarks(basic.Brief, true, cutfrom);
|
||||||
@ -2033,15 +2152,14 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
}
|
}
|
||||||
basic.Name = String.Join(" ", name);
|
basic.Name = String.Join(" ", name);
|
||||||
}
|
}
|
||||||
INISection basicSection = ini.Sections.Add("Basic");
|
INISection basicSection = INITools.FillAndReAdd(ini, "Basic", (BasicSection)Map.BasicSection, new MapContext(Map, false), true);
|
||||||
INI.WriteSection(new MapContext(Map, false), basicSection, Map.BasicSection);
|
|
||||||
return basicSection;
|
return basicSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected INISection SaveIniMap(INI ini)
|
protected INISection SaveIniMap(INI ini)
|
||||||
{
|
{
|
||||||
Map.MapSection.FixBounds();
|
Map.MapSection.FixBounds();
|
||||||
INISection mapSection = ini.Sections.Add("Map");
|
INISection mapSection = INITools.FillAndReAdd(ini, "Map", Map.MapSection, new MapContext(Map, false), true);
|
||||||
if (isMegaMap)
|
if (isMegaMap)
|
||||||
{
|
{
|
||||||
mapSection["Version"] = "1";
|
mapSection["Version"] = "1";
|
||||||
@ -2347,13 +2465,17 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
List<INISection> houseSections = new List<INISection>();
|
List<INISection> houseSections = new List<INISection>();
|
||||||
foreach (var house in Map.Houses)
|
foreach (var house in Map.Houses)
|
||||||
{
|
{
|
||||||
if ((house.Type.ID < 0) || !house.Enabled)
|
if (house.Type.ID < 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
INISection houseSection = ini.Sections.Add(house.Type.Name);
|
House gameHouse = (House)house;
|
||||||
INI.WriteSection(new MapContext(Map, false), houseSection, house);
|
bool enabled = house.Enabled;
|
||||||
houseSections.Add(houseSection);
|
INISection houseSection = INITools.FillAndReAdd(ini, gameHouse.Type.Name, gameHouse, new MapContext(Map, false), enabled);
|
||||||
|
if (houseSection != null)
|
||||||
|
{
|
||||||
|
houseSections.Add(houseSection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return houseSections;
|
return houseSections;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ namespace MobiusEditor.TiberianDawn
|
|||||||
MISSION_AREA_GUARD,
|
MISSION_AREA_GUARD,
|
||||||
//MISSION_RETURN,
|
//MISSION_RETURN,
|
||||||
MISSION_STOP,
|
MISSION_STOP,
|
||||||
//MISSION_AMBUSH,
|
MISSION_AMBUSH,
|
||||||
MISSION_HUNT,
|
MISSION_HUNT,
|
||||||
//MISSION_TIMED_HUNT,
|
//MISSION_TIMED_HUNT,
|
||||||
MISSION_UNLOAD,
|
MISSION_UNLOAD,
|
||||||
|
@ -45,6 +45,8 @@ namespace MobiusEditor.Tools
|
|||||||
private readonly Dictionary<int, CellTrigger> undoCellTriggers = new Dictionary<int, CellTrigger>();
|
private readonly Dictionary<int, CellTrigger> undoCellTriggers = new Dictionary<int, CellTrigger>();
|
||||||
private readonly Dictionary<int, CellTrigger> redoCellTriggers = new Dictionary<int, CellTrigger>();
|
private readonly Dictionary<int, CellTrigger> redoCellTriggers = new Dictionary<int, CellTrigger>();
|
||||||
|
|
||||||
|
private Map previewMap;
|
||||||
|
protected override Map RenderMap => previewMap;
|
||||||
private bool placementMode;
|
private bool placementMode;
|
||||||
|
|
||||||
public string TriggerToolTip { get; set; }
|
public string TriggerToolTip { get; set; }
|
||||||
@ -52,6 +54,7 @@ namespace MobiusEditor.Tools
|
|||||||
public CellTriggersTool(MapPanel mapPanel, MapLayerFlag layers, ToolStripStatusLabel statusLbl, ComboBox triggerCombo, IGamePlugin plugin, UndoRedoList<UndoRedoEventArgs> url)
|
public CellTriggersTool(MapPanel mapPanel, MapLayerFlag layers, ToolStripStatusLabel statusLbl, ComboBox triggerCombo, IGamePlugin plugin, UndoRedoList<UndoRedoEventArgs> url)
|
||||||
: base(mapPanel, layers, statusLbl, plugin, url)
|
: base(mapPanel, layers, statusLbl, plugin, url)
|
||||||
{
|
{
|
||||||
|
previewMap = map;
|
||||||
this.triggerComboBox = triggerCombo;
|
this.triggerComboBox = triggerCombo;
|
||||||
UpdateDataSource();
|
UpdateDataSource();
|
||||||
}
|
}
|
||||||
@ -178,46 +181,48 @@ namespace MobiusEditor.Tools
|
|||||||
{
|
{
|
||||||
RemoveCellTrigger(e.NewCell);
|
RemoveCellTrigger(e.NewCell);
|
||||||
}
|
}
|
||||||
|
mapPanel.Invalidate(map, e.NewCell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetCellTrigger(Point location)
|
private void SetCellTrigger(Point location)
|
||||||
{
|
{
|
||||||
if (triggerComboBox.SelectedItem is string trigger && !Trigger.IsEmpty(trigger))
|
if (!(triggerComboBox.SelectedItem is string trigger) || Trigger.IsEmpty(trigger))
|
||||||
{
|
{
|
||||||
if (map.Metrics.GetCell(location, out int cell))
|
return;
|
||||||
{
|
|
||||||
if (map.CellTriggers[cell] == null)
|
|
||||||
{
|
|
||||||
if (!undoCellTriggers.ContainsKey(cell))
|
|
||||||
{
|
|
||||||
undoCellTriggers[cell] = map.CellTriggers[cell];
|
|
||||||
}
|
|
||||||
var cellTrigger = new CellTrigger(trigger);
|
|
||||||
map.CellTriggers[cell] = cellTrigger;
|
|
||||||
redoCellTriggers[cell] = cellTrigger;
|
|
||||||
mapPanel.Invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!map.Metrics.GetCell(location, out int cell) || map.CellTriggers[cell] != null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!undoCellTriggers.ContainsKey(cell))
|
||||||
|
{
|
||||||
|
undoCellTriggers[cell] = map.CellTriggers[cell];
|
||||||
|
}
|
||||||
|
var cellTrigger = new CellTrigger(trigger);
|
||||||
|
map.CellTriggers[cell] = cellTrigger;
|
||||||
|
redoCellTriggers[cell] = cellTrigger;
|
||||||
|
mapPanel.Invalidate(map, navigationWidget.MouseCell);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveCellTrigger(Point location)
|
private void RemoveCellTrigger(Point location)
|
||||||
{
|
{
|
||||||
if (map.Metrics.GetCell(location, out int cell))
|
if (!map.Metrics.GetCell(location, out int cell))
|
||||||
{
|
{
|
||||||
var cellTrigger = map.CellTriggers[cell];
|
return;
|
||||||
if (cellTrigger != null)
|
|
||||||
{
|
|
||||||
if (!undoCellTriggers.ContainsKey(cell))
|
|
||||||
{
|
|
||||||
undoCellTriggers[cell] = map.CellTriggers[cell];
|
|
||||||
}
|
|
||||||
map.CellTriggers[cell] = null;
|
|
||||||
redoCellTriggers[cell] = null;
|
|
||||||
mapPanel.Invalidate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
var cellTrigger = map.CellTriggers[cell];
|
||||||
|
if (cellTrigger == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!undoCellTriggers.ContainsKey(cell))
|
||||||
|
{
|
||||||
|
undoCellTriggers[cell] = map.CellTriggers[cell];
|
||||||
|
}
|
||||||
|
map.CellTriggers[cell] = null;
|
||||||
|
redoCellTriggers[cell] = null;
|
||||||
|
mapPanel.Invalidate(map, navigationWidget.MouseCell);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnterPlacementMode()
|
private void EnterPlacementMode()
|
||||||
@ -227,6 +232,7 @@ namespace MobiusEditor.Tools
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
placementMode = true;
|
placementMode = true;
|
||||||
|
mapPanel.Invalidate(map, navigationWidget.MouseCell);
|
||||||
UpdateStatus();
|
UpdateStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,6 +243,7 @@ namespace MobiusEditor.Tools
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
placementMode = false;
|
placementMode = false;
|
||||||
|
mapPanel.Invalidate(map, navigationWidget.MouseCell);
|
||||||
UpdateStatus();
|
UpdateStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,8 +272,8 @@ namespace MobiusEditor.Tools
|
|||||||
CellTrigger cellTrig = kv.Value;
|
CellTrigger cellTrig = kv.Value;
|
||||||
bool isValid = cellTrig == null || valid.Any(t => t.Name.Equals(cellTrig.Trigger, StringComparison.InvariantCultureIgnoreCase));
|
bool isValid = cellTrig == null || valid.Any(t => t.Name.Equals(cellTrig.Trigger, StringComparison.InvariantCultureIgnoreCase));
|
||||||
e.Map.CellTriggers[kv.Key] = isValid ? cellTrig : null;
|
e.Map.CellTriggers[kv.Key] = isValid ? cellTrig : null;
|
||||||
|
e.MapPanel.Invalidate(map, kv.Key);
|
||||||
}
|
}
|
||||||
e.MapPanel.Invalidate();
|
|
||||||
if (e.Plugin != null)
|
if (e.Plugin != null)
|
||||||
{
|
{
|
||||||
e.Plugin.Dirty = origDirtyState;
|
e.Plugin.Dirty = origDirtyState;
|
||||||
@ -281,8 +288,8 @@ namespace MobiusEditor.Tools
|
|||||||
CellTrigger cellTrig = kv.Value;
|
CellTrigger cellTrig = kv.Value;
|
||||||
bool isValid = cellTrig == null || valid.Any(t => t.Name.Equals(cellTrig.Trigger, StringComparison.InvariantCultureIgnoreCase));
|
bool isValid = cellTrig == null || valid.Any(t => t.Name.Equals(cellTrig.Trigger, StringComparison.InvariantCultureIgnoreCase));
|
||||||
e.Map.CellTriggers[kv.Key] = isValid ? cellTrig : null;
|
e.Map.CellTriggers[kv.Key] = isValid ? cellTrig : null;
|
||||||
|
e.MapPanel.Invalidate(map, kv.Key);
|
||||||
}
|
}
|
||||||
e.MapPanel.Invalidate();
|
|
||||||
if (e.Plugin != null)
|
if (e.Plugin != null)
|
||||||
{
|
{
|
||||||
e.Plugin.Dirty = true;
|
e.Plugin.Dirty = true;
|
||||||
@ -295,20 +302,50 @@ namespace MobiusEditor.Tools
|
|||||||
|
|
||||||
private void TriggerCombo_SelectedIndexChanged(System.Object sender, System.EventArgs e)
|
private void TriggerCombo_SelectedIndexChanged(System.Object sender, System.EventArgs e)
|
||||||
{
|
{
|
||||||
mapPanel.Invalidate();
|
mapPanel.Invalidate(map, navigationWidget.MouseCell);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PreRenderMap()
|
||||||
|
{
|
||||||
|
base.PreRenderMap();
|
||||||
|
previewMap = map.Clone();
|
||||||
|
if (!placementMode)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string selected = triggerComboBox.SelectedItem as string;
|
||||||
|
if (selected == null || Trigger.IsEmpty(selected))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var location = navigationWidget.MouseCell;
|
||||||
|
if (!previewMap.Metrics.GetCell(location, out int cell))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CellTrigger celltr = previewMap.CellTriggers[location];
|
||||||
|
if (celltr == null)
|
||||||
|
{
|
||||||
|
previewMap.CellTriggers[location] = new CellTrigger(selected);
|
||||||
|
// Tint is not actually used; a lower alpha just indicates that it is a preview item.
|
||||||
|
previewMap.CellTriggers[location].Tint = Color.FromArgb(128, Color.White);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PostRenderMap(Graphics graphics)
|
protected override void PostRenderMap(Graphics graphics)
|
||||||
{
|
{
|
||||||
base.PostRenderMap(graphics);
|
base.PostRenderMap(graphics);
|
||||||
string selected = triggerComboBox.SelectedItem as string;
|
string selected = triggerComboBox.SelectedItem as string;
|
||||||
|
if (selected != null && Trigger.IsEmpty(selected))
|
||||||
|
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, Globals.MapTileScale, Layers, Color.LimeGreen, selected, true);
|
||||||
MapRenderer.RenderCellTriggers(graphics, map, Globals.MapTileSize, Globals.MapTileScale, selectedRange);
|
MapRenderer.RenderCellTriggers(graphics, map, Globals.MapTileSize, Globals.MapTileScale, selectedRange);
|
||||||
if (selected != null)
|
if (selected != null)
|
||||||
{
|
{
|
||||||
MapRenderer.RenderCellTriggers(graphics, map, Globals.MapTileSize, Globals.MapTileScale, Color.Black, Color.Yellow, Color.Yellow, true, false, selectedRange);
|
// Only use preview map if in placement mode.
|
||||||
|
MapRenderer.RenderCellTriggers(graphics, placementMode ? previewMap : map, Globals.MapTileSize, Globals.MapTileScale, Color.Black, Color.Yellow, Color.Yellow, true, false, 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, Globals.MapTileScale, Layers, Color.Yellow, selected, false);
|
||||||
}
|
}
|
||||||
|
@ -488,7 +488,7 @@ namespace MobiusEditor.Tools
|
|||||||
{
|
{
|
||||||
string owningType = toFind.GroupTiles[0];
|
string owningType = toFind.GroupTiles[0];
|
||||||
TemplateType group = map.TemplateTypes.Where(t => t.Name.Equals(owningType, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
|
TemplateType group = map.TemplateTypes.Where(t => t.Name.Equals(owningType, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
|
||||||
templatesToFind.UnionWith(map.TemplateTypes.Where(t => group.GroupTiles.Contains(t.Name, StringComparer.InvariantCultureIgnoreCase)));
|
templatesToFind.UnionWith(map.TemplateTypes.Where(t => group.GroupTiles.Contains(t.Name, StringComparer.OrdinalIgnoreCase)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -517,7 +517,7 @@ namespace MobiusEditor.Tools
|
|||||||
{
|
{
|
||||||
string owningType = tp.GroupTiles[0];
|
string owningType = tp.GroupTiles[0];
|
||||||
TemplateType group = map.TemplateTypes.Where(t => t.Name.Equals(owningType, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
|
TemplateType group = map.TemplateTypes.Where(t => t.Name.Equals(owningType, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
|
||||||
templatesToFind.UnionWith(map.TemplateTypes.Where(t => group.GroupTiles.Contains(t.Name, StringComparer.InvariantCultureIgnoreCase)));
|
templatesToFind.UnionWith(map.TemplateTypes.Where(t => group.GroupTiles.Contains(t.Name, StringComparer.OrdinalIgnoreCase)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -78,7 +78,6 @@ namespace MobiusEditor.Tools
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void MouseoverWidget_MouseCellChanged(object sender, MouseCellChangedEventArgs e)
|
private void MouseoverWidget_MouseCellChanged(object sender, MouseCellChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (placementMode)
|
if (placementMode)
|
||||||
|
@ -173,21 +173,6 @@ namespace MobiusEditor.Utility
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool CheckForIniInfo(INI iniContents, string section)
|
|
||||||
{
|
|
||||||
return CheckForIniInfo(iniContents, section, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CheckForIniInfo(INI iniContents, string section, string key, string value)
|
|
||||||
{
|
|
||||||
INISection iniSection = iniContents[section];
|
|
||||||
if (key == null || value == null)
|
|
||||||
{
|
|
||||||
return iniSection != null;
|
|
||||||
}
|
|
||||||
return iniSection != null && iniSection.Keys.Contains(key) && iniSection[key].Trim() == value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String MakeNew4CharName(IEnumerable<string> currentList, string fallback, params string[] reservedNames)
|
public static String MakeNew4CharName(IEnumerable<string> currentList, string fallback, params string[] reservedNames)
|
||||||
{
|
{
|
||||||
string name = string.Empty;
|
string name = string.Empty;
|
||||||
@ -201,7 +186,7 @@ namespace MobiusEditor.Utility
|
|||||||
for (int l = 'a'; l <= 'z'; ++l)
|
for (int l = 'a'; l <= 'z'; ++l)
|
||||||
{
|
{
|
||||||
name = String.Concat((char)i, (char)j, (char)k, (char)l);
|
name = String.Concat((char)i, (char)j, (char)k, (char)l);
|
||||||
if (!currentList.Contains(name, StringComparer.InvariantCultureIgnoreCase) && !reservedNames.Contains(name, StringComparer.InvariantCultureIgnoreCase))
|
if (!currentList.Contains(name, StringComparer.InvariantCultureIgnoreCase) && !reservedNames.Contains(name, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -44,17 +44,6 @@ namespace MobiusEditor.Utility
|
|||||||
}
|
}
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
};
|
};
|
||||||
|
|
||||||
public static bool IsValidKey(String iniKey, params string[] reservedNames)
|
|
||||||
{
|
|
||||||
foreach (string name in reservedNames) {
|
|
||||||
if (name.Equals(iniKey, StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return iniKey.All(c => c > ' ' && c <= '~' && c != '=' && c != '[' && c != ']');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class INIKeyValueCollection : IEnumerable<(string Key, string Value)>, IEnumerable
|
public class INIKeyValueCollection : IEnumerable<(string Key, string Value)>, IEnumerable
|
||||||
@ -594,6 +583,20 @@ namespace MobiusEditor.Utility
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void RemoveHandledKeys<T>(INISection section, T data)
|
||||||
|
{
|
||||||
|
var propertyDescriptors = TypeDescriptor.GetProperties(data);
|
||||||
|
var properties = data.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetSetMethod() != null);
|
||||||
|
foreach (var property in properties)
|
||||||
|
{
|
||||||
|
if (property.GetCustomAttribute<NonSerializedINIKeyAttribute>() != null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
section.Keys.Remove(property.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void WriteSection<T>(ITypeDescriptorContext context, INISection section, T data)
|
public static void WriteSection<T>(ITypeDescriptorContext context, INISection section, T data)
|
||||||
{
|
{
|
||||||
var propertyDescriptors = TypeDescriptor.GetProperties(data);
|
var propertyDescriptors = TypeDescriptor.GetProperties(data);
|
||||||
|
143
CnCTDRAMapEditor/Utility/INITools.cs
Normal file
143
CnCTDRAMapEditor/Utility/INITools.cs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
using MobiusEditor.Model;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MobiusEditor.Utility
|
||||||
|
{
|
||||||
|
public static class INITools
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether certain ini information was found in the given ini data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ini">ini data.</param>
|
||||||
|
/// <param name="section">Section to find.</param>
|
||||||
|
/// <returns>True if the ini section was found.</returns>
|
||||||
|
public static bool CheckForIniInfo(INI ini, string section)
|
||||||
|
{
|
||||||
|
return CheckForIniInfo(ini, section, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether certain ini information was found in the given ini data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ini">ini data.</param>
|
||||||
|
/// <param name="section">Section to find.</param>
|
||||||
|
/// <param name="key">Optional key to find. If no complete key/value pair is given, only the existence of the section will be checked.</param>
|
||||||
|
/// <param name="value">Optional value to find. If no complete key/value pair is given, only the existence of the section will be checked.</param>
|
||||||
|
/// <returns>True if the ini information was found.</returns>
|
||||||
|
public static bool CheckForIniInfo(INI ini, string section, string key, string value)
|
||||||
|
{
|
||||||
|
INISection iniSection = ini[section];
|
||||||
|
if (key == null || value == null)
|
||||||
|
{
|
||||||
|
return iniSection != null;
|
||||||
|
}
|
||||||
|
return iniSection != null && iniSection.Keys.Contains(key) && iniSection[key].Trim() == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the given string is a valid ini key in an ASCII context.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="iniKey">The key to check.</param>
|
||||||
|
/// <param name="reservedNames">Optional array of reserved names. IF given, any entry in this list will also return false.</param>
|
||||||
|
/// <returns>True if the given string is a valid ini key in an ASCII context.</returns>
|
||||||
|
public static bool IsValidKey(String iniKey, params string[] reservedNames)
|
||||||
|
{
|
||||||
|
if (reservedNames != null)
|
||||||
|
{
|
||||||
|
foreach (string name in reservedNames)
|
||||||
|
{
|
||||||
|
if (name.Equals(iniKey, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iniKey.All(c => c > ' ' && c <= '~' && c != '=' && c != '[' && c != ']');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will find a section in the ini information, parse its data into the given data object, remove all
|
||||||
|
/// keys managed by the data object from the ini section, and, if empty, remove the section from the ini.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Type of the data.</typeparam>
|
||||||
|
/// <param name="ini">Ini object.</param>
|
||||||
|
/// <param name="name">Name of the section.</param>
|
||||||
|
/// <param name="data">Data object.</param>
|
||||||
|
/// <param name="context">Map context to read data.</param>
|
||||||
|
/// <returns>Null if the section was not found, otherwise the trimmed section.</returns>
|
||||||
|
public static INISection ParseAndLeaveRemainder<T>(INI ini, string name, T data, MapContext context)
|
||||||
|
{
|
||||||
|
var dataSection = ini.Sections[name];
|
||||||
|
if (dataSection == null)
|
||||||
|
return null;
|
||||||
|
INI.ParseSection(context, dataSection, data);
|
||||||
|
INI.RemoveHandledKeys(dataSection, data);
|
||||||
|
if (dataSection.Keys.Count() == 0)
|
||||||
|
ini.Sections.Remove(name);
|
||||||
|
return dataSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will extract a section from the ini information, add the current data to it, and re-add it
|
||||||
|
/// at the end of the ini object. If the <see cref="shouldAdd" /> argument is false, and no section
|
||||||
|
/// with this name is found in the current ini object, the object is not added. Otherwise it
|
||||||
|
/// will be added, with the data object info added into it.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Type of the data.</typeparam>
|
||||||
|
/// <param name="ini">Ini object.</param>
|
||||||
|
/// <param name="name">Name of the section.</param>
|
||||||
|
/// <param name="data">Data object.</param>
|
||||||
|
/// <param name="context">Map context to write data.</param>
|
||||||
|
/// <param name="shouldAdd">False if the object is not supposed to be added. This will be ignored if a section with that name is found that contains keys not managed by the data object.</param>
|
||||||
|
/// <returns>Null if the section was not found, otherwise the final re-added section.</returns>
|
||||||
|
public static INISection FillAndReAdd<T>(INI ini, string name, T data, MapContext context, bool shouldAdd)
|
||||||
|
{
|
||||||
|
INISection dataSection = ini.Sections.Extract(name);
|
||||||
|
if (dataSection != null)
|
||||||
|
{
|
||||||
|
INI.RemoveHandledKeys(dataSection, data);
|
||||||
|
if (dataSection.Keys.Count > 0)
|
||||||
|
{
|
||||||
|
// Contains extra keys.
|
||||||
|
shouldAdd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!shouldAdd)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (dataSection != null)
|
||||||
|
{
|
||||||
|
ini.Sections.Add(dataSection);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dataSection = ini.Sections.Add(name);
|
||||||
|
}
|
||||||
|
INI.WriteSection(context, dataSection, data);
|
||||||
|
return dataSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will seek a section in the ini, remove any information in it that is handled by the data object,
|
||||||
|
/// and remove the section from the ini if no keys remain in it.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Type of the data.</typeparam>
|
||||||
|
/// <param name="ini">Ini object.</param>
|
||||||
|
/// <param name="data">Data object.</param>
|
||||||
|
/// <param name="name">Name of the section.</param>
|
||||||
|
public static void ClearDataFrom<T>(INI ini, string name, T data)
|
||||||
|
{
|
||||||
|
var basicSection = ini.Sections[name];
|
||||||
|
if (basicSection != null)
|
||||||
|
{
|
||||||
|
INI.RemoveHandledKeys(basicSection, data);
|
||||||
|
if (basicSection.Keys.Count() == 0)
|
||||||
|
ini.Sections.Remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user