BTGame pane + shell de-hardcode for multi-game pods (BT port phase 3)
BTGame mirrors RPGame - same GameStateData/state-machine/NetworkScan engine driving each pod's MungaGame (take ownership, stream egg on WaitingForEgg, Run/Abort/Stop, countdown) - with the BT differences: ApplicationID.BTL4, a pilots grid carrying Mech/Camo/Patch/Badge/Experience, an Advanced Damage checkbox in place of RP's Score Compression, and the Mech* in-match messages recorded via BTMissionRecorder into BTMissionResults (.btm, gzip + BinaryFormatter like .rpm; scores are 1000-based like RP). Free For All and No Return share the pane; the mode selects the pilots' role. BTDefaults persists per-mode operator defaults to BTDefaults.btd (no dialog yet). RPGame's dead decompile members (sStopToIdleStates, IsAllPodsAppState) were not carried over. TeslaConsoleForm no longer assumes RP: the "AppID != 0 -> Pod Not Running RP" check becomes a GameTag map (RPL4 -> RP, BTL4 -> BT, otherwise Unknown Pod Application) feeding the per-game status strings, and the Games menu gains BattleTech: Free For All / No Return. Deferred to phase 4: mech/arena art, BT defaults dialog, BT score-sheet print document, Apps.xml BT411 product, live-pod verification. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,347 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
|
||||
namespace TeslaConsole.BattleTech;
|
||||
|
||||
/// <summary>
|
||||
/// Operator defaults for the two BattleTech game modes, persisted to
|
||||
/// BTDefaults.btd in the common app-data directory (mirrors
|
||||
/// <c>RPDefaults</c>/.rpd). Both modes share one defaults shape — they differ
|
||||
/// only by role, which comes from the mode, not from a default. There is no
|
||||
/// defaults dialog yet (RPDefaultsDialog's counterpart is a later phase); the
|
||||
/// file is import/export round-trippable in the meantime.
|
||||
/// </summary>
|
||||
internal static class BTDefaults
|
||||
{
|
||||
public class BattleDefaults
|
||||
{
|
||||
private readonly string mNodeName;
|
||||
|
||||
private bool mAdvancedDamage = true;
|
||||
|
||||
private TimeSpan mMissionLength = new TimeSpan(0, 10, 0);
|
||||
|
||||
private string mMapKey;
|
||||
|
||||
private string mVehicleKey;
|
||||
|
||||
private string mTimeOfDayKey;
|
||||
|
||||
private string mWeatherKey;
|
||||
|
||||
private string mExperienceKey;
|
||||
|
||||
private string mCamoKey;
|
||||
|
||||
private string mPatchKey;
|
||||
|
||||
private string mEmblemKey;
|
||||
|
||||
private int mLaunchDelay = 15;
|
||||
|
||||
public bool AdvancedDamage
|
||||
{
|
||||
get
|
||||
{
|
||||
return mAdvancedDamage;
|
||||
}
|
||||
set
|
||||
{
|
||||
mAdvancedDamage = value;
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan MissionLength
|
||||
{
|
||||
get
|
||||
{
|
||||
return mMissionLength;
|
||||
}
|
||||
set
|
||||
{
|
||||
mMissionLength = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string MapKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return mMapKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
mMapKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string VehicleKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return mVehicleKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
mVehicleKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string TimeOfDayKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return mTimeOfDayKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
mTimeOfDayKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string WeatherKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return mWeatherKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
mWeatherKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string ExperienceKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return mExperienceKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
mExperienceKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string CamoKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return mCamoKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
mCamoKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string PatchKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return mPatchKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
mPatchKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string EmblemKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return mEmblemKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
mEmblemKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int LaunchDelay
|
||||
{
|
||||
get
|
||||
{
|
||||
return mLaunchDelay;
|
||||
}
|
||||
set
|
||||
{
|
||||
mLaunchDelay = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal BattleDefaults(string nodeName)
|
||||
{
|
||||
mNodeName = nodeName;
|
||||
}
|
||||
|
||||
public void Save(XmlNode parrentNode)
|
||||
{
|
||||
XmlNode xmlNode = parrentNode.AppendChild(parrentNode.OwnerDocument.CreateElement(mNodeName));
|
||||
xmlNode.AppendChild(xmlNode.OwnerDocument.CreateElement("AdvancedDamage")).InnerText = mAdvancedDamage.ToString();
|
||||
xmlNode.AppendChild(xmlNode.OwnerDocument.CreateElement("MissionLength")).InnerText = mMissionLength.ToString();
|
||||
SaveKey(xmlNode, "MapKey", mMapKey);
|
||||
SaveKey(xmlNode, "VehicleKey", mVehicleKey);
|
||||
SaveKey(xmlNode, "TimeOfDayKey", mTimeOfDayKey);
|
||||
SaveKey(xmlNode, "WeatherKey", mWeatherKey);
|
||||
SaveKey(xmlNode, "ExperienceKey", mExperienceKey);
|
||||
SaveKey(xmlNode, "CamoKey", mCamoKey);
|
||||
SaveKey(xmlNode, "PatchKey", mPatchKey);
|
||||
SaveKey(xmlNode, "EmblemKey", mEmblemKey);
|
||||
xmlNode.AppendChild(xmlNode.OwnerDocument.CreateElement("LaunchDelay")).InnerText = mLaunchDelay.ToString();
|
||||
}
|
||||
|
||||
private static void SaveKey(XmlNode parentNode, string elementName, string value)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
parentNode.AppendChild(parentNode.OwnerDocument.CreateElement(elementName)).InnerText = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Parse(XmlNode scenarioNode)
|
||||
{
|
||||
foreach (XmlNode childNode in scenarioNode.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "AdvancedDamage":
|
||||
{
|
||||
if (bool.TryParse(childNode.InnerText, out var result2))
|
||||
{
|
||||
mAdvancedDamage = result2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "MissionLength":
|
||||
{
|
||||
if (TimeSpan.TryParse(childNode.InnerText, out var result3))
|
||||
{
|
||||
mMissionLength = result3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "MapKey":
|
||||
ParseKey(childNode, ref mMapKey);
|
||||
break;
|
||||
case "VehicleKey":
|
||||
ParseKey(childNode, ref mVehicleKey);
|
||||
break;
|
||||
case "TimeOfDayKey":
|
||||
ParseKey(childNode, ref mTimeOfDayKey);
|
||||
break;
|
||||
case "WeatherKey":
|
||||
ParseKey(childNode, ref mWeatherKey);
|
||||
break;
|
||||
case "ExperienceKey":
|
||||
ParseKey(childNode, ref mExperienceKey);
|
||||
break;
|
||||
case "CamoKey":
|
||||
ParseKey(childNode, ref mCamoKey);
|
||||
break;
|
||||
case "PatchKey":
|
||||
ParseKey(childNode, ref mPatchKey);
|
||||
break;
|
||||
case "EmblemKey":
|
||||
ParseKey(childNode, ref mEmblemKey);
|
||||
break;
|
||||
case "LaunchDelay":
|
||||
{
|
||||
if (int.TryParse(childNode.InnerText, out var result))
|
||||
{
|
||||
mLaunchDelay = result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ParseKey(XmlNode node, ref string field)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(node.InnerText))
|
||||
{
|
||||
field = node.InnerText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public const string FreeForAllNode = "FreeForAllDefaults";
|
||||
|
||||
public const string NoReturnNode = "NoReturnDefaults";
|
||||
|
||||
private static readonly string sDefaultsFilePath;
|
||||
|
||||
private static readonly BattleDefaults sFreeForAll;
|
||||
|
||||
private static readonly BattleDefaults sNoReturn;
|
||||
|
||||
public static BattleDefaults FreeForAll => sFreeForAll;
|
||||
|
||||
public static BattleDefaults NoReturn => sNoReturn;
|
||||
|
||||
static BTDefaults()
|
||||
{
|
||||
sDefaultsFilePath = Path.Combine(Program.GetCommonAppDataDirectory(), "BTDefaults.btd");
|
||||
sFreeForAll = new BattleDefaults("FreeForAllDefaults");
|
||||
sNoReturn = new BattleDefaults("NoReturnDefaults");
|
||||
if (File.Exists(sDefaultsFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
Import(sDefaultsFilePath);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
MessageBox.Show("The BattleTech defaults file appears to be corrupt. Please delete it or export a new one to replace it.", "Error Loading BattleTech Defaults!", MessageBoxButtons.OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Import(string fileName)
|
||||
{
|
||||
XmlDocument xmlDocument = new XmlDocument();
|
||||
xmlDocument.Load(fileName);
|
||||
foreach (XmlNode childNode in xmlDocument.DocumentElement.ChildNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "FreeForAllDefaults":
|
||||
sFreeForAll.Parse(childNode);
|
||||
break;
|
||||
case "NoReturnDefaults":
|
||||
sNoReturn.Parse(childNode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Save()
|
||||
{
|
||||
try
|
||||
{
|
||||
Export(sDefaultsFilePath);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
MessageBox.Show("The BattleTech defaults file could not be saved. These defaults will only be remembered until the application is closed.", "Error Saving BattleTech Defaults!", MessageBoxButtons.OK);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Export(string filePath)
|
||||
{
|
||||
XmlDocument xmlDocument = new XmlDocument();
|
||||
xmlDocument.AppendChild(xmlDocument.CreateElement("BTDefaults"));
|
||||
sFreeForAll.Save(xmlDocument.DocumentElement);
|
||||
sNoReturn.Save(xmlDocument.DocumentElement);
|
||||
string directoryName = Path.GetDirectoryName(filePath);
|
||||
if (!Directory.Exists(directoryName))
|
||||
{
|
||||
Directory.CreateDirectory(directoryName);
|
||||
}
|
||||
xmlDocument.Save(filePath);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user