diff --git a/Console/TeslaConsole.BattleTech/BTDamagedEvent.cs b/Console/TeslaConsole.BattleTech/BTDamagedEvent.cs new file mode 100644 index 0000000..2f8f3a5 --- /dev/null +++ b/Console/TeslaConsole.BattleTech/BTDamagedEvent.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace TeslaConsole.BattleTech; + +/// +/// A mech took damage (MechDamagedMessage). Carries the Red Planet +/// damage fields plus BT's damage-matrix extras: which zone was hit, whether it +/// was destroyed, and the weapon that did it. +/// +[Serializable] +internal class BTDamagedEvent : BTMissionEvent +{ + public readonly BTPlayer Damager; + + public readonly int DamageLoss; + + public readonly int PointsTransfered; + + public readonly int DamageZoneIndex; + + public readonly bool DamageZoneDestroyed; + + public readonly int WeaponIndex; + + public override IEnumerable InvolvedPilots => new BTPlayer[2] { ReportingPilot, Damager }; + + public BTDamagedEvent(BTPlayer reportingPilot, TimeSpan missionTime, BTPlayer damager, int damageLoss, int pointsTransfered, int damageZoneIndex, bool damageZoneDestroyed, int weaponIndex) + : base(reportingPilot, missionTime) + { + Damager = damager; + DamageLoss = damageLoss; + PointsTransfered = pointsTransfered; + DamageZoneIndex = damageZoneIndex; + DamageZoneDestroyed = damageZoneDestroyed; + WeaponIndex = weaponIndex; + } + + private BTDamagedEvent() + { + } +} diff --git a/Console/TeslaConsole.BattleTech/BTDeathWithoutHonorEvent.cs b/Console/TeslaConsole.BattleTech/BTDeathWithoutHonorEvent.cs new file mode 100644 index 0000000..4e88f0c --- /dev/null +++ b/Console/TeslaConsole.BattleTech/BTDeathWithoutHonorEvent.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace TeslaConsole.BattleTech; + +/// +/// A mech died without a killer to credit — overheating, terrain, or +/// self-destruction (MechDeathWithoutHonorMessage). +/// +[Serializable] +internal class BTDeathWithoutHonorEvent : BTMissionEvent +{ + public override IEnumerable InvolvedPilots => new BTPlayer[1] { ReportingPilot }; + + public BTDeathWithoutHonorEvent(BTPlayer reportingPilot, TimeSpan missionTime) + : base(reportingPilot, missionTime) + { + } + + private BTDeathWithoutHonorEvent() + { + } +} diff --git a/Console/TeslaConsole.BattleTech/BTDefaults.cs b/Console/TeslaConsole.BattleTech/BTDefaults.cs new file mode 100644 index 0000000..939f7a0 --- /dev/null +++ b/Console/TeslaConsole.BattleTech/BTDefaults.cs @@ -0,0 +1,347 @@ +using System; +using System.IO; +using System.Windows.Forms; +using System.Xml; + +namespace TeslaConsole.BattleTech; + +/// +/// Operator defaults for the two BattleTech game modes, persisted to +/// BTDefaults.btd in the common app-data directory (mirrors +/// RPDefaults/.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. +/// +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); + } +} diff --git a/Console/TeslaConsole.BattleTech/BTGame.cs b/Console/TeslaConsole.BattleTech/BTGame.cs new file mode 100644 index 0000000..7ed9911 --- /dev/null +++ b/Console/TeslaConsole.BattleTech/BTGame.cs @@ -0,0 +1,1591 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using Munga.Net; +using WeifenLuo.WinFormsUI.Docking; + +namespace TeslaConsole.BattleTech; + +/// +/// The BattleTech game pane: mission-configuration UI plus the run/stop state +/// loop that drives each pod's . A close mirror of +/// TeslaConsole.RedPlanet.RPGame — same GameStateData/state machine/ +/// NetworkScan engine — with the BT differences: the pod app is +/// , the grid carries the BT pilot fields +/// (mech/camo/patch/badge/experience), Advanced Damage replaces Score +/// Compression, and the in-match events are the Mech* messages. Free For All +/// and No Return share this one pane; the mode only selects the pilots' role. +/// The score-sheet printing controls (RPGame's Auto Print / Print Last +/// Mission) are deferred until a BT print document exists; results are still +/// recorded and saved as .btm files. +/// +internal class BTGame : DockContent +{ + private class DragDropData + { + public int StartRow; + + public int EndRow; + + public bool RightClick; + + public DragDropData(int startRow, bool rightClick) + { + StartRow = startRow; + RightClick = rightClick; + } + } + + private class GameStateData + { + public bool EggMessageSent; + + public bool RunMessageSent; + + public bool AbortMessageSent; + + public bool StopMessageSent; + + public bool PodAppearsReset; + + public void Reset() + { + EggMessageSent = (RunMessageSent = (AbortMessageSent = (StopMessageSent = (PodAppearsReset = false)))); + } + } + + private enum BTGameState + { + Idle, + Load, + AutoTransCount, + Run, + Reset + } + + private static readonly Color sDataLockedColor = Color.LightGray; + + private static readonly Random sRand = new Random(); + + private Site mSite; + + private readonly bool mNoReturnMode; + + private readonly string mGameName; + + private EggFileMessage[] mEggFileMessages; + + private BTGameState mCurrentState; + + private BTGameState mRequestedState; + + private TimeSpan mMissionLength; + + private DateTime mGameStart; + + private bool mNormalMissionEnd; + + private bool mProcessingMissionEndStateChangeReq; + + private int mRemainingUntilTranslocate; + + private Dictionary mGameStateData = new Dictionary(); + + private BTMissionRecorder mMissionRecorder; + + private Dictionary mMissionPlayers; + + private LogOutputWindow mLogWindow; + + private BTMissionResults mLastMissionResults; + + private IContainer components; + + private GroupBox mMissionPropertiesGroupBox; + + private Label mIssuesLabel; + + private Label mMissionLengthDisplayLabel; + + private Label mMissionLengthTextLabel; + + private CheckBox mAdvancedDamage; + + private ComboBox mWeather; + + private ComboBox mMap; + + private ComboBox mTimeOfDay; + + private Label mTimeOfDayLabel; + + private Label mWeatherLabel; + + private Label mMapLabel; + + private GroupBox mPilotsGroupBox; + + private TableLayoutPanel mMissionPropertiesTable; + + private DataGridView mPilotsDataGrid; + + private Button mGoButton; + + private ContextMenuStrip mDragDropContextMenu; + + private ToolStripMenuItem mSwapPilots; + + private ToolStripMenuItem mShiftPilots; + + private Timer mNetworkTimer; + + private DataGridViewCheckBoxColumn mEnabledColumn; + + private DataGridViewImageColumn mStatusIconColumn; + + private DataGridViewTextBoxColumn mStatusTextColumn; + + private DataGridViewTextBoxColumn mPilotColumn; + + private DataGridViewComboBoxColumn mVehicleColumn; + + private DataGridViewComboBoxColumn mColorColumn; + + private DataGridViewComboBoxColumn mPatchColumn; + + private DataGridViewComboBoxColumn mBadgeColumn; + + private DataGridViewComboBoxColumn mExperienceColumn; + + private ContextMenuStrip mResetContextMenu; + + private ToolStripMenuItem resetToolStripMenuItem; + + private CheckBox mAutoTranslocateCheckbox; + + private Button mRandomMap; + + private Button mRandomWeather; + + private Button mRandomTimeOfDay; + + private TextBox mMissionLengthTextBox; + + private Timer tmrAutoTranslocate; + + private string GameStatusText + { + set + { + if (string.IsNullOrEmpty(value)) + { + base.TabText = (Text = mGameName); + } + else + { + base.TabText = (Text = $"{mGameName} [{value}]"); + } + } + } + + private BTDefaults.BattleDefaults ModeDefaults => mNoReturnMode ? BTDefaults.NoReturn : BTDefaults.FreeForAll; + + private BTRole ModeRole => BTConfig.FreeForAll.Roles[mNoReturnMode ? "NoReturn" : "Default"]; + + private BTGame() + { + InitializeComponent(); + } + + internal BTGame(Site site, bool noReturnMode) + : this() + { + mNoReturnMode = noReturnMode; + mSite = site; + SuspendLayout(); + mGameName = (mNoReturnMode ? "BattleTech No Return" : "BattleTech Free For All"); + GameStatusText = null; + BTScenario scenario = BTConfig.FreeForAll; + BTDefaults.BattleDefaults defaults = ModeDefaults; + int selectedIndex; + int num = (selectedIndex = 0); + string text = defaults.MapKey; + mMap.DisplayMember = "Name"; + mMap.ValueMember = "Key"; + foreach (BTMap item in scenario.Maps.Values) + { + mMap.Items.Add(item); + if (item.Key == text) + { + selectedIndex = num; + } + num++; + } + mMap.SelectedIndex = selectedIndex; + num = (selectedIndex = 0); + text = defaults.WeatherKey; + mWeather.DisplayMember = "Name"; + mWeather.ValueMember = "Key"; + foreach (BTWeather item2 in scenario.Weather.Values) + { + mWeather.Items.Add(item2); + if (item2.Key == text) + { + selectedIndex = num; + } + num++; + } + mWeather.SelectedIndex = selectedIndex; + num = (selectedIndex = 0); + text = defaults.TimeOfDayKey; + mTimeOfDay.DisplayMember = "Value"; + mTimeOfDay.ValueMember = "Key"; + foreach (KeyValuePair item3 in scenario.TimesOfDay) + { + mTimeOfDay.Items.Add(item3); + if (item3.Key == text) + { + selectedIndex = num; + } + num++; + } + mTimeOfDay.SelectedIndex = selectedIndex; + mAdvancedDamage.Checked = defaults.AdvancedDamage; + mMissionLengthTextBox.Text = defaults.MissionLength.TotalMinutes.ToString(); + num = (selectedIndex = 0); + text = defaults.VehicleKey; + mVehicleColumn.DisplayMember = "Name"; + mVehicleColumn.ValueMember = "Key"; + foreach (BTVehicle item4 in scenario.Vehicles.Values) + { + mVehicleColumn.Items.Add(item4); + if (item4.Key == text) + { + selectedIndex = num; + } + num++; + } + mVehicleColumn.Tag = selectedIndex; + SetupKeyValueColumn(mColorColumn, scenario.Colors, defaults.CamoKey); + SetupKeyValueColumn(mPatchColumn, scenario.Patches, defaults.PatchKey); + SetupKeyValueColumn(mBadgeColumn, scenario.Badges, defaults.EmblemKey); + SetupKeyValueColumn(mExperienceColumn, scenario.Experiences, defaults.ExperienceKey); + List> list = new List>(); + foreach (Squad squad in mSite.Squads) + { + foreach (Pod pod in squad.Pods) + { + if (pod.HostType == HostType.GameMachineHostType) + { + BuildPodRow(squad, pod); + } + else if (pod.HostType == HostType.MissionReviewHostType) + { + list.Add(new Tuple(squad, pod)); + } + } + } + foreach (Tuple item5 in list) + { + BuildPodRow(item5.A, item5.B); + } + CheckAllValues(); + ResumeLayout(); + } + + private static void SetupKeyValueColumn(DataGridViewComboBoxColumn column, Dictionary options, string defaultKey) + { + int num = 0; + int selectedIndex = 0; + column.DisplayMember = "Value"; + column.ValueMember = "Key"; + foreach (KeyValuePair option in options) + { + column.Items.Add(option); + if (option.Key == defaultKey) + { + selectedIndex = num; + } + num++; + } + column.Tag = selectedIndex; + } + + private void BuildPodRow(Squad squad, Pod pod) + { + int index = mPilotsDataGrid.Rows.Add(); + DataGridViewRow row = mPilotsDataGrid.Rows[index]; + row.Tag = pod; + row.HeaderCell.Value = $"{squad.Name} - {pod.Name}"; + row.Cells[mEnabledColumn.Index].Value = false; + if (pod.HostType == HostType.GameMachineHostType) + { + row.Cells[mVehicleColumn.Index].Value = mVehicleColumn.Items[(int)mVehicleColumn.Tag]; + row.Cells[mColorColumn.Index].Value = mColorColumn.Items[(int)mColorColumn.Tag]; + row.Cells[mPatchColumn.Index].Value = mPatchColumn.Items[(int)mPatchColumn.Tag]; + row.Cells[mBadgeColumn.Index].Value = mBadgeColumn.Items[(int)mBadgeColumn.Tag]; + row.Cells[mExperienceColumn.Index].Value = mExperienceColumn.Items[(int)mExperienceColumn.Tag]; + } + else + { + row.Cells[mVehicleColumn.Index].Value = ""; + row.Cells[mColorColumn.Index].Value = ""; + row.Cells[mPatchColumn.Index].Value = ""; + row.Cells[mBadgeColumn.Index].Value = ""; + row.Cells[mExperienceColumn.Index].Value = ""; + row.Cells[mPilotColumn.Index].ReadOnly = true; + row.Cells[mVehicleColumn.Index].ReadOnly = true; + row.Cells[mColorColumn.Index].ReadOnly = true; + row.Cells[mPatchColumn.Index].ReadOnly = true; + row.Cells[mBadgeColumn.Index].ReadOnly = true; + row.Cells[mExperienceColumn.Index].ReadOnly = true; + } + mGameStateData[pod.MungaGame] = new GameStateData(); + SetPodStatus(row, pod.MungaGame); + pod.MungaGame.OnPodStatusUpdated += delegate(object sender, EventArgs e) + { + if (!base.IsDisposed) + { + SetPodStatus(row, (MungaGame)sender); + } + }; + } + + protected override void OnClosing(CancelEventArgs e) + { + if (mCurrentState != 0 && MessageBox.Show("A BattleTech game controlled by this window is currently in progress. If you choose to continue, the game will end immediately. Are you sure you wish to procede?", "Game Running", MessageBoxButtons.OKCancel) == DialogResult.Cancel) + { + e.Cancel = true; + } + else + { + base.OnClosing(e); + } + } + + protected override void OnClosed(EventArgs e) + { + foreach (Squad squad in mSite.Squads) + { + foreach (Pod pod in squad.Pods) + { + ForcePodRelease(pod.MungaGame); + pod.MungaGame.ReleaseRequest(this); + } + } + base.OnClosed(e); + } + + private static string GetStringOrKey(DataGridViewCell cell) + { + if (cell.Value is string) + { + return (string)cell.Value; + } + return ((KeyValuePair)cell.Value).Key; + } + + private void NetworkScan(object sender, EventArgs e) + { + if (mCurrentState == BTGameState.Run && mRequestedState == BTGameState.Run && !mProcessingMissionEndStateChangeReq) + { + mProcessingMissionEndStateChangeReq = true; + TimeSpan timeRemaining = mMissionLength - (DateTime.Now - mGameStart); + if (timeRemaining.Ticks < 0) + { + mNormalMissionEnd = true; + RequestState(BTGameState.Idle); + timeRemaining = new TimeSpan(0L); + } + string gameStatusText = FormatTimeRemaining(timeRemaining); + mMissionLengthDisplayLabel.Text = gameStatusText; + GameStatusText = gameStatusText; + mProcessingMissionEndStateChangeReq = false; + } + bool flag = true; + foreach (DataGridViewRow item in (IEnumerable)mPilotsDataGrid.Rows) + { + Pod pod = (Pod)item.Tag; + if (mRequestedState == BTGameState.Idle) + { + GetPodReleased(pod.MungaGame); + if (pod.MungaGame.IsOwner(this)) + { + flag = false; + } + } + else if (!(bool)item.Cells[mEnabledColumn.Index].Value) + { + if (pod.MungaGame.IsOwner(this)) + { + GetPodReleased(pod.MungaGame); + } + } + else + { + GameStateData gameStateData = mGameStateData[pod.MungaGame]; + if (!gameStateData.PodAppearsReset) + { + if (!pod.MungaGame.IsOwned) + { + pod.MungaGame.TakeOwnership(this); + } + if (!pod.MungaGame.IsOwner(this)) + { + flag = false; + } + else if (!pod.MungaGame.IsPodOperational(ApplicationID.BTL4)) + { + flag = false; + } + else if (mRequestedState == BTGameState.Load) + { + switch (pod.MungaGame.AppState.Value) + { + case ApplicationState.RunningMission: + if (!gameStateData.AbortMessageSent) + { + pod.MungaGame.Send(0, 1, new AbortMissionMessage(0)); + gameStateData.AbortMessageSent = true; + } + break; + case ApplicationState.WaitingForEgg: + if (!pod.MungaGame.EggAcknowledged && pod.MungaGame.EggDelayTimer < DateTime.Now && pod.MungaGame.EggSent.AddSeconds(5.0) < DateTime.Now) + { + LogMessage("Egg Sent."); + EggFileMessage[] array = mEggFileMessages; + foreach (EggFileMessage message in array) + { + pod.MungaGame.Send(0, 1, message); + } + pod.MungaGame.EggSent = DateTime.Now; + } + break; + } + if (!pod.MungaGame.IsPodAppState(ApplicationID.BTL4, ApplicationState.WaitingForLaunch)) + { + flag = false; + } + } + else if (mRequestedState == BTGameState.Run) + { + switch (pod.MungaGame.AppState.Value) + { + case ApplicationState.WaitingForEgg: + gameStateData.PodAppearsReset = true; + GetPodReleased(pod.MungaGame); + break; + case ApplicationState.WaitingForLaunch: + if (!gameStateData.RunMessageSent) + { + pod.MungaGame.Send(0, 1, new RunMissionMessage()); + gameStateData.RunMessageSent = true; + } + break; + } + if (!pod.MungaGame.IsPodAppState(ApplicationID.BTL4, ApplicationState.RunningMission)) + { + flag = false; + } + } + } + } + if (!pod.MungaGame.IsOwner(this)) + { + continue; + } + for (MetaMessage metaMessage = pod.MungaGame.Receive(); metaMessage != null; metaMessage = pod.MungaGame.Receive()) + { + LogMessage(pod, metaMessage); + if (metaMessage.Message is MechDamagedMessage) + { + MechDamagedMessage mechDamagedMessage = (MechDamagedMessage)metaMessage.Message; + mMissionRecorder.PlayerDamaged(mMissionPlayers[mechDamagedMessage.PlayerHostID], mMissionPlayers[mechDamagedMessage.DamagerHostID], mechDamagedMessage.DamageLoss, mechDamagedMessage.PointsTransfered, mechDamagedMessage.DamageZoneIndex, mechDamagedMessage.DamageZoneDestroyed, mechDamagedMessage.WeaponIndex); + } + else if (metaMessage.Message is MechKilledMessage) + { + MechKilledMessage mechKilledMessage = (MechKilledMessage)metaMessage.Message; + mMissionRecorder.PlayerKilled(mMissionPlayers[mechKilledMessage.PlayerHostID], mMissionPlayers[mechKilledMessage.KillerHostID]); + } + else if (metaMessage.Message is MechDeathWithoutHonorMessage) + { + MechDeathWithoutHonorMessage mechDeathWithoutHonorMessage = (MechDeathWithoutHonorMessage)metaMessage.Message; + mMissionRecorder.PlayerDeathWithoutHonor(mMissionPlayers[mechDeathWithoutHonorMessage.PlayerHostID]); + } + else if (metaMessage.Message is MechScoreUpdateMessage) + { + MechScoreUpdateMessage mechScoreUpdateMessage = (MechScoreUpdateMessage)metaMessage.Message; + mMissionRecorder.PlayerScoreUpdate(mMissionPlayers[mechScoreUpdateMessage.PlayerHostID], mechScoreUpdateMessage.PlayerScore); + } + else if (metaMessage.Message is EndMissionMessage) + { + EndMissionMessage endMissionMessage = (EndMissionMessage)metaMessage.Message; + mMissionRecorder.PlayerFinalScore(mMissionPlayers[endMissionMessage.PlayerHostID], endMissionMessage.FinalScore); + } + } + } + if (mCurrentState != mRequestedState && flag) + { + StateChangeApproved(); + } + } + + private void LogMessage(string message) + { + if (mLogWindow != null && !mLogWindow.IsDisposed) + { + mLogWindow.LogMessage(message); + } + } + + private void LogMessage(Pod pod, MetaMessage msg) + { + if (mLogWindow == null || mLogWindow.IsDisposed) + { + return; + } + if (msg.Message is AcknowledgeEggFileMessage) + { + mLogWindow.LogMessage("{0}: {1}: {2}: Egg ACK", pod.Name, msg.Header.ClientID, msg.Message.GetType().Name); + } + else if (msg.Message is EndMissionMessage) + { + EndMissionMessage endMissionMessage = (EndMissionMessage)msg.Message; + mLogWindow.LogMessage("{0}: {1}: {2}: Final Score {3}", pod.Name, msg.Header.ClientID, msg.Message.GetType().Name, endMissionMessage.FinalScore); + } + else if (msg.Message is ReadyToRunMessage) + { + mLogWindow.LogMessage("{0}: {1}: {2}", pod.Name, msg.Header.ClientID, msg.Message.GetType().Name); + } + else if (msg.Message is MechKilledMessage) + { + MechKilledMessage mechKilledMessage = (MechKilledMessage)msg.Message; + mLogWindow.LogMessage("{0}: {1}: {2}: {3} killed {4}", pod.Name, msg.Header.ClientID, msg.Message.GetType().Name, mechKilledMessage.KillerHostID, mechKilledMessage.PlayerHostID); + } + else if (msg.Message is MechDeathWithoutHonorMessage) + { + mLogWindow.LogMessage("{0}: {1}: {2}: {3} died without honor", pod.Name, msg.Header.ClientID, msg.Message.GetType().Name, ((MechDeathWithoutHonorMessage)msg.Message).PlayerHostID); + } + else if (msg.Message is MechScoreUpdateMessage) + { + mLogWindow.LogMessage("{0}: {1}: {2}: {3} Score = {4}", pod.Name, msg.Header.ClientID, msg.Message.GetType().Name, ((MechScoreUpdateMessage)msg.Message).PlayerHostID, ((MechScoreUpdateMessage)msg.Message).PlayerScore); + } + else if (msg.Message is BTTeamScoreUpdateMessage) + { + mLogWindow.LogMessage("{0}: {1}: {2}: Team {3} Score = {4}", pod.Name, msg.Header.ClientID, msg.Message.GetType().Name, ((BTTeamScoreUpdateMessage)msg.Message).TeamID, ((BTTeamScoreUpdateMessage)msg.Message).TeamScore); + } + else if (msg.Message is MechDamagedMessage) + { + MechDamagedMessage mechDamagedMessage = (MechDamagedMessage)msg.Message; + if (mechDamagedMessage.DamageLoss != 0) + { + mLogWindow.LogMessage("{0}: {1}: {2}: {3} Damaged {4} For {5} Points.", pod.Name, msg.Header.ClientID, msg.Message.GetType().Name, mechDamagedMessage.DamagerHostID, mechDamagedMessage.PlayerHostID, mechDamagedMessage.PointsTransfered); + } + } + } + + private string FormatTimeRemaining(TimeSpan timeRemaining) + { + long num = (long)timeRemaining.TotalMinutes; + long num2 = (long)(timeRemaining.TotalSeconds - (double)(num * 60)); + return $"{num:00}:{num2:00}"; + } + + private void ForcePodRelease(MungaGame munga) + { + GetPodReleased(munga); + munga.ReleaseOwnership(this); + } + + private void GetPodReleased(MungaGame munga) + { + if (!munga.IsOwner(this)) + { + return; + } + if (!munga.IsPodOperational(ApplicationID.BTL4)) + { + munga.ReleaseOwnership(this); + return; + } + GameStateData gameStateData = mGameStateData[munga]; + switch (munga.AppState.Value) + { + case ApplicationState.WaitingForLaunch: + if (!gameStateData.AbortMessageSent) + { + munga.Send(0, 1, new AbortMissionMessage(0)); + gameStateData.AbortMessageSent = true; + } + break; + case ApplicationState.RunningMission: + if (!gameStateData.StopMessageSent) + { + munga.Send(0, 1, new StopMissionMessage(0)); + gameStateData.StopMessageSent = true; + } + break; + case ApplicationState.WaitingForEgg: + munga.ReleaseOwnership(this); + break; + case ApplicationState.LoadingMission: + case ApplicationState.LaunchingMission: + break; + } + } + + private void StateChangeApproved() + { + switch (mRequestedState) + { + case BTGameState.Idle: + EndMission(); + GameStatusText = null; + mGoButton.Text = "Load"; + mEggFileMessages = null; + SwitchControlsMode(editMode: true); + CheckAllValues(); + mCurrentState = BTGameState.Idle; + break; + case BTGameState.Load: + GameStatusText = "Loaded"; + mGoButton.Text = "Run Mission"; + mGoButton.Enabled = true; + foreach (GameStateData value in mGameStateData.Values) + { + value.Reset(); + } + mCurrentState = BTGameState.Load; + if (mAutoTranslocateCheckbox.Checked) + { + int num = ModeDefaults.LaunchDelay; + if (num == 0) + { + mGoButton.Text = "Launching..."; + GameStatusText = "Launching..."; + mGoButton.Enabled = false; + RequestState(BTGameState.Run); + } + else + { + mGoButton.Text = $"Launching in {num}..."; + GameStatusText = mGoButton.Text; + mRemainingUntilTranslocate = num; + tmrAutoTranslocate.Start(); + } + } + break; + case BTGameState.Run: + mGameStart = DateTime.Now; + mGoButton.Text = "Stop Mission"; + mGoButton.Enabled = true; + mCurrentState = BTGameState.Run; + mMissionRecorder.SetMissionStart(); + mMissionLengthDisplayLabel.ForeColor = Color.DarkGreen; + break; + case BTGameState.AutoTransCount: + break; + } + } + + private void mGoButton_Click(object sender, EventArgs e) + { + switch (mCurrentState) + { + case BTGameState.Idle: + RequestState(BTGameState.Load); + break; + case BTGameState.Load: + tmrAutoTranslocate.Stop(); + RequestState(BTGameState.Run); + break; + case BTGameState.Run: + mNormalMissionEnd = false; + RequestState(BTGameState.Idle); + break; + case BTGameState.AutoTransCount: + break; + } + } + + private void resetToolStripMenuItem_Click(object sender, EventArgs e) + { + RequestState(BTGameState.Reset); + } + + private void RequestState(BTGameState state) + { + switch (state) + { + case BTGameState.Load: + { + mMissionLength = ParseMissionLength(); + string key = ((BTMap)mMap.SelectedItem).Key; + string key2 = ((KeyValuePair)mTimeOfDay.SelectedItem).Key; + BTWeather bTWeather = (BTWeather)mWeather.SelectedItem; + BTFreeForAllMission bTMission = new BTFreeForAllMission(key, key2, bTWeather.Key, bTWeather.Temperature, mMissionLength); + BTRole role = ModeRole; + mMissionRecorder = new BTMissionRecorder(bTMission); + mMissionPlayers = new Dictionary(); + int num = 2; + foreach (DataGridViewRow item in (IEnumerable)mPilotsDataGrid.Rows) + { + if (!(bool)item.Cells[mEnabledColumn.Index].Value) + { + continue; + } + Pod pod = (Pod)item.Tag; + if (pod.HostType == HostType.GameMachineHostType) + { + string value = (string)item.Cells[mPilotColumn.Index].Value; + BTPlayer bTPlayer = new BTPlayer(pod.IPAddress.ToString(), value, (item.Cells[mVehicleColumn.Index].Value is string) ? ((string)item.Cells[mVehicleColumn.Index].Value) : ((BTVehicle)item.Cells[mVehicleColumn.Index].Value).Key, GetStringOrKey(item.Cells[mColorColumn.Index]), GetStringOrKey(item.Cells[mPatchColumn.Index]), GetStringOrKey(item.Cells[mBadgeColumn.Index]), GetStringOrKey(item.Cells[mExperienceColumn.Index]), role, mAdvancedDamage.Checked); + bTMission.BattlePlayers.Add(bTPlayer); + mMissionPlayers.Add(num++, bTPlayer); + PilotNameCache.PilotNames.Add(value); + } + else + { + bTMission.Cameras.Add(new BTCamera(pod.IPAddress.ToString(), pod.HostType)); + } + } + mEggFileMessages = bTMission.ToEggFileMessages(); + mRequestedState = BTGameState.Load; + SwitchControlsMode(editMode: false); + GameStatusText = "Loading..."; + mGoButton.Text = "Loading..."; + mGoButton.Enabled = false; + break; + } + case BTGameState.Run: + mRequestedState = BTGameState.Run; + GameStatusText = "Launching..."; + mGoButton.Text = "Launching..."; + mGoButton.Enabled = false; + break; + case BTGameState.Idle: + mRequestedState = BTGameState.Idle; + mMissionLengthDisplayLabel.ForeColor = Color.Red; + GameStatusText = "Stopping Game..."; + mGoButton.Text = "Stopping Game..."; + mGoButton.Enabled = false; + break; + case BTGameState.Reset: + foreach (Squad squad in mSite.Squads) + { + foreach (Pod pod2 in squad.Pods) + { + ForcePodRelease(pod2.MungaGame); + } + } + mRequestedState = BTGameState.Idle; + StateChangeApproved(); + break; + case BTGameState.AutoTransCount: + break; + } + } + + private void EndMission() + { + try + { + mLastMissionResults = mMissionRecorder.EndMission(mNormalMissionEnd ? mMissionLength : (DateTime.Now - mGameStart)); + try + { + mLastMissionResults.Save(); + } + catch (Exception ex) + { + if (Debugger.IsAttached) + { + throw; + } + Program.LogExceptionAndShowDialog(ex, "Mission results failed to save.", "Error Saving Mission Results"); + } + } + catch (Exception ex2) + { + if (Debugger.IsAttached) + { + throw; + } + Program.LogExceptionAndShowDialog(ex2, "Failed to create mission results.", "Error Creating Mission Results"); + } + mMissionRecorder = null; + mMissionPlayers = null; + } + + private void SwitchControlsMode(bool editMode) + { + mMap.Enabled = editMode; + mWeather.Enabled = editMode; + mTimeOfDay.Enabled = editMode; + mAdvancedDamage.Enabled = editMode; + mRandomMap.Enabled = editMode; + mRandomWeather.Enabled = editMode; + mRandomTimeOfDay.Enabled = editMode; + mMissionLengthDisplayLabel.Text = FormatTimeRemaining(mMissionLength); + mMissionLengthDisplayLabel.ForeColor = Color.Orange; + mMissionLengthTextBox.Visible = editMode; + mMissionLengthDisplayLabel.Visible = !editMode; + int column = mMissionPropertiesTable.GetColumn(mMissionLengthTextBox); + mMissionPropertiesTable.ColumnStyles[column].Width = 0f; + mMissionPropertiesTable.ColumnStyles[column].SizeType = ((!editMode) ? SizeType.Absolute : SizeType.AutoSize); + int column2 = mMissionPropertiesTable.GetColumn(mMissionLengthDisplayLabel); + mMissionPropertiesTable.ColumnStyles[column2].Width = 0f; + mMissionPropertiesTable.ColumnStyles[column2].SizeType = (editMode ? SizeType.Absolute : SizeType.AutoSize); + mPilotsDataGrid.EditMode = (editMode ? DataGridViewEditMode.EditOnKeystrokeOrF2 : DataGridViewEditMode.EditProgrammatically); + Color backColor = (editMode ? Color.White : sDataLockedColor); + foreach (DataGridViewRow item in (IEnumerable)mPilotsDataGrid.Rows) + { + item.Cells[mEnabledColumn.Index].Style.BackColor = backColor; + if (((Pod)item.Tag).HostType == HostType.GameMachineHostType) + { + Color foreColor = (((bool)item.Cells[mEnabledColumn.Index].Value) ? Color.Black : Color.DarkGray); + foreach (DataGridViewColumn pilotColumn in PilotDataColumns()) + { + item.Cells[pilotColumn.Index].Style.BackColor = backColor; + item.Cells[pilotColumn.Index].Style.ForeColor = foreColor; + } + } + } + if (editMode) + { + CheckAllValues(); + } + } + + private DataGridViewColumn[] PilotDataColumns() + { + return new DataGridViewColumn[6] { mPilotColumn, mVehicleColumn, mColorColumn, mPatchColumn, mBadgeColumn, mExperienceColumn }; + } + + private void SetPodStatus(DataGridViewRow row, MungaGame munga) + { + if (munga.IsOwned && !munga.IsOwner(this)) + { + row.Cells[mStatusIconColumn.Index].Value = ImageCache.PodQuestion16; + row.Cells[mStatusTextColumn.Index].Value = "In Use"; + } + else + { + row.Cells[mStatusIconColumn.Index].Value = munga.Image; + row.Cells[mStatusTextColumn.Index].Value = munga.StatusMessage; + } + if (mCurrentState == BTGameState.Idle && mRequestedState == BTGameState.Idle) + { + CheckAllValues(); + } + } + + private void CheckAllValues() + { + foreach (DataGridViewRow item in (IEnumerable)mPilotsDataGrid.Rows) + { + item.Cells[mPilotColumn.Index].ErrorText = ""; + } + uint num = 0u; + uint num2 = 0u; + uint num3 = 0u; + bool flag = false; + for (int i = 0; i < mPilotsDataGrid.Rows.Count; i++) + { + DataGridViewRow dataGridViewRow = mPilotsDataGrid.Rows[i]; + Pod pod = (Pod)dataGridViewRow.Tag; + if (!(bool)dataGridViewRow.Cells[mEnabledColumn.Index].Value) + { + GreyOutRow(dataGridViewRow); + continue; + } + if (!pod.MungaGame.IsPodAppState(ApplicationID.BTL4, ApplicationState.WaitingForEgg)) + { + num++; + } + if (pod.HostType == HostType.GameMachineHostType) + { + num2++; + DataGridViewCell dataGridViewCell = dataGridViewRow.Cells[mPilotColumn.Index]; + foreach (DataGridViewColumn pilotColumn in PilotDataColumns()) + { + dataGridViewRow.Cells[pilotColumn.Index].Style.ForeColor = pilotColumn.DefaultCellStyle.ForeColor; + if (pilotColumn != mPilotColumn) + { + dataGridViewRow.Cells[pilotColumn.Index].Style.BackColor = pilotColumn.DefaultCellStyle.BackColor; + } + } + if (dataGridViewCell.ErrorText == "") + { + if (dataGridViewCell.Value == null || (string)dataGridViewCell.Value == "") + { + dataGridViewCell.ErrorText = "Pilot name can not be blank."; + num3++; + continue; + } + for (int j = i + 1; j < mPilotsDataGrid.Rows.Count; j++) + { + DataGridViewRow dataGridViewRow2 = mPilotsDataGrid.Rows[j]; + DataGridViewCell dataGridViewCell2 = dataGridViewRow2.Cells[mPilotColumn.Index]; + if (((Pod)dataGridViewRow2.Tag).HostType == HostType.GameMachineHostType && (bool)dataGridViewRow2.Cells[mEnabledColumn.Index].Value && dataGridViewCell2.ErrorText == "" && dataGridViewCell.Value.Equals(dataGridViewCell2.Value)) + { + dataGridViewCell.ErrorText = (dataGridViewCell2.ErrorText = "A pilot with this name already exists."); + flag = true; + } + } + } + } + else + { + GreyOutRow(dataGridViewRow); + } + } + StringBuilder stringBuilder = new StringBuilder(); + if (num2 < 1) + { + stringBuilder.AppendLine("You should put at least one player in the game."); + } + if (num2 > 8) + { + stringBuilder.AppendLine("BattleTech only supports 8 players in a game."); + } + if (num3 != 0) + { + stringBuilder.AppendLine((num3 > 1) ? "Some pilots have a blank name." : "A pilot has a blank name."); + } + if (flag) + { + stringBuilder.AppendLine("Some pilots have duplicate names."); + } + if (num != 0) + { + stringBuilder.AppendLine((num > 1) ? "Some pods are not ready." : "A pod is not ready."); + } + if (ParseMissionLength() == TimeSpan.MinValue) + { + stringBuilder.AppendLine("The mission length is not valid."); + } + else if (ParseMissionLength() < TimeSpan.FromSeconds(10.0)) + { + stringBuilder.AppendLine("The mission length must be at least 10 seconds."); + } + mGoButton.Enabled = stringBuilder.Length <= 0; + mIssuesLabel.Text = stringBuilder.ToString(); + } + + private void GreyOutRow(DataGridViewRow row) + { + foreach (DataGridViewColumn pilotColumn in PilotDataColumns()) + { + row.Cells[pilotColumn.Index].Style.ForeColor = Color.DarkGray; + if (pilotColumn != mPilotColumn || ((Pod)row.Tag).HostType != 0) + { + row.Cells[pilotColumn.Index].Style.BackColor = sDataLockedColor; + } + } + } + + private void mMissionLengthTextBox_TextChanged(object sender, EventArgs e) + { + CheckAllValues(); + } + + private TimeSpan ParseMissionLength() + { + if (!double.TryParse(mMissionLengthTextBox.Text, out var result)) + { + return TimeSpan.MinValue; + } + try + { + return TimeSpan.FromMinutes(result); + } + catch (OverflowException) + { + return TimeSpan.MinValue; + } + } + + private void mPilotsDataGrid_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) + { + if (e.ColumnIndex == mPilotColumn.Index && !(bool)mPilotsDataGrid.Rows[e.RowIndex].Cells[mEnabledColumn.Index].Value) + { + mPilotsDataGrid.Rows[e.RowIndex].Cells[mPilotColumn.Index].Style.ForeColor = mPilotColumn.DefaultCellStyle.ForeColor; + } + } + + private void mPilotsDataGrid_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) + { + if (mPilotsDataGrid.EditingControl is TextBox textBox) + { + textBox.AutoCompleteCustomSource = PilotNameCache.PilotNames; + textBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend; + textBox.AutoCompleteSource = AutoCompleteSource.CustomSource; + } + } + + private void mPilotsDataGrid_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + bool? flag = null; + DataGridViewRow dataGridViewRow = mPilotsDataGrid.Rows[e.RowIndex]; + if (e.ColumnIndex == mPilotColumn.Index) + { + if (dataGridViewRow.Cells[mPilotColumn.Index].Value != null && (string)dataGridViewRow.Cells[mPilotColumn.Index].Value != "") + { + dataGridViewRow.Cells[mEnabledColumn.Index].Value = true; + flag = true; + } + else + { + dataGridViewRow.Cells[mEnabledColumn.Index].Value = false; + flag = false; + } + } + else if (e.ColumnIndex == mEnabledColumn.Index) + { + flag = ((!(bool)dataGridViewRow.Cells[mEnabledColumn.Index].Value) ? new bool?(false) : new bool?(true)); + } + if (flag.HasValue) + { + if (flag.Value) + { + ((Pod)dataGridViewRow.Tag).MungaGame.MakeRequested(this); + } + else + { + ((Pod)dataGridViewRow.Tag).MungaGame.ReleaseRequest(this); + } + } + CheckAllValues(); + } + + private void mPilotsDataGrid_KeyUp(object sender, KeyEventArgs e) + { + if ((e.KeyCode == Keys.Delete || e.KeyCode == Keys.Back) && mPilotsDataGrid.SelectedCells.Count == 1 && mPilotsDataGrid.SelectedCells[0].ColumnIndex == mPilotColumn.Index) + { + mPilotsDataGrid.SelectedCells[0].Value = ""; + DataGridViewRow dataGridViewRow = mPilotsDataGrid.Rows[mPilotsDataGrid.SelectedCells[0].RowIndex]; + dataGridViewRow.Cells[mEnabledColumn.Index].Value = false; + ((Pod)dataGridViewRow.Tag).MungaGame.ReleaseRequest(this); + CheckAllValues(); + } + } + + private void mPilotsDataGrid_MouseDown(object sender, MouseEventArgs e) + { + if (mPilotsDataGrid.FirstDisplayedScrollingRowIndex < 0) + { + return; + } + for (int i = mPilotsDataGrid.FirstDisplayedScrollingRowIndex; i < mPilotsDataGrid.Rows.Count && ((Pod)mPilotsDataGrid.Rows[i].Tag).HostType == HostType.GameMachineHostType; i++) + { + if (mPilotsDataGrid.GetCellDisplayRectangle(-1, i, cutOverflow: true).Contains(e.Location)) + { + mPilotsDataGrid.DoDragDrop(new DragDropData(i, e.Button == MouseButtons.Right), DragDropEffects.Move); + break; + } + } + } + + private void mPilotsDataGrid_DragOver(object sender, DragEventArgs e) + { + if (mPilotsDataGrid.FirstDisplayedScrollingRowIndex >= 0) + { + for (int i = mPilotsDataGrid.FirstDisplayedScrollingRowIndex; i < mPilotsDataGrid.Rows.Count && ((Pod)mPilotsDataGrid.Rows[i].Tag).HostType == HostType.GameMachineHostType; i++) + { + if (!mPilotsDataGrid.GetCellDisplayRectangle(-1, i, cutOverflow: true).Contains(mPilotsDataGrid.PointToClient(new Point(e.X, e.Y)))) + { + continue; + } + if (e.Data.GetDataPresent(typeof(DragDropData))) + { + DragDropData dragDropData = (DragDropData)e.Data.GetData(typeof(DragDropData)); + if (dragDropData.StartRow != i) + { + e.Effect = DragDropEffects.Move; + } + else + { + e.Effect = DragDropEffects.None; + } + } + return; + } + } + e.Effect = DragDropEffects.None; + } + + private void mPilotsDataGrid_DragDrop(object sender, DragEventArgs e) + { + for (int i = mPilotsDataGrid.FirstDisplayedScrollingRowIndex; i < mPilotsDataGrid.Rows.Count; i++) + { + if (!mPilotsDataGrid.GetCellDisplayRectangle(-1, i, cutOverflow: true).Contains(mPilotsDataGrid.PointToClient(new Point(e.X, e.Y)))) + { + continue; + } + if (!e.Data.GetDataPresent(typeof(DragDropData))) + { + break; + } + DragDropData dragDropData = (DragDropData)e.Data.GetData(typeof(DragDropData)); + if (dragDropData.StartRow != i) + { + if (dragDropData.RightClick) + { + dragDropData.EndRow = i; + mDragDropContextMenu.Tag = dragDropData; + mDragDropContextMenu.Show(e.X, e.Y); + } + else + { + SwapPilots(i, dragDropData.StartRow, update: true); + } + } + break; + } + } + + private void swapToolStripMenuItem_Click(object sender, EventArgs e) + { + if (mDragDropContextMenu.Tag is DragDropData) + { + DragDropData dragDropData = (DragDropData)mDragDropContextMenu.Tag; + SwapPilots(dragDropData.StartRow, dragDropData.EndRow, update: true); + } + } + + private void shiftToolStripMenuItem_Click(object sender, EventArgs e) + { + if (!(mDragDropContextMenu.Tag is DragDropData)) + { + return; + } + DragDropData dragDropData = (DragDropData)mDragDropContextMenu.Tag; + if (dragDropData.StartRow < dragDropData.EndRow) + { + for (int i = dragDropData.StartRow; i < dragDropData.EndRow; i++) + { + SwapPilots(i, i + 1, i + 1 == dragDropData.EndRow); + } + return; + } + for (int num = dragDropData.StartRow; num > dragDropData.EndRow; num--) + { + SwapPilots(num, num - 1, num - 1 == dragDropData.EndRow); + } + } + + private void SwapPilots(int row1, int row2, bool update) + { + foreach (DataGridViewColumn column in mPilotsDataGrid.Columns) + { + if (column != mStatusIconColumn && column != mStatusTextColumn && column != mEnabledColumn) + { + object value = mPilotsDataGrid[column.Index, row1].Value; + mPilotsDataGrid[column.Index, row1].Value = mPilotsDataGrid[column.Index, row2].Value; + mPilotsDataGrid[column.Index, row2].Value = value; + } + } + if (update) + { + CheckAllValues(); + mPilotsDataGrid.Refresh(); + } + } + + protected override void OnKeyDown(KeyEventArgs e) + { + if (e.Modifiers == Keys.Control && e.KeyCode == Keys.L) + { + if (mLogWindow == null || mLogWindow.IsDisposed) + { + mLogWindow = new LogOutputWindow(); + } + mLogWindow.Show(); + e.Handled = true; + } + base.OnKeyDown(e); + } + + private void mRandomMap_Click(object sender, EventArgs e) + { + mMap.SelectedIndex = sRand.Next(mMap.Items.Count); + } + + private void mRandomWeather_Click(object sender, EventArgs e) + { + mWeather.SelectedIndex = sRand.Next(mWeather.Items.Count); + } + + private void mRandomTimeOfDay_Click(object sender, EventArgs e) + { + mTimeOfDay.SelectedIndex = sRand.Next(mTimeOfDay.Items.Count); + } + + private void tmrAutoTranslocate_Tick(object sender, EventArgs e) + { + mRemainingUntilTranslocate--; + if (mRemainingUntilTranslocate < 1) + { + RequestState(BTGameState.Run); + tmrAutoTranslocate.Stop(); + } + else + { + string text2 = (GameStatusText = $"Launching in {mRemainingUntilTranslocate}..."); + mGoButton.Text = text2; + } + } + + protected override void Dispose(bool disposing) + { + if (disposing && components != null) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.mMissionPropertiesGroupBox = new System.Windows.Forms.GroupBox(); + this.mMissionPropertiesTable = new System.Windows.Forms.TableLayoutPanel(); + this.mIssuesLabel = new System.Windows.Forms.Label(); + this.mMissionLengthTextLabel = new System.Windows.Forms.Label(); + this.mMap = new System.Windows.Forms.ComboBox(); + this.mMissionLengthDisplayLabel = new System.Windows.Forms.Label(); + this.mWeather = new System.Windows.Forms.ComboBox(); + this.mTimeOfDay = new System.Windows.Forms.ComboBox(); + this.mMapLabel = new System.Windows.Forms.Label(); + this.mWeatherLabel = new System.Windows.Forms.Label(); + this.mTimeOfDayLabel = new System.Windows.Forms.Label(); + this.mAdvancedDamage = new System.Windows.Forms.CheckBox(); + this.mGoButton = new System.Windows.Forms.Button(); + this.mResetContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.resetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.mAutoTranslocateCheckbox = new System.Windows.Forms.CheckBox(); + this.mRandomMap = new System.Windows.Forms.Button(); + this.mRandomWeather = new System.Windows.Forms.Button(); + this.mRandomTimeOfDay = new System.Windows.Forms.Button(); + this.mMissionLengthTextBox = new System.Windows.Forms.TextBox(); + this.mPilotsGroupBox = new System.Windows.Forms.GroupBox(); + this.mPilotsDataGrid = new System.Windows.Forms.DataGridView(); + this.mEnabledColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn(); + this.mStatusIconColumn = new System.Windows.Forms.DataGridViewImageColumn(); + this.mStatusTextColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.mPilotColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.mVehicleColumn = new System.Windows.Forms.DataGridViewComboBoxColumn(); + this.mColorColumn = new System.Windows.Forms.DataGridViewComboBoxColumn(); + this.mPatchColumn = new System.Windows.Forms.DataGridViewComboBoxColumn(); + this.mBadgeColumn = new System.Windows.Forms.DataGridViewComboBoxColumn(); + this.mExperienceColumn = new System.Windows.Forms.DataGridViewComboBoxColumn(); + this.mDragDropContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.mSwapPilots = new System.Windows.Forms.ToolStripMenuItem(); + this.mShiftPilots = new System.Windows.Forms.ToolStripMenuItem(); + this.mNetworkTimer = new System.Windows.Forms.Timer(this.components); + this.tmrAutoTranslocate = new System.Windows.Forms.Timer(this.components); + this.mMissionPropertiesGroupBox.SuspendLayout(); + this.mMissionPropertiesTable.SuspendLayout(); + this.mResetContextMenu.SuspendLayout(); + this.mPilotsGroupBox.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)this.mPilotsDataGrid).BeginInit(); + this.mDragDropContextMenu.SuspendLayout(); + base.SuspendLayout(); + this.mMissionPropertiesGroupBox.Controls.Add(this.mMissionPropertiesTable); + this.mMissionPropertiesGroupBox.Dock = System.Windows.Forms.DockStyle.Top; + this.mMissionPropertiesGroupBox.Location = new System.Drawing.Point(8, 8); + this.mMissionPropertiesGroupBox.Name = "mMissionPropertiesGroupBox"; + this.mMissionPropertiesGroupBox.Padding = new System.Windows.Forms.Padding(5); + this.mMissionPropertiesGroupBox.Size = new System.Drawing.Size(1040, 105); + this.mMissionPropertiesGroupBox.TabIndex = 10; + this.mMissionPropertiesGroupBox.TabStop = false; + this.mMissionPropertiesGroupBox.Text = "Mission Properties"; + this.mMissionPropertiesTable.AutoSize = true; + this.mMissionPropertiesTable.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.mMissionPropertiesTable.ColumnCount = 8; + this.mMissionPropertiesTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.mMissionPropertiesTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.mMissionPropertiesTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.mMissionPropertiesTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.mMissionPropertiesTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.mMissionPropertiesTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 0f)); + this.mMissionPropertiesTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.mMissionPropertiesTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.mMissionPropertiesTable.Controls.Add(this.mIssuesLabel, 7, 0); + this.mMissionPropertiesTable.Controls.Add(this.mMissionLengthTextLabel, 3, 1); + this.mMissionPropertiesTable.Controls.Add(this.mMap, 1, 0); + this.mMissionPropertiesTable.Controls.Add(this.mMissionLengthDisplayLabel, 5, 1); + this.mMissionPropertiesTable.Controls.Add(this.mWeather, 1, 1); + this.mMissionPropertiesTable.Controls.Add(this.mTimeOfDay, 1, 2); + this.mMissionPropertiesTable.Controls.Add(this.mMapLabel, 0, 0); + this.mMissionPropertiesTable.Controls.Add(this.mWeatherLabel, 0, 1); + this.mMissionPropertiesTable.Controls.Add(this.mTimeOfDayLabel, 0, 2); + this.mMissionPropertiesTable.Controls.Add(this.mAdvancedDamage, 3, 0); + this.mMissionPropertiesTable.Controls.Add(this.mGoButton, 3, 2); + this.mMissionPropertiesTable.Controls.Add(this.mAutoTranslocateCheckbox, 6, 0); + this.mMissionPropertiesTable.Controls.Add(this.mRandomMap, 2, 0); + this.mMissionPropertiesTable.Controls.Add(this.mRandomWeather, 2, 1); + this.mMissionPropertiesTable.Controls.Add(this.mRandomTimeOfDay, 2, 2); + this.mMissionPropertiesTable.Controls.Add(this.mMissionLengthTextBox, 4, 1); + this.mMissionPropertiesTable.Dock = System.Windows.Forms.DockStyle.Fill; + this.mMissionPropertiesTable.GrowStyle = System.Windows.Forms.TableLayoutPanelGrowStyle.AddColumns; + this.mMissionPropertiesTable.Location = new System.Drawing.Point(5, 18); + this.mMissionPropertiesTable.MinimumSize = new System.Drawing.Size(0, 85); + this.mMissionPropertiesTable.Name = "mMissionPropertiesTable"; + this.mMissionPropertiesTable.RowCount = 4; + this.mMissionPropertiesTable.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.mMissionPropertiesTable.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.mMissionPropertiesTable.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.mMissionPropertiesTable.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100f)); + this.mMissionPropertiesTable.Size = new System.Drawing.Size(1030, 85); + this.mMissionPropertiesTable.TabIndex = 0; + this.mIssuesLabel.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + this.mIssuesLabel.AutoSize = true; + this.mIssuesLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25f, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, 0); + this.mIssuesLabel.ForeColor = System.Drawing.Color.Red; + this.mIssuesLabel.Location = new System.Drawing.Point(642, 0); + this.mIssuesLabel.Name = "mIssuesLabel"; + this.mMissionPropertiesTable.SetRowSpan(this.mIssuesLabel, 4); + this.mIssuesLabel.Size = new System.Drawing.Size(385, 85); + this.mIssuesLabel.TabIndex = 0; + this.mMissionLengthTextLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.mMissionLengthTextLabel.AutoSize = true; + this.mMissionLengthTextLabel.Location = new System.Drawing.Point(311, 37); + this.mMissionLengthTextLabel.Name = "mMissionLengthTextLabel"; + this.mMissionLengthTextLabel.Size = new System.Drawing.Size(106, 13); + this.mMissionLengthTextLabel.TabIndex = 7; + this.mMissionLengthTextLabel.Text = "Mission Length (min):"; + this.mMap.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.mMap.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.mMap.FormattingEnabled = true; + this.mMap.Location = new System.Drawing.Point(76, 4); + this.mMap.Name = "mMap"; + this.mMap.Size = new System.Drawing.Size(198, 21); + this.mMap.TabIndex = 0; + this.mMissionLengthDisplayLabel.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + this.mMissionLengthDisplayLabel.AutoSize = true; + this.mMissionLengthDisplayLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 12f, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, 0); + this.mMissionLengthDisplayLabel.ForeColor = System.Drawing.Color.Green; + this.mMissionLengthDisplayLabel.Location = new System.Drawing.Point(529, 33); + this.mMissionLengthDisplayLabel.Name = "mMissionLengthDisplayLabel"; + this.mMissionLengthDisplayLabel.Size = new System.Drawing.Size(1, 20); + this.mMissionLengthDisplayLabel.TabIndex = 9; + this.mMissionLengthDisplayLabel.Text = "00:00"; + this.mMissionLengthDisplayLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.mMissionLengthDisplayLabel.Visible = false; + this.mWeather.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.mWeather.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.mWeather.FormattingEnabled = true; + this.mWeather.Location = new System.Drawing.Point(76, 33); + this.mWeather.Name = "mWeather"; + this.mWeather.Size = new System.Drawing.Size(198, 21); + this.mWeather.TabIndex = 1; + this.mTimeOfDay.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.mTimeOfDay.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.mTimeOfDay.FormattingEnabled = true; + this.mTimeOfDay.Location = new System.Drawing.Point(76, 62); + this.mTimeOfDay.Name = "mTimeOfDay"; + this.mTimeOfDay.Size = new System.Drawing.Size(198, 21); + this.mTimeOfDay.TabIndex = 2; + this.mMapLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.mMapLabel.AutoSize = true; + this.mMapLabel.Location = new System.Drawing.Point(3, 8); + this.mMapLabel.Name = "mMapLabel"; + this.mMapLabel.Size = new System.Drawing.Size(31, 13); + this.mMapLabel.TabIndex = 0; + this.mMapLabel.Text = "Map:"; + this.mWeatherLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.mWeatherLabel.AutoSize = true; + this.mWeatherLabel.Location = new System.Drawing.Point(3, 37); + this.mWeatherLabel.Name = "mWeatherLabel"; + this.mWeatherLabel.Size = new System.Drawing.Size(51, 13); + this.mWeatherLabel.TabIndex = 2; + this.mWeatherLabel.Text = "Weather:"; + this.mTimeOfDayLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.mTimeOfDayLabel.AutoSize = true; + this.mTimeOfDayLabel.Location = new System.Drawing.Point(3, 66); + this.mTimeOfDayLabel.Name = "mTimeOfDayLabel"; + this.mTimeOfDayLabel.Size = new System.Drawing.Size(67, 13); + this.mTimeOfDayLabel.TabIndex = 4; + this.mTimeOfDayLabel.Text = "Time of Day:"; + this.mAdvancedDamage.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.mAdvancedDamage.AutoSize = true; + this.mMissionPropertiesTable.SetColumnSpan(this.mAdvancedDamage, 3); + this.mAdvancedDamage.Checked = true; + this.mAdvancedDamage.CheckState = System.Windows.Forms.CheckState.Checked; + this.mAdvancedDamage.Location = new System.Drawing.Point(311, 6); + this.mAdvancedDamage.Name = "mAdvancedDamage"; + this.mAdvancedDamage.Size = new System.Drawing.Size(117, 17); + this.mAdvancedDamage.TabIndex = 6; + this.mAdvancedDamage.Text = "Advanced Damage"; + this.mAdvancedDamage.UseVisualStyleBackColor = true; + this.mGoButton.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + this.mMissionPropertiesTable.SetColumnSpan(this.mGoButton, 3); + this.mGoButton.ContextMenuStrip = this.mResetContextMenu; + this.mGoButton.Location = new System.Drawing.Point(311, 61); + this.mGoButton.Name = "mGoButton"; + this.mGoButton.Size = new System.Drawing.Size(212, 23); + this.mGoButton.TabIndex = 10; + this.mGoButton.Text = "Load"; + this.mGoButton.UseVisualStyleBackColor = true; + this.mGoButton.Click += new System.EventHandler(mGoButton_Click); + this.mResetContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[1] { this.resetToolStripMenuItem }); + this.mResetContextMenu.Name = "mResetContextMenu"; + this.mResetContextMenu.Size = new System.Drawing.Size(103, 26); + this.resetToolStripMenuItem.Name = "resetToolStripMenuItem"; + this.resetToolStripMenuItem.Size = new System.Drawing.Size(102, 22); + this.resetToolStripMenuItem.Text = "&Reset"; + this.resetToolStripMenuItem.Click += new System.EventHandler(resetToolStripMenuItem_Click); + this.mAutoTranslocateCheckbox.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.mAutoTranslocateCheckbox.AutoSize = true; + this.mAutoTranslocateCheckbox.Location = new System.Drawing.Point(529, 6); + this.mAutoTranslocateCheckbox.Name = "mAutoTranslocateCheckbox"; + this.mAutoTranslocateCheckbox.Size = new System.Drawing.Size(107, 17); + this.mAutoTranslocateCheckbox.TabIndex = 8; + this.mAutoTranslocateCheckbox.Text = "Auto Translocate"; + this.mAutoTranslocateCheckbox.UseVisualStyleBackColor = true; + this.mRandomMap.Location = new System.Drawing.Point(280, 3); + this.mRandomMap.Name = "mRandomMap"; + this.mRandomMap.Size = new System.Drawing.Size(25, 23); + this.mRandomMap.TabIndex = 3; + this.mRandomMap.Text = "R"; + this.mRandomMap.UseVisualStyleBackColor = true; + this.mRandomMap.Click += new System.EventHandler(mRandomMap_Click); + this.mRandomWeather.Location = new System.Drawing.Point(280, 32); + this.mRandomWeather.Name = "mRandomWeather"; + this.mRandomWeather.Size = new System.Drawing.Size(25, 23); + this.mRandomWeather.TabIndex = 4; + this.mRandomWeather.Text = "R"; + this.mRandomWeather.UseVisualStyleBackColor = true; + this.mRandomWeather.Click += new System.EventHandler(mRandomWeather_Click); + this.mRandomTimeOfDay.Location = new System.Drawing.Point(280, 61); + this.mRandomTimeOfDay.Name = "mRandomTimeOfDay"; + this.mRandomTimeOfDay.Size = new System.Drawing.Size(25, 23); + this.mRandomTimeOfDay.TabIndex = 5; + this.mRandomTimeOfDay.Text = "R"; + this.mRandomTimeOfDay.UseVisualStyleBackColor = true; + this.mRandomTimeOfDay.Click += new System.EventHandler(mRandomTimeOfDay_Click); + this.mMissionLengthTextBox.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + this.mMissionLengthTextBox.Location = new System.Drawing.Point(423, 33); + this.mMissionLengthTextBox.Name = "mMissionLengthTextBox"; + this.mMissionLengthTextBox.Size = new System.Drawing.Size(100, 20); + this.mMissionLengthTextBox.TabIndex = 12; + this.mMissionLengthTextBox.TextChanged += new System.EventHandler(mMissionLengthTextBox_TextChanged); + this.mPilotsGroupBox.Controls.Add(this.mPilotsDataGrid); + this.mPilotsGroupBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.mPilotsGroupBox.Location = new System.Drawing.Point(8, 113); + this.mPilotsGroupBox.Name = "mPilotsGroupBox"; + this.mPilotsGroupBox.Padding = new System.Windows.Forms.Padding(5); + this.mPilotsGroupBox.Size = new System.Drawing.Size(1040, 425); + this.mPilotsGroupBox.TabIndex = 11; + this.mPilotsGroupBox.TabStop = false; + this.mPilotsGroupBox.Text = "Pilots"; + this.mPilotsDataGrid.AllowDrop = true; + this.mPilotsDataGrid.AllowUserToAddRows = false; + this.mPilotsDataGrid.AllowUserToDeleteRows = false; + this.mPilotsDataGrid.AllowUserToResizeColumns = false; + this.mPilotsDataGrid.AllowUserToResizeRows = false; + this.mPilotsDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.mPilotsDataGrid.Columns.AddRange(this.mEnabledColumn, this.mStatusIconColumn, this.mStatusTextColumn, this.mPilotColumn, this.mVehicleColumn, this.mColorColumn, this.mPatchColumn, this.mBadgeColumn, this.mExperienceColumn); + this.mPilotsDataGrid.Dock = System.Windows.Forms.DockStyle.Fill; + this.mPilotsDataGrid.Location = new System.Drawing.Point(5, 18); + this.mPilotsDataGrid.MultiSelect = false; + this.mPilotsDataGrid.Name = "mPilotsDataGrid"; + this.mPilotsDataGrid.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders; + this.mPilotsDataGrid.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.CellSelect; + this.mPilotsDataGrid.ShowEditingIcon = false; + this.mPilotsDataGrid.Size = new System.Drawing.Size(1030, 402); + this.mPilotsDataGrid.TabIndex = 0; + this.mPilotsDataGrid.MouseDown += new System.Windows.Forms.MouseEventHandler(mPilotsDataGrid_MouseDown); + this.mPilotsDataGrid.CellBeginEdit += new System.Windows.Forms.DataGridViewCellCancelEventHandler(mPilotsDataGrid_CellBeginEdit); + this.mPilotsDataGrid.DragOver += new System.Windows.Forms.DragEventHandler(mPilotsDataGrid_DragOver); + this.mPilotsDataGrid.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(mPilotsDataGrid_CellEndEdit); + this.mPilotsDataGrid.EditingControlShowing += new System.Windows.Forms.DataGridViewEditingControlShowingEventHandler(mPilotsDataGrid_EditingControlShowing); + this.mPilotsDataGrid.KeyUp += new System.Windows.Forms.KeyEventHandler(mPilotsDataGrid_KeyUp); + this.mPilotsDataGrid.DragDrop += new System.Windows.Forms.DragEventHandler(mPilotsDataGrid_DragDrop); + this.mEnabledColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.DisplayedCells; + this.mEnabledColumn.HeaderText = "Enabled"; + this.mEnabledColumn.Name = "mEnabledColumn"; + this.mEnabledColumn.Width = 52; + this.mStatusIconColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.ColumnHeader; + this.mStatusIconColumn.HeaderText = "Status"; + this.mStatusIconColumn.Name = "mStatusIconColumn"; + this.mStatusIconColumn.ReadOnly = true; + this.mStatusIconColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.mStatusIconColumn.Width = 43; + this.mStatusTextColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.mStatusTextColumn.HeaderText = "Status Text"; + this.mStatusTextColumn.MinimumWidth = 100; + this.mStatusTextColumn.Name = "mStatusTextColumn"; + this.mStatusTextColumn.ReadOnly = true; + this.mPilotColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.mPilotColumn.HeaderText = "Pilot"; + this.mPilotColumn.MinimumWidth = 100; + this.mPilotColumn.Name = "mPilotColumn"; + this.mPilotColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.mVehicleColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.mVehicleColumn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.mVehicleColumn.HeaderText = "Mech"; + this.mVehicleColumn.MinimumWidth = 100; + this.mVehicleColumn.Name = "mVehicleColumn"; + this.mColorColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.mColorColumn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.mColorColumn.HeaderText = "Camo"; + this.mColorColumn.MinimumWidth = 80; + this.mColorColumn.Name = "mColorColumn"; + this.mPatchColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.mPatchColumn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.mPatchColumn.HeaderText = "Patch"; + this.mPatchColumn.MinimumWidth = 80; + this.mPatchColumn.Name = "mPatchColumn"; + this.mBadgeColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.mBadgeColumn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.mBadgeColumn.HeaderText = "Badge"; + this.mBadgeColumn.MinimumWidth = 80; + this.mBadgeColumn.Name = "mBadgeColumn"; + this.mExperienceColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.mExperienceColumn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.mExperienceColumn.HeaderText = "Experience"; + this.mExperienceColumn.MinimumWidth = 80; + this.mExperienceColumn.Name = "mExperienceColumn"; + this.mDragDropContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[2] { this.mSwapPilots, this.mShiftPilots }); + this.mDragDropContextMenu.Name = "contextMenuStrip1"; + this.mDragDropContextMenu.Size = new System.Drawing.Size(103, 48); + this.mSwapPilots.Name = "mSwapPilots"; + this.mSwapPilots.Size = new System.Drawing.Size(102, 22); + this.mSwapPilots.Text = "Swap"; + this.mSwapPilots.Click += new System.EventHandler(swapToolStripMenuItem_Click); + this.mShiftPilots.Name = "mShiftPilots"; + this.mShiftPilots.Size = new System.Drawing.Size(102, 22); + this.mShiftPilots.Text = "Shift"; + this.mShiftPilots.Click += new System.EventHandler(shiftToolStripMenuItem_Click); + this.mNetworkTimer.Enabled = true; + this.mNetworkTimer.Tick += new System.EventHandler(NetworkScan); + this.tmrAutoTranslocate.Interval = 1000; + this.tmrAutoTranslocate.Tick += new System.EventHandler(tmrAutoTranslocate_Tick); + base.AutoScaleDimensions = new System.Drawing.SizeF(6f, 13f); + base.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + base.ClientSize = new System.Drawing.Size(1056, 546); + base.Controls.Add(this.mPilotsGroupBox); + base.Controls.Add(this.mMissionPropertiesGroupBox); + this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25f, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); + base.KeyPreview = true; + base.Name = "BTGame"; + base.Padding = new System.Windows.Forms.Padding(8); + base.TabText = "BattleTech Game"; + this.Text = "BattleTech Game"; + this.mMissionPropertiesGroupBox.ResumeLayout(false); + this.mMissionPropertiesGroupBox.PerformLayout(); + this.mMissionPropertiesTable.ResumeLayout(false); + this.mMissionPropertiesTable.PerformLayout(); + this.mResetContextMenu.ResumeLayout(false); + this.mPilotsGroupBox.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)this.mPilotsDataGrid).EndInit(); + this.mDragDropContextMenu.ResumeLayout(false); + base.ResumeLayout(false); + } +} diff --git a/Console/TeslaConsole.BattleTech/BTKilledEvent.cs b/Console/TeslaConsole.BattleTech/BTKilledEvent.cs new file mode 100644 index 0000000..2bbce4b --- /dev/null +++ b/Console/TeslaConsole.BattleTech/BTKilledEvent.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace TeslaConsole.BattleTech; + +/// A mech was destroyed (MechKilledMessage). +[Serializable] +internal class BTKilledEvent : BTMissionEvent +{ + public readonly BTPlayer Killer; + + public override IEnumerable InvolvedPilots => new BTPlayer[2] { ReportingPilot, Killer }; + + public BTKilledEvent(BTPlayer reportingPilot, TimeSpan missionTime, BTPlayer killer) + : base(reportingPilot, missionTime) + { + Killer = killer; + } + + private BTKilledEvent() + { + } +} diff --git a/Console/TeslaConsole.BattleTech/BTMissionEvent.cs b/Console/TeslaConsole.BattleTech/BTMissionEvent.cs new file mode 100644 index 0000000..ab5a72c --- /dev/null +++ b/Console/TeslaConsole.BattleTech/BTMissionEvent.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; + +namespace TeslaConsole.BattleTech; + +/// +/// Base class for a recorded in-match BattleTech event. Mirrors the Red Planet +/// MissionEvent, typed over . +/// +[Serializable] +internal abstract class BTMissionEvent +{ + public readonly TimeSpan GameTime; + + public readonly BTPlayer ReportingPilot; + + public abstract IEnumerable InvolvedPilots { get; } + + public BTMissionEvent(BTPlayer reportingPilot, TimeSpan missionTime) + { + ReportingPilot = reportingPilot; + GameTime = missionTime; + } + + protected BTMissionEvent() + { + } +} diff --git a/Console/TeslaConsole.BattleTech/BTMissionRecorder.cs b/Console/TeslaConsole.BattleTech/BTMissionRecorder.cs new file mode 100644 index 0000000..11d36a9 --- /dev/null +++ b/Console/TeslaConsole.BattleTech/BTMissionRecorder.cs @@ -0,0 +1,99 @@ +using System; + +namespace TeslaConsole.BattleTech; + +/// +/// Records the in-match Munga event messages of one BattleTech mission into a +/// . Mirrors RPMissionRecorder; the event +/// set follows the BT messages in Munga Net.dll (Mech* / EndMission). +/// +internal class BTMissionRecorder +{ + private BTMissionResults mMissionResults; + + private bool mStartSet; + + public BTMissionRecorder(BTMission mission) + { + mMissionResults = new BTMissionResults(mission); + } + + public void SetMissionStart() + { + if (mStartSet) + { + throw new InvalidOperationException(); + } + mMissionResults.mMissionStart = DateTime.Now; + mStartSet = true; + } + + private void ValidatePlayer(BTPlayer player, string param) + { + if (player == null) + { + throw new ArgumentNullException(param); + } + foreach (BTPlayer player2 in mMissionResults.Mission.Players) + { + if (player2 == player) + { + return; + } + } + throw new ArgumentException(param); + } + + private TimeSpan GetMissionTime() + { + if (!mStartSet) + { + return TimeSpan.Zero; + } + return DateTime.Now - mMissionResults.mMissionStart; + } + + public void PlayerKilled(BTPlayer reportingPlayer, BTPlayer killer) + { + ValidatePlayer(reportingPlayer, "reportingPlayer"); + ValidatePlayer(killer, "killer"); + TimeSpan missionTime = GetMissionTime(); + mMissionResults.mEvents.Add(new BTKilledEvent(reportingPlayer, missionTime, killer)); + } + + public void PlayerDeathWithoutHonor(BTPlayer reportingPlayer) + { + ValidatePlayer(reportingPlayer, "reportingPlayer"); + TimeSpan missionTime = GetMissionTime(); + mMissionResults.mEvents.Add(new BTDeathWithoutHonorEvent(reportingPlayer, missionTime)); + } + + public void PlayerScoreUpdate(BTPlayer reportingPlayer, int score) + { + ValidatePlayer(reportingPlayer, "reportingPlayer"); + TimeSpan missionTime = GetMissionTime(); + mMissionResults.mEvents.Add(new BTScoreUpdateEvent(reportingPlayer, missionTime, score)); + } + + public void PlayerDamaged(BTPlayer reportingPlayer, BTPlayer damager, int damageLoss, int pointsTransfered, int damageZoneIndex, bool damageZoneDestroyed, int weaponIndex) + { + ValidatePlayer(reportingPlayer, "reportingPlayer"); + ValidatePlayer(damager, "damager"); + TimeSpan missionTime = GetMissionTime(); + mMissionResults.mEvents.Add(new BTDamagedEvent(reportingPlayer, missionTime, damager, damageLoss, pointsTransfered, damageZoneIndex, damageZoneDestroyed, weaponIndex)); + } + + public void PlayerFinalScore(BTPlayer reportingPlayer, int finalScore) + { + ValidatePlayer(reportingPlayer, "reportingPlayer"); + mMissionResults.mFinalScores.Add(reportingPlayer, finalScore); + } + + public BTMissionResults EndMission(TimeSpan missionLength) + { + mMissionResults.mActuallMissionTime = missionLength; + BTMissionResults result = mMissionResults; + mMissionResults = null; + return result; + } +} diff --git a/Console/TeslaConsole.BattleTech/BTMissionResults.cs b/Console/TeslaConsole.BattleTech/BTMissionResults.cs new file mode 100644 index 0000000..dc6698f --- /dev/null +++ b/Console/TeslaConsole.BattleTech/BTMissionResults.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Runtime.Serialization.Formatters.Binary; + +namespace TeslaConsole.BattleTech; + +/// +/// The recorded outcome of one BattleTech mission, saved as a gzip'd +/// BinaryFormatter blob (.btm) exactly like the RP .rpm mechanism. Mirrors +/// RPMissionResults minus the football branches; the score-sheet print +/// document (RPPrintDocument's counterpart) is deferred until a real BT match +/// has been recorded to design it against. +/// +[Serializable] +internal class BTMissionResults +{ + private BTMission mMission; + + internal DateTime mMissionStart; + + internal TimeSpan mActuallMissionTime; + + internal readonly List mEvents = new List(); + + internal readonly Dictionary mFinalScores = new Dictionary(); + + public BTMission Mission => mMission; + + public DateTime MissionStart => mMissionStart; + + public TimeSpan ActuallMissionTime => mActuallMissionTime; + + public IEnumerable Events => mEvents; + + internal BTMissionResults(BTMission mission) + { + mMission = mission; + } + + public static string GetBTMissionsDirectory() + { + string text = Path.Combine(Program.GetCommonAppDataDirectory(), "BT Missions"); + if (!Directory.Exists(text)) + { + Directory.CreateDirectory(text); + } + return text; + } + + public static BTMissionResults Load(string file) + { + using GZipStream gZipStream = new GZipStream(File.OpenRead(file), CompressionMode.Decompress); + BinaryFormatter binaryFormatter = new BinaryFormatter(); + BTMissionResults result = (BTMissionResults)binaryFormatter.Deserialize(gZipStream); + gZipStream.Close(); + return result; + } + + public void Save() + { + string path = Path.Combine(GetBTMissionsDirectory(), mMissionStart.ToString("yyyy-MM-dd HH-mm-ss.ffff") + ".btm"); + using GZipStream gZipStream = new GZipStream(File.OpenWrite(path), CompressionMode.Compress); + BinaryFormatter binaryFormatter = new BinaryFormatter(); + binaryFormatter.Serialize(gZipStream, this); + gZipStream.Close(); + } + + public int GetScore(BTPlayer player) + { + return GetScore(player, TimeSpan.MaxValue); + } + + public int GetScore(BTPlayer player, TimeSpan gameTime) + { + if (gameTime == TimeSpan.MaxValue && mFinalScores.ContainsKey(player)) + { + return mFinalScores[player]; + } + int result = 1000; + TimeSpan timeSpan = TimeSpan.MinValue; + foreach (BTMissionEvent mEvent in mEvents) + { + if (mEvent is BTScoreUpdateEvent && mEvent.ReportingPilot == player && mEvent.GameTime > timeSpan && mEvent.GameTime <= gameTime) + { + result = ((BTScoreUpdateEvent)mEvent).Score; + timeSpan = mEvent.GameTime; + } + } + return result; + } + + public int GetFinalPlace(BTPlayer player) + { + int num = 1; + int score = GetScore(player, TimeSpan.MaxValue); + foreach (BTPlayer player2 in mMission.Players) + { + if (player2 != player && GetScore(player2, TimeSpan.MaxValue) > score) + { + num++; + } + } + return num; + } +} diff --git a/Console/TeslaConsole.BattleTech/BTRole.cs b/Console/TeslaConsole.BattleTech/BTRole.cs index 17ac67f..b90442c 100644 --- a/Console/TeslaConsole.BattleTech/BTRole.cs +++ b/Console/TeslaConsole.BattleTech/BTRole.cs @@ -1,3 +1,4 @@ +using System; using System.Xml; namespace TeslaConsole.BattleTech; @@ -6,8 +7,11 @@ namespace TeslaConsole.BattleTech; /// A BattleTech pilot role. Each participant references one role /// (role=Role::<Key>); the egg then carries a matching /// [Role::<Key>] model=<Model> block. Free For All uses the -/// Default role, No Return uses the NoReturn role. +/// Default role, No Return uses the NoReturn role. Serializable because it is +/// reachable from a saved via the mission's +/// players (mirrors the .rpm save mechanism). /// +[Serializable] public class BTRole { private readonly string mKey; diff --git a/Console/TeslaConsole.BattleTech/BTScoreUpdateEvent.cs b/Console/TeslaConsole.BattleTech/BTScoreUpdateEvent.cs new file mode 100644 index 0000000..1fc1f67 --- /dev/null +++ b/Console/TeslaConsole.BattleTech/BTScoreUpdateEvent.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace TeslaConsole.BattleTech; + +/// A pilot's running score changed (MechScoreUpdateMessage). +[Serializable] +internal class BTScoreUpdateEvent : BTMissionEvent +{ + public readonly int Score; + + public override IEnumerable InvolvedPilots => new BTPlayer[1] { ReportingPilot }; + + public BTScoreUpdateEvent(BTPlayer reportingPilot, TimeSpan missionTime, int score) + : base(reportingPilot, missionTime) + { + Score = score; + } + + private BTScoreUpdateEvent() + { + } +} diff --git a/Console/TeslaConsole/TeslaConsoleForm.cs b/Console/TeslaConsole/TeslaConsoleForm.cs index 69d73b9..70e802a 100644 --- a/Console/TeslaConsole/TeslaConsoleForm.cs +++ b/Console/TeslaConsole/TeslaConsoleForm.cs @@ -5,6 +5,7 @@ using System.Drawing.Drawing2D; using System.Drawing.Printing; using System.Windows.Forms; using Munga.Net; +using TeslaConsole.BattleTech; using TeslaConsole.RedPlanet; using WeifenLuo.WinFormsUI.Docking; @@ -38,6 +39,10 @@ public class TeslaConsoleForm : Form private ToolStripMenuItem mRpMartianFootball; + private ToolStripMenuItem mBtFreeForAll; + + private ToolStripMenuItem mBtNoReturn; + private ToolStripMenuItem mPlasmaFontTool; private ToolStripMenuItem mRpMissionPrintPreview; @@ -136,15 +141,16 @@ public class TeslaConsoleForm : Form pod.MungaGame.SetStatus(ImageCache.PodQuestion16, "Waiting For State Update..."); break; } - if (pod.MungaGame.AppID.Value != 0) + string gameTag = GameTag(pod.MungaGame.AppID.Value); + if (gameTag == null) { - pod.MungaGame.SetStatus(ImageCache.PodBad16, "Pod Not Running RP"); + pod.MungaGame.SetStatus(ImageCache.PodBad16, "Unknown Pod Application"); break; } switch (pod.MungaGame.AppState.Value) { case ApplicationState.InitializingState: - pod.MungaGame.SetStatus(ImageCache.PodQuestion16, "RP Initalizing"); + pod.MungaGame.SetStatus(ImageCache.PodQuestion16, gameTag + " Initalizing"); break; case ApplicationState.WaitingForEgg: pod.MungaGame.SetStatus(ImageCache.PodOnline16, "Waiting For A Game"); @@ -202,6 +208,26 @@ public class TeslaConsoleForm : Form } } + /// + /// Short display tag for a pod's reported application, or null when the + /// console has no game module for it. RPL4 is Red Planet, BTL4 is + /// BattleTech; NDL4 (the never-released air-combat game) has no console + /// support. The "Initalizing" spelling in the status strings is preserved + /// from the original console. + /// + private static string GameTag(ApplicationID appID) + { + switch (appID) + { + case ApplicationID.RPL4: + return "RP"; + case ApplicationID.BTL4: + return "BT"; + default: + return null; + } + } + private void redPlanetDeathRaceToolStripMenuItem_Click(object sender, EventArgs e) { CreateNewRPGame(footballMode: false); @@ -219,6 +245,23 @@ public class TeslaConsoleForm : Form rPGame.Show(mMainDockPanel, DockState.Document); } + private void battleTechFreeForAllToolStripMenuItem_Click(object sender, EventArgs e) + { + CreateNewBTGame(noReturnMode: false); + } + + private void battleTechNoReturnToolStripMenuItem_Click(object sender, EventArgs e) + { + CreateNewBTGame(noReturnMode: true); + } + + private void CreateNewBTGame(bool noReturnMode) + { + BTGame bTGame = new BTGame(TeslaConsole.Site.Active, noReturnMode); + bTGame.MdiParent = this; + bTGame.Show(mMainDockPanel, DockState.Document); + } + private void plasmaEditorToolStripMenuItem_Click(object sender, EventArgs e) { new PlasmaEditor().Show(); @@ -409,6 +452,8 @@ public class TeslaConsoleForm : Form this.mGamesMenu = new System.Windows.Forms.ToolStripMenuItem(); this.mRpDeathRace = new System.Windows.Forms.ToolStripMenuItem(); this.mRpMartianFootball = new System.Windows.Forms.ToolStripMenuItem(); + this.mBtFreeForAll = new System.Windows.Forms.ToolStripMenuItem(); + this.mBtNoReturn = new System.Windows.Forms.ToolStripMenuItem(); this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.aboutToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.mExceptionsMenu = new System.Windows.Forms.ToolStripMenuItem(); @@ -540,7 +585,7 @@ public class TeslaConsoleForm : Form this.enableCustomBitmapsToolStripMenuItem.Size = new System.Drawing.Size(220, 22); this.enableCustomBitmapsToolStripMenuItem.Text = "Enable Custom Bitmaps"; this.enableCustomBitmapsToolStripMenuItem.Click += new System.EventHandler(enableCustomBitmapsToolStripMenuItem_Click); - this.mGamesMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[2] { this.mRpDeathRace, this.mRpMartianFootball }); + this.mGamesMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[4] { this.mRpDeathRace, this.mRpMartianFootball, this.mBtFreeForAll, this.mBtNoReturn }); this.mGamesMenu.Name = "mGamesMenu"; this.mGamesMenu.Size = new System.Drawing.Size(55, 20); this.mGamesMenu.Text = "Games"; @@ -552,6 +597,14 @@ public class TeslaConsoleForm : Form this.mRpMartianFootball.Size = new System.Drawing.Size(223, 22); this.mRpMartianFootball.Text = "Red Planet: Martian Football"; this.mRpMartianFootball.Click += new System.EventHandler(redPlanetMartianFootballToolStripMenuItem_Click); + this.mBtFreeForAll.Name = "mBtFreeForAll"; + this.mBtFreeForAll.Size = new System.Drawing.Size(223, 22); + this.mBtFreeForAll.Text = "BattleTech: Free For All"; + this.mBtFreeForAll.Click += new System.EventHandler(battleTechFreeForAllToolStripMenuItem_Click); + this.mBtNoReturn.Name = "mBtNoReturn"; + this.mBtNoReturn.Size = new System.Drawing.Size(223, 22); + this.mBtNoReturn.Text = "BattleTech: No Return"; + this.mBtNoReturn.Click += new System.EventHandler(battleTechNoReturnToolStripMenuItem_Click); this.aboutToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[1] { this.aboutToolStripMenuItem1 }); this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; this.aboutToolStripMenuItem.Size = new System.Drawing.Size(52, 20);