diff --git a/EDPlayerJournal/BGS/TransactionParser.cs b/EDPlayerJournal/BGS/TransactionParser.cs
index 3efd67c..f7220d2 100644
--- a/EDPlayerJournal/BGS/TransactionParser.cs
+++ b/EDPlayerJournal/BGS/TransactionParser.cs
@@ -1,6 +1,7 @@
using EDPlayerJournal.Entries;
using System.Collections.Generic;
using System.Reflection.Metadata.Ecma335;
+using System.Transactions;
namespace EDPlayerJournal.BGS;
@@ -10,6 +11,22 @@ internal class TransactionParserContext {
public string? CurrentStation { get; set; }
public string? ControllingFaction { get; set; }
+ public bool IsOnFoot { get; set; } = false;
+
+ public string? LastRecordedAwardingFaction { get; set; }
+
+ public ulong? HighestCombatBond { get; set; }
+
+ ///
+ /// How many on foot kills were done.
+ ///
+ public ulong OnFootKills { get; set; } = 0;
+
+ ///
+ /// How many ship kills were done.
+ ///
+ public ulong ShipKills { get; set; } = 0;
+
///
/// A list of accepted missions index by their mission ID
///
@@ -32,6 +49,67 @@ internal class TransactionParserContext {
///
public Dictionary BuyCost = new();
+ public void DiscernCombatZone(TransactionList transactions) {
+ string grade = "Low";
+ string cztype;
+ ulong? highest = HighestCombatBond;
+
+ if (highest == null || LastRecordedAwardingFaction == null) {
+ return;
+ }
+
+ if (OnFootKills > 0) {
+ cztype = "OnFoot";
+ // High on foot combat zones have enforcers that bring 80k a pop
+ if (highest >= 80000) {
+ grade = "High";
+ } else if (highest >= 4000) {
+ grade = "Medium";
+ }
+ } else if (ShipKills > 0) {
+ // Ship combat zones can be identified by the amount of kills
+ if (ShipKills > 20) {
+ grade = "High";
+ } else if (ShipKills > 10) {
+ grade = "Medium";
+ }
+ cztype = "Ship";
+ } else {
+ transactions.AddIncomplete(new CombatZone(), "Failed to discern combat zone type");
+ return;
+ }
+
+ CombatZone zone = new CombatZone() {
+ System = CurrentSystem,
+ Faction = LastRecordedAwardingFaction,
+ Grade = grade,
+ Type = cztype,
+ Amount = 1,
+ };
+ transactions.Add(zone);
+ }
+
+ public void RecordCombatBond(FactionKillBondEntry e) {
+ if (HighestCombatBond == null || e.Reward > HighestCombatBond) {
+ HighestCombatBond = e.Reward;
+ }
+
+ LastRecordedAwardingFaction = e.AwardingFaction;
+
+ if (IsOnFoot) {
+ ++OnFootKills;
+ } else {
+ ++ShipKills;
+ }
+ }
+
+ public void ResetCombatZone() {
+ HighestCombatBond = null;
+ LastRecordedAwardingFaction = null;
+ OnFootKills = 0;
+ ShipKills = 0;
+ }
+
public void BoughtCargo(string? cargo, long? cost) {
if (cargo == null || cost == null) {
return;
@@ -610,7 +688,36 @@ internal class FactionKillBondParser : TransactionParserPart {
Faction = Factions.PilotsFederation,
Station = context.CurrentStation,
});
+
+ // We are done
+ return;
}
+
+ context.RecordCombatBond(entry);
+ }
+}
+
+internal class EmbarkDisembarkParser : TransactionParserPart {
+ public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
+ if (e.Is(Events.Embark)) {
+ context.IsOnFoot = false;
+ } else if (e.Is(Events.Disembark)) {
+ context.IsOnFoot = true;
+ }
+ }
+}
+
+internal class SupercruiseEntryParser : TransactionParserPart {
+ public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
+ context.DiscernCombatZone(transactions);
+ context.ResetCombatZone();
+ }
+}
+
+internal class ShutdownParser : TransactionParserPart {
+ public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
+ context.DiscernCombatZone(transactions);
+ context.ResetCombatZone();
}
}
@@ -618,7 +725,9 @@ public class TransactionParser {
private static Dictionary ParserParts { get; } = new()
{
{ Events.CommitCrime, new CommitCrimeParser() },
+ { Events.Disembark, new EmbarkDisembarkParser() },
{ Events.Docked, new DockedParser() },
+ { Events.Embark, new EmbarkDisembarkParser() },
{ Events.FactionKillBond, new FactionKillBondParser() },
{ Events.FSDJump, new FSDJumpParser() },
{ Events.Location, new LocationParser() },
@@ -634,6 +743,8 @@ public class TransactionParser {
{ Events.SellMicroResources, new SellMicroResourcesParser() },
{ Events.SellOrganicData, new SellOrganicDataParser() },
{ Events.ShipTargeted, new ShipTargetedParser() },
+ { Events.Shutdown, new ShutdownParser() },
+ { Events.SupercruiseEntry, new SupercruiseEntryParser() },
};
public List? Parse(IEnumerable entries) {
diff --git a/EDPlayerJournal/Entries/DisembarkEntry.cs b/EDPlayerJournal/Entries/DisembarkEntry.cs
new file mode 100644
index 0000000..e07b70a
--- /dev/null
+++ b/EDPlayerJournal/Entries/DisembarkEntry.cs
@@ -0,0 +1,66 @@
+namespace EDPlayerJournal.Entries;
+
+public class DisembarkEntry : Entry {
+ ///
+ /// Disembarked into an SRV?
+ ///
+ public bool SRV { get; set; } = false;
+
+ ///
+ /// Taxi?
+ ///
+ public bool Taxi { get; set; } = false;
+
+ ///
+ /// Multicrew or not.
+ ///
+ public bool Multicrew { get; set; } = false;
+
+ ///
+ /// Player's ship ID
+ ///
+ public ulong? ID { get; set; }
+
+ ///
+ /// Star system
+ ///
+ public string? StarSystem { get; set; }
+
+ ///
+ /// System address
+ ///
+ public ulong? SystemAddress { get; set; }
+
+ ///
+ /// Body, name e.g. HIP 6182 B 2 a
+ ///
+ public string? Body { get; set; }
+
+ ///
+ /// Body ID
+ ///
+ public ulong? BodyID { get; set; }
+
+ ///
+ /// Disembarked on a station?
+ ///
+ public bool OnStation { get; set; } = false;
+
+ ///
+ /// Disembarked on a planet?
+ ///
+ public bool OnPlanet { get; set; } = false;
+
+ protected override void Initialise() {
+ SRV = JSON.Value("SRV") ?? false;
+ Taxi = JSON.Value("Taxi") ?? false;
+ Multicrew = JSON.Value("Multicrew") ?? false;
+ ID = JSON.Value("ID");
+ StarSystem = JSON.Value("StarSystem");
+ SystemAddress = JSON.Value("SystemAddress");
+ Body = JSON.Value("Body");
+ BodyID = JSON.Value("BodyID");
+ OnStation = JSON.Value("OnStation") ?? false;
+ OnPlanet = JSON.Value("OnPlanet") ?? false;
+ }
+}
diff --git a/EDPlayerJournal/Entries/EmbarkEntry.cs b/EDPlayerJournal/Entries/EmbarkEntry.cs
new file mode 100644
index 0000000..462ac2b
--- /dev/null
+++ b/EDPlayerJournal/Entries/EmbarkEntry.cs
@@ -0,0 +1,66 @@
+namespace EDPlayerJournal.Entries;
+
+public class EmbarkEntry : Entry {
+ ///
+ /// Disembarked into an SRV?
+ ///
+ public bool SRV { get; set; } = false;
+
+ ///
+ /// Taxi?
+ ///
+ public bool Taxi { get; set; } = false;
+
+ ///
+ /// Multicrew or not.
+ ///
+ public bool Multicrew { get; set; } = false;
+
+ ///
+ /// Player's ship ID
+ ///
+ public ulong? ID { get; set; }
+
+ ///
+ /// Star system
+ ///
+ public string? StarSystem { get; set; }
+
+ ///
+ /// System address
+ ///
+ public ulong? SystemAddress { get; set; }
+
+ ///
+ /// Body, name e.g. HIP 6182 B 2 a
+ ///
+ public string? Body { get; set; }
+
+ ///
+ /// Body ID
+ ///
+ public ulong? BodyID { get; set; }
+
+ ///
+ /// Disembarked on a station?
+ ///
+ public bool OnStation { get; set; } = false;
+
+ ///
+ /// Disembarked on a planet?
+ ///
+ public bool OnPlanet { get; set; } = false;
+
+ protected override void Initialise() {
+ SRV = JSON.Value("SRV") ?? false;
+ Taxi = JSON.Value("Taxi") ?? false;
+ Multicrew = JSON.Value("Multicrew") ?? false;
+ ID = JSON.Value("ID");
+ StarSystem = JSON.Value("StarSystem");
+ SystemAddress = JSON.Value("SystemAddress");
+ Body = JSON.Value("Body");
+ BodyID = JSON.Value("BodyID");
+ OnStation = JSON.Value("OnStation") ?? false;
+ OnPlanet = JSON.Value("OnPlanet") ?? false;
+ }
+}
diff --git a/EDPlayerJournal/Entries/Entry.cs b/EDPlayerJournal/Entries/Entry.cs
index c9b5659..6ce35f4 100644
--- a/EDPlayerJournal/Entries/Entry.cs
+++ b/EDPlayerJournal/Entries/Entry.cs
@@ -16,9 +16,11 @@ public class Entry {
{ Events.Commander, typeof(CommanderEntry) },
{ Events.CommitCrime, typeof(CommitCrimeEntry) },
{ Events.Died, typeof(DiedEntry) },
+ { Events.Disembark, typeof(DisembarkEntry) },
{ Events.Docked, typeof(DockedEntry) },
- { Events.FileHeader, typeof(FileHeaderEntry) },
+ { Events.Embark, typeof(EmbarkEntry) },
{ Events.FactionKillBond, typeof(FactionKillBondEntry) },
+ { Events.FileHeader, typeof(FileHeaderEntry) },
{ Events.FSDJump, typeof(FSDJumpEntry) },
{ Events.HullDamage, typeof(HullDamageEntry) },
{ Events.LoadGame, typeof(LoadGameEntry) },
@@ -39,6 +41,8 @@ public class Entry {
{ Events.SellOrganicData, typeof(SellOrganicDataEntry) },
{ Events.ShieldState, typeof(ShieldStateEntry) },
{ Events.ShipTargeted, typeof(ShipTargetedEntry) },
+ { Events.SupercruiseEntry, typeof(SupercruiseEntryEntry) },
+ { Events.SupercruiseExit, typeof(SupercruiseExitEntry) },
{ Events.UnderAttack, typeof(UnderAttackEntry) },
};
diff --git a/EDPlayerJournal/Entries/Events.cs b/EDPlayerJournal/Entries/Events.cs
index 288a0d5..a555b0b 100644
--- a/EDPlayerJournal/Entries/Events.cs
+++ b/EDPlayerJournal/Entries/Events.cs
@@ -5,7 +5,9 @@ public class Events {
public static readonly string Commander = "Commander";
public static readonly string CommitCrime = "CommitCrime";
public static readonly string Died = "Died";
+ public static readonly string Disembark = "Disembark";
public static readonly string Docked = "Docked";
+ public static readonly string Embark = "Embark";
public static readonly string FactionKillBond = "FactionKillBond";
public static readonly string FighterDestroyed = "FighterDestroyed";
public static readonly string FileHeader = "Fileheader";
@@ -29,5 +31,8 @@ public class Events {
public static readonly string SellOrganicData = "SellOrganicData";
public static readonly string ShieldState = "ShieldState";
public static readonly string ShipTargeted = "ShipTargeted";
+ public static readonly string Shutdown = "Shutdown";
+ public static readonly string SupercruiseEntry = "SupercruiseEntry";
+ public static readonly string SupercruiseExit = "SupercruiseExit";
public static readonly string UnderAttack = "UnderAttack";
}
diff --git a/EDPlayerJournal/Entries/SupercruiseEntry.cs b/EDPlayerJournal/Entries/SupercruiseEntry.cs
new file mode 100644
index 0000000..f7ec714
--- /dev/null
+++ b/EDPlayerJournal/Entries/SupercruiseEntry.cs
@@ -0,0 +1,30 @@
+namespace EDPlayerJournal.Entries;
+
+public class SupercruiseEntryEntry : Entry {
+ ///
+ /// Taxi?
+ ///
+ public bool Taxi { get; set; } = false;
+
+ ///
+ /// Multicrew or not.
+ ///
+ public bool Multicrew { get; set; } = false;
+
+ ///
+ /// Star system
+ ///
+ public string? StarSystem { get; set; }
+
+ ///
+ /// System address
+ ///
+ public ulong? SystemAddress { get; set; }
+
+ protected override void Initialise() {
+ Taxi = JSON.Value("Taxi") ?? false;
+ Multicrew = JSON.Value("Multicrew") ?? false;
+ StarSystem = JSON.Value("StarSystem");
+ SystemAddress = JSON.Value("SystemAddress");
+ }
+}
diff --git a/EDPlayerJournal/Entries/SupercruiseExitEntry.cs b/EDPlayerJournal/Entries/SupercruiseExitEntry.cs
new file mode 100644
index 0000000..50ac4a5
--- /dev/null
+++ b/EDPlayerJournal/Entries/SupercruiseExitEntry.cs
@@ -0,0 +1,48 @@
+namespace EDPlayerJournal.Entries;
+
+public class SupercruiseExitEntry : Entry {
+ ///
+ /// Taxi?
+ ///
+ public bool Taxi { get; set; } = false;
+
+ ///
+ /// Multicrew or not.
+ ///
+ public bool Multicrew { get; set; } = false;
+
+ ///
+ /// Star system
+ ///
+ public string? StarSystem { get; set; }
+
+ ///
+ /// System address
+ ///
+ public ulong? SystemAddress { get; set; }
+
+ ///
+ /// Body, name e.g. HIP 6182 B 2 a
+ ///
+ public string? Body { get; set; }
+
+ ///
+ /// Body ID
+ ///
+ public ulong? BodyID { get; set; }
+
+ ///
+ /// Body type (star, planet etc.)
+ ///
+ public string? BodyType { get; set; }
+
+ protected override void Initialise() {
+ Taxi = JSON.Value("Taxi") ?? false;
+ Multicrew = JSON.Value("Multicrew") ?? false;
+ StarSystem = JSON.Value("StarSystem");
+ SystemAddress = JSON.Value("SystemAddress");
+ Body = JSON.Value("Body");
+ BodyType = JSON.Value("BodyType");
+ BodyID = JSON.Value("BodyID");
+ }
+}