diff --git a/CnCTDRAMapEditor/CnCTDRAMapEditor.csproj b/CnCTDRAMapEditor/CnCTDRAMapEditor.csproj
index 79de089..e8138a3 100644
--- a/CnCTDRAMapEditor/CnCTDRAMapEditor.csproj
+++ b/CnCTDRAMapEditor/CnCTDRAMapEditor.csproj
@@ -461,7 +461,9 @@
+
+
diff --git a/CnCTDRAMapEditor/Controls/BasicSettings.cs b/CnCTDRAMapEditor/Controls/BasicSettings.cs
index 4ff74af..ced9fda 100644
--- a/CnCTDRAMapEditor/Controls/BasicSettings.cs
+++ b/CnCTDRAMapEditor/Controls/BasicSettings.cs
@@ -55,8 +55,6 @@ namespace MobiusEditor.Controls
percentLabel.Visible = false;
playerComboBox.DataBindings.Add("SelectedItem", basicSection, "Player");
authorTxt.DataBindings.Add("Text", basicSection, "Author");
- isSinglePlayerCheckBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
- isSinglePlayerCheckBox.DataBindings.Add("Checked", basicSection, "SoloMission");
themeComboBox.DataBindings.Add("Text", basicSection, "Theme");
introComboBox.DataBindings.Add("Text", basicSection, "Intro");
briefComboBox.DataBindings.Add("Text", basicSection, "Brief");
@@ -69,6 +67,8 @@ namespace MobiusEditor.Controls
switch (plugin.GameType)
{
case GameType.TiberianDawn:
+ isSinglePlayerCheckBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
+ isSinglePlayerCheckBox.DataBindings.Add("Checked", basicSection, "SoloMission");
buildLevelNud.DataBindings.Add("Value", basicSection, "BuildLevel");
baseLabel.Visible = baseComboBox.Visible = false;
hasExpansionUnitsCheckBox.Visible = false;
@@ -80,15 +80,38 @@ namespace MobiusEditor.Controls
win3ComboBox.DropDownStyle = ComboBoxStyle.DropDown;
win4ComboBox.DropDownStyle = ComboBoxStyle.DropDown;
loseComboBox.DropDownStyle = ComboBoxStyle.DropDown;
+ CheckSinglePlayerOptions();
break;
case GameType.RedAlert:
+ isSinglePlayerCheckBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
+ isSinglePlayerCheckBox.DataBindings.Add("Checked", basicSection, "SoloMission");
buildLevelNud.Visible = buildLevelLabel.Visible = false;
baseComboBox.DataBindings.Add("SelectedItem", basicSection, "BasePlayer");
hasExpansionUnitsCheckBox.DataBindings.Add("Checked", basicSection, "ExpansionEnabled");
+ CheckSinglePlayerOptions();
+ break;
+ case GameType.SoleSurvivor:
+ isSinglePlayerCheckBox.Visible = false;
+ buildLevelNud.DataBindings.Add("Value", basicSection, "BuildLevel");
+ baseLabel.Visible = baseComboBox.Visible = false;
+ hasExpansionUnitsCheckBox.Visible = false;
+ introComboBox.DropDownStyle = ComboBoxStyle.DropDown;
+ briefComboBox.DropDownStyle = ComboBoxStyle.DropDown;
+ actionComboBox.DropDownStyle = ComboBoxStyle.DropDown;
+ winComboBox.DropDownStyle = ComboBoxStyle.DropDown;
+ // Irrelevant for SS; it's all classic.
+ lblCarryoverClassic.Visible = false;
+ lblThemeClassic.Visible = false;
+ // Disable these. Labels and stuff too.
+ win2ComboBox.Visible = false;
+ win3ComboBox.Visible = false;
+ win4ComboBox.Visible = false;
+ loseComboBox.Visible = false;
+
+
+
break;
}
-
- CheckSinglePlayerOptions();
}
private void isSinglePlayerCheckBox_CheckedChanged(object sender, EventArgs e)
diff --git a/CnCTDRAMapEditor/Controls/ObjectProperties.cs b/CnCTDRAMapEditor/Controls/ObjectProperties.cs
index 92a402a..40ea866 100644
--- a/CnCTDRAMapEditor/Controls/ObjectProperties.cs
+++ b/CnCTDRAMapEditor/Controls/ObjectProperties.cs
@@ -206,27 +206,39 @@ namespace MobiusEditor.Controls
directionLabel.Visible = directionVisible;
directionComboBox.Visible = directionVisible;
missionLabel.Visible = missionComboBox.Visible = false;
- basePriorityLabel.Visible = basePriorityNud.Visible = true;
- prebuiltCheckBox.Visible = true;
- prebuiltCheckBox.Enabled = building.BasePriority >= 0;
-
- basePriorityNud.DataBindings.Add("Value", obj, "BasePriority");
- prebuiltCheckBox.DataBindings.Add("Checked", obj, "IsPrebuilt");
-
switch (Plugin.GameType)
{
case GameType.TiberianDawn:
{
+ basePriorityLabel.Visible = basePriorityNud.Visible = true;
+ prebuiltCheckBox.Visible = true;
+ prebuiltCheckBox.Enabled = building.BasePriority >= 0;
+ basePriorityNud.DataBindings.Add("Value", obj, "BasePriority");
+ prebuiltCheckBox.DataBindings.Add("Checked", obj, "IsPrebuilt");
sellableCheckBox.Visible = false;
rebuildCheckBox.Visible = false;
} break;
case GameType.RedAlert:
{
+ basePriorityLabel.Visible = basePriorityNud.Visible = true;
+ prebuiltCheckBox.Visible = true;
+ prebuiltCheckBox.Enabled = building.BasePriority >= 0;
+ basePriorityNud.DataBindings.Add("Value", obj, "BasePriority");
+ prebuiltCheckBox.DataBindings.Add("Checked", obj, "IsPrebuilt");
sellableCheckBox.DataBindings.Add("Checked", obj, "Sellable");
rebuildCheckBox.DataBindings.Add("Checked", obj, "Rebuild");
sellableCheckBox.Visible = true;
rebuildCheckBox.Visible = true;
- } break;
+ }
+ break;
+ case GameType.SoleSurvivor:
+ {
+ basePriorityLabel.Visible = basePriorityNud.Visible = false;
+ prebuiltCheckBox.Visible = false;
+ sellableCheckBox.Visible = false;
+ rebuildCheckBox.Visible = false;
+ }
+ break;
}
}
break;
diff --git a/CnCTDRAMapEditor/Dialogs/MapSettingsDialog.cs b/CnCTDRAMapEditor/Dialogs/MapSettingsDialog.cs
index a5b9c73..d265d58 100644
--- a/CnCTDRAMapEditor/Dialogs/MapSettingsDialog.cs
+++ b/CnCTDRAMapEditor/Dialogs/MapSettingsDialog.cs
@@ -106,6 +106,14 @@ namespace MobiusEditor.Dialogs
}
settingsTreeView.Nodes.Add("RULES", "Rules");
}
+ else
+ {
+ if (this.plugin.GameType == GameType.SoleSurvivor)
+ {
+ settingsTreeView.Nodes.Add("CRATES", "Crates");
+ }
+ settingsTreeView.Nodes.Add("RULES", "Extra ini contents");
+ }
settingsTreeView.Nodes.Add("BRIEFING", "Briefing");
playersNode = settingsTreeView.Nodes.Add("Players");
foreach (var player in this.plugin.Map.Houses)
@@ -150,6 +158,14 @@ namespace MobiusEditor.Dialogs
basicPanel.Dock = DockStyle.Fill;
}
break;
+ case "CRATES":
+ {
+ // TODO make crates setting screen for SS.
+ ScenarioSettings scenPanel = new ScenarioSettings(basicSettingsTracker);
+ settingsPanel.Controls.Add(scenPanel);
+ scenPanel.Dock = DockStyle.Fill;
+ }
+ break;
case "SCENARIO":
{
ScenarioSettings scenPanel = new ScenarioSettings(basicSettingsTracker);
diff --git a/CnCTDRAMapEditor/Interface/IGamePlugin.cs b/CnCTDRAMapEditor/Interface/IGamePlugin.cs
index 75fb20c..b2c1705 100644
--- a/CnCTDRAMapEditor/Interface/IGamePlugin.cs
+++ b/CnCTDRAMapEditor/Interface/IGamePlugin.cs
@@ -13,7 +13,6 @@
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
using MobiusEditor.Model;
-using MobiusEditor.Utility;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -33,7 +32,8 @@ namespace MobiusEditor.Interface
{
None,
TiberianDawn,
- RedAlert
+ RedAlert,
+ SoleSurvivor
}
public interface IGamePlugin : IDisposable
diff --git a/CnCTDRAMapEditor/MainForm.cs b/CnCTDRAMapEditor/MainForm.cs
index efe3495..1cf2ff0 100644
--- a/CnCTDRAMapEditor/MainForm.cs
+++ b/CnCTDRAMapEditor/MainForm.cs
@@ -876,15 +876,15 @@ namespace MobiusEditor
switch (fileType)
{
case FileType.INI:
- {
- gameType = File.Exists(Path.ChangeExtension(loadFilename, ".bin")) ? GameType.TiberianDawn : GameType.RedAlert;
- break;
- }
+ {
+ gameType = File.Exists(Path.ChangeExtension(loadFilename, ".bin")) ? GameType.TiberianDawn : GameType.RedAlert;
+ break;
+ }
case FileType.BIN:
- {
- gameType = File.Exists(Path.ChangeExtension(loadFilename, ".ini")) ? GameType.TiberianDawn : GameType.None;
- break;
- }
+ {
+ gameType = File.Exists(Path.ChangeExtension(loadFilename, ".ini")) ? GameType.TiberianDawn : GameType.None;
+ break;
+ }
#if DEVELOPER
case FileType.PGM:
{
@@ -910,6 +910,13 @@ namespace MobiusEditor
}
#endif
}
+ if (gameType == GameType.TiberianDawn)
+ {
+ if (TiberianDawn.GamePluginSS.CheckForSSmap(loadFilename, fileType))
+ {
+ gameType = GameType.SoleSurvivor;
+ }
+ }
if (gameType == GameType.None)
{
return false;
@@ -923,7 +930,12 @@ namespace MobiusEditor
string[] modPaths = null;
if (ModPaths != null)
{
- ModPaths.TryGetValue(gameType, out modPaths);
+ GameType modGameType = gameType;
+ if (gameType == GameType.SoleSurvivor)
+ {
+ modGameType = GameType.TiberianDawn;
+ }
+ ModPaths.TryGetValue(modGameType, out modPaths);
}
Globals.TheTextureManager.ExpandModPaths = modPaths;
Globals.TheTextureManager.Reset();
@@ -947,6 +959,11 @@ namespace MobiusEditor
plugin = new RedAlert.GamePlugin(this);
}
break;
+ case GameType.SoleSurvivor:
+ Globals.TheTeamColorManager.Reset();
+ Globals.TheTeamColorManager.Load(@"DATA\XML\CNCTDTEAMCOLORS.XML");
+ plugin = new TiberianDawn.GamePluginSS(this);
+ break;
}
string[] errors;
bool modifiedByLoad;
diff --git a/CnCTDRAMapEditor/Model/Waypoint.cs b/CnCTDRAMapEditor/Model/Waypoint.cs
index 9b81b4d..ab7efb6 100644
--- a/CnCTDRAMapEditor/Model/Waypoint.cs
+++ b/CnCTDRAMapEditor/Model/Waypoint.cs
@@ -26,7 +26,9 @@ namespace MobiusEditor.Model
Flare = 1 << 1,
Home = 1 << 2,
Reinforce = 1 << 3,
- Special = 1 << 4
+ Special = 1 << 4,
+ CrateSpawn = 1 << 5,
+
}
public class Waypoint : INamedType
diff --git a/CnCTDRAMapEditor/Render/MapRenderer.cs b/CnCTDRAMapEditor/Render/MapRenderer.cs
index fbfa967..ec903f5 100644
--- a/CnCTDRAMapEditor/Render/MapRenderer.cs
+++ b/CnCTDRAMapEditor/Render/MapRenderer.cs
@@ -409,7 +409,7 @@ namespace MobiusEditor.Render
if (building.Strength <= 128 && !building.Type.IsSingleFrame)
{
maxIcon = Globals.TheTilesetManager.GetTileDataLength(theater.Tilesets, building.Type.Tilename);
- hasCollapseFrame = gameType == GameType.TiberianDawn && maxIcon > 1 && maxIcon % 2 == 1;
+ hasCollapseFrame = (gameType == GameType.TiberianDawn || gameType == GameType.SoleSurvivor) && maxIcon > 1 && maxIcon % 2 == 1;
damageIcon = maxIcon / 2;
collapseIcon = hasCollapseFrame ? maxIcon - 1 : damageIcon;
}
@@ -572,7 +572,7 @@ namespace MobiusEditor.Render
public static (Rectangle, Action) Render(GameType gameType, TheaterType theater, Point topLeft, Size tileSize, Unit unit)
{
int icon = 0;
- if (gameType == GameType.TiberianDawn)
+ if (gameType == GameType.TiberianDawn || gameType == GameType.SoleSurvivor)
{
if ((unit.Type == TiberianDawn.UnitTypes.Tric) ||
(unit.Type == TiberianDawn.UnitTypes.Trex) ||
@@ -745,7 +745,7 @@ namespace MobiusEditor.Render
turretAdjust.Y = -5;
}
}
- else if (gameType == GameType.TiberianDawn)
+ else if (gameType == GameType.TiberianDawn || gameType == GameType.SoleSurvivor)
{
if (unit.Type == TiberianDawn.UnitTypes.Jeep ||
unit.Type == TiberianDawn.UnitTypes.Buggy ||
diff --git a/CnCTDRAMapEditor/TiberianDawn/BuildingTypes.cs b/CnCTDRAMapEditor/TiberianDawn/BuildingTypes.cs
index 50ed345..97d0427 100644
--- a/CnCTDRAMapEditor/TiberianDawn/BuildingTypes.cs
+++ b/CnCTDRAMapEditor/TiberianDawn/BuildingTypes.cs
@@ -39,7 +39,7 @@ namespace MobiusEditor.TiberianDawn
public static readonly BuildingType Barracks = new BuildingType(15, "pyle", "TEXT_STRUCTURE_TITLE_GDI_BARRACKS", 0, 20, new bool[2, 2] { { true, true }, { false, false } }, "Goodguy", BuildingTypeFlag.Bib);
public static readonly BuildingType Tanker = new BuildingType(16, "arco", "Oil Tanker", 0, 0, new bool[1, 2] { { true, true } }, "Neutral");
public static readonly BuildingType Repair = new BuildingType(17, "fix", "TEXT_STRUCTURE_TITLE_GDI_REPAIR_FACILITY", 0, 30, new bool[3, 3] { { false, true, false }, { true, true, true }, { false, true, false} }, "Goodguy", BuildingTypeFlag.Bib);
- public static readonly BuildingType BioLab = new BuildingType(18, "bio", "TEXT_UNIT_TITLE_BIO", 0, 40, 100, new bool[2, 2] { { true, true }, { true, true } }, "Goodguy", BuildingTypeFlag.Bib);
+ public static readonly BuildingType BioLab = new BuildingType(18, "bio", "TEXT_UNIT_TITLE_BIO", 0, 40, 100, new bool[2, 2] { { true, true }, { true, true } }, "Badguy", BuildingTypeFlag.Bib);
public static readonly BuildingType Hand = new BuildingType(19, "hand", "TEXT_STRUCTURE_TITLE_NOD_HAND_OF_NOD", 0, 20, new bool[3, 2] { { false, false }, { true, true }, { false, true } }, "Badguy", BuildingTypeFlag.Bib);
public static readonly BuildingType Temple = new BuildingType(20, "tmpl", "TEXT_STRUCTURE_TITLE_NOD_TEMPLE_OF_NOD", 0, 150, new bool[3, 3] { { false, false, false }, { true, true, true }, { true, true, true } }, "Badguy", BuildingTypeFlag.Bib);
public static readonly BuildingType Eye = new BuildingType(21, "eye", "TEXT_STRUCTURE_TITLE_GDI_ADV_COMM_CENTER", 0, 200, new bool[2, 2] { { true, false }, { true, true } }, "Goodguy", BuildingTypeFlag.Bib);
diff --git a/CnCTDRAMapEditor/TiberianDawn/GamePlugin.cs b/CnCTDRAMapEditor/TiberianDawn/GamePlugin.cs
index 8ed4295..3fda0a7 100644
--- a/CnCTDRAMapEditor/TiberianDawn/GamePlugin.cs
+++ b/CnCTDRAMapEditor/TiberianDawn/GamePlugin.cs
@@ -31,18 +31,18 @@ namespace MobiusEditor.TiberianDawn
{
public class GamePlugin : IGamePlugin
{
- private bool isMegaMap = false;
+ protected bool isMegaMap = false;
- private const int multiStartPoints = 8;
- private static readonly Regex SinglePlayRegex = new Regex("^SC[A-LN-RT-Z]\\d{2}[EWX][A-EL]$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
- private static readonly Regex MovieRegex = new Regex(@"^(?:.*?\\)*(.*?)\.BK2$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ protected const int multiStartPoints = 8;
+ protected static readonly Regex SinglePlayRegex = new Regex("^SC[A-LN-RT-Z]\\d{2}[EWX][A-EL]$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ protected static readonly Regex MovieRegex = new Regex(@"^(?:.*?\\)*(.*?)\.BK2$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
- private static readonly IEnumerable fullTechnoTypes;
+ protected static readonly IEnumerable fullTechnoTypes;
- private const string defVidVal = "x";
- private readonly IEnumerable movieTypes;
+ protected const string defVidVal = "x";
+ protected readonly IEnumerable movieTypes;
- private static readonly IEnumerable movieTypesAdditional = new string[]
+ protected static readonly IEnumerable movieTypesAdditional = new string[]
{
"BODYBAGS (Classic only)",
"REFINT (Classic only)",
@@ -53,7 +53,7 @@ namespace MobiusEditor.TiberianDawn
"TRTKIL_D (Classic only)",
};
- private static readonly IEnumerable themeTypes = new string[]
+ protected static readonly IEnumerable themeTypes = new string[]
{
"No Theme",
"AIRSTRIK",
@@ -100,11 +100,11 @@ namespace MobiusEditor.TiberianDawn
public GameType GameType => GameType.TiberianDawn;
- public Map Map { get; }
+ public Map Map { get; protected set; }
- public Image MapImage { get; private set; }
+ public Image MapImage { get; protected set; }
- IFeedBackHandler feedBackHandler;
+ protected IFeedBackHandler feedBackHandler;
bool isDirty;
public bool Dirty
@@ -113,7 +113,7 @@ namespace MobiusEditor.TiberianDawn
set { isDirty = value; feedBackHandler?.UpdateStatus(); }
}
- private INISectionCollection extraSections;
+ protected INISectionCollection extraSections;
public String ExtraIniText
{
get
@@ -161,9 +161,15 @@ namespace MobiusEditor.TiberianDawn
}
public static bool CheckForMegamap(String path, FileType fileType)
+ {
+ return CheckForIniInfo(path, fileType, "Map", "Version", "1");
+ }
+
+ public static bool CheckForIniInfo(String path, FileType fileType, string section, string key, string value)
{
try
{
+ Encoding enc = new UTF8Encoding(false, true);
String iniContents = null;
switch (fileType)
{
@@ -171,7 +177,6 @@ namespace MobiusEditor.TiberianDawn
case FileType.BIN:
String iniPath = fileType == FileType.INI ? path : Path.ChangeExtension(path, ".ini");
Byte[] bytes = File.ReadAllBytes(path);
- Encoding enc = new UTF8Encoding(false, true);
iniContents = enc.GetString(bytes);
break;
case FileType.MEG:
@@ -181,7 +186,7 @@ namespace MobiusEditor.TiberianDawn
var testIniFile = megafile.Where(p => Path.GetExtension(p).ToLower() == ".ini").FirstOrDefault();
if (testIniFile != null)
{
- using (var iniReader = new StreamReader(megafile.Open(testIniFile)))
+ using (var iniReader = new StreamReader(megafile.Open(testIniFile), enc))
{
iniContents = iniReader.ReadToEnd();
}
@@ -195,8 +200,12 @@ namespace MobiusEditor.TiberianDawn
}
INI checkIni = new INI();
checkIni.Parse(iniContents);
- INISection mapSection = checkIni.Sections.Extract("Map");
- return mapSection.Keys.Contains("Version") && mapSection["Version"].Trim() == "1";
+ INISection iniSection = checkIni.Sections.Extract(section);
+ if (key == null || value == null)
+ {
+ return iniSection != null;
+ }
+ return iniSection != null && iniSection.Keys.Contains(key) && iniSection[key].Trim() == value;
}
catch
{
@@ -214,14 +223,9 @@ namespace MobiusEditor.TiberianDawn
{
}
- public GamePlugin(bool mapImage, bool megaMap, IFeedBackHandler feedBackHandler)
+ public GamePlugin()
{
- this.isMegaMap = megaMap;
- this.feedBackHandler = feedBackHandler;
- var playerWaypoints = Enumerable.Range(0, multiStartPoints).Select(i => new Waypoint(string.Format("P{0}", i), WaypointFlag.PlayerStart));
- var generalWaypoints = Enumerable.Range(multiStartPoints, 25 - multiStartPoints).Select(i => new Waypoint(i.ToString()));
- var specialWaypoints = new Waypoint[] { new Waypoint("Flare", WaypointFlag.Flare), new Waypoint("Home", WaypointFlag.Home), new Waypoint("Reinf.", WaypointFlag.Reinforce) };
- var waypoints = playerWaypoints.Concat(generalWaypoints).Concat(specialWaypoints);
+ // Readonly, so I'm splitting this off
var movies = new List();
using (var megafile = new Megafile(Path.Combine(Globals.MegafilePath, "MOVIES_TD.MEG")))
{
@@ -239,6 +243,17 @@ namespace MobiusEditor.TiberianDawn
movies.Sort(new ExplorerComparer());
movies.Insert(0, defVidVal);
movieTypes = movies.ToArray();
+ }
+
+ public GamePlugin(bool mapImage, bool megaMap, IFeedBackHandler feedBackHandler)
+ :this()
+ {
+ this.isMegaMap = megaMap;
+ this.feedBackHandler = feedBackHandler;
+ var playerWaypoints = Enumerable.Range(0, multiStartPoints).Select(i => new Waypoint(string.Format("P{0}", i), WaypointFlag.PlayerStart));
+ var generalWaypoints = Enumerable.Range(multiStartPoints, 25 - multiStartPoints).Select(i => new Waypoint(i.ToString()));
+ var specialWaypoints = new Waypoint[] { new Waypoint("Flare", WaypointFlag.Flare), new Waypoint("Home", WaypointFlag.Home), new Waypoint("Reinf.", WaypointFlag.Reinforce) };
+ Waypoint[] waypoints = playerWaypoints.Concat(generalWaypoints).Concat(specialWaypoints).ToArray();
var basicSection = new BasicSection();
basicSection.SetDefault();
var houseTypes = HouseTypes.GetTypes();
@@ -249,7 +264,6 @@ namespace MobiusEditor.TiberianDawn
EventTypes.EVENT_PLAYER_ENTERED,
EventTypes.EVENT_NONE
};
-
string[] unitEventTypes =
{
EventTypes.EVENT_DISCOVERED,
@@ -371,7 +385,7 @@ namespace MobiusEditor.TiberianDawn
///
/// Stream reader to read from.
/// The ini file as string, with all double ROAD overlay lines replaced by the dummy Road2 type.
- private string FixRoad2Load(StreamReader iniReader)
+ protected string FixRoad2Load(StreamReader iniReader)
{
// ROAD's second state can only be accessed by applying ROAD overlay to the same cell twice.
// This can be achieved by saving its Overlay line twice in the ini file. However, this is
@@ -482,7 +496,7 @@ namespace MobiusEditor.TiberianDawn
return sb.ToString();
}
- private IEnumerable LoadINI(INI ini, bool forceSoloMission)
+ protected IEnumerable LoadINI(INI ini, bool forceSoloMission)
{
var errors = new List();
Map.BeginUpdate();
@@ -1473,7 +1487,7 @@ namespace MobiusEditor.TiberianDawn
return errors;
}
- private IEnumerable LoadBinaryClassic(BinaryReader reader)
+ protected IEnumerable LoadBinaryClassic(BinaryReader reader)
{
var errors = new List();
Map.Templates.Clear();
@@ -1490,7 +1504,7 @@ namespace MobiusEditor.TiberianDawn
return errors;
}
- private IEnumerable LoadBinaryMega(BinaryReader reader)
+ protected IEnumerable LoadBinaryMega(BinaryReader reader)
{
var errors = new List();
Map.Templates.Clear();
@@ -1518,7 +1532,7 @@ namespace MobiusEditor.TiberianDawn
return errors;
}
- private TemplateType ChecKTemplateType(int typeValue, int iconValue, int x, int y, List errors)
+ protected TemplateType ChecKTemplateType(int typeValue, int iconValue, int x, int y, List errors)
{
TemplateType templateType = Map.TemplateTypes.Where(t => t.Equals(typeValue)).FirstOrDefault();
// Prevent loading of illegal tiles.
@@ -1672,7 +1686,7 @@ namespace MobiusEditor.TiberianDawn
///
/// The generated ini file
/// The stream writer to write the text to.
- private void FixRoad2Save(INI ini, StreamWriter iniWriter)
+ protected void FixRoad2Save(INI ini, StreamWriter iniWriter)
{
// ROAD's second state can only be accessed by applying ROAD overlay to the same cell twice.
// This can be achieved by saving its Overlay line twice in the ini file. However, this is
@@ -1709,7 +1723,7 @@ namespace MobiusEditor.TiberianDawn
}
}
- private void SaveINI(INI ini, FileType fileType, string fileName)
+ protected void SaveINI(INI ini, FileType fileType, string fileName)
{
if (extraSections != null)
{
@@ -1962,7 +1976,7 @@ namespace MobiusEditor.TiberianDawn
}
}
- private void SaveBinaryClassic(BinaryWriter writer)
+ protected void SaveBinaryClassic(BinaryWriter writer)
{
for (var y = 0; y < Map.Metrics.Height; ++y)
{
@@ -1983,7 +1997,7 @@ namespace MobiusEditor.TiberianDawn
}
}
- private void SaveBinaryMega(BinaryWriter writer)
+ protected void SaveBinaryMega(BinaryWriter writer)
{
int height = Map.Metrics.Height;
int width = Map.Metrics.Width;
@@ -2005,12 +2019,12 @@ namespace MobiusEditor.TiberianDawn
}
}
- private void SaveMapPreview(Stream stream, Boolean renderAll)
+ protected void SaveMapPreview(Stream stream, Boolean renderAll)
{
Map.GenerateMapPreview(renderAll ? this.GameType : GameType.None, renderAll).Save(stream);
}
- private void SaveJSON(JsonTextWriter writer)
+ protected void SaveJSON(JsonTextWriter writer)
{
writer.WriteStartObject();
writer.WritePropertyName("MapTileX");
@@ -2103,7 +2117,7 @@ namespace MobiusEditor.TiberianDawn
return ok ? null : sb.ToString();
}
- private void BasicSection_PropertyChanged(object sender, PropertyChangedEventArgs e)
+ protected void BasicSection_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
@@ -2116,7 +2130,7 @@ namespace MobiusEditor.TiberianDawn
}
}
- private void MapSection_PropertyChanged(object sender, PropertyChangedEventArgs e)
+ protected void MapSection_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
@@ -2126,7 +2140,7 @@ namespace MobiusEditor.TiberianDawn
}
}
- private void UpdateBasePlayerHouse()
+ protected void UpdateBasePlayerHouse()
{
Map.BasicSection.BasePlayer = HouseTypes.GetBasePlayer(Map.BasicSection.Player);
var basePlayer = Map.HouseTypesIncludingNone.Where(h => h.Equals(Map.BasicSection.BasePlayer)).FirstOrDefault() ?? Map.HouseTypes.First();
@@ -2140,7 +2154,7 @@ namespace MobiusEditor.TiberianDawn
}
}
- private void UpdateWaypoints()
+ protected void UpdateWaypoints()
{
bool isSolo = Map.BasicSection.SoloMission;
for (int i = 0; i < multiStartPoints; ++i)
@@ -2151,7 +2165,7 @@ namespace MobiusEditor.TiberianDawn
}
#region IDisposable Support
- private bool disposedValue = false;
+ protected bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
diff --git a/CnCTDRAMapEditor/TiberianDawn/GamePluginSS.cs b/CnCTDRAMapEditor/TiberianDawn/GamePluginSS.cs
new file mode 100644
index 0000000..4ff1a19
--- /dev/null
+++ b/CnCTDRAMapEditor/TiberianDawn/GamePluginSS.cs
@@ -0,0 +1,97 @@
+using MobiusEditor.Interface;
+using MobiusEditor.Model;
+using MobiusEditor.Utility;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MobiusEditor.TiberianDawn
+{
+ public class GamePluginSS : GamePlugin
+ {
+
+ protected const int cratePoints = 4;
+ protected const int teamStartPoints = 4;
+
+ public GamePluginSS(IFeedBackHandler feedBackHandler)
+ : this(true, feedBackHandler)
+ {
+ }
+
+ public static bool CheckForSSmap(String path, FileType fileType)
+ {
+ return CheckForMegamap(path, fileType) && CheckForIniInfo(path, fileType, "Crates", null, null);
+ }
+
+ public GamePluginSS(Boolean mapImage, IFeedBackHandler feedBackHandler)
+ : base()
+ {
+ this.isMegaMap = true;
+ this.feedBackHandler = feedBackHandler;
+ var crateWaypoints = Enumerable.Range(0, cratePoints).Select(i => new Waypoint(string.Format("CR{0}", i), WaypointFlag.CrateSpawn));
+ var teamWaypoints = Enumerable.Range(cratePoints, 25 - cratePoints).Select(i => new Waypoint(string.Format("TM{0}", i - cratePoints), WaypointFlag.PlayerStart));
+ var generalWaypoints = Enumerable.Range(cratePoints + teamStartPoints, 25 - cratePoints - teamStartPoints).Select(i => new Waypoint(i.ToString()));
+ var specialWaypoints = new Waypoint[] { new Waypoint("Flare", WaypointFlag.Flare), new Waypoint("Home", WaypointFlag.Home), new Waypoint("Reinf.", WaypointFlag.Reinforce) };
+ Waypoint[] waypoints = crateWaypoints.Concat(teamWaypoints).Concat(generalWaypoints).Concat(specialWaypoints).ToArray();
+ var basicSection = new BasicSection();
+ basicSection.SetDefault();
+ var houseTypes = HouseTypesSS.GetTypes();
+ basicSection.Player = HouseTypesSS.Admin.Name;
+ // Irrelevant for SS. Rebuilding options will be disabled in the editor.
+ basicSection.BasePlayer = HouseTypes.GetBasePlayer(basicSection.Player);
+ // I guess we leave these to the TD defaults.
+ string[] cellEventTypes = new[]
+ {
+ EventTypes.EVENT_PLAYER_ENTERED,
+ EventTypes.EVENT_NONE
+ };
+ string[] unitEventTypes =
+ {
+ EventTypes.EVENT_DISCOVERED,
+ EventTypes.EVENT_ATTACKED,
+ EventTypes.EVENT_DESTROYED,
+ EventTypes.EVENT_ANY,
+ EventTypes.EVENT_NONE
+ };
+ string[] structureEventTypes = (new[] { EventTypes.EVENT_PLAYER_ENTERED }).Concat(unitEventTypes).ToArray();
+ string[] terrainEventTypes =
+ {
+ EventTypes.EVENT_ATTACKED,
+ EventTypes.EVENT_ANY,
+ EventTypes.EVENT_NONE
+ };
+ string[] cellActionTypes = { };
+ string[] unitActionTypes = { };
+ string[] structureActionTypes = { };
+ string[] terrainActionTypes = { };
+ Map = new Map(basicSection, null, Constants.MaxSizeMega, typeof(House),
+ houseTypes, TheaterTypes.GetTypes(), TemplateTypes.GetTypes(),
+ TerrainTypes.GetTypes(), OverlayTypes.GetTypes(), SmudgeTypes.GetTypes(Globals.ConvertCraters),
+ EventTypes.GetTypes(), cellEventTypes, unitEventTypes, structureEventTypes, terrainEventTypes,
+ ActionTypes.GetTypes(), cellActionTypes, unitActionTypes, structureActionTypes, terrainActionTypes,
+ MissionTypes.GetTypes(), DirectionTypes.GetTypes(), InfantryTypes.GetTypes(), UnitTypes.GetTypes(Globals.DisableAirUnits),
+ BuildingTypes.GetTypes(), TeamMissionTypes.GetTypes(), fullTechnoTypes, waypoints, movieTypes, themeTypes)
+ {
+ TiberiumOrGoldValue = 25
+ };
+ Map.MapSection.PropertyChanged += MapSection_PropertyChanged;
+ // Clean up this mess.
+ foreach (House house in Map.Houses)
+ {
+ if (house.Type.ID > HouseTypesSS.Multi1.ID)
+ {
+ house.Enabled = false;
+ }
+ }
+ if (mapImage)
+ {
+ MapImage = new Bitmap(Map.Metrics.Width * Globals.MapTileWidth, Map.Metrics.Height * Globals.MapTileHeight);
+ }
+ }
+
+ }
+}
diff --git a/CnCTDRAMapEditor/TiberianDawn/HouseTypes.cs b/CnCTDRAMapEditor/TiberianDawn/HouseTypes.cs
index d5d4728..084a133 100644
--- a/CnCTDRAMapEditor/TiberianDawn/HouseTypes.cs
+++ b/CnCTDRAMapEditor/TiberianDawn/HouseTypes.cs
@@ -30,12 +30,12 @@ namespace MobiusEditor.TiberianDawn
// Fixed to match actual game. Seems they messed up the naming of the colors in the xml files by taking the color definitions from the C&C
// game code in order, arbitrarily naming those "Multi1" to "Multi6", and then correctly applying those obviously wrongly named colors to
// the multi-Houses in the Remastered game. The editor code logically assumed they were named after their House, and thus got it all wrong.
- public static readonly HouseType Multi1 = new HouseType(4, "Multi1", "MULTI2");
- public static readonly HouseType Multi2 = new HouseType(5, "Multi2", "MULTI5");
- public static readonly HouseType Multi3 = new HouseType(6, "Multi3", "MULTI4");
- public static readonly HouseType Multi4 = new HouseType(7, "Multi4", "MULTI6");
- public static readonly HouseType Multi5 = new HouseType(8, "Multi5", "MULTI1");
- public static readonly HouseType Multi6 = new HouseType(9, "Multi6", "MULTI3");
+ public static readonly HouseType Multi1 = new HouseType(4, "Multi1", "MULTI2"); // Blue (originally teal)
+ public static readonly HouseType Multi2 = new HouseType(5, "Multi2", "MULTI5"); // Orange
+ public static readonly HouseType Multi3 = new HouseType(6, "Multi3", "MULTI4"); // Green
+ public static readonly HouseType Multi4 = new HouseType(7, "Multi4", "MULTI6"); // Teal (originally gray)
+ public static readonly HouseType Multi5 = new HouseType(8, "Multi5", "MULTI1"); // Yellow
+ public static readonly HouseType Multi6 = new HouseType(9, "Multi6", "MULTI3"); // Red
private static readonly HouseType[] Types;
diff --git a/CnCTDRAMapEditor/TiberianDawn/HouseTypesSS.cs b/CnCTDRAMapEditor/TiberianDawn/HouseTypesSS.cs
new file mode 100644
index 0000000..b29d40d
--- /dev/null
+++ b/CnCTDRAMapEditor/TiberianDawn/HouseTypesSS.cs
@@ -0,0 +1,145 @@
+using MobiusEditor.Model;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace MobiusEditor.TiberianDawn
+{
+ public static class HouseTypesSS
+ {
+ // Legacy
+ public static readonly HouseType Good = new HouseType(0, "GoodGuy", "GOOD");
+ public static readonly HouseType Bad = new HouseType(1, "BadGuy", "BAD_UNIT", "BAD_STRUCTURE", ("harv", "BAD_STRUCTURE"), ("mcv", "BAD_STRUCTURE"));
+ public static readonly HouseType Neutral = new HouseType(2, "Neutral", "GOOD");
+ public static readonly HouseType Special = new HouseType(3, "Special", "GOOD");
+ // Special for SS
+ public static readonly HouseType Admin = new HouseType(4, "Admin", "NONE");
+ public static readonly HouseType Spectator = new HouseType(5, "Spectator", "NONE");
+ // Teams for football/CTF games
+ public static readonly HouseType Team1 = new HouseType(6, "Team 1", "MULTI2"); // Blue (originally teal)
+ public static readonly HouseType Team2 = new HouseType(7, "Team 2", "MULTI5"); // Orange
+ public static readonly HouseType Team3 = new HouseType(8, "Team 3", "MULTI4"); // Green
+ public static readonly HouseType Team4 = new HouseType(9, "Team 4", "MULTI6"); // Teal (originally gray)
+ // Guess I'll add these too? Kind of useless though...
+ public static readonly HouseType Multi1 = new HouseType(10, "Multi1", "GOOD");
+ public static readonly HouseType Multi2 = new HouseType(11, "Multi2", "GOOD");
+ public static readonly HouseType Multi3 = new HouseType(12, "Multi3", "GOOD");
+ public static readonly HouseType Multi4 = new HouseType(13, "Multi4", "GOOD");
+ public static readonly HouseType Multi5 = new HouseType(14, "Multi5", "GOOD");
+ public static readonly HouseType Multi6 = new HouseType(15, "Multi6", "GOOD");
+ public static readonly HouseType Multi7 = new HouseType(16, "Multi7", "GOOD");
+ public static readonly HouseType Multi8 = new HouseType(17, "Multi8", "GOOD");
+ public static readonly HouseType Multi9 = new HouseType(18, "Multi9", "GOOD");
+ public static readonly HouseType Multi10 = new HouseType(19, "Multi10", "GOOD");
+ public static readonly HouseType Multi11 = new HouseType(20, "Multi11", "GOOD");
+ public static readonly HouseType Multi12 = new HouseType(21, "Multi12", "GOOD");
+ public static readonly HouseType Multi13 = new HouseType(22, "Multi13", "GOOD");
+ public static readonly HouseType Multi14 = new HouseType(23, "Multi14", "GOOD");
+ public static readonly HouseType Multi15 = new HouseType(24, "Multi15", "GOOD");
+ public static readonly HouseType Multi16 = new HouseType(25, "Multi16", "GOOD");
+ public static readonly HouseType Multi17 = new HouseType(26, "Multi17", "GOOD");
+ public static readonly HouseType Multi18 = new HouseType(27, "Multi18", "GOOD");
+ public static readonly HouseType Multi19 = new HouseType(28, "Multi19", "GOOD");
+ public static readonly HouseType Multi20 = new HouseType(29, "Multi20", "GOOD");
+ public static readonly HouseType Multi21 = new HouseType(30, "Multi21", "GOOD");
+ public static readonly HouseType Multi22 = new HouseType(31, "Multi22", "GOOD");
+ public static readonly HouseType Multi23 = new HouseType(32, "Multi23", "GOOD");
+ public static readonly HouseType Multi24 = new HouseType(33, "Multi24", "GOOD");
+ public static readonly HouseType Multi25 = new HouseType(34, "Multi25", "GOOD");
+ public static readonly HouseType Multi26 = new HouseType(35, "Multi26", "GOOD");
+ public static readonly HouseType Multi27 = new HouseType(36, "Multi27", "GOOD");
+ public static readonly HouseType Multi28 = new HouseType(37, "Multi28", "GOOD");
+ public static readonly HouseType Multi29 = new HouseType(38, "Multi29", "GOOD");
+ public static readonly HouseType Multi30 = new HouseType(39, "Multi30", "GOOD");
+ public static readonly HouseType Multi31 = new HouseType(40, "Multi31", "GOOD");
+ public static readonly HouseType Multi32 = new HouseType(41, "Multi32", "GOOD");
+ public static readonly HouseType Multi33 = new HouseType(42, "Multi33", "GOOD");
+ public static readonly HouseType Multi34 = new HouseType(43, "Multi34", "GOOD");
+ public static readonly HouseType Multi35 = new HouseType(44, "Multi35", "GOOD");
+ public static readonly HouseType Multi36 = new HouseType(45, "Multi36", "GOOD");
+ public static readonly HouseType Multi37 = new HouseType(46, "Multi37", "GOOD");
+ public static readonly HouseType Multi38 = new HouseType(47, "Multi38", "GOOD");
+ public static readonly HouseType Multi39 = new HouseType(48, "Multi39", "GOOD");
+ public static readonly HouseType Multi40 = new HouseType(49, "Multi40", "GOOD");
+ public static readonly HouseType Multi41 = new HouseType(50, "Multi41", "GOOD");
+ public static readonly HouseType Multi42 = new HouseType(51, "Multi42", "GOOD");
+ public static readonly HouseType Multi43 = new HouseType(52, "Multi43", "GOOD");
+ public static readonly HouseType Multi44 = new HouseType(53, "Multi44", "GOOD");
+ public static readonly HouseType Multi45 = new HouseType(54, "Multi45", "GOOD");
+ public static readonly HouseType Multi46 = new HouseType(55, "Multi46", "GOOD");
+ public static readonly HouseType Multi47 = new HouseType(56, "Multi47", "GOOD");
+ public static readonly HouseType Multi48 = new HouseType(57, "Multi48", "GOOD");
+ public static readonly HouseType Multi49 = new HouseType(58, "Multi49", "GOOD");
+ public static readonly HouseType Multi50 = new HouseType(59, "Multi50", "GOOD");
+ public static readonly HouseType Multi51 = new HouseType(60, "Multi51", "GOOD");
+ public static readonly HouseType Multi52 = new HouseType(61, "Multi52", "GOOD");
+ public static readonly HouseType Multi53 = new HouseType(62, "Multi53", "GOOD");
+ public static readonly HouseType Multi54 = new HouseType(63, "Multi54", "GOOD");
+ public static readonly HouseType Multi55 = new HouseType(64, "Multi55", "GOOD");
+ public static readonly HouseType Multi56 = new HouseType(65, "Multi56", "GOOD");
+ public static readonly HouseType Multi57 = new HouseType(66, "Multi57", "GOOD");
+ public static readonly HouseType Multi58 = new HouseType(67, "Multi58", "GOOD");
+ public static readonly HouseType Multi59 = new HouseType(68, "Multi59", "GOOD");
+ public static readonly HouseType Multi60 = new HouseType(69, "Multi60", "GOOD");
+ public static readonly HouseType Multi61 = new HouseType(70, "Multi61", "GOOD");
+ public static readonly HouseType Multi62 = new HouseType(71, "Multi62", "GOOD");
+ public static readonly HouseType Multi63 = new HouseType(72, "Multi63", "GOOD");
+ public static readonly HouseType Multi64 = new HouseType(73, "Multi64", "GOOD");
+ public static readonly HouseType Multi65 = new HouseType(74, "Multi65", "GOOD");
+ public static readonly HouseType Multi66 = new HouseType(75, "Multi66", "GOOD");
+ public static readonly HouseType Multi67 = new HouseType(76, "Multi67", "GOOD");
+ public static readonly HouseType Multi68 = new HouseType(77, "Multi68", "GOOD");
+ public static readonly HouseType Multi69 = new HouseType(78, "Multi69", "GOOD");
+ public static readonly HouseType Multi70 = new HouseType(79, "Multi70", "GOOD");
+ public static readonly HouseType Multi71 = new HouseType(80, "Multi71", "GOOD");
+ public static readonly HouseType Multi72 = new HouseType(81, "Multi72", "GOOD");
+ public static readonly HouseType Multi73 = new HouseType(82, "Multi73", "GOOD");
+ public static readonly HouseType Multi74 = new HouseType(83, "Multi74", "GOOD");
+ public static readonly HouseType Multi75 = new HouseType(84, "Multi75", "GOOD");
+ public static readonly HouseType Multi76 = new HouseType(85, "Multi76", "GOOD");
+ public static readonly HouseType Multi77 = new HouseType(86, "Multi77", "GOOD");
+ public static readonly HouseType Multi78 = new HouseType(87, "Multi78", "GOOD");
+ public static readonly HouseType Multi79 = new HouseType(88, "Multi79", "GOOD");
+ public static readonly HouseType Multi80 = new HouseType(89, "Multi80", "GOOD");
+ public static readonly HouseType Multi81 = new HouseType(90, "Multi81", "GOOD");
+ public static readonly HouseType Multi82 = new HouseType(91, "Multi82", "GOOD");
+ public static readonly HouseType Multi83 = new HouseType(92, "Multi83", "GOOD");
+ public static readonly HouseType Multi84 = new HouseType(93, "Multi84", "GOOD");
+ public static readonly HouseType Multi85 = new HouseType(94, "Multi85", "GOOD");
+ public static readonly HouseType Multi86 = new HouseType(95, "Multi86", "GOOD");
+ public static readonly HouseType Multi87 = new HouseType(96, "Multi87", "GOOD");
+ public static readonly HouseType Multi88 = new HouseType(97, "Multi88", "GOOD");
+ public static readonly HouseType Multi89 = new HouseType(98, "Multi89", "GOOD");
+ public static readonly HouseType Multi90 = new HouseType(99, "Multi90", "GOOD");
+ public static readonly HouseType Multi91 = new HouseType(100, "Multi91", "GOOD");
+ public static readonly HouseType Multi92 = new HouseType(101, "Multi92", "GOOD");
+ public static readonly HouseType Multi93 = new HouseType(102, "Multi93", "GOOD");
+ public static readonly HouseType Multi94 = new HouseType(103, "Multi94", "GOOD");
+ public static readonly HouseType Multi95 = new HouseType(104, "Multi95", "GOOD");
+ public static readonly HouseType Multi96 = new HouseType(105, "Multi96", "GOOD");
+ public static readonly HouseType Multi97 = new HouseType(106, "Multi97", "GOOD");
+ public static readonly HouseType Multi98 = new HouseType(107, "Multi98", "GOOD");
+ public static readonly HouseType Multi99 = new HouseType(108, "Multi99", "GOOD");
+ public static readonly HouseType Multi100 = new HouseType(109, "Multi100", "GOOD");
+
+ private static readonly HouseType[] Types;
+
+ static HouseTypesSS()
+ {
+ Types =
+ (from field in typeof(HouseTypesSS).GetFields(BindingFlags.Static | BindingFlags.Public)
+ where field.IsInitOnly && typeof(HouseType).IsAssignableFrom(field.FieldType)
+ select field.GetValue(null) as HouseType).OrderBy(h => h.ID).ToArray();
+ }
+
+ public static IEnumerable GetTypes()
+ {
+ return Types;
+ }
+
+ public static string GetBasePlayer(string player)
+ {
+ return Admin.Name;
+ }
+ }
+}
diff --git a/README.md b/README.md
index e17fb66..14567cf 100644
--- a/README.md
+++ b/README.md
@@ -351,4 +351,4 @@ These options are all enabled by default, but can be disabled if you wish. Use t
Some ideas that might get implemented in the future:
-* Seems I'm all out!
+* Add Sole Survivor as separate game type