Completes the BattleTech console feature to parity with Red Planet: - BTPrintDocument: the per-pilot landscape score sheet (mech portrait, placing, kill/death/damage stats, randomized mission-highlights narrative, pilot-vs-pilot damage matrix, place-over-time chart), mirroring RPPrintDocument minus the football/lap/boost/score-zone concepts. Wired into BTGame (Auto Print checkbox + Print Last Mission button) and the shell's File menu (BT Mission Print Preview / Print BT Mission, loading .btm files). - BTStrings(.xml): the BT mission-highlight narrative pools (damage tiers, kill, death-without-honor, recap), loaded from BattleTech\BTStrings.xml like RPStrings. - BTDefaultsDialog: two-column (Free For All / No Return) editor for the BT operator defaults, reachable from Settings (Change/Import/Export BattleTech Defaults). Verified via UI Automation: opens with all 18 option combos populated. - Apps.xml: the BattleTech 4.11 product (btl4.exe on the shared RP411 engine, same -net/-res/-lc/-mr command line; deploys to C:\Games\BT411) with Game Client / Live Camera / Mission Review launch entries. CatalogTests updated to 4 products / 8 entries plus the three new BT entry assertions. Role model spelling corrected to "noreturn": the Mac Console.ini tag and the game's BTL4.RES role resource are dfltrole/NoReturn; the 4.10 console's eggs emitted a broken "noretun" that cannot resolve against the RES. BTGoldenEggTests and BTConfig.xml updated accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
145 lines
3.8 KiB
C#
145 lines
3.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing.Printing;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
|
|
namespace TeslaConsole.BattleTech;
|
|
|
|
/// <summary>
|
|
/// The recorded outcome of one BattleTech mission, saved as a gzip'd
|
|
/// BinaryFormatter blob (.btm) exactly like the RP .rpm mechanism. Mirrors
|
|
/// <c>RPMissionResults</c> minus the football branches (BT battle modes have
|
|
/// no teams, so every ranking entry is a single pilot).
|
|
/// </summary>
|
|
[Serializable]
|
|
internal class BTMissionResults
|
|
{
|
|
private BTMission mMission;
|
|
|
|
internal DateTime mMissionStart;
|
|
|
|
internal TimeSpan mActuallMissionTime;
|
|
|
|
internal readonly List<BTMissionEvent> mEvents = new List<BTMissionEvent>();
|
|
|
|
internal readonly Dictionary<BTPlayer, int> mFinalScores = new Dictionary<BTPlayer, int>();
|
|
|
|
public BTMission Mission => mMission;
|
|
|
|
public DateTime MissionStart => mMissionStart;
|
|
|
|
public TimeSpan ActuallMissionTime => mActuallMissionTime;
|
|
|
|
public IEnumerable<BTMissionEvent> 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;
|
|
}
|
|
|
|
public BTPlayer[][] GetChartOrder()
|
|
{
|
|
return GetChartOrder(TimeSpan.MaxValue);
|
|
}
|
|
|
|
public BTPlayer[][] GetChartOrder(TimeSpan gameTime)
|
|
{
|
|
List<Tuple<BTPlayer[], int>> list = new List<Tuple<BTPlayer[], int>>();
|
|
foreach (BTPlayer player in Mission.Players)
|
|
{
|
|
list.Add(new Tuple<BTPlayer[], int>(new BTPlayer[1] { player }, GetScore(player, gameTime)));
|
|
}
|
|
for (int i = 0; i < list.Count - 1; i++)
|
|
{
|
|
for (int j = i + 1; j < list.Count; j++)
|
|
{
|
|
if (list[i].B < list[j].B || (list[i].B == list[j].B && string.CompareOrdinal(list[i].A[0].Name, list[j].A[0].Name) > 0))
|
|
{
|
|
Tuple<BTPlayer[], int> value = list[i];
|
|
list[i] = list[j];
|
|
list[j] = value;
|
|
}
|
|
}
|
|
}
|
|
List<BTPlayer[]> list2 = new List<BTPlayer[]>();
|
|
foreach (Tuple<BTPlayer[], int> item in list)
|
|
{
|
|
list2.Add(item.A);
|
|
}
|
|
return list2.ToArray();
|
|
}
|
|
|
|
public PrintDocument GetPrintDocument()
|
|
{
|
|
return new BTPrintDocument(this);
|
|
}
|
|
}
|