diff --git a/EDPlayerJournal/BGS/CombatZone.cs b/EDPlayerJournal/BGS/CombatZone.cs
index 4f6d8ed..18bb10e 100644
--- a/EDPlayerJournal/BGS/CombatZone.cs
+++ b/EDPlayerJournal/BGS/CombatZone.cs
@@ -92,6 +92,13 @@ public class CombatZone : Transaction {
get { return string.Compare(Type, CombatZones.AXCombatZone) == 0; }
}
+ ///
+ /// Returns true if it is a power combat zone
+ ///
+ public bool IsPower {
+ get { return string.Compare(Type, CombatZones.PowerCombatZone) == 0; }
+ }
+
public override int CompareTo(Transaction? obj) {
if (obj == null || obj.GetType() != typeof(CombatZone)) {
return -1;
diff --git a/EDPlayerJournal/BGS/MeritsGained.cs b/EDPlayerJournal/BGS/MeritsGained.cs
new file mode 100644
index 0000000..872b018
--- /dev/null
+++ b/EDPlayerJournal/BGS/MeritsGained.cs
@@ -0,0 +1,25 @@
+using EDPlayerJournal.Entries;
+
+namespace EDPlayerJournal.BGS;
+
+public class MeritsGained : Transaction {
+ public MeritsGained() { }
+
+ public MeritsGained(Entry entry) {
+ Entries.Add(entry);
+ }
+
+ ///
+ /// Number of merits gained
+ ///
+ public long Merits { get; set; } = 0;
+
+ ///
+ /// For what power those merits were gained
+ ///
+ public string Power { get; set; } = string.Empty;
+
+ public override string ToString() {
+ return string.Format("{0} Merits gained for {1}", Merits, Power);
+ }
+}
diff --git a/EDPlayerJournal/BGS/Parsers/PowerplayParser.cs b/EDPlayerJournal/BGS/Parsers/PowerplayParser.cs
new file mode 100644
index 0000000..a808f23
--- /dev/null
+++ b/EDPlayerJournal/BGS/Parsers/PowerplayParser.cs
@@ -0,0 +1,31 @@
+using EDPlayerJournal.Entries;
+
+namespace EDPlayerJournal.BGS.Parsers;
+
+internal class PowerplayParser : ITransactionParserPart {
+ public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
+ PowerplayEntry? p = entry as PowerplayEntry;
+ if (p == null) {
+ return;
+ }
+
+ if (context.LastMerits == null) {
+ context.LastMerits = p.Merits;
+ }
+
+ context.CurrentMerits = p.Merits;
+
+ if (context.LastMerits != context.CurrentMerits) {
+ if (!options.IgnorePowerplay) {
+ transactions.Add(new MeritsGained(entry) {
+ Merits = ((long)(context.CurrentMerits - context.LastMerits)),
+ Power = p.Power,
+ System = context.CurrentSystem,
+ Faction = p.Power,
+ });
+ }
+ }
+
+ context.LastMerits = context.CurrentMerits;
+ }
+}
diff --git a/EDPlayerJournal/BGS/TransactionParser.cs b/EDPlayerJournal/BGS/TransactionParser.cs
index f8d0c1d..47f86d1 100644
--- a/EDPlayerJournal/BGS/TransactionParser.cs
+++ b/EDPlayerJournal/BGS/TransactionParser.cs
@@ -16,6 +16,12 @@ public class TransactionParserOptions {
///
public bool IgnoreInfluenceSupport { get; set; } = false;
+ ///
+ /// Whether we ignore power play and merits gained for now. Support for this
+ /// is experimental at the moment, so that is why it ist `true`.
+ ///
+ public bool IgnorePowerplay { get; set; } = true;
+
///
/// Whether to ignore market buy. Buying from a market gives a small amount
/// of INF if it is sold to a high demand market, but generally one buys from
@@ -581,14 +587,25 @@ internal class ReceiveTextParser : ITransactionParserPart {
}
}
+internal class SelfDestructParser : ITransactionParserPart {
+ public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
+ context.SelfDestruct = true;
+ }
+}
+
internal class DiedParser : ITransactionParserPart {
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
// Death only matters in ship. On foot you can just redeploy with the dropship.
if (context.IsOnFoot) {
return;
}
- // 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.
+ if (context.SelfDestruct != null && context.SelfDestruct == true) {
+ // Some people just suicide to fast track back to stations after a CZ,
+ // especially since combat bonds don't disappear on death. So count the CZ
+ // on self destruct
+ context.DiscernCombatZone(transactions, entry);
+ context.SelfDestruct = null;
+ }
context.ResetCombatZone();
// Dying also moves you back to another instance
context.LeftInstance();
@@ -627,9 +644,11 @@ public class TransactionParser {
{ Events.Missions, new MissionsParser() },
{ Events.MultiSellExplorationData, new MultiSellExplorationDataParser() },
{ Events.Music, new MusicParser() },
+ { Events.Powerplay, new PowerplayParser() },
{ Events.ReceiveText, new ReceiveTextParser() },
{ Events.RedeemVoucher, new RedeemVoucherParser() },
{ Events.SearchAndRescue, new SearchAndRescueParser() },
+ { Events.SelfDestruct, new SelfDestructParser() },
{ Events.SellExplorationData, new SellExplorationDataParser() },
{ Events.SellMicroResources, new SellMicroResourcesParser() },
{ Events.SellOrganicData, new SellOrganicDataParser() },
diff --git a/EDPlayerJournal/BGS/TransactionParserContext.cs b/EDPlayerJournal/BGS/TransactionParserContext.cs
index 22b3e51..04a0f22 100644
--- a/EDPlayerJournal/BGS/TransactionParserContext.cs
+++ b/EDPlayerJournal/BGS/TransactionParserContext.cs
@@ -62,11 +62,23 @@ internal class TransactionParserContext {
public bool HaveSeenAlliedCorrespondent { get; set; } = false;
public bool HaveSeenEnemyCorrespondent { get; set; } = false;
+ public bool? SelfDestruct { get; set; } = null;
+
///
/// Current Odyssey settlement.
///
public string? Settlement { get; set; } = null;
+ ///
+ /// Current Merits
+ ///
+ public long? CurrentMerits { get; set; } = null;
+
+ ///
+ /// Merits from last login
+ ///
+ public long? LastMerits { get; set; } = null;
+
///
/// Returns true if the current session is legacy
///
@@ -128,16 +140,29 @@ internal class TransactionParserContext {
Settlement = null;
}
+ private bool HadCombatZone() {
+ if (CurrentInstanceType != null &&
+ Instances.IsInstance(CurrentInstanceType, Instances.PowerWarzoneMedium)) {
+ return true;
+ }
+
+ if (HighestCombatBond == null &&
+ LastRecordedAwardingFaction == null &&
+ HaveSeenAXWarzoneNPC == false &&
+ CurrentInstanceType == null) {
+ return false;
+ }
+
+ return true;
+ }
+
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 &&
- CurrentInstanceType == null) {
+ if (!HadCombatZone()) {
return;
}
@@ -157,7 +182,8 @@ internal class TransactionParserContext {
return;
}
if (LastRecordedAwardingFaction == null &&
- Instances.IsHumanWarzone(CurrentInstanceType)) {
+ (Instances.IsHumanWarzone(CurrentInstanceType) ||
+ Instances.IsPowerWarzone(CurrentInstanceType))) {
transactions.AddIncomplete(new CombatZone(),
"Could not discern for whom you fought for, " +
"as it seems you haven't killed anyone in the ship combat zone.",
@@ -187,6 +213,9 @@ internal class TransactionParserContext {
} else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidVeryHigh)) {
cztype = CombatZones.AXCombatZone;
grade = CombatZones.DifficultyVeryHigh;
+ } else if (Instances.IsInstance(CurrentInstanceType, Instances.PowerWarzoneMedium)) {
+ cztype = CombatZones.PowerCombatZone;
+ grade = CombatZones.DifficultyMedium;
} else {
transactions.AddIncomplete(new CombatZone(),
"Unknown conflict zone difficulty",
diff --git a/EDPlayerJournal/CombatZones.cs b/EDPlayerJournal/CombatZones.cs
index 3c59477..4888f41 100644
--- a/EDPlayerJournal/CombatZones.cs
+++ b/EDPlayerJournal/CombatZones.cs
@@ -14,6 +14,11 @@ public class CombatZones {
///
public static readonly string ShipCombatZone = "Ship";
+ ///
+ /// Power combat zones, new in Ascendancy update.
+ ///
+ public static readonly string PowerCombatZone = "Power";
+
///
/// AX combat zone
///
diff --git a/EDPlayerJournal/Entries/Entry.cs b/EDPlayerJournal/Entries/Entry.cs
index c4fa681..cd703a1 100644
--- a/EDPlayerJournal/Entries/Entry.cs
+++ b/EDPlayerJournal/Entries/Entry.cs
@@ -39,9 +39,11 @@ public class Entry {
{ Events.Missions, typeof(MissionsEntry) },
{ Events.MultiSellExplorationData, typeof(MultiSellExplorationDataEntry) },
{ Events.Music, typeof(MusicEntry) },
+ { Events.Powerplay, typeof(PowerplayEntry) },
{ Events.ReceiveText, typeof(ReceiveTextEntry) },
{ Events.RedeemVoucher, typeof(RedeemVoucherEntry) },
{ Events.SearchAndRescue, typeof(SearchAndRescueEntry) },
+ { Events.SelfDestruct, typeof(SelfDestructEntry) },
{ Events.SellExplorationData, typeof(SellExplorationDataEntry) },
{ Events.SellMicroResources, typeof(SellMicroResourcesEntry) },
{ Events.SellOrganicData, typeof(SellOrganicDataEntry) },
diff --git a/EDPlayerJournal/Entries/Events.cs b/EDPlayerJournal/Entries/Events.cs
index d9b2fb6..649eff2 100644
--- a/EDPlayerJournal/Entries/Events.cs
+++ b/EDPlayerJournal/Entries/Events.cs
@@ -29,9 +29,11 @@ public class Events {
public static readonly string Missions = "Missions";
public static readonly string MultiSellExplorationData = "MultiSellExplorationData";
public static readonly string Music = "Music";
+ public static readonly string Powerplay = "Powerplay";
public static readonly string ReceiveText = "ReceiveText";
public static readonly string RedeemVoucher = "RedeemVoucher";
public static readonly string SearchAndRescue = "SearchAndRescue";
+ public static readonly string SelfDestruct = "SelfDestruct";
public static readonly string SellExplorationData = "SellExplorationData";
public static readonly string SellMicroResources = "SellMicroResources";
public static readonly string SellOrganicData = "SellOrganicData";
diff --git a/EDPlayerJournal/Entries/PowerplayEntry.cs b/EDPlayerJournal/Entries/PowerplayEntry.cs
new file mode 100644
index 0000000..22d9fc1
--- /dev/null
+++ b/EDPlayerJournal/Entries/PowerplayEntry.cs
@@ -0,0 +1,32 @@
+using System.Reflection;
+
+namespace EDPlayerJournal.Entries {
+ public class PowerplayEntry : Entry {
+ ///
+ /// Name of the power
+ ///
+ public string Power { get; set; } = string.Empty;
+
+ ///
+ /// Player rank
+ ///
+ public int Rank { get; set; } = 0;
+
+ ///
+ /// Current merits of the player
+ ///
+ public long Merits { get; set; } = 0;
+
+ ///
+ /// Time pledged (in seconds?)
+ ///
+ public long TimePledged { get; set; } = 0;
+
+ protected override void Initialise() {
+ Power = JSON.Value("Power") ?? string.Empty;
+ Rank = JSON.Value("Rank") ?? 0;
+ Merits = JSON.Value("Merits") ?? 0;
+ TimePledged = JSON.Value("TimePledged") ?? 0;
+ }
+ }
+}
diff --git a/EDPlayerJournal/Entries/SelfDestructEntry.cs b/EDPlayerJournal/Entries/SelfDestructEntry.cs
new file mode 100644
index 0000000..79f723b
--- /dev/null
+++ b/EDPlayerJournal/Entries/SelfDestructEntry.cs
@@ -0,0 +1,5 @@
+namespace EDPlayerJournal.Entries {
+ public class SelfDestructEntry : Entry {
+ // Has no data
+ }
+}
diff --git a/EDPlayerJournal/Instances.cs b/EDPlayerJournal/Instances.cs
index c9068d0..1587425 100644
--- a/EDPlayerJournal/Instances.cs
+++ b/EDPlayerJournal/Instances.cs
@@ -18,6 +18,11 @@ public class Instances {
///
public static readonly string WarzoneHigh = "$Warzone_PointRace_High";
+ ///
+ /// Medium power play conflict zone, new in PP 2.0 Ascendancy update
+ ///
+ public static readonly string PowerWarzoneMedium = "$Warzone_Powerplay_Med";
+
///
/// Low Thargoid combat zone
///
@@ -52,8 +57,17 @@ public class Instances {
;
}
+ public static bool IsPowerWarzone(string type) {
+ return
+ IsInstance(type, PowerWarzoneMedium)
+ ;
+ }
+
public static bool IsWarzone(string type) {
- return IsHumanWarzone(type) || IsThargoidWarzone(type);
+ return IsHumanWarzone(type) ||
+ IsThargoidWarzone(type) ||
+ IsPowerWarzone(type)
+ ;
}
public static bool IsInstance(string type, string instance) {
diff --git a/EliteBGS/CHANGELOG.md b/EliteBGS/CHANGELOG.md
index 18ea6e8..681cbe6 100644
--- a/EliteBGS/CHANGELOG.md
+++ b/EliteBGS/CHANGELOG.md
@@ -1,5 +1,12 @@
# EliteBGS changelog
+## 0.4.4 on ??.??.202?
+
+* Add support for Power Conflict Zones
+* Show no inf as "Zero INF", so the Nova Navy bot can parse it properly
+* Add support for MeritsGained, but disable it for now, as the player
+ journal is massively lacking in terms of Powerplay 2.0 support.
+
## 0.4.3 on 18.09.2024
* Add possibility to post log reports to Discord webhooks.
diff --git a/EliteBGS/DiscordLogGenerator.cs b/EliteBGS/DiscordLogGenerator.cs
index d941366..22a23ed 100644
--- a/EliteBGS/DiscordLogGenerator.cs
+++ b/EliteBGS/DiscordLogGenerator.cs
@@ -21,6 +21,7 @@ public class DiscordLogGenerator {
new CargoSoldFormatter(),
new VistaGenomicsFormat(),
new SearchAndRescueFormat(),
+ new MeritsGainedFormat(),
};
protected virtual string GetToolVersion() {
diff --git a/EliteBGS/EliteBGS - Backup.csproj b/EliteBGS/EliteBGS - Backup.csproj
deleted file mode 100644
index fc32da3..0000000
--- a/EliteBGS/EliteBGS - Backup.csproj
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
- net7.0-windows
- WinExe
- 0.2.6
- false
- true
- true
- true
-
-
- EliteBGSApplication
-
-
- Salus.ico
- BGS reporting and logging tool for Elite:Dangerous
- nola
- Copyright 2019 by Florian Stinglmayr
- https://git.aror.org/florian/EDBGS
- ED;Elite Dangerous;BGS
- https://bgs.n0la.org
- README.md
-
-
-
- PreserveNewest
-
-
- PreserveNewest
- True
- \
-
-
- Always
-
-
-
-
- PreserveNewest
-
-
-
-
- PreserveNewest
-
-
-
-
-
-
-
- Always
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
- True
- Resources.resx
-
-
-
-
- PublicResXFileCodeGenerator
- Resources.Designer.cs
-
-
-
\ No newline at end of file
diff --git a/EliteBGS/LogGenerator/MeritsGainedFormat.cs b/EliteBGS/LogGenerator/MeritsGainedFormat.cs
new file mode 100644
index 0000000..564394a
--- /dev/null
+++ b/EliteBGS/LogGenerator/MeritsGainedFormat.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using EDPlayerJournal;
+using EDPlayerJournal.BGS;
+
+namespace EliteBGS.LogGenerator;
+
+public class MeritsGainedFormat : LogFormatter {
+ public string GenerateLog(Objective objective) {
+ var builder = new StringBuilder();
+
+ var merits = objective
+ .EnabledOfType()
+ .GroupBy(x => x.Power)
+ .ToDictionary(x => x.Key, x => x.Sum(x => x.Merits))
+ ;
+
+ if (merits == null || merits.Count == 0) {
+ return "";
+ }
+
+ foreach (var merit in merits) {
+ builder.AppendFormat("{0} merits gained for {1}\n", merit.Value, merit.Key);
+ }
+
+ return builder.ToString().Trim();
+ }
+
+ public string GenerateSummary(Objective objective) {
+ var builder = new StringBuilder();
+
+ var merits = objective
+ .EnabledOfType()
+ .GroupBy(x => x.Power)
+ .ToDictionary(x => x.Key, x => x.Sum(x => x.Merits))
+ ;
+
+ if (merits == null || merits.Count == 0) {
+ return "";
+ }
+
+ foreach (var merit in merits) {
+ builder.AppendFormat("MRT: {0}, {1}; ", merit.Key, merit.Value);
+ }
+
+ return builder.ToString().Trim().TrimEnd(';');
+ }
+}
diff --git a/EliteBGS/LogGenerator/MissionFormat.cs b/EliteBGS/LogGenerator/MissionFormat.cs
index c92e539..ea70637 100644
--- a/EliteBGS/LogGenerator/MissionFormat.cs
+++ b/EliteBGS/LogGenerator/MissionFormat.cs
@@ -64,6 +64,7 @@ public class MissionFormat : LogFormatter {
Dictionary passengers = new();
StringBuilder output = new StringBuilder();
long total_influence = 0;
+ bool hadmissions = false;
var missions = objective.EnabledOfType();
var support = objective.EnabledOfType();
@@ -85,6 +86,7 @@ public class MissionFormat : LogFormatter {
++collated[m.MissionName][m.Influence];
+ hadmissions = true;
total_influence += m.Influence.Length;
if (m.AcceptedEntry != null &&
@@ -121,19 +123,23 @@ public class MissionFormat : LogFormatter {
output.Append(failedlog);
output.Append("\n");
}
+ if (failed.Count > 0) {
+ hadmissions = true;
+ }
total_influence += failed.Sum(x => x.InfluenceAmount);
foreach (InfluenceSupport inf in support) {
output.Append(inf.ToString());
output.Append("\n");
+ hadmissions = true;
total_influence += inf.Influence.InfluenceAmount;
}
- if (support.Count() > 0) {
+ if (support.Count > 0) {
output.Append("\n");
}
- if (total_influence != 0) {
+ if (hadmissions) {
output.AppendFormat("Total Influence: {0}", total_influence);
}
@@ -141,6 +147,10 @@ public class MissionFormat : LogFormatter {
}
public string GenerateSummary(Objective objective) {
+ bool hadmissions = objective
+ .EnabledOfType()
+ .Count > 0
+ ;
long influence = objective
.EnabledOfType()
.Sum(x => x.Influence.Length)
@@ -154,7 +164,7 @@ public class MissionFormat : LogFormatter {
.Sum(x => x.InfluenceAmount)
;
- if (influence == 0 && support == 0 && failed == 0) {
+ if (influence == 0 && support == 0 && failed == 0 && !hadmissions) {
return "";
}
diff --git a/EliteBGS/MainWindow.xaml b/EliteBGS/MainWindow.xaml
index 4412c87..fff5493 100644
--- a/EliteBGS/MainWindow.xaml
+++ b/EliteBGS/MainWindow.xaml
@@ -121,6 +121,7 @@
+
@@ -261,6 +262,7 @@
+
@@ -269,6 +271,7 @@
+
diff --git a/EliteBGS/MainWindow.xaml.cs b/EliteBGS/MainWindow.xaml.cs
index 5983d66..66499d9 100644
--- a/EliteBGS/MainWindow.xaml.cs
+++ b/EliteBGS/MainWindow.xaml.cs
@@ -64,6 +64,7 @@ public partial class MainWindow : MetroWindow {
this.NoInfluenceSupport.IsOn = Config.Global.IgnoreInfluenceSupport;
this.NoMarketBuy.IsOn = Config.Global.IgnoreMarketBuy;
this.NoFleetCarrier.IsOn = Config.Global.IgnoreFleetCarrier;
+ this.NoPowerplay.IsOn = Config.Global.IgnorePowerplay;
// Apply theme
try {
@@ -182,6 +183,7 @@ public partial class MainWindow : MetroWindow {
options.IgnoreInfluenceSupport = Config.Global.IgnoreInfluenceSupport;
options.IgnoreMarketBuy = Config.Global.IgnoreMarketBuy;
options.IgnoreFleetCarrierFaction = Config.Global.IgnoreFleetCarrier;
+ options.IgnorePowerplay = Config.Global.IgnorePowerplay;
List transactions = parser.Parse(entries, options);
@@ -476,6 +478,16 @@ public partial class MainWindow : MetroWindow {
RefreshView();
}
+ private void Power_Click(object sender, RoutedEventArgs e) {
+ CombatZone transaction = GetTransaction(sender);
+ if (transaction == null) {
+ return;
+ }
+
+ transaction.Type = CombatZones.PowerCombatZone;
+ RefreshView();
+ }
+
private void Thargoid_Click(object sender, RoutedEventArgs e) {
CombatZone transaction = GetTransaction(sender);
if (transaction == null) {
@@ -573,6 +585,10 @@ public partial class MainWindow : MetroWindow {
Config.Global.IgnoreFleetCarrier = this.NoFleetCarrier.IsOn;
}
+ private void NoPowerplay_Toggled(object sender, RoutedEventArgs e) {
+ Config.Global.IgnorePowerplay = this.NoPowerplay.IsOn;
+ }
+
private void OpenInExplorer_Click(object sender, RoutedEventArgs e) {
try {
Process.Start(new ProcessStartInfo(Config.Global.JournalLocation) {
diff --git a/EliteBGS/Objective.cs b/EliteBGS/Objective.cs
index 755ce7f..f728d22 100644
--- a/EliteBGS/Objective.cs
+++ b/EliteBGS/Objective.cs
@@ -59,7 +59,9 @@ public class UITransaction : INotifyPropertyChanged {
return Visibility.Hidden;
}
- if (string.Compare(combat.Type, CombatZones.ShipCombatZone) == 0) {
+ // Both normal and power combat zones have special objectives
+ if (string.Compare(combat.Type, CombatZones.ShipCombatZone) == 0 ||
+ string.Compare(combat.Type, CombatZones.PowerCombatZone) == 0) {
return Visibility.Visible;
}
diff --git a/EliteBGS/Util/AppConfig.cs b/EliteBGS/Util/AppConfig.cs
index cec6dfa..3b26745 100644
--- a/EliteBGS/Util/AppConfig.cs
+++ b/EliteBGS/Util/AppConfig.cs
@@ -67,6 +67,11 @@ public class AppConfig {
///
public bool IgnoreFleetCarrier { get; set; } = true;
+ ///
+ /// Ignore power play?
+ ///
+ public bool IgnorePowerplay { get; set; } = true;
+
///
/// List of Webhooks configured
///