Compare commits
151 Commits
a49859b079
...
0.2.6
| Author | SHA1 | Date | |
|---|---|---|---|
| 29dc6e9cba | |||
| aeb16c675b | |||
| 00f94ef939 | |||
| 785efad4c0 | |||
| 3a968a7c55 | |||
| 44d5a2b91c | |||
| 69b6e8b306 | |||
| 3bfe599c11 | |||
| 0b47b7331e | |||
| 2fae724bd2 | |||
| 132d090fd5 | |||
| 9d686bea61 | |||
| 78c2636a40 | |||
| 4549413b00 | |||
| f32f1f7dff | |||
| 86f2356f35 | |||
| 6608f33d8d | |||
| 42987cdb12 | |||
| 4f6376d39b | |||
| 273d151358 | |||
| a9ce5be266 | |||
| 3bd0cc1055 | |||
| 1d1ea3f5ef | |||
| b12ab287b6 | |||
| 9deafa6653 | |||
| efbbaa8abf | |||
| b96e40299d | |||
| 194add4436 | |||
| 02286e19a8 | |||
| b4e6b1b46c | |||
| e9b79a8c7a | |||
| 86d27fb2a3 | |||
| 271b151a72 | |||
| e75e0773fd | |||
| ba9b108e5e | |||
| 93a76bc429 | |||
| 0cb8641056 | |||
| c2082df6f1 | |||
| 65d12cb052 | |||
| 44410e86c8 | |||
| 5c7580a3c0 | |||
| f0692c3936 | |||
| a181a3cdd2 | |||
| 40d93e7c84 | |||
| db192748b0 | |||
| a43ade2f3c | |||
| a6b16fd5b8 | |||
| 99373b47c0 | |||
| f5f85586ec | |||
| ba4936ccb0 | |||
| 44774c5cad | |||
| 8d3d48d846 | |||
| a3b54b1326 | |||
| bf43262a8e | |||
| ef8e71cd8a | |||
| bd0d5cf0b6 | |||
| 365c34bdb0 | |||
| 7fa19c0733 | |||
| ea07c4dbcb | |||
| 6f9d3a64ff | |||
| abdaca2524 | |||
| 1f673970ee | |||
| 2608aeab6f | |||
| b84d028115 | |||
| 123fa15884 | |||
| 43ae93658f | |||
| 8dea9fd094 | |||
| 8a0d21d039 | |||
| c20bc3d0bf | |||
| cb8698dd42 | |||
| f5f6d538f0 | |||
| eaeaa5e0b4 | |||
| 3df82af239 | |||
| 0e92ee8ab4 | |||
| 72cb379c95 | |||
| 84dfd73283 | |||
| 22d0bedf53 | |||
| 1e73c6b7eb | |||
| 661a4672d9 | |||
| 67966ca27a | |||
| 914aa43d33 | |||
| 8d72808fbf | |||
| ac3d1cd8b9 | |||
| 634ba657b4 | |||
| 6b2bef0d30 | |||
| d6b86d28aa | |||
| bfae0adcae | |||
| 454af4ad8f | |||
| 7f73159bb0 | |||
| 0820998d3e | |||
| f14982f37a | |||
| f0977b774b | |||
| 04a839417e | |||
| 93359321d6 | |||
| 6bbc063c25 | |||
| 6fe6f5e26f | |||
| 9f1065c6ea | |||
| 674757d734 | |||
| 712c416725 | |||
| 91bca70168 | |||
| 800ac73331 | |||
| d79ee5a153 | |||
| f683bc372e | |||
| 12ba6d4d96 | |||
| dd1d7ff091 | |||
| 65fec2cd1e | |||
| bb74d72b13 | |||
| d2aadf9882 | |||
| 6b14909335 | |||
| db67ef21fa | |||
| f3134d36d4 | |||
| 1a53a3ba8d | |||
| c7e2f352f2 | |||
| f7c3a1bb41 | |||
| 2648b1390b | |||
| aad688026e | |||
| a451392e93 | |||
| 10351af7f9 | |||
| 697cbc2bc6 | |||
| 0cc8a1f29a | |||
| 22396c9b22 | |||
| 8d95a42698 | |||
| aa7f0bcd1a | |||
| 6e5f8f504f | |||
| e01d3a869d | |||
| 1da4549e2c | |||
| 0be9791abc | |||
| 027f8a892d | |||
| 32e5898b02 | |||
| 34934c82a6 | |||
| 5a8ea2940c | |||
| a13a708c22 | |||
| fbd5a66156 | |||
| 0be0896e91 | |||
| f8559bbe06 | |||
| 987d9c5f49 | |||
| 24f3897582 | |||
| afa4e0d536 | |||
| 1d8f03200b | |||
| 955a108f2e | |||
| fe28a4d17d | |||
| dc9e654351 | |||
| c2037f28e2 | |||
| e6e0233e6d | |||
| 1a6183ba9d | |||
| 3a5d0a90ef | |||
| 8514331701 | |||
| e8de768d01 | |||
| 61f1b10f29 | |||
| e0e7cb5792 | |||
| 5f9fff3922 |
@@ -9,6 +9,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EDPlayerJournalTests", "EDP
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EliteBGS", "EliteBGS\EliteBGS.csproj", "{14B03115-B9D5-4006-A993-9A5069BB172E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1381D5DE-139E-4FEC-BDC4-A3FDADEAEE5C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
@@ -16,6 +16,22 @@ the game:
|
||||
}
|
||||
```
|
||||
|
||||
## Bounty vouchers show up twice
|
||||
|
||||
Sometimes bounty vouchers are redeemed twice. This happens because FDev writes out two
|
||||
`RedeemVoucher` entries with the same values:
|
||||
|
||||
```
|
||||
{ "timestamp":"2022-11-20T14:30:30Z", "event":"RedeemVoucher", "Type":"bounty", "Amount":3197549,
|
||||
"Factions":[ { "Faction":"Nova Paresa", "Amount":3197549 } ] }
|
||||
{ "timestamp":"2022-11-20T14:30:34Z", "event":"RedeemVoucher", "Type":"bounty", "Amount":4785831,
|
||||
"Factions":[ { "Faction":"", "Amount":723175 }, { "Faction":"Nova Paresa", "Amount":3197549 }, { "Faction":"Prismatic Imperium", "Amount":4062656 } ] }
|
||||
```
|
||||
|
||||
Two separate events (apart by four seconds) containing the same entries twice. This
|
||||
happens when you turn in one bounty manually, and then click the "redeem all" button
|
||||
again, which contains the already turned in vouchers.
|
||||
|
||||
## Combat zones
|
||||
|
||||
Combat zones receive no mention within the player journal whatsoever. There is no event
|
||||
|
||||
@@ -3,15 +3,70 @@ using System.Linq;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
public class CombatZone : Transaction {
|
||||
public string Type { get; set; } = "";
|
||||
public string Grade { get; set; } = "";
|
||||
public int Amount { get; set; } = 0;
|
||||
public DateTime Completed { get; set; } = DateTime.UtcNow;
|
||||
/// <summary>
|
||||
/// Type, either on foot or ship
|
||||
/// </summary>
|
||||
public string Type { get; set; } = CombatZones.ShipCombatZone;
|
||||
|
||||
public override string CompletedAt {
|
||||
/// <summary>
|
||||
/// Difficulty type, low, medium or high. Null means unknown.
|
||||
/// </summary>
|
||||
public string? Grade { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether spec ops were won.
|
||||
/// </summary>
|
||||
public bool? SpecOps { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether captain was won
|
||||
/// </summary>
|
||||
public bool? Captain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether correspondent objective was won
|
||||
/// </summary>
|
||||
public bool? Correspondent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether cap ship objective was won
|
||||
/// </summary>
|
||||
public bool? CapitalShip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How many optional objectives were completed?
|
||||
/// </summary>
|
||||
public int OptionalObjectivesCompleted {
|
||||
get {
|
||||
return Completed.ToString("dd.MM.yyyy HH:mm UTC");
|
||||
if (IsGround) {
|
||||
return 0;
|
||||
}
|
||||
return new List<bool?>() { SpecOps, Captain, Correspondent, CapitalShip }
|
||||
.Where(x => x != null && x == true)
|
||||
.Count()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if it is an on foot/ground combat zone
|
||||
/// </summary>
|
||||
public bool IsGround {
|
||||
get { return string.Compare(Type, CombatZones.GroundCombatZone) == 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if it is an on foot combat zone
|
||||
/// </summary>
|
||||
public bool IsShip {
|
||||
get { return string.Compare(Type, CombatZones.ShipCombatZone) == 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if it is a thargoid combat zone
|
||||
/// </summary>
|
||||
public bool IsThargoid {
|
||||
get { return string.Compare(Type, CombatZones.AXCombatZone) == 0; }
|
||||
}
|
||||
|
||||
public override int CompareTo(Transaction? obj) {
|
||||
@@ -36,7 +91,10 @@ public class CombatZone : Transaction {
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return string.Format("Won {0} x {1} {2} Combat Zone(s) for {3}",
|
||||
Amount, Grade, Type, Faction);
|
||||
if (!string.IsNullOrEmpty(Grade)) {
|
||||
return string.Format("Won {0} {1} Combat Zone", Grade, Type);
|
||||
} else {
|
||||
return string.Format("Won {0} Combat Zone", Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
namespace EDPlayerJournal.BGS;
|
||||
internal class IncompleteTransaction : Transaction {
|
||||
using EDPlayerJournal.Entries;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
|
||||
public class IncompleteTransaction : Transaction {
|
||||
public Transaction? UnderlyingTransaction { get; set; } = null;
|
||||
public string Reason { get; set; } = "";
|
||||
|
||||
public IncompleteTransaction() { }
|
||||
|
||||
public IncompleteTransaction(Transaction? underlying, string reason) {
|
||||
public IncompleteTransaction(Transaction? underlying, string reason, Entry entry) {
|
||||
UnderlyingTransaction = underlying;
|
||||
Reason = reason;
|
||||
Entries.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,23 @@ namespace EDPlayerJournal.BGS;
|
||||
/// </summary>
|
||||
public class InfluenceSupport : Transaction {
|
||||
public string Influence { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Relevant mission completed entry
|
||||
/// </summary>
|
||||
public MissionCompletedEntry? RelevantMission { get; set; }
|
||||
|
||||
public override string CompletedAt {
|
||||
/// <summary>
|
||||
/// Mission information
|
||||
/// </summary>
|
||||
public Mission? Mission { get; set; }
|
||||
|
||||
public override DateTime? CompletedAtDateTime {
|
||||
get {
|
||||
if (RelevantMission == null) {
|
||||
return "";
|
||||
return null;
|
||||
}
|
||||
return RelevantMission.Timestamp.ToString("dd.MM.yyyy hh:mm UTC");
|
||||
return RelevantMission.Timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +35,7 @@ public class InfluenceSupport : Transaction {
|
||||
string? missionname;
|
||||
|
||||
if (RelevantMission != null && RelevantMission.Mission != null) {
|
||||
missionname = RelevantMission.Mission.LocalisedName;
|
||||
missionname = RelevantMission.Mission.FriendlyName;
|
||||
} else {
|
||||
missionname = "UNKNOWN MISSION";
|
||||
}
|
||||
|
||||
@@ -1,50 +1,73 @@
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using EDPlayerJournal.Entries;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
|
||||
public class MissionCompleted : Transaction {
|
||||
public MissionCompletedEntry? CompletedEntry { get; set; }
|
||||
|
||||
public MissionAcceptedEntry? AcceptedEntry { get; set; }
|
||||
|
||||
public Mission? Mission { get; set; }
|
||||
|
||||
public MissionCompleted() { }
|
||||
public MissionCompleted(MissionCompletedEntry e) {
|
||||
Entries.Add(e);
|
||||
|
||||
public override DateTime? CompletedAtDateTime {
|
||||
get {
|
||||
if (CompletedEntry == null) {
|
||||
return null;
|
||||
}
|
||||
return CompletedEntry.Timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
public string MissionName {
|
||||
get {
|
||||
MissionCompletedEntry? c = Entries[0] as MissionCompletedEntry;
|
||||
if (c == null || c.Mission == null) {
|
||||
if (CompletedEntry == null || CompletedEntry.Mission == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return c.Mission.FriendlyName;
|
||||
return CompletedEntry.Mission.FriendlyName;
|
||||
}
|
||||
}
|
||||
|
||||
public string Influence {
|
||||
get {
|
||||
MissionCompletedEntry? e = (Entries[0] as MissionCompletedEntry);
|
||||
|
||||
if (e == null || Faction == null || e.Mission == null) {
|
||||
if (CompletedEntry == null || Faction == null || CompletedEntry.Mission == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return (e.Mission.GetInfluenceForFaction(Faction, SystemAddress) ?? "");
|
||||
return (CompletedEntry.Mission.GetInfluenceForFaction(Faction, SystemAddress) ?? "");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rescue missions contribute to the system.
|
||||
/// </summary>
|
||||
public override bool SystemContribution {
|
||||
get {
|
||||
if (Mission == null || Mission.Name == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the mission starts with the name for thargoid war mission
|
||||
// names, we assume its a system contribution
|
||||
if (Mission.Name.Contains("Mission_TW_")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
if (Faction == null || Entries.Count <= 0) {
|
||||
if (Faction == null || CompletedEntry == null || CompletedEntry.Mission == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
var entry = Entries[0] as MissionCompletedEntry;
|
||||
|
||||
if (entry == null || entry.Mission == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var influence = entry.Mission.GetInfluenceForFaction(Faction, SystemAddress);
|
||||
var influence = CompletedEntry.Mission.GetInfluenceForFaction(Faction, SystemAddress);
|
||||
|
||||
builder.AppendFormat("{0}", MissionName);
|
||||
if (influence != "") {
|
||||
|
||||
@@ -4,16 +4,13 @@ using EDPlayerJournal.Entries;
|
||||
namespace EDPlayerJournal.BGS;
|
||||
public class MissionFailed : Transaction {
|
||||
public MissionFailedEntry? Failed { get; set; }
|
||||
public MissionAcceptedEntry? Accepted { get; set; }
|
||||
public Mission? Mission { get; set; }
|
||||
|
||||
public MissionFailed() { }
|
||||
|
||||
public MissionFailed(MissionAcceptedEntry accepted) {
|
||||
if (accepted.Mission == null) {
|
||||
throw new Exception("Mission cannot be null");
|
||||
}
|
||||
Accepted = accepted;
|
||||
Faction = accepted.Mission.Faction;
|
||||
public MissionFailed(MissionFailedEntry failed) {
|
||||
Entries.Add(failed);
|
||||
Failed = failed;
|
||||
}
|
||||
|
||||
public override int CompareTo(Transaction? other) {
|
||||
@@ -39,20 +36,15 @@ public class MissionFailed : Transaction {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int Amount {
|
||||
get { return Entries.Count + 1; }
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (Failed == null || Accepted == null) {
|
||||
if (Failed == null || Mission == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
builder.AppendFormat("{0}x Mission failed: \"{1}\"",
|
||||
Amount,
|
||||
Failed?.Mission?.FriendlyName
|
||||
builder.AppendFormat(" Mission failed: \"{0}\"",
|
||||
Mission?.FriendlyName
|
||||
);
|
||||
|
||||
return builder.ToString();
|
||||
|
||||
@@ -1,664 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using EDPlayerJournal.Entries;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
|
||||
public class Report {
|
||||
private List<Objective> objectives = new List<Objective>();
|
||||
|
||||
public delegate void OnLogDelegate(string log);
|
||||
|
||||
public event OnLogDelegate? OnLog;
|
||||
|
||||
public List<Objective> Objectives {
|
||||
get { return objectives; }
|
||||
set { objectives = value; }
|
||||
}
|
||||
|
||||
public bool AddObjective(Objective objective) {
|
||||
var found = objectives.Find(x => x.CompareTo(objective) == 0);
|
||||
bool added = false;
|
||||
|
||||
if (found == null) {
|
||||
objectives.Add(objective);
|
||||
added = true;
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
public static bool IsRelevant(Entry e) {
|
||||
return e.Is(Events.CommitCrime) ||
|
||||
e.Is(Events.Docked) ||
|
||||
e.Is(Events.FactionKillBond) ||
|
||||
e.Is(Events.FSDJump) ||
|
||||
e.Is(Events.Location) ||
|
||||
e.Is(Events.MarketBuy) ||
|
||||
e.Is(Events.MarketSell) ||
|
||||
e.Is(Events.MissionAccepted) ||
|
||||
e.Is(Events.MissionFailed) ||
|
||||
e.Is(Events.MultiSellExplorationData) ||
|
||||
e.Is(Events.RedeemVoucher) ||
|
||||
e.Is(Events.SearchAndRescue) ||
|
||||
e.Is(Events.SellExplorationData) ||
|
||||
e.Is(Events.SellMicroResources) ||
|
||||
e.Is(Events.SellOrganicData) ||
|
||||
e.Is(Events.ShipTargeted) ||
|
||||
e.Is(Events.MissionCompleted)
|
||||
;
|
||||
}
|
||||
|
||||
public void Scan(PlayerJournal journal, DateTime start, DateTime end) {
|
||||
/* Log files only get rotated if you restart the game client. This means that there might
|
||||
* be - say - entries from the 4th of May in the file with a timestamp of 3rd of May. This
|
||||
* happens if you happen to play a session late into the night.
|
||||
* At first I tried extracting the first and last line of a file to see the date range, but
|
||||
* if you have a lot of files this becomes quite slow, and quite the memory hog (as journal
|
||||
* files have to be read in their entirety to check this). So we assume that you can't play
|
||||
* three days straight, and keep the code fast.
|
||||
*/
|
||||
DateTime actualstart = start.AddDays(-3);
|
||||
List<Entry> entries = journal.Files
|
||||
.Where(f => f.NormalisedDateTime >= actualstart && f.NormalisedDateTime <= end)
|
||||
.SelectMany(e => e.Entries)
|
||||
.ToList()
|
||||
;
|
||||
// Now further sort the list down to entries that are actually within the given datetime
|
||||
// Note that entry datetimes are not normalised, so we have to sort until end + 1 day
|
||||
DateTime actualend = end.AddDays(1);
|
||||
|
||||
entries = entries
|
||||
.Where(e => e.Timestamp >= start && e.Timestamp < actualend)
|
||||
.ToList()
|
||||
;
|
||||
Scan(entries);
|
||||
}
|
||||
|
||||
public void Scan(List<Entry> entries) {
|
||||
if (entries.Count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Entry> relevant = entries
|
||||
.Where(x => IsRelevant(x))
|
||||
.ToList()
|
||||
;
|
||||
|
||||
Dictionary<ulong, MissionAcceptedEntry> acceptedMissions = new Dictionary<ulong, MissionAcceptedEntry>();
|
||||
Dictionary<string, long> buyCost = new Dictionary<string, long>();
|
||||
Dictionary<ulong, string> systems = new Dictionary<ulong, string>();
|
||||
Dictionary<string, string> npcfactions = new Dictionary<string, string>();
|
||||
Dictionary<string, List<Faction>> system_factions = new Dictionary<string, List<Faction>>();
|
||||
|
||||
// A dictionary resolving to a station at which each mission was accepted
|
||||
Dictionary<ulong, string> acceptedStations = new Dictionary<ulong, string>();
|
||||
// A dictionary resolving to a system at which each mission was accepted
|
||||
Dictionary<ulong, ulong> acceptedSystems = new Dictionary<ulong, ulong>();
|
||||
|
||||
string? current_system = null;
|
||||
ulong? current_system_address = null;
|
||||
string? current_station = null;
|
||||
string? controlling_faction = null;
|
||||
|
||||
objectives.ForEach(x => x.Clear());
|
||||
|
||||
foreach (Entry e in relevant) {
|
||||
List<Transaction> results = new List<Transaction>();
|
||||
bool collate = false;
|
||||
|
||||
if (e.Is(Events.Docked)) {
|
||||
DockedEntry? docked = e as DockedEntry;
|
||||
if (docked == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* gleem the current station from this message
|
||||
*/
|
||||
current_station = docked.StationName;
|
||||
current_system = docked.StarSystem;
|
||||
controlling_faction = docked.StationFaction;
|
||||
current_system_address = docked.SystemAddress;
|
||||
|
||||
if (current_system_address != null && current_system != null) {
|
||||
if (!systems.ContainsKey(current_system_address.Value)) {
|
||||
systems.Add(current_system_address.Value, current_system);
|
||||
}
|
||||
}
|
||||
} else if (e.Is(Events.FSDJump)) {
|
||||
/* Gleem current system and controlling faction from this message.
|
||||
*/
|
||||
FSDJumpEntry? fsd = e as FSDJumpEntry;
|
||||
|
||||
if (fsd == null || fsd.StarSystem == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
current_system_address = fsd.SystemAddress;
|
||||
current_system = fsd.StarSystem;
|
||||
controlling_faction = fsd.SystemFaction;
|
||||
|
||||
if (!systems.ContainsKey(fsd.SystemAddress)) {
|
||||
systems.Add(fsd.SystemAddress, fsd.StarSystem);
|
||||
}
|
||||
|
||||
if (!system_factions.ContainsKey(fsd.StarSystem) &&
|
||||
fsd.SystemFactions.Count > 0) {
|
||||
system_factions[fsd.StarSystem] = fsd.SystemFactions;
|
||||
}
|
||||
} else if (e.Is(Events.Location)) {
|
||||
/* Get current system, faction name and station from Location message
|
||||
*/
|
||||
LocationEntry? location = e as LocationEntry;
|
||||
|
||||
if (location == null || location.StarSystem == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
current_system = location.StarSystem;
|
||||
current_system_address = location.SystemAddress;
|
||||
|
||||
if (!systems.ContainsKey(location.SystemAddress)) {
|
||||
systems.Add(location.SystemAddress, location.StarSystem);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(location.SystemFaction)) {
|
||||
controlling_faction = location.SystemFaction;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(location.StationName)) {
|
||||
current_station = location.StationName;
|
||||
}
|
||||
|
||||
if (!system_factions.ContainsKey(location.StarSystem) &&
|
||||
location.SystemFactions.Count > 0) {
|
||||
system_factions[location.StarSystem] = location.SystemFactions;
|
||||
}
|
||||
} else if (e.Is(Events.ShipTargeted)) {
|
||||
ShipTargetedEntry? targeted = e as ShipTargetedEntry;
|
||||
|
||||
if (targeted == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(targeted.PilotNameLocalised) ||
|
||||
string.IsNullOrEmpty(targeted.Faction)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
npcfactions[targeted.PilotNameLocalised] = targeted.Faction;
|
||||
} else if (e.Is(Events.CommitCrime)) {
|
||||
CommitCrimeEntry? crime = e as CommitCrimeEntry;
|
||||
if (crime == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string? faction = crime.Faction;
|
||||
|
||||
if (faction == null || !crime.IsMurder) {
|
||||
/* we don't care about anything but murder for now */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* use localised victim name if we have it, otherwise use normal name */
|
||||
string? victim = crime.VictimLocalised;
|
||||
if (string.IsNullOrEmpty(victim)) {
|
||||
victim = crime.Victim;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(victim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!npcfactions.ContainsKey(victim)) {
|
||||
/* The faction in the crime report is the faction that issues the bounty,
|
||||
* and not the faction of the victim.
|
||||
*/
|
||||
OnLog?.Invoke(string.Format(
|
||||
"No faction found for victim \"{0}\", using faction that issued the bounty instead.",
|
||||
victim, crime.Faction
|
||||
));
|
||||
} else {
|
||||
faction = npcfactions[victim];
|
||||
}
|
||||
|
||||
results.Add(new FoulMurder(crime) {
|
||||
System = current_system,
|
||||
Faction = faction,
|
||||
});
|
||||
collate = true;
|
||||
} else if (e.Is(Events.MissionCompleted)) {
|
||||
MissionCompletedEntry? completed = e as MissionCompletedEntry;
|
||||
|
||||
if (completed == null ||
|
||||
completed.Mission == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MissionAcceptedEntry? accepted = null;
|
||||
MissionCompleted? main_mission = null;
|
||||
ulong accepted_address;
|
||||
string? accepted_system;
|
||||
|
||||
string? target_faction_name = completed.Mission.TargetFaction;
|
||||
string? source_faction_name = completed.Mission.Faction;
|
||||
|
||||
if (!acceptedMissions.TryGetValue(completed.Mission.MissionID, out accepted)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to find mission acceptance for mission \"{0}\". " +
|
||||
"Please extend range to include the mission acceptance.", completed.Mission.LocalisedName
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!acceptedSystems.TryGetValue(completed.Mission.MissionID, out accepted_address)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which system mission \"{0}\" was accepted.", completed.Mission.LocalisedName
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!systems.TryGetValue(accepted_address, out accepted_system)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which system mission \"{0}\" was accepted.", completed.Mission.LocalisedName
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var other in completed.Mission.Influences) {
|
||||
string faction = other.Key;
|
||||
if (string.IsNullOrEmpty(faction)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Mission \"{0}\" has empty faction name in influence block, "+
|
||||
"so this influence support was ignored. " +
|
||||
"Please check the README on why this happens.", completed.Mission.LocalisedName)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now comes the fun part. Sometimes the influence list is empty for a faction.
|
||||
* This happens if the faction in question
|
||||
*/
|
||||
if (other.Value.Count() == 0) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Mission \"{0}\" gave no influence to \"{1}\", so we assume this is because the " +
|
||||
"faction is in a conflict and cannot gain influence right now. " +
|
||||
"If this assessment is wrong, just remove the entry from the objective list.",
|
||||
completed.Mission.LocalisedName, faction
|
||||
));
|
||||
|
||||
if (string.Compare(target_faction_name, faction, true) == 0) {
|
||||
/* here we assume that if the faction in question is the target faction,
|
||||
* that we gave said target faction no influence in the target system, aka
|
||||
* current system
|
||||
*/
|
||||
if (current_system_address == null) {
|
||||
continue;
|
||||
}
|
||||
other.Value.Add(current_system_address.Value, "");
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Mission \"{0}\" gave no influence to \"{1}\". Since \"{1}\" is the target faction " +
|
||||
"of the mission, we assume the influence was gained in \"{2}\". " +
|
||||
"Please remove the entry if this assumption is wrong.",
|
||||
completed.Mission.LocalisedName, faction, current_system
|
||||
));
|
||||
} else if (string.Compare(source_faction_name, faction, true) == 0) {
|
||||
/* source faction of the mission is not getting any influence. This could be because
|
||||
* the source faction is in an election state in its home system and cannot gain any
|
||||
* influence. It may also very well be that the source and target faction are the same
|
||||
* since the faction is present in both target and source system. In which case we add
|
||||
* both and hope for the best.
|
||||
*/
|
||||
other.Value.Add(accepted_address, "");
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Mission \"{0}\" gave no influence to \"{1}\". Since \"{1}\" is the source faction " +
|
||||
"of the mission, we assume the influence was gained in \"{2}\". " +
|
||||
"Please remove the entry if this assumption is wrong.",
|
||||
completed.Mission.LocalisedName, faction, accepted_system
|
||||
));
|
||||
|
||||
/* check if source/target faction are equal, in which case we also need an entry
|
||||
* for the target system. As said factions can be present in two systems, and can
|
||||
* give missions that target each other.
|
||||
*/
|
||||
if (string.Compare(source_faction_name, target_faction_name, true) == 0 &&
|
||||
current_system_address != null) {
|
||||
other.Value.Add(current_system_address.Value, "");
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Mission \"{0}\" gave no influence to \"{1}\". Since \"{1}\" is the source and target faction " +
|
||||
"of the mission, we assume the influence was also gained in target system \"{2}\". " +
|
||||
"Please remove the entry if this assumption is wrong.",
|
||||
completed.Mission.LocalisedName, faction, current_system
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var influences in other.Value) {
|
||||
ulong system_address = influences.Key;
|
||||
string? system;
|
||||
string? accepted_station;
|
||||
|
||||
if (completed.Mission == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!systems.TryGetValue(system_address, out system)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unknown system \"{0}\" unable to assign that mission a target.", system_address
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!acceptedStations.TryGetValue(completed.Mission.MissionID, out accepted_station)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which station mission \"{0}\" was accepted.", completed.Mission.LocalisedName
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (faction.Equals(source_faction_name) && system_address == accepted_address) {
|
||||
/* This is the influence block for the origin of the mission.
|
||||
*/
|
||||
main_mission = new MissionCompleted(completed) {
|
||||
System = accepted_system,
|
||||
Faction = source_faction_name,
|
||||
SystemAddress = accepted_address,
|
||||
Station = accepted_station,
|
||||
};
|
||||
results.Add(main_mission);
|
||||
} else if (!faction.Equals(source_faction_name) ||
|
||||
(faction.Equals(source_faction_name) && system_address != accepted_address)) {
|
||||
/* This block is for secondary factions (first if), or if the secondary faction
|
||||
* is the same as the mission giver, but in another system (second if).
|
||||
*/
|
||||
results.Add(new InfluenceSupport() {
|
||||
Faction = faction,
|
||||
Influence = influences.Value,
|
||||
System = system,
|
||||
SystemAddress = system_address,
|
||||
RelevantMission = completed
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (e.Is(Events.MissionAccepted)) {
|
||||
MissionAcceptedEntry? accepted = e as MissionAcceptedEntry;
|
||||
|
||||
if (accepted == null ||
|
||||
current_station == null ||
|
||||
current_system_address == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (accepted.Mission == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ulong id = accepted.Mission.MissionID;
|
||||
|
||||
if (!acceptedMissions.ContainsKey(id)) {
|
||||
acceptedMissions[id] = accepted;
|
||||
}
|
||||
if (!acceptedStations.ContainsKey(id)) {
|
||||
acceptedStations[id] = current_station;
|
||||
}
|
||||
if (!acceptedSystems.ContainsKey(id)) {
|
||||
acceptedSystems[id] = current_system_address.Value;
|
||||
}
|
||||
} else if (e.Is(Events.MissionFailed)) {
|
||||
MissionFailedEntry? failed = e as MissionFailedEntry;
|
||||
MissionAcceptedEntry? accepted = null;
|
||||
ulong accepted_address = 0;
|
||||
string? accepted_system;
|
||||
string? accepted_station;
|
||||
|
||||
if (failed == null || failed.Mission == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!acceptedMissions.TryGetValue(failed.Mission.MissionID, out accepted)) {
|
||||
OnLog?.Invoke("A mission failed which wasn't accepted in the given time frame. " +
|
||||
"Please adjust start date to when the mission was accepted to include it in the list.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (accepted.Mission == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!acceptedSystems.TryGetValue(failed.Mission.MissionID, out accepted_address)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which system mission \"{0}\" was accepted.", accepted.Mission.Name
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!systems.TryGetValue(accepted_address, out accepted_system)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which system mission \"{0}\" was accepted.", accepted.Mission.Name
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!acceptedStations.TryGetValue(failed.Mission.MissionID, out accepted_station)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which station mission \"{0}\" was accepted.", accepted.Mission.Name
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
results.Add(new MissionFailed(accepted) {
|
||||
Failed = failed,
|
||||
System = accepted_system,
|
||||
Station = accepted_station,
|
||||
Faction = accepted.Mission.Faction,
|
||||
SystemAddress = accepted_address,
|
||||
});
|
||||
|
||||
/* Mission failed should be collated if they are in the same system/station
|
||||
*/
|
||||
collate = true;
|
||||
} else if (e.Is(Events.SellExplorationData)) {
|
||||
SellExplorationDataEntry? explo = e as SellExplorationDataEntry;
|
||||
|
||||
if (explo == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.Add(new Cartographics(explo) {
|
||||
System = current_system,
|
||||
Station = current_station,
|
||||
Faction = controlling_faction,
|
||||
});
|
||||
|
||||
/* colate single cartographic selling into one */
|
||||
collate = true;
|
||||
} else if (e.Is(Events.SellOrganicData)) {
|
||||
SellOrganicDataEntry? organic = e as SellOrganicDataEntry;
|
||||
|
||||
if (organic == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* organic data sold to Vista Genomics */
|
||||
results.Add(new OrganicData(organic) {
|
||||
System = current_system,
|
||||
Station = current_station,
|
||||
Faction = controlling_faction,
|
||||
});
|
||||
|
||||
collate = true;
|
||||
} else if (e.Is(Events.MultiSellExplorationData)) {
|
||||
MultiSellExplorationDataEntry? explo = e as MultiSellExplorationDataEntry;
|
||||
|
||||
if (explo == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* For multi-sell-exploraton-data only the controlling faction of the station sold to matters.
|
||||
*/
|
||||
results.Add(new Cartographics(explo) {
|
||||
System = current_system,
|
||||
Station = current_station,
|
||||
Faction = controlling_faction
|
||||
});
|
||||
|
||||
collate = true;
|
||||
} else if (e.Is(Events.RedeemVoucher)) {
|
||||
RedeemVoucherEntry? voucher = e as RedeemVoucherEntry;
|
||||
List<Faction> current_factions = new List<Faction>();
|
||||
|
||||
if (voucher == null || current_system == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (system_factions.ContainsKey(current_system)) {
|
||||
current_factions = system_factions[current_system];
|
||||
} else {
|
||||
OnLog?.Invoke("There are no current system factions, so turned in vouchers were ignored.");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (string faction in voucher.Factions) {
|
||||
if (current_factions.Find(x => x.Name == faction) == null) {
|
||||
OnLog?.Invoke(
|
||||
string.Format("Vouchers for \"{0}\" were ignored in \"{1}\" since said " +
|
||||
"faction is not present there.", faction, current_system)
|
||||
);
|
||||
continue; /* faction is not present, so it is ignored */
|
||||
}
|
||||
|
||||
/* Same for selling combat vouchers. Only the current controlling faction matters here.
|
||||
*/
|
||||
results.Add(new Vouchers(voucher) {
|
||||
System = current_system,
|
||||
Station = current_station,
|
||||
Faction = faction,
|
||||
ControllingFaction = controlling_faction,
|
||||
});
|
||||
}
|
||||
|
||||
collate = true;
|
||||
} else if (e.Is(Events.SellMicroResources)) {
|
||||
SellMicroResourcesEntry? smr = e as SellMicroResourcesEntry;
|
||||
|
||||
if (smr == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.Add(new SellMicroResources(smr) {
|
||||
Faction = controlling_faction,
|
||||
Station = current_station,
|
||||
System = current_system
|
||||
});
|
||||
} else if (e.Is(Events.MarketBuy)) {
|
||||
MarketBuyEntry? buy = e as MarketBuyEntry;
|
||||
|
||||
if (buy == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(buy.Type) || buy.BuyPrice == 0) {
|
||||
continue;
|
||||
}
|
||||
buyCost[buy.Type] = buy.BuyPrice;
|
||||
|
||||
results.Add(new BuyCargo(buy) {
|
||||
Faction = controlling_faction,
|
||||
Station = current_station,
|
||||
System = current_system,
|
||||
});
|
||||
|
||||
collate = true;
|
||||
} else if (e.Is(Events.SearchAndRescue)) {
|
||||
SearchAndRescueEntry? sar = e as SearchAndRescueEntry;
|
||||
|
||||
if (sar == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.Add(new SearchAndRescue(sar) {
|
||||
Faction = controlling_faction,
|
||||
Station = current_station,
|
||||
System = current_system,
|
||||
});
|
||||
|
||||
collate = true;
|
||||
} else if (e.Is(Events.MarketSell)) {
|
||||
MarketSellEntry? sell = e as MarketSellEntry;
|
||||
long profit = 0;
|
||||
|
||||
if (sell == null || sell.Type == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!buyCost.ContainsKey(sell.Type)) {
|
||||
OnLog?.Invoke("Could not find buy order for the given commodity. Please adjust profit manually.");
|
||||
} else {
|
||||
long avg = buyCost[sell.Type];
|
||||
profit = (long)sell.TotalSale - (avg * sell.Count);
|
||||
}
|
||||
|
||||
results.Add(new SellCargo(sell) {
|
||||
Faction = controlling_faction,
|
||||
Station = current_station,
|
||||
System = current_system,
|
||||
Profit = profit
|
||||
});
|
||||
}
|
||||
|
||||
if (results == null || results.Count <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (Transaction entry in results) {
|
||||
/* Find all objectives that generally match.
|
||||
*/
|
||||
var matches = objectives
|
||||
.Where(x => x.Matches(entry) >= 2)
|
||||
.OrderBy(x => x.Matches(entry))
|
||||
;
|
||||
|
||||
Objective? objective = null;
|
||||
if (matches != null && matches.Count() > 0) {
|
||||
/* Then select the one that matches the most.
|
||||
*/
|
||||
objective = matches
|
||||
.OrderBy(x => x.Matches(entry))
|
||||
.Reverse()
|
||||
.First()
|
||||
;
|
||||
} else {
|
||||
/* create a new objective if we don't have one */
|
||||
objective = new Objective() {
|
||||
Station = (entry.Station ?? ""),
|
||||
Faction = (entry.Faction ?? ""),
|
||||
System = (entry.System ?? ""),
|
||||
};
|
||||
objectives.Add(objective);
|
||||
}
|
||||
|
||||
Transaction? existing = null;
|
||||
|
||||
existing = objective.LogEntries.Find(x => {
|
||||
try {
|
||||
return x.CompareTo(entry) == 0;
|
||||
} catch (NotImplementedException) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (collate && existing != null) {
|
||||
existing.Entries.Add(e);
|
||||
} else if (!collate || existing == null) {
|
||||
objective.LogEntries.Add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Scan(PlayerJournal journal) {
|
||||
Scan(journal, DateTime.Now, DateTime.Now);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,4 @@
|
||||
using EDPlayerJournal.Entries;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
|
||||
@@ -25,10 +20,18 @@ public class ThargoidKill : Transaction {
|
||||
get { return (ulong)Entries.OfType<FactionKillBondEntry>().Sum(x => (decimal)x.Reward); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kiling thargoids contributes to the system wide effort of
|
||||
/// the thargoid war.
|
||||
/// </summary>
|
||||
public override bool SystemContribution {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public ThargoidKill() { }
|
||||
|
||||
public ThargoidKill(FactionKillBondEntry entry) {
|
||||
if (string.Compare(entry.VictimFaction, Thargoid.ThargoidFaction) != 0) {
|
||||
if (!Factions.IsThargoid(entry.VictimFaction)) {
|
||||
throw new Exception("Not a valid thargoid kill");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,52 @@
|
||||
using EDPlayerJournal.Entries;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
|
||||
public class Transaction : IComparable<Transaction> {
|
||||
public List<Entry> Entries { get; } = new List<Entry>();
|
||||
|
||||
public virtual string CompletedAt {
|
||||
public string CompletedAt {
|
||||
get {
|
||||
DateTime? datetime = CompletedAtDateTime;
|
||||
if (datetime == null) {
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
return datetime.Value.ToString("dd.MM.yyyy HH:mm UTC");
|
||||
}
|
||||
}
|
||||
|
||||
public virtual DateTime? CompletedAtDateTime {
|
||||
get {
|
||||
var items = Entries
|
||||
.OrderBy(x => x.Timestamp)
|
||||
.ToArray()
|
||||
;
|
||||
if (items == null || items.Length == 0) {
|
||||
return "Unknown";
|
||||
return null;
|
||||
}
|
||||
|
||||
Entry last = items.Last();
|
||||
return last.Timestamp.ToString("dd.MM.yyyy HH:mm UTC");
|
||||
return last.Timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the transaction helps the entire system.
|
||||
/// While all transactions are related to one faction, sometimes their
|
||||
/// overall effect on the system as a whole is more important, than to
|
||||
/// their faction. For example, rescuing refugees helps the Thargoid war
|
||||
/// effort in the system as a whole, not just for the faction.
|
||||
/// So this is true for transactions that help the system as a whole.
|
||||
/// </summary>
|
||||
public virtual bool SystemContribution { get; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this transaction was completed in legacy ED
|
||||
/// </summary>
|
||||
public bool IsLegacy { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Controlling faction of the station this entry was made/turned into.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using EDPlayerJournal.Entries;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using EDPlayerJournal;
|
||||
using EDPlayerJournal.Entries;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
|
||||
@@ -10,10 +9,51 @@ 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; }
|
||||
|
||||
public bool HaveSeenCapShip { get; set; } = false;
|
||||
public bool HaveSeenCaptain { get; set; } = false;
|
||||
public bool HaveSeenSpecOps { get; set; } = false;
|
||||
public bool HaveSeenCorrespondent { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the current session is legacy
|
||||
/// </summary>
|
||||
public bool IsLegacy { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// How many on foot kills were done.
|
||||
/// </summary>
|
||||
public ulong OnFootKills { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// How many ship kills were done.
|
||||
/// </summary>
|
||||
public ulong ShipKills { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Thargoid scouts killed
|
||||
/// </summary>
|
||||
public ulong ThargoidScoutKills { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Thargoid interceptor kills
|
||||
/// </summary>
|
||||
public ulong ThargoidInterceptorKills { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Whether we have seen an AX warzone NPC talk to us with ReceiveText
|
||||
/// </summary>
|
||||
public bool HaveSeenAXWarzoneNPC { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// A list of accepted missions index by their mission ID
|
||||
/// </summary>
|
||||
public Dictionary<ulong, MissionAcceptedEntry> AcceptedMissions { get; } = new();
|
||||
public Dictionary<ulong, Mission> AcceptedMissions { get; } = new();
|
||||
public Dictionary<ulong, Location> AcceptedMissionLocation { get; } = new();
|
||||
/// <summary>
|
||||
/// A way to lookup a system by its system id
|
||||
@@ -32,6 +72,106 @@ internal class TransactionParserContext {
|
||||
/// </summary>
|
||||
public Dictionary<string, long> BuyCost = new();
|
||||
|
||||
public void DiscernCombatZone(TransactionList transactions, Entry e) {
|
||||
string? grade = CombatZones.DifficultyLow;
|
||||
string cztype;
|
||||
ulong highest = HighestCombatBond ?? 0;
|
||||
string? faction = LastRecordedAwardingFaction;
|
||||
|
||||
if (HighestCombatBond == null &&
|
||||
LastRecordedAwardingFaction == null &&
|
||||
HaveSeenAXWarzoneNPC == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (OnFootKills > 0 || IsOnFoot == true) {
|
||||
cztype = CombatZones.GroundCombatZone;
|
||||
// High on foot combat zones have enforcers that bring 80k a pop
|
||||
if (highest >= 60000) {
|
||||
grade = CombatZones.DifficultyHigh;
|
||||
} else if (highest >= 30000) {
|
||||
// In medium conflict zones, the enforcers are worth 30k
|
||||
grade = CombatZones.DifficultyMedium;
|
||||
} else {
|
||||
grade = CombatZones.DifficultyLow;
|
||||
}
|
||||
} else if (ShipKills > 0 && !IsOnFoot) {
|
||||
// Ship combat zones can be identified by the amount of kills
|
||||
if (ShipKills > 20) {
|
||||
grade = CombatZones.DifficultyHigh;
|
||||
} else if (ShipKills > 10) {
|
||||
grade = CombatZones.DifficultyMedium;
|
||||
}
|
||||
|
||||
// Cap ship, means a high conflict zone
|
||||
if (HaveSeenCapShip) {
|
||||
grade = CombatZones.DifficultyHigh;
|
||||
} else {
|
||||
int warzoneNpcs = new List<bool>() { HaveSeenCaptain, HaveSeenCorrespondent, HaveSeenSpecOps }
|
||||
.Where(x => x == true)
|
||||
.Count()
|
||||
;
|
||||
|
||||
if (warzoneNpcs >= 1 && grade == CombatZones.DifficultyLow) {
|
||||
grade = CombatZones.DifficultyMedium;
|
||||
}
|
||||
}
|
||||
cztype = CombatZones.ShipCombatZone;
|
||||
} else if ((ThargoidScoutKills > 0 && ThargoidInterceptorKills > 0) ||
|
||||
HaveSeenAXWarzoneNPC == true) {
|
||||
// Could be a thargoid combat zones if interceptors and scouts are there
|
||||
cztype = CombatZones.AXCombatZone;
|
||||
// Still unknown
|
||||
grade = null;
|
||||
} else {
|
||||
transactions.AddIncomplete(new CombatZone(), "Failed to discern combat zone type", e);
|
||||
return;
|
||||
}
|
||||
|
||||
CombatZone zone = new CombatZone() {
|
||||
System = CurrentSystem,
|
||||
Faction = faction,
|
||||
IsLegacy = IsLegacy,
|
||||
Grade = grade,
|
||||
Type = cztype,
|
||||
// Sad truth is, if HaveSeenXXX is false, we just don't know for certain
|
||||
CapitalShip = HaveSeenCapShip ? true : null,
|
||||
SpecOps = HaveSeenSpecOps ? true : null,
|
||||
Correspondent = HaveSeenCorrespondent ? true : null,
|
||||
Captain = HaveSeenCaptain ? true : null,
|
||||
};
|
||||
zone.Entries.Add(e);
|
||||
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;
|
||||
HaveSeenCapShip = false;
|
||||
HaveSeenCaptain = false;
|
||||
HaveSeenCorrespondent = false;
|
||||
HaveSeenSpecOps = false;
|
||||
LastRecordedAwardingFaction = null;
|
||||
OnFootKills = 0;
|
||||
ShipKills = 0;
|
||||
ThargoidInterceptorKills = 0;
|
||||
ThargoidScoutKills = 0;
|
||||
HaveSeenAXWarzoneNPC = false;
|
||||
}
|
||||
|
||||
public void BoughtCargo(string? cargo, long? cost) {
|
||||
if (cargo == null || cost == null) {
|
||||
return;
|
||||
@@ -48,16 +188,24 @@ internal class TransactionParserContext {
|
||||
return SystemFactions[system];
|
||||
}
|
||||
|
||||
public void MissionAccepted(MissionAcceptedEntry accepted) {
|
||||
public void MissionAccepted(MissionAcceptedEntry? entry) {
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MissionAccepted(entry.Mission);
|
||||
}
|
||||
|
||||
public void MissionAccepted(Mission? mission) {
|
||||
if (CurrentSystem == null || CurrentSystemAddress == null) {
|
||||
throw new Exception("Mission accepted without knowing where.");
|
||||
}
|
||||
|
||||
if (accepted.Mission == null) {
|
||||
if (mission == null) {
|
||||
throw new Exception("Mission is null");
|
||||
}
|
||||
|
||||
AcceptedMissions.TryAdd(accepted.Mission.MissionID, accepted);
|
||||
AcceptedMissions.TryAdd(mission.MissionID, mission);
|
||||
|
||||
Location location = new() {
|
||||
StarSystem = CurrentSystem,
|
||||
@@ -65,13 +213,13 @@ internal class TransactionParserContext {
|
||||
Station = (CurrentStation ?? ""),
|
||||
};
|
||||
|
||||
AcceptedMissionLocation.TryAdd(accepted.Mission.MissionID, location);
|
||||
AcceptedMissionLocation.TryAdd(mission.MissionID, location);
|
||||
}
|
||||
}
|
||||
|
||||
public class TransactionList : List<Transaction> {
|
||||
public void AddIncomplete(Transaction underlying, string reason) {
|
||||
Add(new IncompleteTransaction(underlying, reason));
|
||||
public void AddIncomplete(Transaction underlying, string reason, Entry entry) {
|
||||
Add(new IncompleteTransaction(underlying, reason, entry));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +286,12 @@ internal class FSDJumpParser : TransactionParserPart {
|
||||
throw new InvalidJournalEntryException();
|
||||
}
|
||||
|
||||
// If you FSD jump straight out of the combat zone into a different system
|
||||
// then the combat zone will be placed in the wrong system otherwise.
|
||||
// This call needs to be *before* changing the current system.
|
||||
context.DiscernCombatZone(transactions, e);
|
||||
context.ResetCombatZone();
|
||||
|
||||
context.CurrentSystem = entry.StarSystem;
|
||||
context.CurrentSystemAddress = entry.SystemAddress;
|
||||
|
||||
@@ -197,6 +351,21 @@ internal class ShipTargetedParser : TransactionParserPart {
|
||||
!string.IsNullOrEmpty(entry.Faction)) {
|
||||
context.NPCFaction.TryAdd(entry.PilotNameLocalised, entry.Faction);
|
||||
}
|
||||
|
||||
// We have seen a captain?
|
||||
if (NPCs.IsWarzoneCaptain(entry.PilotName)) {
|
||||
context.HaveSeenCaptain = true;
|
||||
}
|
||||
|
||||
// Spec ops?
|
||||
if (NPCs.IsSpecOps(entry.PilotName)) {
|
||||
context.HaveSeenSpecOps = true;
|
||||
}
|
||||
|
||||
// Correspondent?
|
||||
if (NPCs.IsWarzoneCorrespondent(entry.PilotName)) {
|
||||
context.HaveSeenCorrespondent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,20 +397,64 @@ internal class CommitCrimeParser : TransactionParserPart {
|
||||
victim = "Unknown";
|
||||
}
|
||||
|
||||
string faction;
|
||||
|
||||
if (entry.IsCrime(CrimeTypes.OnFootMurder)) {
|
||||
if (entry.Faction == null) {
|
||||
transactions.AddIncomplete(
|
||||
new FoulMurder(),
|
||||
"On foot murder victim did not have a faction", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
// On foot murders are different, there the faction is
|
||||
// the faction the NPC belonged too
|
||||
faction = entry.Faction;
|
||||
} else {
|
||||
if (!context.NPCFaction.ContainsKey(victim)) {
|
||||
transactions.AddIncomplete(
|
||||
new FoulMurder(),
|
||||
"Crime victim was not properly scanned."
|
||||
"Crime victim was not properly scanned.", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
faction = context.NPCFaction[victim];
|
||||
}
|
||||
|
||||
transactions.Add(new FoulMurder(entry) {
|
||||
System = context.CurrentSystem,
|
||||
IsLegacy = context.IsLegacy,
|
||||
Faction = faction,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
internal class MissionsParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
MissionsEntry? missions = entry as MissionsEntry;
|
||||
|
||||
if (missions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.CurrentSystem == null || context.CurrentSystemAddress == null) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
"Could not determine current location on Missions event.",
|
||||
entry
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
string faction = context.NPCFaction[victim];
|
||||
|
||||
transactions.Add(new FoulMurder(entry) {
|
||||
System = context.CurrentSystem,
|
||||
Faction = faction,
|
||||
});
|
||||
foreach (Mission mission in missions.Active) {
|
||||
try {
|
||||
context.MissionAccepted(mission);
|
||||
} catch (Exception exception) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
exception.Message,
|
||||
entry
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +467,8 @@ internal class MissionAcceptedParser : TransactionParserPart {
|
||||
|
||||
if (context.CurrentSystem == null || context.CurrentSystemAddress == null) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
"Could not determine current location on mission acceptance."
|
||||
"Could not determine current location on mission acceptance.",
|
||||
e
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -263,7 +477,8 @@ internal class MissionAcceptedParser : TransactionParserPart {
|
||||
context.MissionAccepted(entry);
|
||||
} catch (Exception exception) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
exception.Message
|
||||
exception.Message,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -276,23 +491,23 @@ internal class MissionCompletedParser : TransactionParserPart {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
MissionAcceptedEntry? accepted = null;
|
||||
Mission? mission = null;
|
||||
Location? accepted_location = null;
|
||||
string? target_faction_name = entry.Mission.TargetFaction;
|
||||
string? source_faction_name = entry.Mission.Faction;
|
||||
|
||||
// We did not find when the mission was accepted.
|
||||
if (!context.AcceptedMissions.TryGetValue(entry.Mission.MissionID, out accepted)) {
|
||||
if (!context.AcceptedMissions.TryGetValue(entry.Mission.MissionID, out mission)) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
String.Format("Mission acceptance for mission id {0} was not found",
|
||||
entry.Mission.MissionID));
|
||||
entry.Mission.MissionID), e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.AcceptedMissionLocation.TryGetValue(entry.Mission.MissionID, out accepted_location)) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
String.Format("Location for acceptance for mission id {0} was not found",
|
||||
entry.Mission.MissionID));
|
||||
entry.Mission.MissionID), e);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -340,7 +555,8 @@ internal class MissionCompletedParser : TransactionParserPart {
|
||||
|
||||
if (!context.SystemsByID.TryGetValue(system_address, out system)) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
string.Format("Unknown system {0}, unable to assign that mission a target", system_address)
|
||||
string.Format("Unknown system {0}, unable to assign that mission a target", system_address),
|
||||
e
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -349,11 +565,14 @@ internal class MissionCompletedParser : TransactionParserPart {
|
||||
system_address == accepted_location.SystemAddress) {
|
||||
// Source and target faction are the same, and this is the block
|
||||
// for the source system. So we make a full mission completed entry.
|
||||
transactions.Add(new MissionCompleted(entry) {
|
||||
transactions.Add(new MissionCompleted() {
|
||||
CompletedEntry = entry,
|
||||
Mission = mission,
|
||||
System = accepted_location.StarSystem,
|
||||
Faction = source_faction_name,
|
||||
SystemAddress = accepted_location.SystemAddress,
|
||||
Station = accepted_location.Station,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
} else if (string.Compare(faction, source_faction_name, true) != 0 ||
|
||||
(string.Compare(faction, source_faction_name) == 0 &&
|
||||
@@ -362,11 +581,13 @@ internal class MissionCompletedParser : TransactionParserPart {
|
||||
// differs. Sometimes missions go to different systems but to
|
||||
// the same faction.
|
||||
transactions.Add(new InfluenceSupport() {
|
||||
Mission = mission,
|
||||
Faction = faction,
|
||||
Influence = influences.Value,
|
||||
System = system,
|
||||
SystemAddress = system_address,
|
||||
RelevantMission = entry,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -376,7 +597,7 @@ internal class MissionCompletedParser : TransactionParserPart {
|
||||
|
||||
internal class MissionFailedParser : TransactionParserPart {
|
||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
||||
MissionAcceptedEntry? accepted = null;
|
||||
Mission? mission = null;
|
||||
Location? accepted_location = null;
|
||||
string? accepted_system = null;
|
||||
|
||||
@@ -389,34 +610,42 @@ internal class MissionFailedParser : TransactionParserPart {
|
||||
throw new InvalidJournalEntryException("No mission specified in mission failure");
|
||||
}
|
||||
|
||||
if (!context.AcceptedMissions.TryGetValue(entry.Mission.MissionID, out accepted)) {
|
||||
if (!context.AcceptedMissions.TryGetValue(entry.Mission.MissionID, out mission)) {
|
||||
transactions.AddIncomplete(new MissionFailed(),
|
||||
"Mission acceptance was not found"
|
||||
"Mission acceptance was not found", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.AcceptedMissionLocation.TryGetValue(entry.Mission.MissionID, out accepted_location)) {
|
||||
if (!context.AcceptedMissionLocation.TryGetValue(mission.MissionID, out accepted_location)) {
|
||||
transactions.AddIncomplete(new MissionFailed(),
|
||||
"Unable to figure out where failed mission was accepted"
|
||||
"Unable to figure out where failed mission was accepted", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.SystemsByID.TryGetValue(accepted_location.SystemAddress, out accepted_system)) {
|
||||
transactions.AddIncomplete(new MissionFailed(),
|
||||
"Unable to figure out in which system failed mission was accepted"
|
||||
"Unable to figure out in which system failed mission was accepted", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
transactions.Add(new MissionFailed() {
|
||||
Accepted = accepted,
|
||||
Faction = accepted.Mission?.Faction,
|
||||
Failed = entry,
|
||||
if (string.IsNullOrEmpty(mission.Faction)) {
|
||||
transactions.AddIncomplete(new MissionFailed(),
|
||||
"Could not determine for what faction you failed a mission. This happens if the " +
|
||||
"mission acceptance is not within the given time frame.",
|
||||
entry
|
||||
);
|
||||
}
|
||||
|
||||
transactions.Add(new MissionFailed(entry) {
|
||||
Faction = mission?.Faction,
|
||||
Mission = mission,
|
||||
Station = accepted_location.Station,
|
||||
System = accepted_location.StarSystem,
|
||||
SystemAddress = accepted_location.SystemAddress,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -432,6 +661,7 @@ internal class SellExplorationDataParser : TransactionParserPart {
|
||||
System = context.CurrentSystem,
|
||||
Station = context.CurrentStation,
|
||||
Faction = context.ControllingFaction,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -447,6 +677,7 @@ internal class SellOrganicDataParser : TransactionParserPart {
|
||||
System = context.CurrentSystem,
|
||||
Station = context.CurrentStation,
|
||||
Faction = context.ControllingFaction,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -462,6 +693,7 @@ internal class MultiSellExplorationDataParser : TransactionParserPart {
|
||||
System = context.CurrentSystem,
|
||||
Station = context.CurrentStation,
|
||||
Faction = context.ControllingFaction,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -475,7 +707,7 @@ internal class RedeemVoucherParser : TransactionParserPart {
|
||||
|
||||
if (context.CurrentSystem == null) {
|
||||
transactions.AddIncomplete(new Vouchers(),
|
||||
"Could not find out where the vouchers were redeemed"
|
||||
"Could not find out where the vouchers were redeemed", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -483,27 +715,44 @@ internal class RedeemVoucherParser : TransactionParserPart {
|
||||
List<Faction>? current_factions = context.GetFactions(context.CurrentSystem);
|
||||
if (current_factions == null) {
|
||||
transactions.AddIncomplete(new Vouchers(),
|
||||
"Current system factions are unknown, so vouchers were ineffective");
|
||||
return;
|
||||
"Current system factions are unknown, so vouchers were ineffective", e);
|
||||
}
|
||||
|
||||
foreach (string faction in entry.Factions) {
|
||||
if (current_factions.Find(x => string.Compare(x.Name, faction, true) == 0) == null) {
|
||||
transactions.AddIncomplete(new Vouchers(),
|
||||
string.Format("Vouchers for {0} were ignored in {1} since said " +
|
||||
"faction is not present here", faction, context.CurrentSystem)
|
||||
);
|
||||
continue;
|
||||
bool relevantBond = false;
|
||||
string relevantFaction = faction;
|
||||
|
||||
if (string.Compare(faction, Factions.PilotsFederationVouchers) == 0) {
|
||||
// Target faction is pilots' federation, so we assume thargoid bonks
|
||||
// Also assign this combat bond to the Pilots Federation
|
||||
relevantFaction = Factions.PilotsFederation;
|
||||
relevantBond = true;
|
||||
}
|
||||
|
||||
if (current_factions != null && !relevantBond) {
|
||||
// If we have local factions, and it ain't thargoid bonds see if the bonds were
|
||||
// useful in the current system
|
||||
if (current_factions.Find(x => string.Compare(x.Name, faction, true) == 0) != null) {
|
||||
relevantBond = true;
|
||||
} else {
|
||||
transactions.AddIncomplete(new Vouchers(),
|
||||
string.Format("Vouchers for \"{0}\" had no effect in \"{1}\" since said " +
|
||||
"faction is not present there", faction, context.CurrentSystem), e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (relevantBond) {
|
||||
transactions.Add(new Vouchers(entry) {
|
||||
System = context.CurrentSystem,
|
||||
Station = context.CurrentStation,
|
||||
Faction = faction,
|
||||
Faction = relevantFaction,
|
||||
ControllingFaction = context.ControllingFaction,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class SellMicroResourcesParser : TransactionParserPart {
|
||||
@@ -517,6 +766,7 @@ internal class SellMicroResourcesParser : TransactionParserPart {
|
||||
System = context.CurrentSystem,
|
||||
Station = context.CurrentStation,
|
||||
Faction = context.ControllingFaction,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -532,6 +782,7 @@ internal class SearchAndRescueParser : TransactionParserPart {
|
||||
Faction = context.ControllingFaction,
|
||||
Station = context.CurrentStation,
|
||||
System = context.CurrentSystem,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -549,6 +800,7 @@ internal class MarketBuyParser : TransactionParserPart {
|
||||
Faction = context.ControllingFaction,
|
||||
Station = context.CurrentStation,
|
||||
System = context.CurrentSystem,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -576,6 +828,7 @@ internal class MarketSellParser : TransactionParserPart {
|
||||
Station = context.CurrentStation,
|
||||
System = context.CurrentSystem,
|
||||
Profit = profit,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -587,19 +840,135 @@ internal class FactionKillBondParser : TransactionParserPart {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
if (string.Compare(entry.VictimFaction, Thargoid.ThargoidFaction) == 0) {
|
||||
if (Factions.IsThargoid(entry.VictimFaction)) {
|
||||
// Thargoid bonk
|
||||
transactions.Add(new ThargoidKill(entry));
|
||||
transactions.Add(new ThargoidKill(entry) {
|
||||
System = context.CurrentSystem,
|
||||
Faction = Factions.PilotsFederation,
|
||||
Station = context.CurrentStation,
|
||||
IsLegacy = context.IsLegacy,
|
||||
});
|
||||
|
||||
ThargoidVessel vessel = Thargoid.GetVesselByPayout(entry.Reward);
|
||||
if (vessel != ThargoidVessel.Unknown) {
|
||||
if (vessel == ThargoidVessel.Scout) {
|
||||
++context.ThargoidScoutKills;
|
||||
} else {
|
||||
++context.ThargoidInterceptorKills;
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// After a super cruise entry we are no longer on foot.
|
||||
context.IsOnFoot = false;
|
||||
context.DiscernCombatZone(transactions, entry);
|
||||
context.ResetCombatZone();
|
||||
}
|
||||
}
|
||||
|
||||
internal class ShutdownParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
context.DiscernCombatZone(transactions, entry);
|
||||
context.ResetCombatZone();
|
||||
}
|
||||
}
|
||||
|
||||
internal class CapShipBondParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
if (entry.GetType() != typeof(CapShipBondEntry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.HaveSeenCapShip = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal class FileHeaderParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
FileHeaderEntry? fileheader = entry as FileHeaderEntry;
|
||||
|
||||
if (fileheader == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.IsLegacy = fileheader.IsLegacy;
|
||||
}
|
||||
}
|
||||
|
||||
internal class ReceiveTextParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
ReceiveTextEntry? receivetext = entry as ReceiveTextEntry;
|
||||
|
||||
if (receivetext == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Compare(receivetext.Channel, Channels.NPC) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Compare(receivetext.NPCCategory, NPCs.AXMilitary) == 0) {
|
||||
context.HaveSeenAXWarzoneNPC = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class DiedParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
// You can't complete a combat zone if you die in it. Others might keep it open
|
||||
// for you, but still you will not have completed it unless you jump back in.
|
||||
context.ResetCombatZone();
|
||||
}
|
||||
}
|
||||
|
||||
internal class DropshipDeployParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
// On drop ship deploy we are now on foot
|
||||
context.IsOnFoot = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal class CommanderParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
// A commander entry happens when you log out, and log back in again
|
||||
// for example when switching from Open, to Solo or PG.
|
||||
context.DiscernCombatZone(transactions, entry);
|
||||
context.ResetCombatZone();
|
||||
}
|
||||
}
|
||||
|
||||
public class TransactionParser {
|
||||
private static Dictionary<string, TransactionParserPart> ParserParts { get; } = new()
|
||||
{
|
||||
{ Events.CapShipBond, new CapShipBondParser() },
|
||||
{ Events.Commander, new CommanderParser() },
|
||||
{ Events.CommitCrime, new CommitCrimeParser() },
|
||||
{ Events.Died, new DiedParser() },
|
||||
{ Events.Disembark, new EmbarkDisembarkParser() },
|
||||
{ Events.Docked, new DockedParser() },
|
||||
{ Events.DropshipDeploy, new DropshipDeployParser() },
|
||||
{ Events.Embark, new EmbarkDisembarkParser() },
|
||||
{ Events.FactionKillBond, new FactionKillBondParser() },
|
||||
{ Events.FileHeader, new FileHeaderParser() },
|
||||
{ Events.FSDJump, new FSDJumpParser() },
|
||||
{ Events.Location, new LocationParser() },
|
||||
{ Events.MarketBuy, new MarketBuyParser() },
|
||||
@@ -607,15 +976,30 @@ public class TransactionParser {
|
||||
{ Events.MissionAccepted, new MissionAcceptedParser() },
|
||||
{ Events.MissionCompleted, new MissionCompletedParser() },
|
||||
{ Events.MissionFailed, new MissionFailedParser() },
|
||||
{ Events.Missions, new MissionsParser() },
|
||||
{ Events.MultiSellExplorationData, new MultiSellExplorationDataParser() },
|
||||
{ Events.ReceiveText, new ReceiveTextParser() },
|
||||
{ Events.RedeemVoucher, new RedeemVoucherParser() },
|
||||
{ Events.SearchAndRescue, new SearchAndRescueParser() },
|
||||
{ Events.SellExplorationData, new SellExplorationDataParser() },
|
||||
{ Events.SellMicroResources, new SellMicroResourcesParser() },
|
||||
{ Events.SellOrganicData, new SellOrganicDataParser() },
|
||||
{ Events.ShipTargeted, new ShipTargetedParser() },
|
||||
{ Events.Shutdown, new ShutdownParser() },
|
||||
{ Events.SupercruiseEntry, new SupercruiseEntryParser() },
|
||||
};
|
||||
|
||||
public bool IsRelevant(string entry) {
|
||||
return ParserParts.ContainsKey(entry);
|
||||
}
|
||||
|
||||
public bool IsRelevant(Entry e) {
|
||||
if (e.Event == null) {
|
||||
return false;
|
||||
}
|
||||
return IsRelevant(e.Event);
|
||||
}
|
||||
|
||||
public List<Transaction>? Parse(IEnumerable<Entry> entries) {
|
||||
TransactionList transactions = new();
|
||||
TransactionParserContext context = new();
|
||||
|
||||
@@ -13,6 +13,16 @@ public class Vouchers : Transaction {
|
||||
Entries.Add(e);
|
||||
}
|
||||
|
||||
public override bool SystemContribution {
|
||||
get {
|
||||
if (Faction == Factions.PilotsFederation && Type == "Combat Bond") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public long TotalSum {
|
||||
get {
|
||||
if (Faction == null) {
|
||||
@@ -20,8 +30,8 @@ public class Vouchers : Transaction {
|
||||
}
|
||||
return Entries
|
||||
.OfType<RedeemVoucherEntry>()
|
||||
.Where(x => x.FactionBounties.ContainsKey(Faction))
|
||||
.Sum(x => x.FactionBounties[Faction])
|
||||
.ToList()
|
||||
.Sum(x => (long)x.GetBountyForFaction(Faction))
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -39,9 +49,9 @@ public class Vouchers : Transaction {
|
||||
.First();
|
||||
if (v == null) {
|
||||
return null;
|
||||
} else if (v == "CombatBond") {
|
||||
} else if (v == Bonds.CombatBond) {
|
||||
type = "Combat Bond";
|
||||
} else if (v == "bounty") {
|
||||
} else if (v == Bonds.Bounty) {
|
||||
type = "Bounty";
|
||||
} else {
|
||||
type = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(v);
|
||||
|
||||
13
EDPlayerJournal/Bonds.cs
Normal file
13
EDPlayerJournal/Bonds.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace EDPlayerJournal;
|
||||
|
||||
public class Bonds {
|
||||
/// <summary>
|
||||
/// Internal string name for combat bonds.
|
||||
/// </summary>
|
||||
public static readonly string CombatBond = "CombatBond";
|
||||
|
||||
/// <summary>
|
||||
/// Internal string name for bounties.
|
||||
/// </summary>
|
||||
public static readonly string Bounty = "bounty";
|
||||
}
|
||||
8
EDPlayerJournal/Channels.cs
Normal file
8
EDPlayerJournal/Channels.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace EDPlayerJournal;
|
||||
|
||||
public class Channels {
|
||||
/// <summary>
|
||||
/// Channel NPCs use to talk to the commander.
|
||||
/// </summary>
|
||||
public static readonly string NPC = "npc";
|
||||
}
|
||||
41
EDPlayerJournal/CombatZones.cs
Normal file
41
EDPlayerJournal/CombatZones.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace EDPlayerJournal;
|
||||
|
||||
/// <summary>
|
||||
/// Static strings related to combat zones
|
||||
/// </summary>
|
||||
public class CombatZones {
|
||||
/// <summary>
|
||||
/// Type string for ground combat zone
|
||||
/// </summary>
|
||||
public static readonly string GroundCombatZone = "Ground";
|
||||
|
||||
/// <summary>
|
||||
/// Type string for ship combat zones
|
||||
/// </summary>
|
||||
public static readonly string ShipCombatZone = "Ship";
|
||||
|
||||
/// <summary>
|
||||
/// AX combat zone
|
||||
/// </summary>
|
||||
public static readonly string AXCombatZone = "AX";
|
||||
|
||||
/// <summary>
|
||||
/// Difficulty low
|
||||
/// </summary>
|
||||
public static readonly string DifficultyLow = "Low";
|
||||
|
||||
/// <summary>
|
||||
/// Difficulty medium
|
||||
/// </summary>
|
||||
public static readonly string DifficultyMedium = "Medium";
|
||||
|
||||
/// <summary>
|
||||
/// Difficulty high
|
||||
/// </summary>
|
||||
public static readonly string DifficultyHigh = "High";
|
||||
|
||||
/// <summary>
|
||||
/// Very high difficulty, so far AX combat zone only
|
||||
/// </summary>
|
||||
public static readonly string DifficultyVeryHigh = "Very High";
|
||||
}
|
||||
@@ -1,27 +1,27 @@
|
||||
using EDPlayerJournal.BGS;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System;
|
||||
|
||||
namespace EDPlayerJournal;
|
||||
namespace EDPlayerJournal;
|
||||
|
||||
public class EnglishMissionNames {
|
||||
public static Dictionary<string, string> MissionNames { get; } = new Dictionary<string, string>() {
|
||||
{"Chain_FindThePirateLord_name", "Assassination (Pirate Lord) (Chain)"},
|
||||
{"Chain_RegainFooting_name", "Regain Footing (Chain)"},
|
||||
{"Chain_SalvageJustice_name", "Assassination (Legal) (Chain)"},
|
||||
{"Mission_Altruism_Bust_name", "Donate (Bust)" },
|
||||
{"Mission_Altruism_CivilUnrest_name", "Donate (Civil Unrest)" },
|
||||
{"Mission_Altruism_name", "Donate"},
|
||||
{"Mission_Altruism_Outbreak_name", "Donate (Outbreak)" },
|
||||
{"Mission_AltruismCredits_Bust_name", "Donate Credits (Bust)"},
|
||||
{"Mission_AltruismCredits_CivilUnrest_name", "Donate Credits (Civil Unrest)" },
|
||||
{"Mission_AltruismCredits_Famine_name", "Donate Credits (Famine)"},
|
||||
{"Mission_AltruismCredits_name", "Donate Credits"},
|
||||
{"Mission_AltruismCredits_Outbreak_name", "Donate Credits (Outbreak)" },
|
||||
{"Mission_Assassinate_Illegal_BLOPS_name", "Assassination (Illegal)"},
|
||||
{"Mission_Assassinate_Legal_Corporate_name", "Corporate Assassination (Legal)"},
|
||||
{"Mission_Assassinate_Legal_Bust_name", "Assassination (Bust, Legal)" },
|
||||
{"MISSION_assassinate_legal_CivilUnrest_name", "Assassination (Civil Unrest, Legal)" },
|
||||
{"Mission_Assassinate_Legal_Communism_name", "Assassination (Communism, Legal)" },
|
||||
{"Mission_Assassinate_Legal_Corporate_name", "Assassination (Corporate, Legal)"},
|
||||
{"Mission_Assassinate_Legal_War_name", "Assassination (War, Legal)" },
|
||||
{"Mission_Assassinate_name", "Assassination"},
|
||||
{"Mission_Assassinate_Planetary_Expansion_name", "Assassination (Planetary Scan, Expansion)" },
|
||||
{"Mission_Assassinate_Planetary_name", "Assassination (Planetary Scan)"},
|
||||
{"Mission_Collect_Bust_name", "Provide (Bust)"},
|
||||
{"Mission_Collect_CivilLiberty_name", "Provide (Civil Liberty)"},
|
||||
@@ -29,8 +29,10 @@ public class EnglishMissionNames {
|
||||
{"Mission_Collect_Famine_name", "Provide (Famine)"},
|
||||
{"Mission_Collect_Industrial_name", "Provide (Industrial)"},
|
||||
{"Mission_Collect_name", "Provide"},
|
||||
{"Mission_Collect_Outbreak_name", "Provide (Outbreak)" },
|
||||
{"Mission_Collect_RankEmp_name", "Provide (Imperial Navy)"},
|
||||
{"Mission_Collect_Retreat_name", "Provide (Retreat)"},
|
||||
{"Mission_Courier_CivilUnrest_name", "Courier (Divil Unrest)" },
|
||||
{"Mission_Courier_Democracy_name", "Courier (Democracy)"},
|
||||
{"Mission_Courier_Elections_name", "Courier (Elections)"},
|
||||
{"Mission_Courier_Expansion_name", "Courier (Expansion)"},
|
||||
@@ -38,8 +40,10 @@ public class EnglishMissionNames {
|
||||
{"Mission_Courier_Lockdown_name", "Courier (Lockdown)"},
|
||||
{"Mission_Courier_name", "Courier"},
|
||||
{"Mission_Courier_RankEmp_name", "Courier (Imperial Navy)"},
|
||||
{"Mission_Courier_War_name", "Courier (War)" },
|
||||
{"Mission_Delivery_Agriculture_name", "Delivery (Agriculture)"},
|
||||
{"Mission_Delivery_Boom_name", "Delivery (Boom)"},
|
||||
{"Mission_Delivery_CivilUnrest_name", "Delivery (Civil Unrest)"},
|
||||
{"Mission_Delivery_Democracy_name", "Delivery (Democracy)"},
|
||||
{"Mission_Delivery_Investment_name", "Delivery (Investment)"},
|
||||
{"Mission_Delivery_name", "Delivery"},
|
||||
@@ -59,14 +63,19 @@ public class EnglishMissionNames {
|
||||
{"Mission_Massacre_RankEmp_name", "Massacre (Imperial Navy)"},
|
||||
{"Mission_MassacreWing_Legal_Bust_name", "Massacre (Wing) (Bust)"},
|
||||
{"Mission_MassacreWing_name", "Massacre (Wing)"},
|
||||
{"Mission_Mining_name", "Mining" },
|
||||
{"Mission_OnFoot_Assassination_MB_name", "On Foot Assassination"},
|
||||
{"Mission_OnFoot_AssassinationIllegal_MB_name", "On Foot Assassination (Illegal)"},
|
||||
{"Mission_OnFoot_AssassinationIllegal_NCD_MB_name", "On Foot Assassination (Illegal)" },
|
||||
{"Mission_OnFoot_Collect_Contact_MB_name", "On Foot Collect"},
|
||||
{"Mission_OnFoot_Collect_MB_name", "On Foot Collection"},
|
||||
{"Mission_OnFoot_Delivery_Contact_MB_name", "On Foot Delivery (Contact)"},
|
||||
{"Mission_OnFoot_Hack_Upload_Covert_MB_name", "On Foot Hack (Covert Upload)"},
|
||||
{"Mission_OnFoot_Hack_Upload_MB_name", "On Foot Hack (Upload)"},
|
||||
{"Mission_OnFoot_Heist_MB_name", "On Foot Heist" },
|
||||
{"Mission_OnFoot_Heist_POI_MB_name", "On Foot Heist (POI)"},
|
||||
{"Mission_OnFoot_Massacre_MB_name", "On Foot Massacre" },
|
||||
{"Mission_OnFoot_MassacreIllegal_MB_name", "On Foot Massacre (Illegal)" },
|
||||
{"Mission_OnFoot_Onslaught_MB_name", "On Foot Onslaught"},
|
||||
{"Mission_OnFoot_Onslaught_Offline_MB_name", "On Foot Onslaught (Offline)"},
|
||||
{"Mission_OnFoot_ProductionHeist_Covert_MB_name", "On Foot Production Heist (Covert)"},
|
||||
@@ -76,13 +85,16 @@ public class EnglishMissionNames {
|
||||
{"Mission_OnFoot_Sabotage_Production_Covert_MB_name", "On Foot Sabotage Production (Covert)"},
|
||||
{"Mission_OnFoot_Salvage_MB_name", "On Foot Salvage"},
|
||||
{"Mission_OnFoot_SalvageIllegal_MB_name", "On Foot Salvage (Illegal)"},
|
||||
{"Mission_PassengerBulk_AIDWORKER_ARRIVING", "Aid Workers Seeking Transport"},
|
||||
{"Mission_OnFoot_Smuggle_Contact_MB_name", "On Foot Smuggling" },
|
||||
{"Mission_PassengerBulk_AIDWORKER_ARRIVING", "Seeking Transport (Aid Workers)"},
|
||||
{"Mission_PassengerBulk_name", "Seeking Transport" },
|
||||
{"Mission_PassengerVIP", "Passenger (VIP)"},
|
||||
{"Mission_PassengerVIP_Criminal_BOOM_name", "Passenger Criminal (VIP) (Boom)"},
|
||||
{"Mission_PassengerVIP_name", "Passenger (VIP)"},
|
||||
{"Mission_PassengerVIP_Scientist_FAMINE_name", "Passenger Scientist (VIP) (Famine)"},
|
||||
{"Mission_PassengerVIP_Tourist_BOOM_name", "Passenger Tourist (VIP) (Boom)"},
|
||||
{"Mission_Rescue_Planet_name", "Planet Rescue"},
|
||||
{"Mission_Rescue_Planet_Expansion_name", "Planet Rescue (Expansion)" },
|
||||
{"MISSION_Salvage_CivilUnrest_name", "Salvage (Civil Unrest)"},
|
||||
{"MISSION_Salvage_Expansion_name", "Salvage (Expansion)"},
|
||||
{"MISSION_Salvage_Illegal_name", "Salvage (Illegal)"},
|
||||
@@ -93,6 +105,15 @@ public class EnglishMissionNames {
|
||||
{"MISSION_Scan_name", "Scan"},
|
||||
{"Mission_Sightseeing_Criminal_FAMINE_name", "Sightseeing (Criminal) (Famine)"},
|
||||
{"Mission_Sightseeing_name", "Sightseeing"},
|
||||
{"Mission_Smuggle_Anarchy_name", "Smuggling (Anarchy)" },
|
||||
{"Mission_TW_Massacre_Basilisk_Plural_name", "Kill Basilisk" },
|
||||
{"Mission_TW_Massacre_Basilisk_Singular_name", "Kill Basilisk" },
|
||||
{"Mission_TW_Massacre_Cyclops_Plural_name", "Kill Cyclops" },
|
||||
{"Mission_TW_Massacre_Cyclops_Singular_name", "Kill Cyclops" },
|
||||
{"Mission_TW_Massacre_Scout_Plural_name", "Kill Scouts (Wing)" },
|
||||
{"Mission_TW_PassengerEvacuation_Burning_name", "Passenger Evacuation (Significant Damage)" },
|
||||
{"Mission_TW_PassengerEvacuation_UnderAttack_name", "Passenger Evacuation (Thargoid Invasion)" },
|
||||
{"Mission_TW_Rescue_UnderAttack_name", "Rescue (Thargoid Attack)" },
|
||||
};
|
||||
|
||||
public static string? Translate(string name) {
|
||||
|
||||
24
EDPlayerJournal/Entries/CapShipBondEntry.cs
Normal file
24
EDPlayerJournal/Entries/CapShipBondEntry.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace EDPlayerJournal.Entries;
|
||||
|
||||
public class CapShipBondEntry : Entry {
|
||||
/// <summary>
|
||||
/// Reward gained
|
||||
/// </summary>
|
||||
public ulong Reward { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Victim faction, i.e. to whom the cap ship belongs
|
||||
/// </summary>
|
||||
public string? VictimFaction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Awarding faction.
|
||||
/// </summary>
|
||||
public string? AwardingFaction { get; set; }
|
||||
|
||||
protected override void Initialise() {
|
||||
Reward = JSON.Value<ulong?>("Reward") ?? 0;
|
||||
VictimFaction = JSON.Value<string?>("VictimFaction");
|
||||
AwardingFaction = JSON.Value<string?>("AwardingFaction");
|
||||
}
|
||||
}
|
||||
@@ -19,4 +19,12 @@ public class CommitCrimeEntry : Entry {
|
||||
public bool IsMurder {
|
||||
get { return CrimeType?.CompareTo(CrimeTypes.Murder) == 0 || CrimeType?.CompareTo(CrimeTypes.OnFootMurder) == 0; }
|
||||
}
|
||||
|
||||
public bool IsCrime(string crimetype) {
|
||||
if (CrimeType == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return string.Compare(CrimeType, crimetype) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
66
EDPlayerJournal/Entries/DisembarkEntry.cs
Normal file
66
EDPlayerJournal/Entries/DisembarkEntry.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
namespace EDPlayerJournal.Entries;
|
||||
|
||||
public class DisembarkEntry : Entry {
|
||||
/// <summary>
|
||||
/// Disembarked into an SRV?
|
||||
/// </summary>
|
||||
public bool SRV { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Taxi?
|
||||
/// </summary>
|
||||
public bool Taxi { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Multicrew or not.
|
||||
/// </summary>
|
||||
public bool Multicrew { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Player's ship ID
|
||||
/// </summary>
|
||||
public ulong? ID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Star system
|
||||
/// </summary>
|
||||
public string? StarSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// System address
|
||||
/// </summary>
|
||||
public ulong? SystemAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Body, name e.g. HIP 6182 B 2 a
|
||||
/// </summary>
|
||||
public string? Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Body ID
|
||||
/// </summary>
|
||||
public ulong? BodyID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disembarked on a station?
|
||||
/// </summary>
|
||||
public bool OnStation { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Disembarked on a planet?
|
||||
/// </summary>
|
||||
public bool OnPlanet { get; set; } = false;
|
||||
|
||||
protected override void Initialise() {
|
||||
SRV = JSON.Value<bool?>("SRV") ?? false;
|
||||
Taxi = JSON.Value<bool?>("Taxi") ?? false;
|
||||
Multicrew = JSON.Value<bool?>("Multicrew") ?? false;
|
||||
ID = JSON.Value<ulong?>("ID");
|
||||
StarSystem = JSON.Value<string?>("StarSystem");
|
||||
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
||||
Body = JSON.Value<string?>("Body");
|
||||
BodyID = JSON.Value<ulong?>("BodyID");
|
||||
OnStation = JSON.Value<bool?>("OnStation") ?? false;
|
||||
OnPlanet = JSON.Value<bool?>("OnPlanet") ?? false;
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,36 @@
|
||||
|
||||
namespace EDPlayerJournal.Entries;
|
||||
public class DockedEntry : Entry {
|
||||
/// <summary>
|
||||
/// Name of the station
|
||||
/// </summary>
|
||||
public string? StationName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Star system of the station
|
||||
/// </summary>
|
||||
public string? StarSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// System address
|
||||
/// </summary>
|
||||
public ulong? SystemAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Faction owning the station.
|
||||
/// </summary>
|
||||
public string? StationFaction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// State of the station, new in Update 14
|
||||
/// </summary>
|
||||
public string? StationState { get; set; }
|
||||
|
||||
protected override void Initialise() {
|
||||
StationName = JSON.Value<string>("StationName");
|
||||
StarSystem = JSON.Value<string>("StarSystem");
|
||||
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
||||
StationState = JSON.Value<string>("StationState");
|
||||
JObject? faction = JSON.Value<JObject>("StationFaction");
|
||||
if (faction != null) {
|
||||
StationFaction = faction.Value<string>("Name") ?? "";
|
||||
|
||||
42
EDPlayerJournal/Entries/DropshipDeployEntry.cs
Normal file
42
EDPlayerJournal/Entries/DropshipDeployEntry.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
namespace EDPlayerJournal.Entries;
|
||||
|
||||
public class DropshipDeployEntry : Entry {
|
||||
/// <summary>
|
||||
/// Star system this drop happened in.
|
||||
/// </summary>
|
||||
public string? StarSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// System address
|
||||
/// </summary>
|
||||
public ulong? SystemAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Planetary body
|
||||
/// </summary>
|
||||
public string? Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Body ID
|
||||
/// </summary>
|
||||
public ulong? BodyID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether it happened on station.
|
||||
/// </summary>
|
||||
public bool? OnStation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether it happened on a planet.
|
||||
/// </summary>
|
||||
public bool? OnPlanet { get; set; }
|
||||
|
||||
protected override void Initialise() {
|
||||
StarSystem = JSON.Value<string?>("StarSystem");
|
||||
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
||||
Body = JSON.Value<string?>("Body");
|
||||
BodyID = JSON.Value<ulong?>("BodyID");
|
||||
OnStation = JSON.Value<bool?>("OnStation");
|
||||
OnPlanet = JSON.Value<bool?>("OnPlanet");
|
||||
}
|
||||
}
|
||||
66
EDPlayerJournal/Entries/EmbarkEntry.cs
Normal file
66
EDPlayerJournal/Entries/EmbarkEntry.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
namespace EDPlayerJournal.Entries;
|
||||
|
||||
public class EmbarkEntry : Entry {
|
||||
/// <summary>
|
||||
/// Disembarked into an SRV?
|
||||
/// </summary>
|
||||
public bool SRV { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Taxi?
|
||||
/// </summary>
|
||||
public bool Taxi { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Multicrew or not.
|
||||
/// </summary>
|
||||
public bool Multicrew { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Player's ship ID
|
||||
/// </summary>
|
||||
public ulong? ID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Star system
|
||||
/// </summary>
|
||||
public string? StarSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// System address
|
||||
/// </summary>
|
||||
public ulong? SystemAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Body, name e.g. HIP 6182 B 2 a
|
||||
/// </summary>
|
||||
public string? Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Body ID
|
||||
/// </summary>
|
||||
public ulong? BodyID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disembarked on a station?
|
||||
/// </summary>
|
||||
public bool OnStation { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Disembarked on a planet?
|
||||
/// </summary>
|
||||
public bool OnPlanet { get; set; } = false;
|
||||
|
||||
protected override void Initialise() {
|
||||
SRV = JSON.Value<bool?>("SRV") ?? false;
|
||||
Taxi = JSON.Value<bool?>("Taxi") ?? false;
|
||||
Multicrew = JSON.Value<bool?>("Multicrew") ?? false;
|
||||
ID = JSON.Value<ulong?>("ID");
|
||||
StarSystem = JSON.Value<string?>("StarSystem");
|
||||
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
||||
Body = JSON.Value<string?>("Body");
|
||||
BodyID = JSON.Value<ulong?>("BodyID");
|
||||
OnStation = JSON.Value<bool?>("OnStation") ?? false;
|
||||
OnPlanet = JSON.Value<bool?>("OnPlanet") ?? false;
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,16 @@ namespace EDPlayerJournal.Entries;
|
||||
public class Entry {
|
||||
private static readonly Dictionary<string, Type> classes = new Dictionary<string, Type> {
|
||||
{ Events.Bounty, typeof(BountyEntry) },
|
||||
{ Events.CapShipBond, typeof(CapShipBondEntry) },
|
||||
{ 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.DropshipDeploy, typeof(DropshipDeployEntry) },
|
||||
{ Events.Embark, typeof(EmbarkEntry) },
|
||||
{ Events.FactionKillBond, typeof(FactionKillBondEntry) },
|
||||
{ Events.FileHeader, typeof(FileHeaderEntry) },
|
||||
{ Events.FSDJump, typeof(FSDJumpEntry) },
|
||||
{ Events.HullDamage, typeof(HullDamageEntry) },
|
||||
{ Events.LoadGame, typeof(LoadGameEntry) },
|
||||
@@ -32,6 +36,7 @@ public class Entry {
|
||||
{ Events.MissionRedirected, typeof(MissionRedirectedEntry) },
|
||||
{ Events.Missions, typeof(MissionsEntry) },
|
||||
{ Events.MultiSellExplorationData, typeof(MultiSellExplorationDataEntry) },
|
||||
{ Events.ReceiveText, typeof(ReceiveTextEntry) },
|
||||
{ Events.RedeemVoucher, typeof(RedeemVoucherEntry) },
|
||||
{ Events.SearchAndRescue, typeof(SearchAndRescueEntry) },
|
||||
{ Events.SellExplorationData, typeof(SellExplorationDataEntry) },
|
||||
@@ -39,6 +44,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) },
|
||||
};
|
||||
|
||||
@@ -98,7 +105,7 @@ public class Entry {
|
||||
this.datetime = json.GetValue("timestamp")?.ToString();
|
||||
|
||||
if (!string.IsNullOrEmpty(this.datetime)) {
|
||||
this.timestamp = DateTime.Parse(this.datetime);
|
||||
this.timestamp = DateTime.Parse(this.datetime, null, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
|
||||
public class Events {
|
||||
public static readonly string Bounty = "Bounty";
|
||||
public static readonly string CapShipBond = "CapShipBond";
|
||||
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 DropshipDeploy = "DropshipDeploy";
|
||||
public static readonly string Embark = "Embark";
|
||||
public static readonly string FactionKillBond = "FactionKillBond";
|
||||
public static readonly string FighterDestroyed = "FighterDestroyed";
|
||||
public static readonly string FileHeader = "Fileheader";
|
||||
@@ -22,6 +26,7 @@ public class Events {
|
||||
public static readonly string MissionRedirected = "MissionRedirected";
|
||||
public static readonly string Missions = "Missions";
|
||||
public static readonly string MultiSellExplorationData = "MultiSellExplorationData";
|
||||
public static readonly string ReceiveText = "ReceiveText";
|
||||
public static readonly string RedeemVoucher = "RedeemVoucher";
|
||||
public static readonly string SearchAndRescue = "SearchAndRescue";
|
||||
public static readonly string SellExplorationData = "SellExplorationData";
|
||||
@@ -29,5 +34,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";
|
||||
}
|
||||
|
||||
@@ -26,6 +26,22 @@ public class FileHeaderEntry : Entry {
|
||||
/// </summary>
|
||||
public string? Build { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the version is legacy (3.X)
|
||||
/// <summary>
|
||||
public bool IsLegacy {
|
||||
get {
|
||||
return GameVersion.StartsWith("3.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the version is live (4.x)
|
||||
/// </summary>
|
||||
public bool IsLive {
|
||||
get { return !IsLegacy; }
|
||||
}
|
||||
|
||||
protected override void Initialise() {
|
||||
Part = JSON.Value<ulong?>("part") ?? 1;
|
||||
Language = JSON.Value<string?>("language") ?? string.Empty;
|
||||
|
||||
77
EDPlayerJournal/Entries/ReceiveTextEntry.cs
Normal file
77
EDPlayerJournal/Entries/ReceiveTextEntry.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
namespace EDPlayerJournal.Entries;
|
||||
|
||||
public class ReceiveTextEntry : Entry {
|
||||
/// <summary>
|
||||
/// From whom this message is
|
||||
/// </summary>
|
||||
public string? From { get; set; }
|
||||
/// <summary>
|
||||
/// The message, if it is just an NPC text, it will be a message ID
|
||||
/// </summary>
|
||||
public string? Message { get; set; }
|
||||
/// <summary>
|
||||
/// Message localised
|
||||
/// </summary>
|
||||
public string? MessageLocalised { get; set; }
|
||||
/// <summary>
|
||||
/// On what channel this was received.
|
||||
/// </summary>
|
||||
public string? Channel { get; set; }
|
||||
|
||||
public bool HasNPCCategory {
|
||||
get {
|
||||
if (From == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (From.Contains(';') && From.StartsWith("$")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the NPC's category, if it has one.
|
||||
/// </summary>
|
||||
public string? NPCCategory {
|
||||
get {
|
||||
if (!HasNPCCategory || From == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string[] parts = From.Split(";", StringSplitOptions.TrimEntries);
|
||||
if (parts.Length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return string.Format("{0};", parts[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the NPC's category, if it has one.
|
||||
/// </summary>
|
||||
public string? NPCName {
|
||||
get {
|
||||
if (!HasNPCCategory || From == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string[] parts = From.Split(";", StringSplitOptions.TrimEntries);
|
||||
if (parts.Length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parts[1];
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Initialise() {
|
||||
From = JSON.Value<string>("From");
|
||||
Message = JSON.Value<string>("Message");
|
||||
MessageLocalised = JSON.Value<string>("Message_localised");
|
||||
Channel = JSON.Value<string>("Channel");
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||
namespace EDPlayerJournal.Entries;
|
||||
public class RedeemVoucherEntry : Entry {
|
||||
protected override void Initialise() {
|
||||
Amount = (JSON.Value<int?>("Amount") ?? 0);
|
||||
Amount = (JSON.Value<ulong?>("Amount") ?? 0);
|
||||
Type = JSON.Value<string>("Type");
|
||||
|
||||
/* according to API, there should be a Factions structure */
|
||||
@@ -12,7 +12,7 @@ public class RedeemVoucherEntry : Entry {
|
||||
if (factions != null) {
|
||||
foreach (JObject faction in factions.Children<JObject>()) {
|
||||
string? faction_name = faction.Value<string>("Faction");
|
||||
long? faction_bounty = faction.Value<long?>("Amount");
|
||||
ulong? faction_bounty = faction.Value<ulong?>("Amount");
|
||||
if (faction_name == null || faction_name.Length <= 0 || faction_bounty == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -35,8 +35,29 @@ public class RedeemVoucherEntry : Entry {
|
||||
}
|
||||
}
|
||||
|
||||
public int Amount { get; set; } = 0;
|
||||
public ulong GetBountyForFaction(string? a) {
|
||||
if (a == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var relevant = FactionBounties.Where(x => EDPlayerJournal.Factions.CompareFactions(x.Key, a) == 0).ToList();
|
||||
if (relevant == null || relevant.Count() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (ulong)relevant.Sum(x => (decimal)x.Value);
|
||||
}
|
||||
|
||||
public ulong Amount { get; set; } = 0;
|
||||
public string? Type { get; set; } = "Bounty";
|
||||
public List<string> Factions { get; set; } = new List<string>();
|
||||
public Dictionary<string, long> FactionBounties { get; set; } = new Dictionary<string, long>();
|
||||
|
||||
/// <summary>
|
||||
/// List of factions
|
||||
/// </summary>
|
||||
public List<string> Factions { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Bounties awarded by faction
|
||||
/// </summary>
|
||||
public Dictionary<string, ulong> FactionBounties { get; set; } = new();
|
||||
}
|
||||
|
||||
@@ -8,11 +8,17 @@ public class BioData {
|
||||
public string? SpeciesLocalised { get; set; }
|
||||
public long Value { get; set; } = 0;
|
||||
public long Bonus { get; set; } = 0;
|
||||
public long TotalValue => Value + Bonus;
|
||||
|
||||
public long TotalValue {
|
||||
get {
|
||||
return Value + Bonus;
|
||||
}
|
||||
}
|
||||
}
|
||||
public class SellOrganicDataEntry : Entry {
|
||||
public long MarketID { get; set; }
|
||||
public List<BioData> BioData => new List<BioData>();
|
||||
|
||||
public List<BioData> BioData { get; } = new();
|
||||
|
||||
protected override void Initialise() {
|
||||
MarketID = JSON.Value<long?>("MarketID") ?? 0;
|
||||
|
||||
30
EDPlayerJournal/Entries/SupercruiseEntry.cs
Normal file
30
EDPlayerJournal/Entries/SupercruiseEntry.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace EDPlayerJournal.Entries;
|
||||
|
||||
public class SupercruiseEntryEntry : Entry {
|
||||
/// <summary>
|
||||
/// Taxi?
|
||||
/// </summary>
|
||||
public bool Taxi { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Multicrew or not.
|
||||
/// </summary>
|
||||
public bool Multicrew { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Star system
|
||||
/// </summary>
|
||||
public string? StarSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// System address
|
||||
/// </summary>
|
||||
public ulong? SystemAddress { get; set; }
|
||||
|
||||
protected override void Initialise() {
|
||||
Taxi = JSON.Value<bool?>("Taxi") ?? false;
|
||||
Multicrew = JSON.Value<bool?>("Multicrew") ?? false;
|
||||
StarSystem = JSON.Value<string?>("StarSystem");
|
||||
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
||||
}
|
||||
}
|
||||
48
EDPlayerJournal/Entries/SupercruiseExitEntry.cs
Normal file
48
EDPlayerJournal/Entries/SupercruiseExitEntry.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace EDPlayerJournal.Entries;
|
||||
|
||||
public class SupercruiseExitEntry : Entry {
|
||||
/// <summary>
|
||||
/// Taxi?
|
||||
/// </summary>
|
||||
public bool Taxi { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Multicrew or not.
|
||||
/// </summary>
|
||||
public bool Multicrew { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Star system
|
||||
/// </summary>
|
||||
public string? StarSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// System address
|
||||
/// </summary>
|
||||
public ulong? SystemAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Body, name e.g. HIP 6182 B 2 a
|
||||
/// </summary>
|
||||
public string? Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Body ID
|
||||
/// </summary>
|
||||
public ulong? BodyID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Body type (star, planet etc.)
|
||||
/// </summary>
|
||||
public string? BodyType { get; set; }
|
||||
|
||||
protected override void Initialise() {
|
||||
Taxi = JSON.Value<bool?>("Taxi") ?? false;
|
||||
Multicrew = JSON.Value<bool?>("Multicrew") ?? false;
|
||||
StarSystem = JSON.Value<string?>("StarSystem");
|
||||
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
||||
Body = JSON.Value<string?>("Body");
|
||||
BodyType = JSON.Value<string?>("BodyType");
|
||||
BodyID = JSON.Value<ulong?>("BodyID");
|
||||
}
|
||||
}
|
||||
@@ -33,12 +33,78 @@ public class Factions {
|
||||
/// <summary>
|
||||
/// Internal name for the Pilots Federation faction
|
||||
/// </summary>
|
||||
public static string PilotsFederation = "$faction_PilotsFederation;";
|
||||
public static string PilotsFederationInternal = "$faction_PilotsFederation;";
|
||||
|
||||
/// <summary>
|
||||
/// Name used for Pilots Federation in vouchers
|
||||
/// </summary>
|
||||
public static string PilotsFederationVouchers = "PilotsFederation";
|
||||
|
||||
/// <summary>
|
||||
/// Friendly name of the Pilots Federation
|
||||
/// </summary>
|
||||
public static string PilotsFederation = "Pilots' Federation";
|
||||
|
||||
/// <summary>
|
||||
/// Internal name for the Thargoid faction
|
||||
/// </summary>
|
||||
public static string Thargoid = "$faction_Thargoid;";
|
||||
public static string ThargoidInternal = "$faction_Thargoid;";
|
||||
|
||||
/// <summary>
|
||||
/// Localised name of the Thargoids
|
||||
/// </summary>
|
||||
public static string Thargoid = "Thargoids";
|
||||
|
||||
public static bool IsPilotsFederation(string? name) {
|
||||
if (name == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.Compare(name, PilotsFederationInternal) == 0 ||
|
||||
string.Compare(name, PilotsFederationVouchers) == 0 ||
|
||||
string.Compare(name, PilotsFederation) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsThargoid(string? name) {
|
||||
if (name == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.Compare(name, ThargoidInternal) == 0 ||
|
||||
string.Compare(name, Thargoid) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two factions names and sees if they are the same faction. Since
|
||||
/// factions can have an internal name, and a public name, this function takes
|
||||
/// these into account.
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
public static int CompareFactions(string? a, string? b) {
|
||||
if (a == null || b == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (IsPilotsFederation(a) && IsPilotsFederation(b)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IsThargoid(a) && IsThargoid(b)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return string.Compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
public class Faction {
|
||||
|
||||
@@ -109,6 +109,11 @@ public class MissionFactionEffects {
|
||||
}
|
||||
|
||||
public class Mission : IComparable<Mission> {
|
||||
/// <summary>
|
||||
/// Passenger type for refugees
|
||||
/// </summary>
|
||||
public static readonly string PassengerTypeRefugee = "Refugee";
|
||||
|
||||
public ulong MissionID { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
@@ -250,6 +255,43 @@ public class Mission : IComparable<Mission> {
|
||||
/// </summary>
|
||||
public List<MissionFactionEffects> FactionEffects { get; set; } = new List<MissionFactionEffects>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the name is an on foot mission.
|
||||
/// </summary>
|
||||
public bool IsOnFoot {
|
||||
get {
|
||||
if (string.IsNullOrEmpty(Name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Name.Contains("OnFoot");
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPassengerMission {
|
||||
get {
|
||||
if (PassengerCount == null || PassengerCount == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRescueMission {
|
||||
get {
|
||||
if (!IsPassengerMission) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.Compare(PassengerType, PassengerTypeRefugee) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a friendly human-readable name for the mission. If a localised name is available
|
||||
/// it will use that, baring that it will check EnglishMissionNames for a translation, and
|
||||
|
||||
122
EDPlayerJournal/NPC.cs
Normal file
122
EDPlayerJournal/NPC.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
namespace EDPlayerJournal;
|
||||
|
||||
public class NPCs {
|
||||
/// <summary>
|
||||
/// Internal name of Spec Ops Wing Alpha
|
||||
/// </summary>
|
||||
public static string SpecOpsAInternal = "$LUASC_Scenario_Warzone_NPC_SpecOps_A;";
|
||||
|
||||
/// <summary>
|
||||
/// Internal name of Spec Ops Wing Beta
|
||||
/// </summary>
|
||||
public static string SpecOpsBInternal = "$LUASC_Scenario_Warzone_NPC_SpecOps_B;";
|
||||
|
||||
/// <summary>
|
||||
/// Internal name of Spec Ops Wing Gamma
|
||||
/// </summary>
|
||||
public static string SpecOpsGInternal = "$LUASC_Scenario_Warzone_NPC_SpecOps_G;";
|
||||
|
||||
/// <summary>
|
||||
/// Internal name of Spec Ops Wing Delta
|
||||
/// </summary>
|
||||
public static string SpecOpsDInternal = "$LUASC_Scenario_Warzone_NPC_SpecOps_D;";
|
||||
|
||||
/// <summary>
|
||||
/// Empire captain
|
||||
/// </summary>
|
||||
public static string EmpireCaptain = "$LUASC_Scenario_Warzone_NPC_WarzoneGeneral_Emp;";
|
||||
|
||||
/// <summary>
|
||||
/// Federation captain
|
||||
/// </summary>
|
||||
public static string FederationCaptain = "$LUASC_Scenario_Warzone_NPC_WarzoneGeneral_Fed;";
|
||||
|
||||
/// <summary>
|
||||
/// Federation captain
|
||||
/// </summary>
|
||||
public static string IndependentCaptain = "$LUASC_Scenario_Warzone_NPC_WarzoneGeneral_Ind;";
|
||||
|
||||
/// <summary>
|
||||
/// Warzone correspondant
|
||||
/// </summary>
|
||||
public static string WarzoneCorrespondent = "$LUASC_Scenario_Warzone_NPC_WarzoneCorrespondent;";
|
||||
|
||||
/// <summary>
|
||||
/// AX Military NPC
|
||||
/// </summary>
|
||||
public static string AXMilitary = "$Name_AX_Military;";
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the pilotname is either a captain, specops, or correspondent
|
||||
/// </summary>
|
||||
/// <param name="pilotname"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsWarzoneNPC(string? pilotname) {
|
||||
if (IsWarzoneCaptain(pilotname) ||
|
||||
IsWarzoneCorrespondent(pilotname) ||
|
||||
IsSpecOps(pilotname)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given pilot name is a warzone correspondent
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsWarzoneCorrespondent(string? pilotname) {
|
||||
if (pilotname == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.Compare(pilotname, WarzoneCorrespondent) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given pilot name is a spec ops wing.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsSpecOps(string? pilotname) {
|
||||
if (pilotname == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.Compare(pilotname, SpecOpsAInternal) == 0 ||
|
||||
string.Compare(pilotname, SpecOpsBInternal) == 0 ||
|
||||
string.Compare(pilotname, SpecOpsGInternal) == 0 ||
|
||||
string.Compare(pilotname, SpecOpsDInternal) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given pilot name is a warzone captain
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsWarzoneCaptain(string? pilotname) {
|
||||
if (pilotname == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.Compare(pilotname, EmpireCaptain) == 0 ||
|
||||
string.Compare(pilotname, FederationCaptain) == 0 ||
|
||||
string.Compare(pilotname, IndependentCaptain) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class NPC {
|
||||
}
|
||||
@@ -1,17 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EDPlayerJournal;
|
||||
namespace EDPlayerJournal;
|
||||
|
||||
public enum ThargoidVessel {
|
||||
Unknown = 0,
|
||||
Scout = 1,
|
||||
/// <summary>
|
||||
/// According to AX wiki no longer found ingame
|
||||
/// </summary>
|
||||
Orthrus = 2,
|
||||
Cyclops = 3,
|
||||
Basilisk = 4,
|
||||
@@ -23,10 +14,24 @@ public class Thargoid {
|
||||
public static string ThargoidFaction = Factions.Thargoid;
|
||||
|
||||
public static Dictionary<ulong, ThargoidVessel> VesselPayout { get; } = new() {
|
||||
// Up to date values ever since 14.02
|
||||
{ 65000, ThargoidVessel.Scout },
|
||||
{ 75000, ThargoidVessel.Scout },
|
||||
{ 6500000, ThargoidVessel.Cyclops },
|
||||
{ 20000000, ThargoidVessel.Basilisk },
|
||||
{ 25000000, ThargoidVessel.Orthrus },
|
||||
{ 34000000, ThargoidVessel.Medusa },
|
||||
{ 50000000, ThargoidVessel.Hydra },
|
||||
// These are the old values pre Update 14.02
|
||||
{ 80000, ThargoidVessel.Scout },
|
||||
{ 8000000, ThargoidVessel.Cyclops },
|
||||
{ 24000000, ThargoidVessel.Basilisk },
|
||||
// In Update 14.1 the payout for Orthrus has been rebalanced.
|
||||
{ 30000000, ThargoidVessel.Orthrus },
|
||||
{ 40000000, ThargoidVessel.Medusa },
|
||||
// This used to be the old payout value for Orthrus, it now conflicts
|
||||
// with Post Update 14.02 Hydra values
|
||||
//{ 50000000, ThargoidVessel.Orthrus },
|
||||
{ 60000000, ThargoidVessel.Hydra },
|
||||
};
|
||||
|
||||
|
||||
28
EDPlayerJournalTests/CombatZoneTest.cs
Normal file
28
EDPlayerJournalTests/CombatZoneTest.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using EDPlayerJournal;
|
||||
using EDPlayerJournal.Entries;
|
||||
using EDPlayerJournal.BGS;
|
||||
|
||||
namespace EDPlayerJournalTests;
|
||||
|
||||
[TestClass]
|
||||
public class CombatZoneTest {
|
||||
[TestMethod]
|
||||
public void DropshipDeployTest() {
|
||||
TransactionParser parser = new();
|
||||
|
||||
List<Entry>? entries = Helper.LoadTestData("dropship-deploy.txt");
|
||||
Assert.IsNotNull(entries);
|
||||
|
||||
List<Transaction>? transactions = parser.Parse(entries);
|
||||
Assert.IsNotNull(transactions);
|
||||
|
||||
Vouchers? vouchers = transactions[0] as Vouchers;
|
||||
Assert.IsNotNull(vouchers);
|
||||
|
||||
CombatZone? combatzone = transactions[1] as CombatZone;
|
||||
Assert.IsNotNull(combatzone);
|
||||
|
||||
Assert.AreEqual(combatzone.Type, CombatZones.GroundCombatZone);
|
||||
Assert.AreEqual(combatzone.Grade, CombatZones.DifficultyHigh);
|
||||
}
|
||||
}
|
||||
2
EDPlayerJournalTests/DoubleVouchers.txt
Normal file
2
EDPlayerJournalTests/DoubleVouchers.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
{ "timestamp":"2022-11-20T14:30:30Z", "event":"RedeemVoucher", "Type":"bounty", "Amount":3197549, "Factions":[ { "Faction":"Nova Paresa", "Amount":3197549 } ] }
|
||||
{ "timestamp":"2022-11-20T14:30:34Z", "event":"RedeemVoucher", "Type":"bounty", "Amount":4785831, "Factions":[ { "Faction":"", "Amount":723175 }, { "Faction":"Nova Paresa", "Amount":3197549 }, { "Faction":"Prismatic Imperium", "Amount":4062656 } ] }
|
||||
@@ -26,6 +26,12 @@
|
||||
<None Update="double-support.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="dropship-deploy.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="legacy-transaction.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="mission-failed.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
@@ -44,6 +50,9 @@
|
||||
<None Update="SellOrganicData.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ThargoidBonds.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ThargoidKills.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
||||
@@ -21,6 +21,8 @@ public class FileHeaderTest {
|
||||
Assert.AreEqual(header.Language, "English/UK");
|
||||
Assert.AreEqual(header.Odyssey, true);
|
||||
Assert.AreEqual(header.GameVersion, "4.0.0.1450");
|
||||
Assert.AreEqual(header.IsLegacy, false);
|
||||
Assert.AreEqual(header.IsLive, true);
|
||||
// Someone at FDev messed up string building there.
|
||||
Assert.AreEqual(header.Build, "r286858/r0 ");
|
||||
}
|
||||
@@ -44,6 +46,8 @@ public class FileHeaderTest {
|
||||
Assert.AreEqual(header.Language, """English\UK""");
|
||||
Assert.AreEqual(header.Odyssey, false);
|
||||
Assert.AreEqual(header.GameVersion, "3.5.3.400 EDH");
|
||||
Assert.AreEqual(header.IsLegacy, true);
|
||||
Assert.AreEqual(header.IsLive, false);
|
||||
// ~73k commits in two years. Not bad.
|
||||
Assert.AreEqual(header.Build, "r213094/r0 ");
|
||||
}
|
||||
|
||||
@@ -6,6 +6,29 @@ namespace EDPlayerJournalTests;
|
||||
|
||||
[TestClass]
|
||||
public class TestTransactionParser {
|
||||
[TestMethod]
|
||||
public void Legacy() {
|
||||
TransactionParser parser = new();
|
||||
|
||||
// File header, followed by two legacy transactions, followed by another
|
||||
// file header with an Odyssey transaction
|
||||
List<Entry>? entries = Helper.LoadTestData("legacy-transaction.txt");
|
||||
Assert.IsNotNull(entries, "could not load test data");
|
||||
|
||||
if (entries == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Transaction>? transactions = parser.Parse(entries);
|
||||
Assert.IsNotNull(transactions, "could not parse entries");
|
||||
Assert.AreEqual(transactions.Count, 3);
|
||||
|
||||
Assert.AreEqual(transactions[0].IsLegacy, true);
|
||||
Assert.AreEqual(transactions[1].IsLegacy, true);
|
||||
|
||||
Assert.AreEqual(transactions[2].IsLegacy, false);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DoubleFiveINF() {
|
||||
TransactionParser parser = new();
|
||||
|
||||
3
EDPlayerJournalTests/ThargoidBonds.txt
Normal file
3
EDPlayerJournalTests/ThargoidBonds.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
{ "timestamp":"2022-11-25T10:10:43Z", "event":"FSDJump", "Taxi":false, "Multicrew":false, "StarSystem":"Nyalayan", "SystemAddress":1458309042898, "StarPos":[29.71875,-172.71875,-6.46875], "SystemAllegiance":"Independent", "SystemEconomy":"$economy_Agri;", "SystemEconomy_Localised":"Agriculture", "SystemSecondEconomy":"$economy_Refinery;", "SystemSecondEconomy_Localised":"Refinery", "SystemGovernment":"$government_Theocracy;", "SystemGovernment_Localised":"Theocracy", "SystemSecurity":"$SYSTEM_SECURITY_medium;", "SystemSecurity_Localised":"Medium Security", "Population":1920608781, "Body":"Nyalayan A", "BodyID":1, "BodyType":"Star", "JumpDist":7.769, "FuelUsed":0.142448, "FuelLevel":15.857553, "Factions":[ { "Name":"Nyalayan Imperial Society", "FactionState":"Election", "Government":"Patronage", "Influence":0.165138, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":17.496799, "ActiveStates":[ { "State":"Election" } ] }, { "Name":"Reret Emperor's Grace", "FactionState":"War", "Government":"Patronage", "Influence":0.257900, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":100.000000, "ActiveStates":[ { "State":"Expansion" }, { "State":"War" } ] }, { "Name":"Nyalayan Silver Transport Org", "FactionState":"None", "Government":"Corporate", "Influence":0.076453, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":81.875000 }, { "Name":"Nyalayan Power & Co", "FactionState":"None", "Government":"Corporate", "Influence":0.060143, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":23.173201 }, { "Name":"Amanogawa Enlight", "FactionState":"War", "Government":"Theocracy", "Influence":0.257900, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":-1.210600, "ActiveStates":[ { "State":"Expansion" }, { "State":"War" } ] }, { "Name":"Nyalayan Crimson Dragons", "FactionState":"None", "Government":"Anarchy", "Influence":0.017329, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":-13.530000 }, { "Name":"Traditional Nyalayan Front", "FactionState":"Election", "Government":"Dictatorship", "Influence":0.165138, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":64.699997, "ActiveStates":[ { "State":"Election" } ] } ], "SystemFaction":{ "Name":"Amanogawa Enlight", "FactionState":"War" }, "Conflicts":[ { "WarType":"election", "Status":"active", "Faction1":{ "Name":"Nyalayan Imperial Society", "Stake":"Pilcher Port", "WonDays":2 }, "Faction2":{ "Name":"Traditional Nyalayan Front", "Stake":"Lamar Falls", "WonDays":0 } }, { "WarType":"war", "Status":"active", "Faction1":{ "Name":"Reret Emperor's Grace", "Stake":"", "WonDays":1 }, "Faction2":{ "Name":"Amanogawa Enlight", "Stake":"Sutter Ring", "WonDays":2 } } ] }
|
||||
{ "timestamp":"2022-11-25T10:13:32Z", "event":"Docked", "StationName":"Pilcher Port", "StationType":"Orbis", "Taxi":false, "Multicrew":false, "StarSystem":"Nyalayan", "SystemAddress":1458309042898, "MarketID":3222853120, "StationFaction":{ "Name":"Nyalayan Imperial Society", "FactionState":"Election" }, "StationGovernment":"$government_Patronage;", "StationGovernment_Localised":"Patronage", "StationAllegiance":"Empire", "StationServices":[ "dock", "autodock", "commodities", "contacts", "exploration", "missions", "outfitting", "crewlounge", "rearm", "refuel", "repair", "shipyard", "tuning", "engineer", "missionsgenerated", "flightcontroller", "stationoperations", "powerplay", "searchrescue", "stationMenu", "shop", "livery", "socialspace", "bartender", "vistagenomics", "pioneersupplies", "apexinterstellar", "frontlinesolutions" ], "StationEconomy":"$economy_Refinery;", "StationEconomy_Localised":"Refinery", "StationEconomies":[ { "Name":"$economy_Refinery;", "Name_Localised":"Refinery", "Proportion":1.000000 } ], "DistFromStarLS":76.465557, "LandingPads":{ "Small":8, "Medium":11, "Large":6 } }
|
||||
{ "timestamp":"2022-11-25T10:13:53Z", "event":"RedeemVoucher", "Type":"CombatBond", "Amount":24240000, "Faction":"PilotsFederation" }
|
||||
@@ -1,10 +1,6 @@
|
||||
using EDPlayerJournal.BGS;
|
||||
using EDPlayerJournal;
|
||||
using EDPlayerJournal.BGS;
|
||||
using EDPlayerJournal.Entries;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EDPlayerJournalTests;
|
||||
|
||||
@@ -21,13 +17,38 @@ public class ThargoidKills {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Transaction>? transactions = parser.Parse(entries);
|
||||
List<ThargoidKill>? transactions = parser.Parse(entries)?.OfType<ThargoidKill>().ToList();
|
||||
|
||||
Assert.IsNotNull(transactions, "could not parse entries");
|
||||
Assert.AreEqual(transactions.Count, 4);
|
||||
Assert.AreEqual(transactions.Count, 3);
|
||||
|
||||
Assert.IsInstanceOfType(transactions[0], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
||||
Assert.AreEqual(transactions[0].ThargoidType, EDPlayerJournal.ThargoidVessel.Scout);
|
||||
|
||||
Assert.IsInstanceOfType(transactions[1], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
||||
Assert.AreEqual(transactions[1].ThargoidType, EDPlayerJournal.ThargoidVessel.Basilisk);
|
||||
|
||||
Assert.IsInstanceOfType(transactions[2], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
||||
Assert.AreEqual(transactions[2].ThargoidType, EDPlayerJournal.ThargoidVessel.Scout);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ThargoidBonds() {
|
||||
TransactionParser parser = new();
|
||||
|
||||
List<Entry>? entries = Helper.LoadTestData("ThargoidBonds.txt");
|
||||
Assert.IsNotNull(entries, "could not load test data");
|
||||
|
||||
if (entries == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Vouchers>? transactions = parser.Parse(entries)?.OfType<Vouchers>().ToList();
|
||||
|
||||
Assert.IsNotNull(transactions, "could not parse entries");
|
||||
Assert.AreEqual(transactions.Count, 1);
|
||||
Assert.AreEqual(Factions.IsPilotsFederation(transactions[0].Faction), true);
|
||||
Assert.AreEqual(transactions[0].TotalSum, 24240000L);
|
||||
Assert.AreEqual(transactions[0].Type, "Combat Bond");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{ "timestamp":"2022-11-25T09:50:45Z", "event":"FactionKillBond", "Reward":80000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||
{ "timestamp":"2022-11-25T09:52:28Z", "event":"FactionKillBond", "Reward":24000000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||
{ "timestamp":"2022-11-25T09:47:19Z", "event":"FactionKillBond", "Reward":80000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||
{ "timestamp":"2022-11-25T10:13:53Z", "event":"RedeemVoucher", "Type":"CombatBond", "Amount":24240000, "Faction":"PilotsFederation" }
|
||||
6
EDPlayerJournalTests/ThargoidKillsAndBonds.txt
Normal file
6
EDPlayerJournalTests/ThargoidKillsAndBonds.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
{ "timestamp":"2022-11-25T10:10:43Z", "event":"FSDJump", "Taxi":false, "Multicrew":false, "StarSystem":"Nyalayan", "SystemAddress":1458309042898, "StarPos":[29.71875,-172.71875,-6.46875], "SystemAllegiance":"Independent", "SystemEconomy":"$economy_Agri;", "SystemEconomy_Localised":"Agriculture", "SystemSecondEconomy":"$economy_Refinery;", "SystemSecondEconomy_Localised":"Refinery", "SystemGovernment":"$government_Theocracy;", "SystemGovernment_Localised":"Theocracy", "SystemSecurity":"$SYSTEM_SECURITY_medium;", "SystemSecurity_Localised":"Medium Security", "Population":1920608781, "Body":"Nyalayan A", "BodyID":1, "BodyType":"Star", "JumpDist":7.769, "FuelUsed":0.142448, "FuelLevel":15.857553, "Factions":[ { "Name":"Nyalayan Imperial Society", "FactionState":"Election", "Government":"Patronage", "Influence":0.165138, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":17.496799, "ActiveStates":[ { "State":"Election" } ] }, { "Name":"Reret Emperor's Grace", "FactionState":"War", "Government":"Patronage", "Influence":0.257900, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":100.000000, "ActiveStates":[ { "State":"Expansion" }, { "State":"War" } ] }, { "Name":"Nyalayan Silver Transport Org", "FactionState":"None", "Government":"Corporate", "Influence":0.076453, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":81.875000 }, { "Name":"Nyalayan Power & Co", "FactionState":"None", "Government":"Corporate", "Influence":0.060143, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":23.173201 }, { "Name":"Amanogawa Enlight", "FactionState":"War", "Government":"Theocracy", "Influence":0.257900, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":-1.210600, "ActiveStates":[ { "State":"Expansion" }, { "State":"War" } ] }, { "Name":"Nyalayan Crimson Dragons", "FactionState":"None", "Government":"Anarchy", "Influence":0.017329, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":-13.530000 }, { "Name":"Traditional Nyalayan Front", "FactionState":"Election", "Government":"Dictatorship", "Influence":0.165138, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":64.699997, "ActiveStates":[ { "State":"Election" } ] } ], "SystemFaction":{ "Name":"Amanogawa Enlight", "FactionState":"War" }, "Conflicts":[ { "WarType":"election", "Status":"active", "Faction1":{ "Name":"Nyalayan Imperial Society", "Stake":"Pilcher Port", "WonDays":2 }, "Faction2":{ "Name":"Traditional Nyalayan Front", "Stake":"Lamar Falls", "WonDays":0 } }, { "WarType":"war", "Status":"active", "Faction1":{ "Name":"Reret Emperor's Grace", "Stake":"", "WonDays":1 }, "Faction2":{ "Name":"Amanogawa Enlight", "Stake":"Sutter Ring", "WonDays":2 } } ] }
|
||||
{ "timestamp":"2022-11-25T09:50:45Z", "event":"FactionKillBond", "Reward":80000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||
{ "timestamp":"2022-11-25T09:52:28Z", "event":"FactionKillBond", "Reward":24000000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||
{ "timestamp":"2022-11-25T09:47:19Z", "event":"FactionKillBond", "Reward":80000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||
{ "timestamp":"2022-11-25T10:13:32Z", "event":"Docked", "StationName":"Pilcher Port", "StationType":"Orbis", "Taxi":false, "Multicrew":false, "StarSystem":"Nyalayan", "SystemAddress":1458309042898, "MarketID":3222853120, "StationFaction":{ "Name":"Nyalayan Imperial Society", "FactionState":"Election" }, "StationGovernment":"$government_Patronage;", "StationGovernment_Localised":"Patronage", "StationAllegiance":"Empire", "StationServices":[ "dock", "autodock", "commodities", "contacts", "exploration", "missions", "outfitting", "crewlounge", "rearm", "refuel", "repair", "shipyard", "tuning", "engineer", "missionsgenerated", "flightcontroller", "stationoperations", "powerplay", "searchrescue", "stationMenu", "shop", "livery", "socialspace", "bartender", "vistagenomics", "pioneersupplies", "apexinterstellar", "frontlinesolutions" ], "StationEconomy":"$economy_Refinery;", "StationEconomy_Localised":"Refinery", "StationEconomies":[ { "Name":"$economy_Refinery;", "Name_Localised":"Refinery", "Proportion":1.000000 } ], "DistFromStarLS":76.465557, "LandingPads":{ "Small":8, "Medium":11, "Large":6 } }
|
||||
{ "timestamp":"2022-11-25T10:13:53Z", "event":"RedeemVoucher", "Type":"CombatBond", "Amount":24240000, "Faction":"PilotsFederation" }
|
||||
63
EDPlayerJournalTests/dropship-deploy.txt
Normal file
63
EDPlayerJournalTests/dropship-deploy.txt
Normal file
@@ -0,0 +1,63 @@
|
||||
{"timestamp":"2022-12-09T14:23:52Z","event":"Fileheader","part":1,"language":"English/UK","Odyssey":true,"gameversion":"4.0.0.1476","build":"r289925/r0 "}
|
||||
{"timestamp":"2022-12-09T14:33:01Z","event":"Location","DistFromStarLS":774.492896,"Docked":false,"OnFoot":true,"StarSystem":"Kazahua","SystemAddress":2871050905001,"StarPos":[93.28125,-180.25,14.6875],"SystemAllegiance":"Empire","SystemEconomy":"$economy_Industrial;","SystemEconomy_Localised":"Industrial","SystemSecondEconomy":"$economy_Colony;","SystemSecondEconomy_Localised":"Colony","SystemGovernment":"$government_Patronage;","SystemGovernment_Localised":"Patronage","SystemSecurity":"$SYSTEM_SECURITY_low;","SystemSecurity_Localised":"Low Security","Population":17949,"Body":"Kazahua 4 a","BodyID":5,"BodyType":"Planet","Factions":[{"Name":"Kazahua Co","FactionState":"None","Government":"Corporate","Influence":0.049098,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"Kazahua Crimson Ring","FactionState":"None","Government":"Anarchy","Influence":0.01002,"Allegiance":"Independent","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"HIP 10611 Shared","FactionState":"None","Government":"Cooperative","Influence":0.091182,"Allegiance":"Independent","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":2.97},{"Name":"Traditional Yao Tzu Liberty Party","FactionState":"None","Government":"Dictatorship","Influence":0.058116,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":-10.56},{"Name":"Sapii allied","FactionState":"War","Government":"Cooperative","Influence":0.395792,"Allegiance":"Independent","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":-6.0,"ActiveStates":[{"State":"War"}]},{"Name":"Nova Paresa","FactionState":"War","Government":"Patronage","Influence":0.395792,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","SquadronFaction":true,"MyReputation":63.045399,"ActiveStates":[{"State":"War"}]}],"SystemFaction":{"Name":"Nova Paresa","FactionState":"War"},"Conflicts":[{"WarType":"war","Status":"active","Faction1":{"Name":"Sapii allied","Stake":"Barmin Installation","WonDays":0},"Faction2":{"Name":"Nova Paresa","Stake":"Rabinowitz Colony","WonDays":0}}]}
|
||||
{"timestamp":"2022-12-09T14:33:05Z","event":"ReceiveText","From":"Barmin Installation","Message":"$STATION_NoFireZone_entered;","Message_Localised":"No fire zone entered.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:36:52Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_EndPatrol02;","Message_Localised":"Requesting docking clearance, Control.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:39:54Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_StartPatrol01;","Message_Localised":"Patrol craft checking in. Pre-flight checks complete, I'm heading out.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:42:02Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_EndPatrol04;","Message_Localised":"Negative, Tower, I'm bingo on fuel, RTB.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:42:05Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_EndPatrol02;","Message_Localised":"Requesting docking clearance, Control.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:45:23Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_StartPatrol01;","Message_Localised":"Patrol craft checking in. Pre-flight checks complete, I'm heading out.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:45:51Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_StartPatrol04;","Message_Localised":"I'm away, heading to patrol route alpha now.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:46:22Z","event":"RedeemVoucher","Type":"CombatBond","Amount":17406041,"Faction":"Nova Paresa"}
|
||||
{"timestamp":"2022-12-09T14:49:17Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_EndPatrol02;","Message_Localised":"Requesting docking clearance, Control.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:49:43Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_EndPatrol05;","Message_Localised":"Patrol completed, Command, I'm heading home.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:52:32Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_StartPatrol01;","Message_Localised":"Patrol craft checking in. Pre-flight checks complete, I'm heading out.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:52:34Z","event":"Embark","SRV":false,"Taxi":true,"Multicrew":false,"StarSystem":"Kazahua","SystemAddress":2871050905001,"Body":"Kazahua 4 a","BodyID":5,"OnStation":false,"OnPlanet":true}
|
||||
{"timestamp":"2022-12-09T14:53:29Z","event":"SupercruiseEntry","Taxi":true,"Multicrew":false,"StarSystem":"Kazahua","SystemAddress":2871050905001}
|
||||
{"timestamp":"2022-12-09T14:58:16Z","event":"DropshipDeploy","StarSystem":"Kazahua","SystemAddress":2871050905001,"Body":"Kazahua 2","BodyID":2,"OnStation":false,"OnPlanet":true}
|
||||
{"timestamp":"2022-12-09T14:59:38Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:00:02Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:00:12Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:00:33Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:00:45Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:01:07Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:01:11Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough06;","Message_Localised":"On patrol. Scanning for hostiles.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:02:12Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:21Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:24Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:32Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:42Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:45Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:50Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough09;","Message_Localised":"This is a routine patrol. There's nothing to worry about.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:04:03Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:04:03Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough06;","Message_Localised":"On patrol. Scanning for hostiles.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:04:09Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:04:13Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:04:25Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:05:06Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough06;","Message_Localised":"On patrol. Scanning for hostiles.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:05:10Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough10;","Message_Localised":"System sweep in operation.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:05:19Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough06;","Message_Localised":"On patrol. Scanning for hostiles.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:05:22Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:05:35Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:05:44Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:06:11Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:06:22Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough08;","Message_Localised":"Patrol waypoint reached. Scanning.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:06:27Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:06:27Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:06:39Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:06:44Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough09;","Message_Localised":"This is a routine patrol. There's nothing to worry about.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:06:50Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:07:03Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:07:11Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:07:15Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:07:26Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:08:20Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:08:26Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:08:29Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough07;","Message_Localised":"No need to worry, the navy is here.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:08:33Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:08:47Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:08:48Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:09:00Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:09:00Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:09:08Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:09:20Z","event":"FactionKillBond","Reward":78777,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:09:46Z","event":"Shutdown"}
|
||||
7
EDPlayerJournalTests/legacy-transaction.txt
Normal file
7
EDPlayerJournalTests/legacy-transaction.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
{ "timestamp":"2022-02-06T16:36:53Z", "event":"Fileheader", "part":1, "language":"English/UK", "gameversion":"3.8.0.1102", "build":"r280672/r0 " }
|
||||
{ "timestamp":"2022-02-06T18:10:26Z", "event":"FSDJump", "Taxi":false, "Multicrew":false, "StarSystem":"Akualanu", "SystemAddress":5069805856169, "StarPos":[63.78125,-128.50000,3.00000], "SystemAllegiance":"Empire", "SystemEconomy":"$economy_Tourism;", "SystemEconomy_Localised":"Tourism", "SystemSecondEconomy":"$economy_HighTech;", "SystemSecondEconomy_Localised":"High Tech", "SystemGovernment":"$government_Patronage;", "SystemGovernment_Localised":"Patronage", "SystemSecurity":"$SYSTEM_SECURITY_low;", "SystemSecurity_Localised":"Low Security", "Population":787019, "Body":"Akualanu A", "BodyID":1, "BodyType":"Star", "Powers":[ "A. Lavigny-Duval" ], "PowerplayState":"Exploited", "JumpDist":40.001, "FuelUsed":4.849240, "FuelLevel":22.573641, "Factions":[ { "Name":"Akualanu United & Co", "FactionState":"War", "Government":"Corporate", "Influence":0.158000, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand3;", "Happiness_Localised":"Discontented", "MyReputation":100.000000, "RecoveringStates":[ { "State":"InfrastructureFailure", "Trend":0 } ], "ActiveStates":[ { "State":"Lockdown" }, { "State":"Famine" }, { "State":"War" } ] }, { "Name":"Alacagui Holdings", "FactionState":"War", "Government":"Corporate", "Influence":0.086000, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":55.000000, "RecoveringStates":[ { "State":"PirateAttack", "Trend":0 } ], "ActiveStates":[ { "State":"War" } ] }, { "Name":"Left Party of Akualanu", "FactionState":"War", "Government":"Communism", "Influence":0.086000, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand3;", "Happiness_Localised":"Discontented", "MyReputation":95.899399, "RecoveringStates":[ { "State":"InfrastructureFailure", "Trend":0 } ], "ActiveStates":[ { "State":"Lockdown" }, { "State":"Famine" }, { "State":"War" } ] }, { "Name":"Cartel of Akualanu", "FactionState":"Famine", "Government":"Anarchy", "Influence":0.028000, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":29.040001, "RecoveringStates":[ { "State":"InfrastructureFailure", "Trend":0 } ], "ActiveStates":[ { "State":"Famine" } ] }, { "Name":"Revolutionary Akualanu Liberals", "FactionState":"Bust", "Government":"Democracy", "Influence":0.085000, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand3;", "Happiness_Localised":"Discontented", "MyReputation":43.093700, "PendingStates":[ { "State":"Lockdown", "Trend":0 } ], "ActiveStates":[ { "State":"InfrastructureFailure" }, { "State":"Bust" } ] }, { "Name":"Conservatives of Cockaigne", "FactionState":"War", "Government":"Dictatorship", "Influence":0.138000, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand3;", "Happiness_Localised":"Discontented", "MyReputation":70.000000, "ActiveStates":[ { "State":"CivilUnrest" }, { "State":"InfrastructureFailure" }, { "State":"War" } ] }, { "Name":"Nova Paresa", "FactionState":"Investment", "Government":"Patronage", "Influence":0.419000, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand1;", "Happiness_Localised":"Elated", "SquadronFaction":true, "MyReputation":100.000000, "ActiveStates":[ { "State":"Investment" }, { "State":"CivilLiberty" } ] } ], "SystemFaction":{ "Name":"Nova Paresa", "FactionState":"Investment" }, "Conflicts":[ { "WarType":"war", "Status":"active", "Faction1":{ "Name":"Akualanu United & Co", "Stake":"Konig Institution", "WonDays":0 }, "Faction2":{ "Name":"Conservatives of Cockaigne", "Stake":"", "WonDays":1 } }, { "WarType":"war", "Status":"active", "Faction1":{ "Name":"Alacagui Holdings", "Stake":"Ware Cultivation Facility", "WonDays":2 }, "Faction2":{ "Name":"Left Party of Akualanu", "Stake":"", "WonDays":2 } } ] }
|
||||
{ "timestamp":"2022-02-06T18:13:30Z", "event":"Docked", "StationName":"Hughes Vista", "StationType":"Coriolis", "Taxi":false, "Multicrew":false, "StarSystem":"Akualanu", "SystemAddress":5069805856169, "MarketID":3222969088, "StationFaction":{ "Name":"Nova Paresa", "FactionState":"Investment" }, "StationGovernment":"$government_Patronage;", "StationGovernment_Localised":"Patronage", "StationAllegiance":"Empire", "StationServices":[ "dock", "autodock", "commodities", "contacts", "exploration", "missions", "outfitting", "crewlounge", "rearm", "refuel", "repair", "shipyard", "tuning", "engineer", "missionsgenerated", "facilitator", "flightcontroller", "stationoperations", "powerplay", "searchrescue", "stationMenu", "shop", "livery", "socialspace", "bartender", "vistagenomics", "pioneersupplies", "apexinterstellar", "frontlinesolutions" ], "StationEconomy":"$economy_Tourism;", "StationEconomy_Localised":"Tourism", "StationEconomies":[ { "Name":"$economy_Tourism;", "Name_Localised":"Tourism", "Proportion":1.000000 } ], "DistFromStarLS":78.917615, "LandingPads":{ "Small":13, "Medium":16, "Large":8 } }
|
||||
{ "timestamp":"2022-11-25T09:52:28Z", "event":"FactionKillBond", "Reward":24000000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||
{ "timestamp":"2022-11-21T15:56:08Z", "event":"MarketSell", "MarketID":3222176256, "Type":"silver", "Count":224, "SellPrice":40996, "TotalSale":9183104, "AvgPricePaid":34311 }
|
||||
{ "timestamp":"2022-02-06T16:36:53Z", "event":"Fileheader", "part":1, "language":"English/UK", "Odyssey":true, "gameversion":"4.0.0.1102", "build":"r280672/r0 " }
|
||||
{ "timestamp":"2022-02-06T18:17:44Z", "event":"SellOrganicData", "MarketID":3222969088, "BioData":[ { "Genus":"$Codex_Ent_Stratum_Genus_Name;", "Genus_Localised":"Stratum", "Species":"$Codex_Ent_Stratum_07_Name;", "Species_Localised":"Stratum Tectonicas", "Value":806300, "Bonus":0 }, { "Genus":"$Codex_Ent_Aleoids_Genus_Name;", "Genus_Localised":"Aleoida", "Species":"$Codex_Ent_Aleoids_05_Name;", "Species_Localised":"Aleoida Gravis", "Value":596500, "Bonus":0 } ] }
|
||||
@@ -1,24 +0,0 @@
|
||||
<Window x:Class="EliteBGS.AdjustProfitWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:EliteBGS"
|
||||
mc:Ignorable="d"
|
||||
Title="Adjust Trade Profit" Height="130" Width="450">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Content="Use this dialog to adjust trade profits" Grid.Row="0" Grid.ColumnSpan="2" />
|
||||
<TextBox x:Name="Profit" Grid.Row="1" Grid.ColumnSpan="2" Margin="10,10,10,10"/>
|
||||
<Button x:Name="Cancel" Content="Cancel" Width="60" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right" Margin="5,0,5,0" IsCancel="true" Click="Cancel_Click"/>
|
||||
<Button x:Name="Accept" Content="Accept" Width="60" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Right" Margin="5,0,5,0" IsDefault="true" Click="Accept_Click" />
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,34 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace EliteBGS {
|
||||
/// <summary>
|
||||
/// Interaction logic for AdjustProfitWindow.xaml
|
||||
/// </summary>
|
||||
public partial class AdjustProfitWindow : Window {
|
||||
public AdjustProfitWindow() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Cancel_Click(object sender, RoutedEventArgs e) {
|
||||
DialogResult = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void Accept_Click(object sender, RoutedEventArgs e) {
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
{
|
||||
"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json",
|
||||
"version": "2.1.0",
|
||||
"runs": [
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "Dependency Analysis",
|
||||
"semanticVersion": "0.4.355802",
|
||||
"informationUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview",
|
||||
"rules": [
|
||||
{
|
||||
"id": "UA106",
|
||||
"name": "PackageToBeAdded",
|
||||
"fullDescription": {
|
||||
"text": "Packages that need to be added in order to upgrade the project to chosen TFM"
|
||||
},
|
||||
"helpUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "UA106",
|
||||
"message": {
|
||||
"text": "Package Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers, Version=0.4.355802 needs to be added."
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
||||
},
|
||||
"region": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ruleId": "UA106",
|
||||
"message": {
|
||||
"text": "Package Microsoft.Windows.Compatibility, Version=7.0.0 needs to be added."
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
||||
},
|
||||
"region": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"columnKind": "utf16CodeUnits"
|
||||
},
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "API Upgradability",
|
||||
"semanticVersion": "0.4.355802",
|
||||
"informationUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview"
|
||||
}
|
||||
},
|
||||
"results": [],
|
||||
"columnKind": "utf16CodeUnits"
|
||||
},
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "Component Analysis",
|
||||
"semanticVersion": "0.4.355802",
|
||||
"informationUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview",
|
||||
"rules": [
|
||||
{
|
||||
"id": "UA209",
|
||||
"name": "Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.WinformsDefaultFontUpdater",
|
||||
"fullDescription": {
|
||||
"text": "Default Font API Alert"
|
||||
},
|
||||
"helpUri": "about:blank"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "UA209",
|
||||
"message": {
|
||||
"text": "Default font in Windows Forms has been changed from Microsoft Sans Serif to Seg Segoe UI, in order to change the default font use the API - Application.SetDefaultFont(Font font). For more details see here - https://devblogs.microsoft.com/dotnet/whats-new-in-windows-forms-in-net-6-0-preview-5/#application-wide-default-font."
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
||||
},
|
||||
"region": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"columnKind": "utf16CodeUnits"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
<Window x:Class="EliteBGS.CombatZoneDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:EliteBGS"
|
||||
mc:Ignorable="d"
|
||||
Title="Add Combat Zone Wins" Height="150" Width="370" Icon="EliteBGS.ico" WindowStartupLocation="CenterOwner">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<GroupBox Header="Add Combat Zone" Grid.Row="0" Grid.Column="0" Width="Auto">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<ComboBox x:Name="type" Grid.Column="0" VerticalAlignment="Top" Width="Auto" IsReadOnly="True" Height="23" Margin="5" SelectedIndex="0">
|
||||
<ComboBoxItem Content="Ship"/>
|
||||
<ComboBoxItem Content="On Foot"/>
|
||||
</ComboBox>
|
||||
<ComboBox x:Name="grade" Grid.Column="1" VerticalAlignment="Top" IsReadOnly="True" Margin="5" Height="23" Width="Auto" SelectedIndex="0">
|
||||
<ComboBoxItem Content="Low"/>
|
||||
<ComboBoxItem Content="Medium"/>
|
||||
<ComboBoxItem Content="High"/>
|
||||
</ComboBox>
|
||||
<TextBox x:Name="amount" Grid.Column="2" Height="23" TextWrapping="Wrap" Text="1" VerticalAlignment="Top" Width="Auto" Margin="5" HorizontalContentAlignment="Right"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button x:Name="Accept" Content="Accept" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" Width="75" Margin="5" IsDefault="True" Click="Accept_Click"/>
|
||||
<Button x:Name="Cancel" Content="Cancel" HorizontalAlignment="Right" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Width="75" Margin="5" IsCancel="True" Click="Cancel_Click"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,47 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace EliteBGS {
|
||||
/// <summary>
|
||||
/// Interaction logic for CombatZoneDialog.xaml
|
||||
/// </summary>
|
||||
public partial class CombatZoneDialog : Window {
|
||||
public CombatZoneDialog() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string Type => (type.SelectedItem as ComboBoxItem).Content.ToString();
|
||||
public string Grade => (grade.SelectedItem as ComboBoxItem).Content.ToString();
|
||||
public int Amount {
|
||||
get {
|
||||
try {
|
||||
return int.Parse(amount.Text);
|
||||
} catch (Exception) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Accept_Click(object sender, RoutedEventArgs e) {
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void Cancel_Click(object sender, RoutedEventArgs e) {
|
||||
DialogResult = false;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ public class DiscordLogGenerator {
|
||||
new FailedMissionFormat(),
|
||||
new MurderFormat(),
|
||||
new VoucherFormat(),
|
||||
new ThargoidFormatter(),
|
||||
new CombatZoneFormat(),
|
||||
new KillBondsFormat(),
|
||||
new CartographicsFormat(),
|
||||
@@ -33,10 +34,26 @@ public class DiscordLogGenerator {
|
||||
protected virtual string GenerateObjectiveHeader(Objective objective) {
|
||||
StringBuilder log = new StringBuilder();
|
||||
|
||||
string location;
|
||||
|
||||
if (!string.IsNullOrEmpty(objective.System) && !string.IsNullOrEmpty(objective.Faction)) {
|
||||
location = string.Format("{0}, {1}", objective.System, objective.Faction);
|
||||
} else if (!string.IsNullOrEmpty(objective.System)) {
|
||||
location = objective.System;
|
||||
} else {
|
||||
location = "Unknown Location";
|
||||
}
|
||||
|
||||
int legacycount = objective.Transactions
|
||||
.Where(x => x.IsLegacy)
|
||||
.Count()
|
||||
;
|
||||
|
||||
log.AppendFormat("**Date:** {0}\n", DateTime.Now.ToString("dd/MM/yyyy"));
|
||||
log.AppendFormat("**Location:** {0}, {1}\n", objective.System, objective.Faction);
|
||||
log.AppendFormat("**Faction:** {0}\n", objective.Faction);
|
||||
log.AppendLine("");
|
||||
log.AppendFormat("**Target:** {0}\n", location);
|
||||
if (legacycount > 0) {
|
||||
log.AppendFormat("**Warning:** Some actions were performed on ED Legacy\n");
|
||||
}
|
||||
log.AppendLine("```");
|
||||
|
||||
return log.ToString();
|
||||
@@ -46,6 +63,16 @@ public class DiscordLogGenerator {
|
||||
return "```\n";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is called to do final adjustments to the log body of a given objective.
|
||||
/// </summary>
|
||||
/// <param name="objective">Objective in question.</param>
|
||||
/// <param name="log">Final log as generated.</param>
|
||||
/// <returns>The transformed log.</returns>
|
||||
protected virtual string TransformFinalLogForObjective(Objective objective, string log) {
|
||||
return log;
|
||||
}
|
||||
|
||||
public virtual string GenerateDiscordLog(Report report) {
|
||||
StringBuilder log = new StringBuilder();
|
||||
|
||||
@@ -61,12 +88,12 @@ public class DiscordLogGenerator {
|
||||
return "";
|
||||
}
|
||||
|
||||
log.AppendFormat("{0}\n", GenerateHeader());
|
||||
log.AppendFormat("{0}", GenerateHeader());
|
||||
|
||||
foreach (Objective objective in objectives) {
|
||||
StringBuilder objlog = new StringBuilder();
|
||||
|
||||
log.AppendFormat("{0}\n", GenerateObjectiveHeader(objective));
|
||||
log.AppendFormat("{0}", GenerateObjectiveHeader(objective));
|
||||
|
||||
foreach (LogFormatter formatter in formatters) {
|
||||
string text = formatter.GenerateLog(objective);
|
||||
@@ -76,12 +103,15 @@ public class DiscordLogGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
log.AppendFormat("{0}\n", objlog.ToString().Trim());
|
||||
string finallog = objlog.ToString().Trim();
|
||||
finallog = TransformFinalLogForObjective(objective, finallog);
|
||||
|
||||
log.AppendFormat("{0}\n", GenerateObjectiveFooter(objective));
|
||||
log.AppendFormat("{0}\n", finallog);
|
||||
|
||||
log.AppendFormat("{0}", GenerateObjectiveFooter(objective));
|
||||
}
|
||||
|
||||
log.AppendFormat("{0}\n", GenerateFooter());
|
||||
log.AppendFormat("{0}", GenerateFooter());
|
||||
|
||||
return log.ToString().Trim();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<Version>0.2.6</Version>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
@@ -11,22 +12,23 @@
|
||||
<StartupObject>EliteBGSApplication</StartupObject>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>EliteBGS.ico</ApplicationIcon>
|
||||
<ApplicationIcon>Salus.ico</ApplicationIcon>
|
||||
<Title>BGS reporting and logging tool for Elite:Dangerous</Title>
|
||||
<Authors>nola</Authors>
|
||||
<Copyright>Copyright 2019 by Florian Stinglmayr</Copyright>
|
||||
<RepositoryUrl>https://git.aror.org/florian/EDBGS</RepositoryUrl>
|
||||
<PackageTags>ED;Elite Dangerous;BGS</PackageTags>
|
||||
<PackageProjectUrl>https://bgs.n0la.org</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="EDJournal, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\edjournal\bin\Debug\EDJournal.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Design" />
|
||||
<Reference Include="System.Security" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="main-page.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
<None Update="README.md">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
<None Update="docs\CHANGELOG.md">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
@@ -42,6 +44,9 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Salus.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="logo_v4.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
@@ -54,21 +59,28 @@
|
||||
<Resource Include="EliteBGS.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.355802">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Windows.Compatibility" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EDPlayerJournal\EDPlayerJournal.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="BGS\" />
|
||||
<Compile Update="Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resources.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 200 KiB |
@@ -6,6 +6,7 @@ using System.Windows;
|
||||
using Microsoft.Win32;
|
||||
using EDPlayerJournal.Entries;
|
||||
using EliteBGS.Util;
|
||||
using EDPlayerJournal.BGS;
|
||||
|
||||
namespace EliteBGS;
|
||||
|
||||
@@ -85,6 +86,8 @@ public partial class LoadEntriesWindow : Window {
|
||||
return;
|
||||
}
|
||||
|
||||
TransactionParser parser = new();
|
||||
|
||||
try {
|
||||
List<Entry> entries = new List<Entry>();
|
||||
|
||||
@@ -93,8 +96,10 @@ public partial class LoadEntriesWindow : Window {
|
||||
continue;
|
||||
}
|
||||
Entry entry = Entry.Parse(line);
|
||||
if (parser.IsRelevant(entry)) {
|
||||
entries.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (entries.Count <= 0) {
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,46 @@
|
||||
using EDPlayerJournal.BGS;
|
||||
using EDPlayerJournal;
|
||||
using EDPlayerJournal.BGS;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace EliteBGS.LogGenerator;
|
||||
|
||||
class CombatZoneFormat : GenericFormat<CombatZone> {
|
||||
class CombatZoneFormat : LogFormatter {
|
||||
public string GenerateLog(Objective objective) {
|
||||
var logs = objective
|
||||
.EnabledOfType<CombatZone>()
|
||||
.GroupBy(x => new { x.Type, x.Grade })
|
||||
.ToDictionary(x => x.Key, x => x.ToList())
|
||||
;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (logs == null || logs.Count() <= 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
foreach (var log in logs) {
|
||||
int optionals = log.Value
|
||||
.Sum(x => x.OptionalObjectivesCompleted)
|
||||
;
|
||||
if (!string.IsNullOrEmpty(log.Key.Grade)) {
|
||||
builder.AppendFormat("Won {0}x {1} {2} Combat Zone(s)",
|
||||
log.Value.Count,
|
||||
log.Key.Grade,
|
||||
log.Key.Type
|
||||
);
|
||||
} else {
|
||||
builder.AppendFormat("Won {0}x {1} Combat Zone(s)",
|
||||
log.Value.Count,
|
||||
log.Key.Type
|
||||
);
|
||||
}
|
||||
|
||||
if (optionals > 0) {
|
||||
builder.AppendFormat(" (with {0} optional objectives)", optionals);
|
||||
}
|
||||
builder.Append("\n");
|
||||
}
|
||||
|
||||
return builder.ToString().Trim();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,19 +8,25 @@ namespace EliteBGS.LogGenerator;
|
||||
public class FailedMissionFormat : LogFormatter {
|
||||
public string GenerateLog(Objective objective) {
|
||||
var missions = objective.EnabledOfType<MissionFailed>();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (missions.Count <= 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
foreach (MissionFailed failed in missions) {
|
||||
MissionFailedEntry f = failed.Failed;
|
||||
builder.AppendFormat("Failed {0} mission(s) \"{1}\" targeting {2}\n",
|
||||
failed.Amount,
|
||||
string.IsNullOrEmpty(f.Mission.LocalisedName) ? f.Mission.Name : f.Mission.LocalisedName,
|
||||
failed.Faction
|
||||
);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
var grouping = missions
|
||||
.GroupBy(x => x.Mission.IsOnFoot)
|
||||
;
|
||||
|
||||
foreach (var group in grouping) {
|
||||
int amount = group.Count();
|
||||
|
||||
if (group.Key) {
|
||||
builder.AppendFormat("Failed {0} On Foot Mission(s)\n", amount);
|
||||
} else {
|
||||
builder.AppendFormat("Failed {0} Ship Mission(s)\n", amount);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.ToString().Trim();
|
||||
|
||||
@@ -7,13 +7,16 @@ namespace EliteBGS.LogGenerator;
|
||||
|
||||
public class MissionFormat : LogFormatter {
|
||||
public string GenerateLog(Objective objective) {
|
||||
Dictionary<string, Dictionary<string, int>> collated = new Dictionary<string, Dictionary<string, int>>();
|
||||
Dictionary<string, Dictionary<string, int>> collated = new();
|
||||
Dictionary<string, ulong> passengers = new();
|
||||
StringBuilder output = new StringBuilder();
|
||||
int total_influence = 0;
|
||||
|
||||
var missions = objective.EnabledOfType<MissionCompleted>();
|
||||
var support = objective.EnabledOfType<InfluenceSupport>();
|
||||
|
||||
if (missions == null || missions.Count == 0) {
|
||||
if ((missions == null || missions.Count == 0) &&
|
||||
(support == null || support.Count == 0)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -28,23 +31,35 @@ public class MissionFormat : LogFormatter {
|
||||
++collated[m.MissionName][m.Influence];
|
||||
|
||||
total_influence += m.Influence.Length;
|
||||
|
||||
if (m.AcceptedEntry != null &&
|
||||
m.AcceptedEntry.Mission != null &&
|
||||
m.AcceptedEntry.Mission.IsPassengerMission) {
|
||||
if (!passengers.ContainsKey(m.MissionName)) {
|
||||
passengers[m.MissionName] = 0;
|
||||
}
|
||||
passengers[m.MissionName] += (m.AcceptedEntry.Mission.PassengerCount ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var mission in collated) {
|
||||
if (objective.Faction != null) {
|
||||
output.AppendFormat("{0}\n", mission.Key);
|
||||
} else {
|
||||
output.AppendFormat("{0}\n", mission.Key);
|
||||
}
|
||||
output.AppendFormat("{0}: ", mission.Key);
|
||||
output.Append("(");
|
||||
foreach (var influence in mission.Value.OrderBy(x => x.Key.Length)) {
|
||||
output.AppendFormat("Inf{0} x{1}, ", influence.Key, influence.Value);
|
||||
}
|
||||
output.Remove(output.Length - 2, 2); // remove last ", "
|
||||
output.Append(")\n\n");
|
||||
output.Append(")");
|
||||
|
||||
if (passengers.ContainsKey(mission.Key)) {
|
||||
output.AppendFormat(" ({0} Passengers)", passengers[mission.Key]);
|
||||
}
|
||||
|
||||
var support = objective.EnabledOfType<InfluenceSupport>();
|
||||
output.Append("\n");
|
||||
}
|
||||
|
||||
output.Append("\n");
|
||||
|
||||
foreach (InfluenceSupport inf in support) {
|
||||
output.Append(inf.ToString());
|
||||
output.Append("\n");
|
||||
|
||||
@@ -1,6 +1,48 @@
|
||||
using EDPlayerJournal.BGS;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using EDPlayerJournal;
|
||||
|
||||
namespace EliteBGS.LogGenerator;
|
||||
|
||||
public class MurderFormat : GenericFormat<FoulMurder> {
|
||||
public class MurderFormat : LogFormatter {
|
||||
public string GenerateLog(Objective objective) {
|
||||
var logs = objective
|
||||
.EnabledOfType<FoulMurder>()
|
||||
.GroupBy(x => x.CrimeType)
|
||||
.ToDictionary(x => x.Key, x => x.ToList())
|
||||
;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (logs == null || logs.Count() <= 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
foreach (var log in logs) {
|
||||
string type;
|
||||
|
||||
if (string.Compare(log.Key, CrimeTypes.Murder) == 0) {
|
||||
if (log.Value.Count > 1) {
|
||||
type = "ships";
|
||||
} else {
|
||||
type = "ship";
|
||||
}
|
||||
} else {
|
||||
if (log.Value.Count > 1) {
|
||||
type = "people";
|
||||
} else {
|
||||
type = "person";
|
||||
}
|
||||
}
|
||||
builder.AppendFormat("Murdered {0} {1} (Bounties: {2}, Fines: {3})",
|
||||
log.Value.Count, type,
|
||||
log.Value.Sum(x => x.Bounties),
|
||||
log.Value.Sum(x => x.Fines)
|
||||
);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
32
EliteBGS/LogGenerator/ThargoidFormatter.cs
Normal file
32
EliteBGS/LogGenerator/ThargoidFormatter.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using EDPlayerJournal;
|
||||
using EDPlayerJournal.BGS;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EliteBGS.LogGenerator;
|
||||
|
||||
public class ThargoidFormatter : LogFormatter {
|
||||
public string GenerateLog(Objective objective) {
|
||||
List<ThargoidKill> kills = objective.EnabledOfType<ThargoidKill>().ToList();
|
||||
|
||||
if (kills.Count == 0 ) {
|
||||
return "";
|
||||
}
|
||||
|
||||
Dictionary<ThargoidVessel, List<ThargoidKill>> sorted = kills
|
||||
.GroupBy(x => x.ThargoidType)
|
||||
.ToDictionary(x => x.Key, x => x.ToList())
|
||||
;
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
foreach (var k in sorted) {
|
||||
string name = Thargoid.GetVesselName(k.Key);
|
||||
builder.AppendFormat("{0}x {1}(s) killed\n", k.Value.Count, name);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,10 @@ namespace EliteBGS.LogGenerator;
|
||||
public class VoucherFormat : LogFormatter {
|
||||
public string GenerateLog(Objective objective) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
var missions = objective.UITransactions
|
||||
.Where(x => x.IsEnabled)
|
||||
.Select(x => x.Transaction)
|
||||
.OfType<Vouchers>()
|
||||
var missions = objective
|
||||
.EnabledOfType<Vouchers>()
|
||||
.GroupBy(x => x.Type)
|
||||
.ToDictionary(x => x.Key, x => x.ToList())
|
||||
;
|
||||
|
||||
if (missions == null || missions.Count() <= 0) {
|
||||
@@ -19,9 +19,8 @@ public class VoucherFormat : LogFormatter {
|
||||
}
|
||||
|
||||
foreach (var m in missions) {
|
||||
builder.AppendFormat("Handed in {0} vouchers for {1}\n", m.Type, m.Faction);
|
||||
builder.AppendFormat("(Total value: {0})\n", Credits.FormatCredits(m.TotalSum));
|
||||
builder.AppendFormat("\n");
|
||||
ulong total = (ulong)m.Value.Sum(x => (decimal)x.TotalSum);
|
||||
builder.AppendFormat("Handed in {0} vouchers: {1}\n", m.Key, Credits.FormatCredits(total));
|
||||
}
|
||||
|
||||
return builder.ToString().Trim();
|
||||
|
||||
@@ -4,10 +4,17 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:abc="http://wpfcontrols.com/"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
xmlns:local="clr-namespace:EliteBGS"
|
||||
xmlns:Util="clr-namespace:EliteBGS.Util" d:DataContext="{d:DesignInstance Type=Util:AppConfig}" x:Name="window" x:Class="EliteBGS.MainWindow"
|
||||
mc:Ignorable="d"
|
||||
Title="Elite: Dangerous BGS Helper" Height="520" Width="890" Icon="EliteBGS.ico" Closing="window_Closing">
|
||||
Title="Elite: Dangerous BGS Helper" Height="520" Width="950" Icon="Salus.ico" Closing="window_Closing">
|
||||
<Window.Resources>
|
||||
<Style x:Key="StretchingTreeViewStyle" TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
</Style>
|
||||
<local:MinusFortyFiveConverter x:Key="MinusFortyFiveConverter" />
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
@@ -21,45 +28,114 @@
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ToolBar VerticalAlignment="Top" Grid.Row="1" Width="Auto" Margin="0,0,0,0" Height="Auto" Grid.ColumnSpan="3" HorizontalAlignment="Left">
|
||||
<ToolBar VerticalAlignment="Top" Grid.Row="0" Width="Auto" Margin="0,0,0,0" Height="Auto" Grid.ColumnSpan="3" HorizontalAlignment="Left">
|
||||
<Button x:Name="ParseJournal" Content="Parse Journal" VerticalAlignment="Center" Click="ParseJournal_Click" HorizontalAlignment="Center"/>
|
||||
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
||||
<Label Content="From:" VerticalAlignment="Center" VerticalContentAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<DatePicker x:Name="startdate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<Label Content="To:" Height="26.2857142857143" VerticalAlignment="Top"/>
|
||||
<DatePicker x:Name="enddate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<Label Content="From (UTC):" VerticalAlignment="Center" VerticalContentAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<xctk:DateTimePicker x:Name="startdate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<Label Content="To (UTC):" Height="26.2857142857143" VerticalAlignment="Top"/>
|
||||
<xctk:DateTimePicker x:Name="enddate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
||||
<CheckBox x:Name="collate" Margin="1" Content="Collate entries" IsChecked="True" IsThreeState="False"/>
|
||||
<Separator Height="26.2857142857143" Margin="0" VerticalAlignment="Top"/>
|
||||
<Button x:Name="AddCombatZone" Content="Add Combat Zone Win" VerticalAlignment="Stretch" Margin="0,0,0,0.286" RenderTransformOrigin="0.5,0.505" Click="AddCombatZone_Click"/>
|
||||
<Separator Height="26.2857142857143" Margin="0" VerticalAlignment="Top"/>
|
||||
<Button x:Name="AdjustProfit" Content="Adjust Trade Profit" Margin="0" VerticalAlignment="Stretch" Click="AdjustProfit_Click" />
|
||||
<Button x:Name="ResetTime" Content="Reset Time" Click="ResetTime_Click" />
|
||||
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
||||
<Button x:Name="ManuallyParse" Content="Manually Parse JSON" Click="ManuallyParse_Click" />
|
||||
<Button x:Name="ManuallyParse" Content="Manually Parse" Click="ManuallyParse_Click" />
|
||||
</ToolBar>
|
||||
<TreeView CheckBox.Checked="TreeView_CheckBox_Updated" CheckBox.Unchecked="TreeView_CheckBox_Updated" x:Name="entries" Margin="0,0,0,0" Grid.ColumnSpan="3" Grid.Row="2" KeyUp="entries_KeyUp">
|
||||
<ToolBar Grid.Row="1" HorizontalAlignment="Left" Height="36" VerticalAlignment="Top" Width="Auto" Grid.ColumnSpan="3">
|
||||
<Button x:Name="GenerateDiscord" Content="Generate Discord Report" VerticalAlignment="Stretch" Margin="0,0,0,0" VerticalContentAlignment="Center" Click="GenerateDiscord_Click" Height="26"/>
|
||||
<Separator />
|
||||
<ComboBox x:Name="LogType" VerticalAlignment="Stretch" Margin="0,3,0,3" Width="140" SelectionChanged="LogType_SelectionChanged" />
|
||||
</ToolBar>
|
||||
<TreeView CheckBox.Checked="TreeView_CheckBox_Updated"
|
||||
CheckBox.Unchecked="TreeView_CheckBox_Updated"
|
||||
x:Name="entries" Margin="0,0,0,0"
|
||||
Grid.ColumnSpan="3" Grid.Row="2"
|
||||
KeyUp="entries_KeyUp"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
>
|
||||
<TreeView.ItemTemplate>
|
||||
<HierarchicalDataTemplate DataType="{x:Type local:Objective}" ItemsSource="{Binding UITransactions}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<HierarchicalDataTemplate DataType="{x:Type local:Objective}" ItemsSource="{Binding UITransactions}" ItemContainerStyle="{StaticResource StretchingTreeViewStyle}">
|
||||
<Grid
|
||||
HorizontalAlignment="Stretch"
|
||||
Width="{Binding ActualWidth, ElementName=entries, Converter={StaticResource MinusFortyFiveConverter}}"
|
||||
>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,2,0,2">
|
||||
<CheckBox Focusable="False" IsChecked="{Binding IsEnabled}" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding Name}" Margin="5,0" />
|
||||
<TextBlock Text="System: " Visibility="{Binding HasSystem}" Margin="2,0,0,0"/>
|
||||
<TextBlock Text="{Binding System}" FontWeight="DemiBold" Visibility="{Binding HasSystem}"/>
|
||||
<TextBlock Text="Faction: " Visibility="{Binding HasFaction}" Margin="2,0,0,0"/>
|
||||
<TextBlock Text="{Binding Faction}" FontWeight="DemiBold" Visibility="{Binding HasFaction}"/>
|
||||
</StackPanel>
|
||||
<Separator Visibility="Hidden" Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" />
|
||||
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<ToggleButton x:Name="ToggleAll" Content="Toggle All" Click="ToggleAll_Click" IsChecked="True" IsThreeState="False"/>
|
||||
<Separator Margin="2,0,2,0" />
|
||||
<Button x:Name="AddCombatZone" Content="Add Combat Zone" Click="AddCombatZone_Click" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<HierarchicalDataTemplate.ItemTemplate>
|
||||
<HierarchicalDataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<!-- This will stretch out the width of the item-->
|
||||
<Grid Initialized="Transaction_Initialized"
|
||||
HorizontalAlignment="Stretch"
|
||||
Width="{Binding ActualWidth, ElementName=entries, Converter={StaticResource MinusFortyFiveConverter}}"
|
||||
Margin="0,2,0,2"
|
||||
>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Center">
|
||||
<CheckBox Focusable="False" IsChecked="{Binding IsEnabled}" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding CompletedAt}" Margin="5,0,5,0" HorizontalAlignment="Right"/>
|
||||
<TextBlock Text="{Binding Name}" FontWeight="DemiBold"/>
|
||||
<TextBlock Text="{Binding CompletedAt}" Margin="2,0,2,0" HorizontalAlignment="Right" TextAlignment="Center"/>
|
||||
<TextBlock Text="{Binding Name}" FontWeight="DemiBold" TextAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Right" x:Name="CombatZone" Visibility="{Binding IsCombatZone}">
|
||||
<Expander Header="Optional Objectives" Visibility="{Binding IsShipCombatZone}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<ToggleButton x:Name="CapitalShip" Margin="2,0,2,0" Content="Capital Ship" IsChecked="{Binding HasCapitalShip, Mode=TwoWay}" IsThreeState="False"/>
|
||||
<ToggleButton x:Name="Captain" Margin="2,0,2,0" Content="Captain" IsChecked="{Binding HasCaptain, Mode=TwoWay}" IsThreeState="False"/>
|
||||
<ToggleButton x:Name="Correspondent" Margin="2,0,2,0" Content="Correspondent" IsChecked="{Binding HasCorrespondent, Mode=TwoWay}" IsThreeState="False"/>
|
||||
<ToggleButton x:Name="SpecOps" Margin="2,0,2,0" Content="Spec Ops" IsChecked="{Binding HasSpecOps, Mode=TwoWay}" IsThreeState="False"/>
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
<Expander Header="Difficulty">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Button x:Name="Low" Content="Low" Click="Low_Click"/>
|
||||
<Button x:Name="Med" Content="Med" Click="Med_Click"/>
|
||||
<Button x:Name="High" Content="High" Click="High_Click"/>
|
||||
<Button x:Name="VeryHigh" Content="Very High" Click="VeryHigh_Click" />
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
<Expander Header="Type">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Button Content="Ground" x:Name="Ground" Click="Ground_Click"/>
|
||||
<Button Content="Ship" x:Name="Ship" Click="Ship_Click"/>
|
||||
<Button Content="AX" x:Name="Thargoid" Click="Thargoid_Click"/>
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Right" x:Name="SellCargo" Visibility="{Binding IsSellCargo}">
|
||||
<TextBlock Text="Adjust Profit: " TextAlignment="Center" />
|
||||
<TextBox x:Name="Profit" MinWidth="80" HorizontalContentAlignment="Right" Text="{Binding Profit, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" LostFocus="Profit_LostFocus" KeyUp="Profit_KeyUp"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</HierarchicalDataTemplate>
|
||||
</HierarchicalDataTemplate.ItemTemplate>
|
||||
</HierarchicalDataTemplate>
|
||||
@@ -70,12 +146,8 @@
|
||||
</Style>
|
||||
</TreeView.ItemContainerStyle>
|
||||
</TreeView>
|
||||
<ToolBar HorizontalAlignment="Left" Height="36" VerticalAlignment="Top" Width="Auto" Grid.Row="3" Grid.ColumnSpan="2">
|
||||
<Button x:Name="GenerateDiscord" Content="Generate Discord Report" VerticalAlignment="Center" Margin="0,0,0,4.857" Click="GenerateDiscord_Click" Height="26"/>
|
||||
<Separator />
|
||||
<ComboBox x:Name="LogType" Height="36" Margin="0" VerticalAlignment="Center" Width="140" SelectionChanged="LogType_SelectionChanged" />
|
||||
</ToolBar>
|
||||
<TextBox x:Name="DiscordLog" Height="Auto" TextWrapping="Wrap" FontFamily="Consolas" FontSize="14" Grid.Row="4" Grid.ColumnSpan="3" AcceptsReturn="True" AcceptsTab="True"/>
|
||||
<GridSplitter Background="LightSkyBlue" Grid.Row="3" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Top" Grid.ColumnSpan="3" ResizeBehavior="PreviousAndNext"/>
|
||||
<TextBox x:Name="DiscordLog" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="4" Height="Auto" TextWrapping="Wrap" FontFamily="Consolas" FontSize="14" Grid.ColumnSpan="3" AcceptsReturn="True" AcceptsTab="True"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="Settings" HorizontalAlignment="Left" Height="20" VerticalAlignment="Top" Width="53.7142857142857">
|
||||
|
||||
@@ -11,6 +11,9 @@ using EDPlayerJournal.BGS;
|
||||
using EDPlayerJournal.Entries;
|
||||
using EliteBGS.BGS;
|
||||
using EliteBGS.Util;
|
||||
using System.Globalization;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace EliteBGS;
|
||||
|
||||
@@ -28,6 +31,7 @@ public partial class MainWindow : Window {
|
||||
private static readonly List<DiscordLogGenerator> logtypes = new List<DiscordLogGenerator>() {
|
||||
new NonaDiscordLog(),
|
||||
new GenericDiscordLog(),
|
||||
new OneLineDiscordLog(),
|
||||
};
|
||||
|
||||
public MainWindow() {
|
||||
@@ -54,29 +58,25 @@ public partial class MainWindow : Window {
|
||||
journal = new PlayerJournal(Config.Global.JournalLocation);
|
||||
|
||||
// Set both to now
|
||||
startdate.SelectedDate = DateTime.Now;
|
||||
enddate.SelectedDate = DateTime.Now;
|
||||
InitialiseTime();
|
||||
|
||||
journallocation.Text = Config.Global.JournalLocation;
|
||||
}
|
||||
|
||||
private void InitialiseTime() {
|
||||
DateTime today = DateTime.Today;
|
||||
DateTime tomorrow = today.AddDays(1);
|
||||
|
||||
startdate.CultureInfo = enddate.CultureInfo = CultureInfo.InvariantCulture;
|
||||
|
||||
startdate.Value = today;
|
||||
enddate.Value = tomorrow;
|
||||
}
|
||||
|
||||
private void TreeView_CheckBox_Updated(object sender, RoutedEventArgs args) {
|
||||
GenerateLog();
|
||||
}
|
||||
|
||||
private void Loadentries_EntriesLoaded(List<Entry> lines) {
|
||||
try {
|
||||
TransactionParser parser = new TransactionParser();
|
||||
List<Transaction> transactions = parser.Parse(lines);
|
||||
|
||||
report = new Report(transactions);
|
||||
this.entries.ItemsSource = report.Objectives;
|
||||
} catch (Exception exception) {
|
||||
Log("Something went terribly wrong while parsing the E:D player journal.");
|
||||
Log("Please send this to CMDR Hekateh:");
|
||||
Log(exception.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void Report_OnLog(string message) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
@@ -92,12 +92,47 @@ public partial class MainWindow : Window {
|
||||
Report_OnLog(message);
|
||||
}
|
||||
|
||||
private void HandleEntries(List<Entry> entries, DateTime start, DateTime end) {
|
||||
try {
|
||||
TransactionParser parser = new TransactionParser();
|
||||
List<Transaction> transactions = parser.Parse(entries);
|
||||
|
||||
// Filter the transactions down to the given time frame
|
||||
transactions = transactions
|
||||
.Where(t => t.CompletedAtDateTime >= start && t.CompletedAtDateTime <= end)
|
||||
.ToList()
|
||||
;
|
||||
|
||||
List<IncompleteTransaction> incompletes = transactions.OfType<IncompleteTransaction>().ToList();
|
||||
// Log incomplete and remove them from the results.
|
||||
foreach (var incomplete in incompletes) {
|
||||
Log(incomplete.Reason);
|
||||
}
|
||||
transactions.RemoveAll(x => incompletes.Contains(x));
|
||||
|
||||
report = new Report(transactions);
|
||||
this.entries.ItemsSource = report.Objectives;
|
||||
} catch (Exception exception) {
|
||||
Log("Something went terribly wrong while parsing the E:D player journal.");
|
||||
Log("Please send this to CMDR Hekateh:");
|
||||
Log(exception.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEntries(List<Entry> entries) {
|
||||
HandleEntries(entries, startdate.Value ?? DateTime.Now, enddate.Value ?? DateTime.Now);
|
||||
}
|
||||
|
||||
private void Loadentries_EntriesLoaded(List<Entry> lines) {
|
||||
HandleEntries(lines);
|
||||
}
|
||||
|
||||
private void ParseJournal_Click(object sender, RoutedEventArgs e) {
|
||||
try {
|
||||
TransactionParser parser = new TransactionParser();
|
||||
|
||||
DateTime start = startdate.SelectedDate ?? DateTime.Now;
|
||||
DateTime end = enddate.SelectedDate ?? DateTime.Now;
|
||||
DateTime start = startdate.Value ?? DateTime.Now;
|
||||
DateTime end = enddate.Value ?? DateTime.Now;
|
||||
|
||||
journal.Open(); // Load all files
|
||||
// Log files only get rotated if you restart the game client. This means that there might
|
||||
@@ -108,25 +143,14 @@ public partial class MainWindow : Window {
|
||||
// files have to be read in their entirety to check this). So we assume that you can't play
|
||||
// three days straight, and keep the code fast.
|
||||
DateTime actualstart = start.AddDays(-3);
|
||||
DateTime actualend = end.AddDays(1);
|
||||
List<Entry> entries = journal.Files
|
||||
.Where(f => f.NormalisedDateTime >= actualstart && f.NormalisedDateTime <= end)
|
||||
.Where(f => f.NormalisedDateTime >= actualstart && f.NormalisedDateTime <= actualend)
|
||||
.SelectMany(e => e.Entries)
|
||||
.ToList()
|
||||
;
|
||||
// Now further sort the list down to entries that are actually within the given datetime
|
||||
// Note that entry datetimes are not normalised, so we have to sort until end + 1 day
|
||||
DateTime actualend = end.AddDays(1);
|
||||
|
||||
entries = entries
|
||||
.Where(e => e.Timestamp >= start && e.Timestamp < actualend)
|
||||
.ToList()
|
||||
;
|
||||
|
||||
List<Transaction> transactions = parser.Parse(entries);
|
||||
report = new Report(transactions);
|
||||
|
||||
this.entries.ItemsSource = report.Objectives;
|
||||
|
||||
HandleEntries(entries, start, end);
|
||||
GenerateLog();
|
||||
} catch (Exception exception) {
|
||||
Log("Something went terribly wrong while parsing the E:D player journal.");
|
||||
@@ -172,11 +196,11 @@ public partial class MainWindow : Window {
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
GenerateLog();
|
||||
RefreshView();
|
||||
}
|
||||
}
|
||||
|
||||
private void entries_KeyUp(object sender, KeyEventArgs e) {
|
||||
private void entries_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) {
|
||||
if (e.Key == Key.Delete) {
|
||||
RemoveCurrentObjective();
|
||||
}
|
||||
@@ -194,82 +218,39 @@ public partial class MainWindow : Window {
|
||||
journal = new PlayerJournal(Config.Global.JournalLocation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the currently selected objective, even if a log entry in said objective
|
||||
/// is selected instead. If nothing is selected, returns null.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private Objective GetSelectedObjective() {
|
||||
var obj = entries.SelectedItem;
|
||||
|
||||
if (obj == null) {
|
||||
private Objective GetObjectiveFromControl(object sender) {
|
||||
System.Windows.Controls.Control control = sender as System.Windows.Controls.Control;
|
||||
if (control == null || control.DataContext == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (obj.GetType() == typeof(Objective)) {
|
||||
return obj as Objective;
|
||||
}
|
||||
|
||||
// Some form of entry perhaps?
|
||||
if (obj.GetType().IsSubclassOf(typeof(Transaction))) {
|
||||
Transaction entry = obj as Transaction;
|
||||
Objective objective = entries.Items
|
||||
.OfType<Objective>()
|
||||
.First(x => x.Transactions.Contains(entry))
|
||||
;
|
||||
|
||||
return objective;
|
||||
}
|
||||
|
||||
return null;
|
||||
return control.DataContext as Objective;
|
||||
}
|
||||
|
||||
private void AddCombatZone_Click(object sender, RoutedEventArgs e) {
|
||||
Objective objective = GetSelectedObjective();
|
||||
|
||||
Objective objective = GetObjectiveFromControl(sender);
|
||||
if (objective == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
CombatZoneDialog dialog = new CombatZoneDialog() { Owner = this };
|
||||
|
||||
if (!(dialog.ShowDialog() ?? false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CombatZone zone = new CombatZone {
|
||||
Faction = objective.Faction,
|
||||
System = objective.System,
|
||||
|
||||
Grade = dialog.Grade,
|
||||
Type = dialog.Type,
|
||||
Amount = dialog.Amount
|
||||
Grade = "Low",
|
||||
Type = "Ship",
|
||||
};
|
||||
|
||||
objective.Transactions.Add(zone);
|
||||
UITransaction uitransaction = new UITransaction(zone);
|
||||
objective.UITransactions.Add(uitransaction);
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void RefreshView() {
|
||||
entries.Items.Refresh();
|
||||
GenerateLog();
|
||||
}
|
||||
|
||||
private void AdjustProfit_Click(object sender, RoutedEventArgs e) {
|
||||
if (entries.SelectedItem == null || entries.SelectedItem.GetType() != typeof(SellCargo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SellCargo sell = entries.SelectedItem as SellCargo;
|
||||
AdjustProfitWindow adjust = new AdjustProfitWindow() { Owner = this };
|
||||
|
||||
adjust.Profit.Text = sell.Profit.ToString();
|
||||
|
||||
if (!(adjust.ShowDialog() ?? false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (int.TryParse(adjust.Profit.Text, out int newprofit)) {
|
||||
sell.Profit = newprofit;
|
||||
GenerateLog();
|
||||
}
|
||||
}
|
||||
|
||||
private void LogType_SelectionChanged(object sender, SelectionChangedEventArgs e) {
|
||||
if (LogType.SelectedItem == null) {
|
||||
return;
|
||||
@@ -300,4 +281,135 @@ public partial class MainWindow : Window {
|
||||
loadentries?.Close();
|
||||
loadentries = null;
|
||||
}
|
||||
|
||||
private void Transaction_Initialized(object sender, EventArgs e) {
|
||||
}
|
||||
|
||||
private TransactionType GetTransaction<TransactionType>(object sender) where TransactionType : Transaction {
|
||||
System.Windows.Controls.Control button = sender as System.Windows.Controls.Control;
|
||||
if (button == null || button.DataContext == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
UITransaction transaction = button.DataContext as UITransaction;
|
||||
if (transaction == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return transaction.Transaction as TransactionType;
|
||||
}
|
||||
|
||||
private void Low_Click(object sender, RoutedEventArgs e) {
|
||||
CombatZone transaction = GetTransaction<CombatZone>(sender);
|
||||
if (transaction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
transaction.Grade = CombatZones.DifficultyLow;
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void Med_Click(object sender, RoutedEventArgs e) {
|
||||
CombatZone transaction = GetTransaction<CombatZone>(sender);
|
||||
if (transaction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
transaction.Grade = CombatZones.DifficultyMedium;
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void High_Click(object sender, RoutedEventArgs e) {
|
||||
CombatZone transaction = GetTransaction<CombatZone>(sender);
|
||||
if (transaction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
transaction.Grade = CombatZones.DifficultyHigh;
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void VeryHigh_Click(object sender, RoutedEventArgs e) {
|
||||
CombatZone transaction = GetTransaction<CombatZone>(sender);
|
||||
if (transaction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
transaction.Grade = CombatZones.DifficultyVeryHigh;
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void Ground_Click(object sender, RoutedEventArgs e) {
|
||||
CombatZone transaction = GetTransaction<CombatZone>(sender);
|
||||
if (transaction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
transaction.Type = CombatZones.GroundCombatZone;
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void Ship_Click(object sender, RoutedEventArgs e) {
|
||||
CombatZone transaction = GetTransaction<CombatZone>(sender);
|
||||
if (transaction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
transaction.Type = CombatZones.ShipCombatZone;
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void Thargoid_Click(object sender, RoutedEventArgs e) {
|
||||
CombatZone transaction = GetTransaction<CombatZone>(sender);
|
||||
if (transaction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
transaction.Type = CombatZones.AXCombatZone;
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void Profit_LostFocus(object sender, RoutedEventArgs e) {
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void Profit_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) {
|
||||
if (e.Key == Key.Enter) {
|
||||
RefreshView();
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime ResetTimeToZero(DateTime d) {
|
||||
DateTime obj = d;
|
||||
|
||||
obj = obj.AddHours(d.Hour * -1);
|
||||
obj = obj.AddMinutes(d.Minute * -1);
|
||||
obj = obj.AddSeconds(d.Second * -1);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private void ResetTime_Click(object sender, RoutedEventArgs e) {
|
||||
DateTime? d = startdate.Value;
|
||||
if (d != null) {
|
||||
startdate.Value = ResetTimeToZero(d.Value);
|
||||
}
|
||||
|
||||
d = enddate.Value;
|
||||
if (d != null) {
|
||||
enddate.Value = ResetTimeToZero(d.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleAll_Click(object sender, RoutedEventArgs e) {
|
||||
ToggleButton button = sender as ToggleButton;
|
||||
Objective objective = GetObjectiveFromControl(sender);
|
||||
if (objective == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
objective.UITransactions
|
||||
.ForEach(x => x.IsEnabled = (button.IsChecked ?? true))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
19
EliteBGS/MinusFortyFiveConverter.cs
Normal file
19
EliteBGS/MinusFortyFiveConverter.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System;
|
||||
|
||||
namespace EliteBGS;
|
||||
|
||||
public class MinusFortyFiveConverter : IValueConverter {
|
||||
/// <inheritdoc/>
|
||||
public object Convert(
|
||||
object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return (double)value - 65;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object ConvertBack(
|
||||
object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
throw new NotSupportedException("Cannot convert back");
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Text;
|
||||
using System.Globalization;
|
||||
using EDPlayerJournal;
|
||||
using System.Linq;
|
||||
|
||||
namespace EliteBGS.BGS;
|
||||
|
||||
@@ -9,14 +10,15 @@ public class NonaDiscordLog : DiscordLogGenerator {
|
||||
private string FormatDate() {
|
||||
CultureInfo cultureInfo = CultureInfo.InvariantCulture;
|
||||
StringBuilder date = new StringBuilder();
|
||||
DateTime today = DateTime.Now;
|
||||
DateTime today = DateTime.UtcNow;
|
||||
string suffix;
|
||||
|
||||
if (today.Day == 1 || today.Day == 21 || today.Day == 31) {
|
||||
suffix = "st";
|
||||
} else if (today.Day == 2 || today.Day == 22) {
|
||||
suffix = "nd";
|
||||
} else if (today.Day == 23) {
|
||||
// Shakaka wins the price for finding this "bug"!
|
||||
} else if (today.Day == 3 || today.Day == 23) {
|
||||
suffix = "rd";
|
||||
} else {
|
||||
suffix = "th";
|
||||
@@ -34,23 +36,41 @@ public class NonaDiscordLog : DiscordLogGenerator {
|
||||
protected override string GenerateObjectiveHeader(Objective objective) {
|
||||
StringBuilder log = new StringBuilder();
|
||||
|
||||
log.AppendFormat(":globe_with_meridians: `Location:` {0}, {1}\n", objective.System, objective.Faction);
|
||||
string location;
|
||||
|
||||
if (!string.IsNullOrEmpty(objective.System) && !string.IsNullOrEmpty(objective.Faction)) {
|
||||
location = string.Format("{0}, {1}", objective.System, objective.Faction);
|
||||
} else if (!string.IsNullOrEmpty(objective.System)) {
|
||||
location = objective.System;
|
||||
} else {
|
||||
location = "Unknown Location";
|
||||
}
|
||||
|
||||
int legacycount = objective.Transactions
|
||||
.Where(x => x.IsLegacy)
|
||||
.Count()
|
||||
;
|
||||
|
||||
log.AppendFormat(":globe_with_meridians: `Target:` {0}\n", location);
|
||||
if (legacycount > 0) {
|
||||
log.Append(":rotating_light: `Warning`: Some actions were done in E:D Legacy\n");
|
||||
}
|
||||
log.Append(":clipboard: `Conducted:`\n");
|
||||
log.Append("```");
|
||||
log.Append("```\n");
|
||||
|
||||
return log.ToString();
|
||||
}
|
||||
|
||||
protected override string GenerateObjectiveFooter(Objective objective) {
|
||||
return "```";
|
||||
return "```\n";
|
||||
}
|
||||
|
||||
protected override string GenerateHeader() {
|
||||
return string.Format(":clock2: `Date:` {0}", FormatDate());
|
||||
return string.Format(":clock2: `Date:` {0}\n", FormatDate());
|
||||
}
|
||||
|
||||
protected override string GenerateFooter() {
|
||||
return "";
|
||||
return "\n";
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
|
||||
@@ -4,14 +4,184 @@ using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using EDPlayerJournal.BGS;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using EDPlayerJournal;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace EliteBGS;
|
||||
|
||||
public class UITransaction {
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
public class UITransaction : INotifyPropertyChanged {
|
||||
private bool isenabled = true;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public bool IsEnabled {
|
||||
get { return isenabled; }
|
||||
set {
|
||||
isenabled = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsEnabled"));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsExpanded { get; set; } = true;
|
||||
|
||||
public Visibility IsCombatZone {
|
||||
get {
|
||||
return (Transaction != null && Transaction.GetType() == typeof(CombatZone)) ? Visibility.Visible : Visibility.Hidden;
|
||||
}
|
||||
}
|
||||
|
||||
public Visibility IsSellCargo {
|
||||
get {
|
||||
return (Transaction != null && Transaction.GetType() == typeof(SellCargo)) ? Visibility.Visible : Visibility.Hidden;
|
||||
}
|
||||
}
|
||||
|
||||
public Visibility IsGroundCombatZone {
|
||||
get {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return Visibility.Hidden;
|
||||
}
|
||||
|
||||
if (string.Compare(combat.Type, CombatZones.GroundCombatZone) == 0) {
|
||||
return Visibility.Visible;
|
||||
}
|
||||
|
||||
return Visibility.Hidden;
|
||||
}
|
||||
}
|
||||
|
||||
public Visibility IsShipCombatZone {
|
||||
get {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return Visibility.Hidden;
|
||||
}
|
||||
|
||||
if (string.Compare(combat.Type, CombatZones.ShipCombatZone) == 0) {
|
||||
return Visibility.Visible;
|
||||
}
|
||||
|
||||
return Visibility.Hidden;
|
||||
}
|
||||
}
|
||||
|
||||
public Visibility IsAXCombatZone {
|
||||
get {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return Visibility.Hidden;
|
||||
}
|
||||
|
||||
if (string.Compare(combat.Type, CombatZones.AXCombatZone) == 0) {
|
||||
return Visibility.Visible;
|
||||
}
|
||||
|
||||
return Visibility.Hidden;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasSpecOps {
|
||||
get {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return combat.SpecOps ?? false;
|
||||
}
|
||||
set {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
combat.SpecOps = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasCapitalShip {
|
||||
get {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return combat.CapitalShip ?? false;
|
||||
}
|
||||
set {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
combat.CapitalShip = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasCaptain {
|
||||
get {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return combat.Captain ?? false;
|
||||
}
|
||||
set {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
combat.Captain = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasCorrespondent {
|
||||
get {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return combat.Correspondent ?? false;
|
||||
}
|
||||
set {
|
||||
CombatZone combat = Transaction as CombatZone;
|
||||
if (combat == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
combat.Correspondent = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Profit from selling, used in the XAML ui for binding
|
||||
/// </summary>
|
||||
public string Profit {
|
||||
get {
|
||||
SellCargo cargo = Transaction as SellCargo;
|
||||
if (cargo == null) {
|
||||
return "";
|
||||
}
|
||||
return cargo.Profit.ToString();
|
||||
}
|
||||
set {
|
||||
SellCargo cargo = Transaction as SellCargo;
|
||||
if (cargo == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
long profit_as_number = Convert.ToInt64(value);
|
||||
cargo.Profit = profit_as_number;
|
||||
} catch (FormatException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Transaction Transaction { get; set; }
|
||||
|
||||
public UITransaction() { }
|
||||
@@ -42,6 +212,14 @@ public class Objective : IComparable<Objective> {
|
||||
get { return UITransactions.Select(x => x.Transaction).ToList<Transaction>(); }
|
||||
}
|
||||
|
||||
public Visibility HasSystem {
|
||||
get { return string.IsNullOrEmpty(System) ? Visibility.Hidden : Visibility.Visible; }
|
||||
}
|
||||
|
||||
public Visibility HasFaction {
|
||||
get { return string.IsNullOrEmpty(Faction) ? Visibility.Hidden : Visibility.Visible; }
|
||||
}
|
||||
|
||||
public string Name {
|
||||
get { return this.ToString(); }
|
||||
}
|
||||
@@ -60,6 +238,10 @@ public class Objective : IComparable<Objective> {
|
||||
string.Compare(faction, Faction) == 0;
|
||||
}
|
||||
|
||||
public bool Matches(string system) {
|
||||
return string.Compare(system, System) == 0;
|
||||
}
|
||||
|
||||
public int CompareTo(Objective other) {
|
||||
return (other.System == System &&
|
||||
other.Faction == Faction) ? 0 : -1;
|
||||
@@ -77,6 +259,8 @@ public class Objective : IComparable<Objective> {
|
||||
StringBuilder str = new StringBuilder();
|
||||
if (!string.IsNullOrEmpty(System)) {
|
||||
str.AppendFormat("System: {0}", System);
|
||||
} else {
|
||||
str.AppendFormat("System: Unknown");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Faction)) {
|
||||
if (str.Length > 0) {
|
||||
|
||||
32
EliteBGS/OneLineDiscordLog.cs
Normal file
32
EliteBGS/OneLineDiscordLog.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace EliteBGS;
|
||||
|
||||
public class OneLineDiscordLog : DiscordLogGenerator {
|
||||
protected override string GenerateObjectiveHeader(Objective objective) {
|
||||
if (!string.IsNullOrEmpty(objective.Faction)) {
|
||||
return string.Format("**{0}** for **{1}**: ", objective.System, objective.Faction);
|
||||
} else {
|
||||
return string.Format("**{0}**: ", objective.System);
|
||||
}
|
||||
}
|
||||
|
||||
protected override string GenerateObjectiveFooter(Objective objective) {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected override string GenerateFooter() {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected override string GenerateHeader() {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected override string TransformFinalLogForObjective(Objective objective, string log) {
|
||||
string[] lines = log.Split("\n", System.StringSplitOptions.RemoveEmptyEntries);
|
||||
return string.Join(", ", lines);
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return "One Line Report";
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
# EliteBGS
|
||||
# EDBGS
|
||||
|
||||
This tool is meant to help people contributing to the BGS effort to create BGS reports.
|
||||
The tool allows you to configure BGS objectives, and will then parse your player journal
|
||||
for tasks you completed relating to that BGS objective. Once the JSON player journal has
|
||||
been parsed, you may then generate a BGS report you can copy/paste into Discord.
|
||||
|
||||
Source code is available [here](https://git.aror.org/florian/elitebgs).
|
||||
Source code is available at [https://codeberg.org/nola/edbgs](https://codeberg.org/nola/edbgs).
|
||||
|
||||
Binary downloads can be found here: [https://bgs.n0la.org/](https://bgs.n0la.org/).
|
||||
|
||||
@@ -24,6 +24,8 @@ transactions. Currently the tool recognises the following transactions:
|
||||
* Selling of micro resources (Odyssey only)
|
||||
* Selling of organic data (Odyssey only)
|
||||
* Vouchers, including bounty vouchers, combat bonds, and settlement vouchers (aka intel packages)
|
||||
* Thargoid kills
|
||||
* Contributions to Thargoid war effort
|
||||
|
||||
Vouchers help the faction that is listed for them. If said faction is not present in the
|
||||
current system, then there is no BGS impact. So the tool looks for all system factions, and
|
||||
@@ -221,13 +223,11 @@ It would be helpful if you included the JSON player journal. This player journal
|
||||
|
||||
## Build Dependencies
|
||||
|
||||
Handling of Elite Dangerous player journals have been moved to a separate project called `EDJournal`.
|
||||
Its source can be found [here](https://git.aror.org/florian/edjournal). This project simply depends
|
||||
on the binary DLL that `EDJournal` builds.
|
||||
The project also requires:
|
||||
|
||||
The project also requires `Ookii.Dialogs.WPF` controls, which contains the auto complete text box.
|
||||
|
||||
And of course, `Newtonsoft.Json` as the JSON parser.
|
||||
* `Ookii.Dialogs.WPF`
|
||||
* `Newtonsoft.Json`
|
||||
* `Extended.Wpf.Toolkit`
|
||||
|
||||
## About
|
||||
|
||||
|
||||
@@ -18,10 +18,19 @@ public class Report {
|
||||
}
|
||||
|
||||
foreach (Transaction t in transactions) {
|
||||
Objective o = Objectives.Find(x => x.Matches(t.System, t.Faction));
|
||||
Objective o;
|
||||
if (t.SystemContribution) {
|
||||
o = Objectives.Find(x => x.Matches(t.System));
|
||||
} else {
|
||||
o = Objectives.Find(x => x.Matches(t.System, t.Faction));
|
||||
}
|
||||
|
||||
if (o == null) {
|
||||
if (t.SystemContribution) {
|
||||
o = new Objective() { System = t.System };
|
||||
} else {
|
||||
o = new Objective() { Faction = t.Faction, System = t.System };
|
||||
}
|
||||
Objectives.Add(o);
|
||||
}
|
||||
|
||||
|
||||
30
EliteBGS/Resources.Designer.cs
generated
30
EliteBGS/Resources.Designer.cs
generated
@@ -19,10 +19,10 @@ namespace EliteBGS {
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
public class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace EliteBGS {
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("EliteBGS.Resources", typeof(Resources).Assembly);
|
||||
@@ -51,7 +51,7 @@ namespace EliteBGS {
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
@@ -63,11 +63,31 @@ namespace EliteBGS {
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||
/// </summary>
|
||||
internal static System.Drawing.Icon EliteBGS {
|
||||
public static System.Drawing.Icon EliteBGS {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("EliteBGS", resourceCulture);
|
||||
return ((System.Drawing.Icon)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
public static System.Drawing.Bitmap logo_v5 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("logo_v5", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||
/// </summary>
|
||||
public static System.Drawing.Icon Salus {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Salus", resourceCulture);
|
||||
return ((System.Drawing.Icon)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,4 +121,10 @@
|
||||
<data name="EliteBGS" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>EliteBGS.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="logo_v5" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>logo_v5.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="Salus" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>Salus.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
||||
BIN
EliteBGS/Salus.ico
Normal file
BIN
EliteBGS/Salus.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 200 KiB |
@@ -1,192 +0,0 @@
|
||||
{
|
||||
"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json",
|
||||
"version": "2.1.0",
|
||||
"runs": [
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "Convert project file to SDK style",
|
||||
"semanticVersion": "",
|
||||
"informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
|
||||
"rules": [
|
||||
{
|
||||
"id": "Microsoft.DotNet.UpgradeAssistant.Steps.ProjectFormat.TryConvertProjectConverterStep",
|
||||
"fullDescription": {
|
||||
"text": "Project file converted successfully! The project may require additional changes to build successfully against the new .NET target."
|
||||
},
|
||||
"helpUri": "about:blank"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.ProjectFormat.TryConvertProjectConverterStep",
|
||||
"message": {
|
||||
"text": "Complete: Project file converted successfully! The project may require additional changes to build successfully against the new .NET target."
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
||||
},
|
||||
"region": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"columnKind": "utf16CodeUnits"
|
||||
},
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "Add package 'Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers'",
|
||||
"semanticVersion": "",
|
||||
"informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
|
||||
"rules": [
|
||||
{
|
||||
"id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
|
||||
"fullDescription": {
|
||||
"text": "Add package 'Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers'"
|
||||
},
|
||||
"helpUri": "about:blank"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
|
||||
"message": {
|
||||
"text": "Complete: Add package 'Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers'"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
||||
},
|
||||
"region": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"columnKind": "utf16CodeUnits"
|
||||
},
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "Update TFM",
|
||||
"semanticVersion": "",
|
||||
"informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
|
||||
"rules": [
|
||||
{
|
||||
"id": "Microsoft.DotNet.UpgradeAssistant.Steps.ProjectFormat.SetTFMStep",
|
||||
"fullDescription": {
|
||||
"text": "Updated TFM to net7.0-windows"
|
||||
},
|
||||
"helpUri": "about:blank"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.ProjectFormat.SetTFMStep",
|
||||
"message": {
|
||||
"text": "Complete: Updated TFM to net7.0-windows"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
||||
},
|
||||
"region": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"columnKind": "utf16CodeUnits"
|
||||
},
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "Add package 'Microsoft.Windows.Compatibility'",
|
||||
"semanticVersion": "",
|
||||
"informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
|
||||
"rules": [
|
||||
{
|
||||
"id": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
|
||||
"fullDescription": {
|
||||
"text": "Add package 'Microsoft.Windows.Compatibility'"
|
||||
},
|
||||
"helpUri": "about:blank"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "Microsoft.DotNet.UpgradeAssistant.Steps.Packages.PackageUpdaterStep+PackageManipulationStep`1[[Microsoft.DotNet.UpgradeAssistant.NuGetReference, Microsoft.DotNet.UpgradeAssistant.Abstractions, Version=0.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
|
||||
"message": {
|
||||
"text": "Complete: Add package 'Microsoft.Windows.Compatibility'"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
||||
},
|
||||
"region": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"columnKind": "utf16CodeUnits"
|
||||
},
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "Default Font API Alert",
|
||||
"semanticVersion": "",
|
||||
"informationUri": "https://github.com/dotnet/upgrade-assistant#usage",
|
||||
"rules": [
|
||||
{
|
||||
"id": "UA209",
|
||||
"name": "Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.WinformsDefaultFontUpdater",
|
||||
"fullDescription": {
|
||||
"text": "Default Font API Alert"
|
||||
},
|
||||
"helpUri": "about:blank"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "UA209",
|
||||
"message": {
|
||||
"text": "Success: Default font in Windows Forms has been changed from Microsoft Sans Serif to Seg Segoe UI, in order to change the default font use the API - Application.SetDefaultFont(Font font). For more details see here - https://devblogs.microsoft.com/dotnet/whats-new-in-windows-forms-in-net-6-0-preview-5/#application-wide-default-font."
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
||||
},
|
||||
"region": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"columnKind": "utf16CodeUnits"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,62 @@
|
||||
# EliteBGS changelog
|
||||
|
||||
## 0.2.6 on 04.02.2023
|
||||
|
||||
* Update Post 14.02 Thargoid bounties
|
||||
* Just summarise failed missions by on-foot and ship, instead of a detailed view
|
||||
* Add some more English mission names
|
||||
* Move code hosting to [CodeBerg](https://codeberg.org/)
|
||||
|
||||
## 0.2.5 on 20.12.2022
|
||||
|
||||
* Repaired mission fails.
|
||||
* Added support for Missions entry.
|
||||
|
||||
## 0.2.4 on 18.12.2022
|
||||
|
||||
* Fixed bug with organic data.
|
||||
* Fixed bug in mission format.
|
||||
* You can now select also a time when filtering transactions.
|
||||
* Added a button to toggle all children on and off at once.
|
||||
* Date in Nova Navy discord log is now UTC.
|
||||
* Added a divider so you can rescale the objectives and the log to a preferred aspect ratio.
|
||||
|
||||
## 0.2.3 on 11.12.2022
|
||||
|
||||
* Fixed detection of medium ground combat zones.
|
||||
* Improve detection of things done near or around a new day. The tool should not properly
|
||||
pick up missions done the previous day, and completed at the selected day.
|
||||
* Add support for ground combat zones when done using Frontier Solutions (DropshipDeploy).
|
||||
* Add more mission names for Thargoid war.
|
||||
* Relogs in an on foot combat zone are now properly detected.
|
||||
|
||||
## 0.2.2 on 07.12.2022
|
||||
|
||||
* Orthrus interceptor payout changed to U14.1 values.
|
||||
* Detection of AX combat zones has been improved.
|
||||
* All thargoid war missions now contribute to the system.
|
||||
* Thargoid combat zones go to "Very High".
|
||||
* Passenger missions show amount of people rescued.
|
||||
|
||||
## 0.2.1 on 03.12.2022
|
||||
|
||||
* Add support for Thargoid combat zones.
|
||||
* Make some missions "system related", meaning they are sorted into an objective with just
|
||||
the system name. This makes sense for contributions for towards a system goal, rather than
|
||||
a faction goal - like Thargoid wars.
|
||||
* Fixed a bug about the visibility of war zone side objectives.
|
||||
|
||||
## 0.2.0 on 29.11.2022
|
||||
|
||||
* Moved project to .NET 7.0
|
||||
* Added an experimental combat zone detector. Since there is no dedicated entry in the journal
|
||||
for a combat zone, this code will do a lot of guessing.
|
||||
* Add thargoid kills and thargoid vouchers.
|
||||
* Add a warning if something has been done in E:D Legacy.
|
||||
* Fixed a bug were on foot murders were not properly recognised.
|
||||
* "On Foot" combat zones are now called Ground Combat Zones.
|
||||
* GUI has been reworked, all functions are now near the relevant items.
|
||||
|
||||
## 0.1.7 on 09.11.2022
|
||||
|
||||
* Fixed a bug related to total amount of credits gained by turning in organic data.
|
||||
|
||||
BIN
EliteBGS/docs/combatzone.png
Normal file
BIN
EliteBGS/docs/combatzone.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
21
EliteBGS/docs/combatzones.md
Normal file
21
EliteBGS/docs/combatzones.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Combat Zones
|
||||
|
||||
Starting with version 0.2.0, the EliteBGS tool will attempt to figure out when you
|
||||
have participated in a combat zone.
|
||||
|
||||
Since there is no official journal entry for combat zones as of yet (Update 13), the
|
||||
tool has to make an educated guess on what sort of combat zone it is.
|
||||
|
||||
For Odyssey on foot combat zones the tool can attempt to determine the difficulty
|
||||
from the from the highest combat bond you have been awarded. Enforcers in high on foot
|
||||
combat zones nets you roughly 88k credits, and the payout reduces from there.
|
||||
|
||||
Ship combat zones are more difficult. If you ship scan one of the warzone NPCs (either
|
||||
a captain, spec ops, or a correspondent), the tool can assume you are either in a medium
|
||||
or a high combat zone. If you get more than 10 kills, you are also either in a medium or
|
||||
high combat zone (a low combat zone is complete with 8 kills).
|
||||
|
||||
None of this perfect however, and the tool *will* get it wrong. For your convenience there
|
||||
are several small buttons next to the combat zone entry, where you can fix the result:
|
||||
|
||||

|
||||
@@ -24,6 +24,13 @@ missions. Currently the tool recognises the following completed tasks:
|
||||
* Selling of micro resources (Odyssey only)
|
||||
* Selling of organic data (Odyssey only)
|
||||
* Vouchers, including bounty vouchers, combat bonds, and settlement vouchers (aka intel packages)
|
||||
* Thargoid kills
|
||||
* Combat zones (experimental)
|
||||
|
||||
Combat zone detection is highly wonky at this time. There is no direct event for detecting
|
||||
combat zones, and so the tool makes a few assumptions and goes from there. If you disembark
|
||||
it will assume on foot combat zones, and if you don't, it will assume a ship CZ. This
|
||||
detection can, and will be wrong, so caution is advised.
|
||||
|
||||
Vouchers help the faction that is listed for them. If said faction is not present in the
|
||||
current system, then there is no BGS impact. So the tool looks for all system factions, and
|
||||
@@ -223,10 +230,6 @@ It would be helpful if you included the JSON player journal. This player journal
|
||||
|
||||
## Build Dependencies
|
||||
|
||||
Handling of Elite Dangerous player journals have been moved to a separate project called `EDJournal`.
|
||||
Its source can be found [here](https://git.aror.org/florian/edjournal). This project simply depends
|
||||
on the binary DLL that `EDJournal` builds.
|
||||
|
||||
The project also requires `Ookii.Dialogs.WPF` controls, which contains the auto complete text box.
|
||||
|
||||
And of course, `Newtonsoft.Json` as the JSON parser.
|
||||
@@ -18,12 +18,6 @@ Open the file explorer, and go to the path `%AppData%`. Once there, delete the
|
||||
folder called `EliteBGS` to delete the tool's configuration and cache. If it
|
||||
still doesn't work, contact me directly.
|
||||
|
||||
### I pressed 'Download Data' and it is hanging now and won't respond. Help?
|
||||
|
||||
Go and delete the `EliteBGS` folder as described above to undo that action.
|
||||
Also please upgrade to version 0.1.3, where this feature was removed for
|
||||
exactly this reason.
|
||||
|
||||
### Why is it unable to find my player journal?
|
||||
|
||||
Usually your player journal lives in the Saved Games folder in your home
|
||||
@@ -91,4 +85,3 @@ Sometimes, due to a bug, the bounty vouchers in the journal have no faction info
|
||||
associated with them. Here the tool simply cannot associate the vouchers to a faction
|
||||
or station. If you are sure they aided in BGS, simply add them by editing the Discord
|
||||
report.
|
||||
|
||||
|
||||
@@ -3,12 +3,37 @@
|
||||
EliteBGS is a Windows desktop application, that helps you sum up your BGS related actions.
|
||||
It then creates a report from your actions, so you can post it your Squadron's discord.
|
||||
|
||||
## Origins
|
||||
|
||||
The tool originated from the [Nova Navy](https://inara.cz/elite/squadron/5058/), which required
|
||||
BGS contributions to be posted to the Navy's discord, in a very specific format. Writing those
|
||||
logs manually was a lot of work, so CMDR Hekateh created a tool to automate this process.
|
||||
|
||||
## Downloads
|
||||
|
||||
The tool requires .NET 7.0, you can download it from Microsoft here:
|
||||
|
||||
* [https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0)
|
||||
|
||||
If you have problems with the installer, you might try running the following in the Windows
|
||||
command line:
|
||||
|
||||
```
|
||||
winget install Microsoft.DotNet.DesktopRuntime.7
|
||||
```
|
||||
|
||||
You can download the **latest** version **0.2.5** here:
|
||||
|
||||
* [https://bgs.n0la.org/elitebgs-0.2.5.zip](https://bgs.n0la.org/elitebgs-0.2.5.zip)
|
||||
|
||||
## Old Versions
|
||||
|
||||
The latest version of the **old** EliteBGS **0.1.7** is available for download here:
|
||||
|
||||
* [https://bgs.n0la.org/archive/elitebgs-0.1.7.zip](https://bgs.n0la.org/archive/elitebgs-0.1.7.zip)
|
||||
|
||||
Older versions are available in the archive:
|
||||
|
||||
* [https://bgs.n0la.org/archive/](https://bgs.n0la.org/archive/)
|
||||
|
||||
## Overview
|
||||
|
||||
EliteBGS reads through your player journal for BGS relevant activity, and sorts them into
|
||||
@@ -31,10 +56,12 @@ You can then select which of the two actions goes into the final log.
|
||||
* Selling of micro resources (Odyssey only)
|
||||
* Selling of organic data (Odyssey only)
|
||||
* Vouchers, including bounty vouchers, combat bonds, and settlement vouchers (aka intel packages)
|
||||
* Thargoid kills
|
||||
* Combat zones (experimental feature)
|
||||
|
||||
### What it does not detect:
|
||||
|
||||
* Combat zone wins, and its objectives
|
||||
* Combat zone objectives
|
||||
* Megaship scenarios
|
||||
* On foot missions accepted by NPCs in stations (pre Update 13)
|
||||
* Murders of NPCs you haven't fully scanned
|
||||
@@ -45,21 +72,7 @@ The tool itself is Open Source, licenced unter the GPLv3.
|
||||
|
||||
The source code can be found here:
|
||||
|
||||
* [https://git.aror.org/florian/EliteBGS](https://git.aror.org/florian/EliteBGS)
|
||||
|
||||
It requires a separate library, called EDJournal, which is also open source:
|
||||
|
||||
* [https://git.aror.org/florian/edjournal](https://git.aror.org/florian/edjournal)
|
||||
|
||||
## Downloads
|
||||
|
||||
The latest version of EliteBGS **0.1.7** is available for download here:
|
||||
|
||||
* [https://bgs.n0la.org/elitebgs-0.1.7.zip](https://bgs.n0la.org/elitebgs-0.1.7.zip)
|
||||
|
||||
Older versions are available in the archive:
|
||||
|
||||
* [https://bgs.n0la.org/archive/](https://bgs.n0la.org/archive/)
|
||||
* [https://codeberg.org/nola/edbgs](https://codeberg.org/nola/edbgs)
|
||||
|
||||
## Contact
|
||||
|
||||
|
||||
BIN
EliteBGS/logo_v5.png
Normal file
BIN
EliteBGS/logo_v5.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
@@ -10,5 +10,6 @@ theme:
|
||||
nav:
|
||||
- Overview: 'index.md'
|
||||
- "Detailed Description": 'description.md'
|
||||
- "Combat Zones": 'combatzones.md'
|
||||
- FAQ: 'faq.md'
|
||||
- Changelog: 'CHANGELOG.md'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
11
README.md
Normal file
11
README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# EDBGS
|
||||
|
||||
EDBGS is a project containing the EliteBGS BGS application. It also contains the dotnet
|
||||
class library EDPlayerJournal, which reads and parses Elite Dangerous player journals.
|
||||
|
||||
See [https://bgs.n0la.org/](https://bgs.n0la.org) for further details.
|
||||
|
||||
## Requirements
|
||||
|
||||
This repository depends on dotnet desktop SDK 7, as well as Newtonsoft.JSON, Extended
|
||||
WPF toolkit, and Ookii Dialogs.
|
||||
Reference in New Issue
Block a user