Sole Survivor plugin basics

This commit is contained in:
Nyeguds 2022-09-20 18:40:27 +02:00
parent 2ded2a0574
commit fa897da332
14 changed files with 404 additions and 76 deletions

View File

@ -461,7 +461,9 @@
<Compile Include="TiberianDawn\DirectionTypes.cs" />
<Compile Include="TiberianDawn\EventTypes.cs" />
<Compile Include="TiberianDawn\GamePlugin.cs" />
<Compile Include="TiberianDawn\GamePluginSS.cs" />
<Compile Include="TiberianDawn\House.cs" />
<Compile Include="TiberianDawn\HouseTypesSS.cs" />
<Compile Include="TiberianDawn\HouseTypes.cs" />
<Compile Include="TiberianDawn\BuildingTypes.cs" />
<Compile Include="TiberianDawn\MissionTypes.cs" />

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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<Graphics>) 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 ||

View File

@ -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);

View File

@ -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<ITechnoType> fullTechnoTypes;
protected static readonly IEnumerable<ITechnoType> fullTechnoTypes;
private const string defVidVal = "x";
private readonly IEnumerable<string> movieTypes;
protected const string defVidVal = "x";
protected readonly IEnumerable<string> movieTypes;
private static readonly IEnumerable<string> movieTypesAdditional = new string[]
protected static readonly IEnumerable<string> movieTypesAdditional = new string[]
{
"BODYBAGS (Classic only)",
"REFINT (Classic only)",
@ -53,7 +53,7 @@ namespace MobiusEditor.TiberianDawn
"TRTKIL_D (Classic only)",
};
private static readonly IEnumerable<string> themeTypes = new string[]
protected static readonly IEnumerable<string> 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<string>();
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
/// </summary>
/// <param name="iniReader">Stream reader to read from.</param>
/// <returns>The ini file as string, with all double ROAD overlay lines replaced by the dummy Road2 type.</returns>
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<string> LoadINI(INI ini, bool forceSoloMission)
protected IEnumerable<string> LoadINI(INI ini, bool forceSoloMission)
{
var errors = new List<string>();
Map.BeginUpdate();
@ -1473,7 +1487,7 @@ namespace MobiusEditor.TiberianDawn
return errors;
}
private IEnumerable<string> LoadBinaryClassic(BinaryReader reader)
protected IEnumerable<string> LoadBinaryClassic(BinaryReader reader)
{
var errors = new List<string>();
Map.Templates.Clear();
@ -1490,7 +1504,7 @@ namespace MobiusEditor.TiberianDawn
return errors;
}
private IEnumerable<string> LoadBinaryMega(BinaryReader reader)
protected IEnumerable<string> LoadBinaryMega(BinaryReader reader)
{
var errors = new List<string>();
Map.Templates.Clear();
@ -1518,7 +1532,7 @@ namespace MobiusEditor.TiberianDawn
return errors;
}
private TemplateType ChecKTemplateType(int typeValue, int iconValue, int x, int y, List<string> errors)
protected TemplateType ChecKTemplateType(int typeValue, int iconValue, int x, int y, List<string> errors)
{
TemplateType templateType = Map.TemplateTypes.Where(t => t.Equals(typeValue)).FirstOrDefault();
// Prevent loading of illegal tiles.
@ -1672,7 +1686,7 @@ namespace MobiusEditor.TiberianDawn
/// </summary>
/// <param name="ini">The generated ini file</param>
/// <param name="iniWriter">The stream writer to write the text to.</param>
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)
{

View File

@ -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);
}
}
}
}

View File

@ -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;

View File

@ -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<HouseType> GetTypes()
{
return Types;
}
public static string GetBasePlayer(string player)
{
return Admin.Name;
}
}
}

View File

@ -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