Compare commits

..

19 Commits

Author SHA1 Message Date
4cefc393b5 add merits to the log 2025-04-16 15:09:56 +02:00
693d49be14 add new entries
the content is not yet known, but we do know the event name
2025-03-06 09:58:44 +01:00
32dbde2c82 add file to identify powers 2025-03-06 09:58:18 +01:00
894918b5ba Merge branch 'master' of codeberg.org:nola/EDBGS 2024-12-18 09:24:11 +01:00
41fca4fa8c delete old obsolete docs 2024-12-18 09:03:57 +01:00
2acb63025c remove backup file 2024-11-18 09:07:50 +01:00
eaa4bda098 update changelog 2024-11-14 14:08:36 +01:00
9d8f0c1b9a strip out tailing semi-colon 2024-11-14 13:55:03 +01:00
88b770e5ec add format for merits gained in log 2024-11-14 13:52:17 +01:00
d9dd2cc524 add option to ignore power play to UI 2024-11-14 13:40:25 +01:00
2905696641 add option to ignore powerplay for now 2024-11-14 13:33:49 +01:00
aeaa6b5220 add preliminary support for merits gained 2024-11-14 13:30:31 +01:00
cdbca10f2d add support for Powerplay message 2024-11-14 12:14:36 +01:00
1da6f41ec8 update changelog 2024-11-14 11:43:24 +01:00
2c6eb9190a count conflict zones you SelfDestruct out of 2024-11-14 11:32:04 +01:00
8a92cac02a add support for SelfDestruct 2024-11-14 11:31:46 +01:00
4fe77e6946 add support for power combat zones in UI 2024-11-14 11:18:01 +01:00
912e8b602f add support for power combat zones in parsing 2024-11-14 11:17:43 +01:00
be3bceb880 make sure missions read as 0 INF if no INF was generated 2024-11-14 10:51:18 +01:00
29 changed files with 426 additions and 538 deletions

View File

@ -92,6 +92,13 @@ public class CombatZone : Transaction {
get { return string.Compare(Type, CombatZones.AXCombatZone) == 0; }
}
/// <summary>
/// Returns true if it is a power combat zone
/// </summary>
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;

View File

@ -0,0 +1,32 @@
using EDPlayerJournal.Entries;
namespace EDPlayerJournal.BGS;
public class MeritsGained : Transaction {
public MeritsGained() { }
public MeritsGained(Entry entry) {
Entries.Add(entry);
}
/// <summary>
/// Number of merits gained
/// </summary>
public long Merits {
get {
return Entries
.OfType<PowerplayMeritsEntry>()
.Sum(x => x.MeritsGained)
;
}
}
/// <summary>
/// For what power those merits were gained
/// </summary>
public string Power { get; set; } = string.Empty;
public override string ToString() {
return string.Format("{0} Merits gained for {1}", Merits, Power);
}
}

View File

@ -0,0 +1,31 @@
using EDPlayerJournal.Entries;
namespace EDPlayerJournal.BGS.Parsers;
internal class PowerplayMeritsParser : ITransactionParserPart {
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
PowerplayMeritsEntry? e = entry as PowerplayMeritsEntry;
if (e == null) {
throw new ApplicationException("not a valid PowerplayMerits entry");
}
MeritsGained? transaction = null;
transaction = transactions
.OfType<MeritsGained>()
.Where(x => x.System == context.CurrentSystem &&
x.Power == e.Power)
.FirstOrDefault()
;
if (transaction == null) {
transaction = new MeritsGained(e) {
System = context.CurrentSystem,
Power = e.Power,
Faction = e.Power,
};
transactions.Add(transaction);
} else {
transaction.Entries.Add(e);
}
}
}

View File

@ -16,6 +16,12 @@ public class TransactionParserOptions {
/// </summary>
public bool IgnoreInfluenceSupport { get; set; } = false;
/// <summary>
/// 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`.
/// </summary>
public bool IgnorePowerplay { get; set; } = true;
/// <summary>
/// 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.PowerplayMerits, new PowerplayMeritsParser() },
{ 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() },

View File

@ -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;
/// <summary>
/// Current Odyssey settlement.
/// </summary>
public string? Settlement { get; set; } = null;
/// <summary>
/// Current Merits
/// </summary>
public long? CurrentMerits { get; set; } = null;
/// <summary>
/// Merits from last login
/// </summary>
public long? LastMerits { get; set; } = null;
/// <summary>
/// Returns true if the current session is legacy
/// </summary>
@ -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",

View File

@ -14,6 +14,11 @@ public class CombatZones {
/// </summary>
public static readonly string ShipCombatZone = "Ship";
/// <summary>
/// Power combat zones, new in Ascendancy update.
/// </summary>
public static readonly string PowerCombatZone = "Power";
/// <summary>
/// AX combat zone
/// </summary>

View File

@ -39,9 +39,15 @@ public class Entry {
{ Events.Missions, typeof(MissionsEntry) },
{ Events.MultiSellExplorationData, typeof(MultiSellExplorationDataEntry) },
{ Events.Music, typeof(MusicEntry) },
{ Events.Powerplay, typeof(PowerplayEntry) },
{ Events.PowerplayCollect, typeof(PowerplayCollectEntry) },
{ Events.PowerplayDeliver, typeof(PowerplayDeliverEntry) },
{ Events.PowerplayMerits, typeof(PowerplayMeritsEntry) },
{ Events.PowerplayRank, typeof(PowerplayRankEntry) },
{ 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) },

View File

@ -29,9 +29,15 @@ 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 PowerplayCollect = "PowerplayCollect";
public static readonly string PowerplayDeliver = "PowerplayDeliver";
public static readonly string PowerplayMerits = "PowerplayMerits";
public static readonly string PowerplayRank = "PowerplayRank";
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";

View File

@ -0,0 +1,7 @@
namespace EDPlayerJournal.Entries;
public class PowerplayCollectEntry : Entry {
protected override void Initialise() {
// TODO
}
}

View File

@ -0,0 +1,7 @@
namespace EDPlayerJournal.Entries;
public class PowerplayDeliverEntry : Entry {
protected override void Initialise() {
// TODO
}
}

View File

@ -0,0 +1,32 @@
using System.Reflection;
namespace EDPlayerJournal.Entries {
public class PowerplayEntry : Entry {
/// <summary>
/// Name of the power
/// </summary>
public string Power { get; set; } = string.Empty;
/// <summary>
/// Player rank
/// </summary>
public int Rank { get; set; } = 0;
/// <summary>
/// Current merits of the player
/// </summary>
public long Merits { get; set; } = 0;
/// <summary>
/// Time pledged (in seconds?)
/// </summary>
public long TimePledged { get; set; } = 0;
protected override void Initialise() {
Power = JSON.Value<string>("Power") ?? string.Empty;
Rank = JSON.Value<int?>("Rank") ?? 0;
Merits = JSON.Value<long?>("Merits") ?? 0;
TimePledged = JSON.Value<long?>("TimePledged") ?? 0;
}
}
}

View File

@ -0,0 +1,15 @@
namespace EDPlayerJournal.Entries;
public class PowerplayMeritsEntry : Entry {
protected override void Initialise() {
Power = JSON.Value<string?>("Power") ?? string.Empty;
MeritsGained = JSON.Value<long?>("MeritsGained") ?? 0;
TotalMerits = JSON.Value<long?>("TotalMerits") ?? 0;
}
public string Power { get; set; } = string.Empty;
public long MeritsGained { get; set; } = 0;
public long TotalMerits { get; set; } = 0;
}

View File

@ -0,0 +1,7 @@
namespace EDPlayerJournal.Entries;
public class PowerplayRankEntry : Entry {
protected override void Initialise() {
// TODO
}
}

View File

@ -0,0 +1,5 @@
namespace EDPlayerJournal.Entries {
public class SelfDestructEntry : Entry {
// Has no data
}
}

View File

@ -18,6 +18,11 @@ public class Instances {
/// </summary>
public static readonly string WarzoneHigh = "$Warzone_PointRace_High";
/// <summary>
/// Medium power play conflict zone, new in PP 2.0 Ascendancy update
/// </summary>
public static readonly string PowerWarzoneMedium = "$Warzone_Powerplay_Med";
/// <summary>
/// Low Thargoid combat zone
/// </summary>
@ -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) {

View File

@ -0,0 +1,101 @@
namespace EDPlayerJournal.PowerPlay;
/// <summary>
/// Holds a list of all available powers in E:D, and helps
/// to translate commonly used short-hands and aliases to
/// journal approved power names.
/// </summary>
public class Powers {
public static readonly string
// Basking
ALavignyDuval = "A. Lavigny-Duval",
AislingDuval = "Aisling Duval",
DentonPatreus = "Denton Patreus",
ZeminaTorval = "Zemina Torval",
// Feds
JeromeArcher = "Jerome Archer",
FeliciaWinters = "Felicia Winters",
// Alliance
EdmunMahon = "Edmund Mahon",
NakatoKaine = "Nakato Kaine",
// Independents
YuriGrom = "Yuri Grom",
ArchonDelaine = "Archon Delaine",
LiYongRui = "Li Yong-Rui",
PranavAntal = "Pranav Antal"
;
public static readonly Dictionary<string, string> aliases = new() {
// ALD
{ Powers.ALavignyDuval, Powers.ALavignyDuval },
{ "ALD", Powers.ALavignyDuval },
{ "Arissa", Powers.ALavignyDuval },
{ "Emperor", Powers.ALavignyDuval },
{ "Kaiser", Powers.ALavignyDuval },
// AD
{ Powers.AislingDuval, Powers.AislingDuval },
{ "AD", Powers.AislingDuval },
{ "Aisling", Powers.AislingDuval },
// DP
{ Powers.DentonPatreus, Powers.DentonPatreus },
{ "DP", Powers.DentonPatreus },
{ "Denton", Powers.DentonPatreus },
// ZT
{ Powers.ZeminaTorval, Powers.ZeminaTorval },
{ "ZT", Powers.ZeminaTorval },
{ "Torval", Powers.ZeminaTorval },
// Archer
{ Powers.JeromeArcher, Powers.JeromeArcher },
{ "JA", Powers.JeromeArcher },
{ "Archer", Powers.JeromeArcher },
// Winters
{ Powers.FeliciaWinters, Powers.FeliciaWinters },
{ "FW", Powers.FeliciaWinters },
{ "Winters", Powers.FeliciaWinters },
// Mahon
{ Powers.EdmunMahon, Powers.EdmunMahon },
{ "EM", Powers.EdmunMahon },
{ "Mahon", Powers.EdmunMahon },
// Kaine
{ Powers.NakatoKaine, Powers.NakatoKaine },
{ "NK", Powers.NakatoKaine },
{ "Kaine", Powers.NakatoKaine },
// Grom
{ Powers.YuriGrom, Powers.YuriGrom },
{ "YG", Powers.YuriGrom },
{ "Grom", Powers.YuriGrom },
// Archon
{ Powers.ArchonDelaine, Powers.ArchonDelaine },
{ "Archon", Powers.ArchonDelaine },
{ "Kumo", Powers.ArchonDelaine },
{ "KumoBurger", Powers.ArchonDelaine },
// LYR
{ Powers.LiYongRui, Powers.LiYongRui },
{ "LYR", Powers.LiYongRui },
// Pranav
{ Powers.PranavAntal, Powers.PranavAntal },
{ "PA", Powers.PranavAntal },
{ "Pranav", Powers.PranavAntal },
};
public static bool IsValidPower(string power) {
try {
string p = GetPower(power);
return true;
} catch (Exception) {
return false;
}
}
public static string GetPower(string nameOrAlias) {
string? val = aliases
.Where(x => string.Compare(x.Key, nameOrAlias, StringComparison.InvariantCultureIgnoreCase) == 0)
.Select(x => x.Value)
.FirstOrDefault()
;
if (string.IsNullOrEmpty(val)) {
throw new ApplicationException($"not a valid power: {nameOrAlias}");
}
return val;
}
}

View File

@ -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.

View File

@ -21,6 +21,7 @@ public class DiscordLogGenerator {
new CargoSoldFormatter(),
new VistaGenomicsFormat(),
new SearchAndRescueFormat(),
new MeritsGainedFormat(),
};
protected virtual string GetToolVersion() {

View File

@ -1,86 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
<OutputType>WinExe</OutputType>
<Version>0.2.6</Version>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
</PropertyGroup>
<PropertyGroup>
<StartupObject>EliteBGSApplication</StartupObject>
</PropertyGroup>
<PropertyGroup>
<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>
<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>
</None>
</ItemGroup>
<ItemGroup>
<Resource Include="docs\main-page.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource>
</ItemGroup>
<ItemGroup>
<Content Include="LICENCE.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Resource Include="Salus.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="logo_v4.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\EliteBGS.ico" />
</ItemGroup>
<ItemGroup>
<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="Microsoft.Windows.Compatibility" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<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>
<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>

View File

@ -0,0 +1,47 @@
using System.Linq;
using System.Text;
using EDPlayerJournal.BGS;
namespace EliteBGS.LogGenerator;
public class MeritsGainedFormat : LogFormatter {
public string GenerateLog(Objective objective) {
var builder = new StringBuilder();
var merits = objective
.EnabledOfType<MeritsGained>()
.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<MeritsGained>()
.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(';');
}
}

View File

@ -64,6 +64,7 @@ public class MissionFormat : LogFormatter {
Dictionary<string, ulong> passengers = new();
StringBuilder output = new StringBuilder();
long total_influence = 0;
bool hadmissions = false;
var missions = objective.EnabledOfType<MissionCompleted>();
var support = objective.EnabledOfType<InfluenceSupport>();
@ -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<MissionCompleted>()
.Count > 0
;
long influence = objective
.EnabledOfType<MissionCompleted>()
.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 "";
}

View File

@ -121,6 +121,7 @@
<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"/>
<Button Content="Power" x:Name="Power" Click="Power_Click"/>
</StackPanel>
</Expander>
</StackPanel>
@ -261,6 +262,7 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
@ -269,6 +271,7 @@
<mah:ToggleSwitch x:Name="NoInfluenceSupport" Grid.Row="0" Grid.ColumnSpan="2" Content="Ignore secondary influence support given out by certain missions" Toggled="NoInfluenceSupport_Toggled"/>
<mah:ToggleSwitch x:Name="NoMarketBuy" Grid.Row="1" Grid.ColumnSpan="2" Content="Ignore commodities bought at stations" Toggled="NoMarketBuy_Toggled"/>
<mah:ToggleSwitch x:Name="NoFleetCarrier" Grid.Row="2" Grid.ColumnSpan="2" Content="Ignore transactions done on a Fleet Carrier" Toggled="NoFleetCarrier_Toggled" />
<mah:ToggleSwitch x:Name="NoPowerplay" Grid.Row="3" Grid.ColumnSpan="2" Content="Ignore Powerplay Merits" Toggled="NoPowerplay_Toggled" />
</Grid>
</GroupBox>
<GroupBox Header="Discord Webhooks" Grid.Row="3" VerticalAlignment="Top" Width="Auto" Grid.ColumnSpan="3" Margin="0,5,0,0">

View File

@ -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<Transaction> 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<CombatZone>(sender);
if (transaction == null) {
return;
}
transaction.Type = CombatZones.PowerCombatZone;
RefreshView();
}
private void Thargoid_Click(object sender, RoutedEventArgs e) {
CombatZone transaction = GetTransaction<CombatZone>(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) {

View File

@ -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;
}

View File

@ -67,6 +67,11 @@ public class AppConfig {
/// </summary>
public bool IgnoreFleetCarrier { get; set; } = true;
/// <summary>
/// Ignore power play?
/// </summary>
public bool IgnorePowerplay { get; set; } = true;
/// <summary>
/// List of Webhooks configured
/// </summary>

View File

@ -1,21 +0,0 @@
# 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:
![combat zone](combatzone.png)

View File

@ -1,240 +0,0 @@
# EliteBGS
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://codeberg.org/nola/EDBGS).
Binary downloads can be found here: [https://bgs.n0la.org/](https://bgs.n0la.org/).
## How To
Press "Parse Journal", which will check your Elite Dangerous player journal for completed
missions. Currently the tool recognises the following completed tasks:
* Buying of cargo from stations (new in Update 10)
* Completed missions
* Failed missions
* Murders
* Search and Rescue contributions
* Selling cartography data
* Selling of cargo to stations
* Selling of micro resources (Odyssey only)
* Vouchers, including bounty vouchers, combat bonds, and settlement vouchers (aka intel packages)
* Thargoid kills
* Combat zones (experimental)
The following transactions are recognised but not listed, because they do not affect BGS:
* Selling of organic data (Odyssey only)
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
makes sure that your vouchers actually have a BGS impact, otherwise it won't list them.
Selling cargo attempts to discern the profit and/or loss, which is helpful to gauge BGS
impact. But the player journal does not tell the amount of profit in the sell message.
So the tool looks for a buy a message related to the same commodity, and calculates loss
and/or profit from that. If the buy of the commodity is not within the time and date range,
or some other shenanigans happen that the tool does not yet support, the profit/loss could
be wrong. You can use the "Adjust Trade Profit" button to manually adjust the trade profit,
or you could simply edit the discord log manually.
Please note that cartography data, and micro resources only help the controlling faction
of a station. The tool is clever enough to exclude these if the station you turn them in at, is not
controlled by the faction you specified in the objective.
Some missions may show up having zero influence for the given faction. This happens if you do
missions for a faction which is currently in an election state. You do not gain influence for
the faction so the influence reads as zero. But you contribute towards the election, so the
missions are selected anyway.
There is no entry in the journal if you win a combat zone. So you have to add those manually. Select
an objective for which you wish to log a combat zone. The faction in the objective, must be the
faction you fought for in the combat zone. Then click "Add Combat Zone Win". Select type,
either "On Foot" for Odyssey, or "Ship" for regular ones. Then select the grade (low, medium or
high), and how many you won. Then press "Accept". Select "Cancel" to abort. You can of course remove
the combat zone entries by selecting them, and pressing "DEL".
If you deliberately fail a mission (to log negative INF towards a faction), the tool cannot detect
it, if the day you accepted the mission is outside of the given date range. It needs the journal
entry where you accept the mission to connect the mission to a faction, system and station. The tool
will warn you if this happens, with a message in the error log in the fourth tab.
When committing murder, the journal entry contains the faction information of the faction that gave
you the bounty. And not the faction of the victim. The tool will look for an event in which you
scanned your victim, and gleem the victim's faction from that. If you did not scan your victim, then
sadly the tool cannot connect the victim's faction to the victim.
![Main Window with entries](main-page.png)
The window will then list all the journal entries it has found, and group them by objectives. You
can select which objectives you wish to report, by using the checkmarks.
You can exclude a specific entry within an objective by deselecting the checkbox next to them.
This way said entry will not appear in the final log. You can also remove individual entries
(if you think the tool detected something you thought was wrong), by selecting the entry,
and pressing the "DEL" key.
Once you are satisfied with the result, you can copy and paste the final report to the discord
server of your choice. Before you copy/paste it into the discord of your squadron, you should
check the log. You can of course also edit it, either if something is wrong because the tool
missed something, or you just wish to add a note the report itself.
If you wish to regenerate the discord log, simply click "Generate Log".
## Known Issues and Bugs
### Settlement Vouchers
Settlement vouchers (aka Intel Packages) help every faction aligned with the given superpower.
So if you turn in an Imperial intel package on an imperial station, all factions aligned with
the Empire will gain a bit of INF boost. The tool currently cannot handle that. All intel packages
are displayed instead.
### Bugged bounty vouchers
Sometimes bounty vouchers are not properly recognised. This is a bug in the player journal, where
the faction information is not properly written out in the journal:
```
{
"timestamp":"2021-10-07T14:57:50Z", "event":"RedeemVoucher",
"Type":"bounty", "Amount":20750,
"Factions":[ { "Faction":"", "Amount":500 }, { "Faction":"", "Amount":20250 }]
}
```
Since the tool does not know for which faction these bounties were redeemed for, it cannot assign
it to an objective.
### Combat Zones
The player journal currently does not make an entry when you win or lose a combat zone. This is a
an ommission from FDev:
* [https://issues.frontierstore.net/issue-detail/43509](https://issues.frontierstore.net/issue-detail/43509)
Please upvote the issue to get it fixed. Until then, you have to add combat zone wins manually.
### On-Foot NPC givers
Up until update 13 missions accepted from NPCs in Odyssey concourses do not get a player journal entry.
This has been fixed in update 13. Any on foot missions from NPCs accepted before update 13, do not have
an entry in the player journal.
### Failed vs. Abandoned Missions
The tool also currently cannot differentiate between missions you have abandoned in the transaction
tab before it was completed, and those that you have failed - either delibaretly or by time-out. So
it will find and add them all, and you simply can remove those that you have abandoned manually.
### Influence given to empty/non-existent faction
Sometimes the log will state that it gave positive or negative influence to a faction, but the
faction name is empty:
```
"FactionEffects": [
{
"Faction": "",
"Effects": [
{
"Effect": "$MISSIONUTIL_Interaction_Summary_EP_down;",
"Effect_Localised": "The economic status of $#MinorFaction; has declined in the $#System; system.",
"Trend": "DownBad"
}
],
"Influence": [
{
"SystemAddress": 251012319587,
"Trend": "DownBad",
"Influence": "+"
}
],
"ReputationTrend": "DownBad",
"Reputation": "+"
}
]
```
This happens for example if you do a scan/heist mission from a surface POI, but no one owns said
surface POI. Randomly generated surface POIs sometimes have no owner, and said non-existant owner
then gets the negative influence.
### Mission Completed but no one gains influence
Sometimes missions are completed but no one gains any influence:
```
{
"timestamp": "2022-02-25T21:30:45Z",
"event": "MissionCompleted",
"Faction": "Social LHS 6103 Confederation",
"Name": "Mission_Courier_Elections_name",
"MissionID": 850025233,
"TargetFaction": "Delphin Blue Federal PLC",
"DestinationSystem": "Delphin",
"DestinationStation": "Aristotle Orbital",
"Reward": 122300,
"FactionEffects": [
{
"Faction": "Social LHS 6103 Confederation",
"Effects": [
{
"Effect": "$MISSIONUTIL_Interaction_Summary_EP_up;",
"Effect_Localised": "The economic status of $#MinorFaction; has improved in the $#System; system.",
"Trend": "UpGood"
}
],
"Influence": [],
"ReputationTrend": "UpGood",
"Reputation": "+"
},
{
"Faction": "Delphin Blue Federal PLC",
"Effects": [],
"Influence": [],
"ReputationTrend": "UpGood",
"Reputation": "+"
}
]
}
```
Here the is known that at the time of completion the Confederation was in an Election and could not
have gained any influence regardless. It is unclear whether this also holds true for Delphin Blue
Federal PLC. So to be save, the tool assumes that if no influence was gained for the source faction,
it still has to make an entry for the source system. The same applies for the target faction: if no
influence is gained for the target faction, still add an entry for the target faction in the missions
target system.
Since it is not possible to differentiate between missions that give no influence no matter what, and
no influence gained because of an election, we have to assume it *gave* influence and let the user
decide whether it was because of an election, or not.
Future tool versions should probably take faction states into account in such matters.
## Nothing's Perfect
The tool itself is still a work in progress, and it might miss something. If you think the tool
missed a task you have done, please contact `Hekateh` on the Elite Dangerous community discord.
It would be helpful if you included the JSON player journal. This player journal can be found here:
```
%userprofile%\saved Games\Frontier Developments\Elite Dangerous\
```
## Build Dependencies
The project also requires `Ookii.Dialogs.WPF` controls, which contains the auto complete text box.
And of course, `Newtonsoft.Json` as the JSON parser.
`MahApps` is used to generate a prettier look, and for its dark themes.

View File

@ -1,90 +0,0 @@
## FAQ
Most frequently asked questions:
### Windows complains that it does not wish to run the application, what gives?
The tool contains no viruses, but it is not seen as "trustworthy". You can however
right-click EliteBGS.exe and "Unblock" the application.
### Does this work for console players?
Sorry, no. Console players don't have a player journal per se, and the tool does
not support Frontier Commander API.
### Why won't the tool start anymore?
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.
### Why is it unable to find my player journal?
Usually your player journal lives in the Saved Games folder in your home
directory. If, for some reason, this doesn't match up, you can point the
tool towards your player journal in the third tab.
### Why do some of the objective not show up in the final discord log?
Only objectives with the little checkbox enabled show up there. Those
that the tool generates by itself are not enabled per default.
### Can I delete an objective or an entry?
Click on an objective or entry and press the Delete key.
### I deleted something I didn't want to. What now?
Just press "Parse Journal" again, and the tool will generate all
the entries again.
### What are micro resources?
Odyssey cargo that you sell at the bartender. Just like normal cargo,
they aid the controlling faction of the station where you sold them.
### Why are missions accepted in a concourse or in a settlement from an NPC missing?
Because up until Update 13, they did not show up in player journal. This should
now be fixed.
### Some mission names are weird. What gives?
That's because the tool uses the game generated mission name, if it doesn't
have a clean and nice mission name on file for the certain mission type. The
fourth tab "Event Log" should have an entry about it, so please post those
names into this channel.
### Some missions say they have 0 influence?
That happens for missions that aid an Election. The faction in question does
not gain influence during an election, as influence is locked during conflicts.
But since you are contributing towards the election win of that faction,
the tool picks them anyway.
### Why are some failed missions not showing up?
The time span you specify must include the day where you accepted the mission,
as well as the day where you failed the mission. Otherwise the tool cannot handle
that failed mission.
Prior to update 15 missions only failed once you dismissed them from your transaction
tab. With update 15, this behaviour should be fixed.
### The tool complains about missing factions for an NPC I murdered.
The player journal only tells the faction that issued the bounty upon murder, and
not the faction of the NPC killed. The tool has to fetch that from you scanning the
ship. If you didn't fully scan the ship before murdering it, the tool won't know
the faction of the NPC.
### Why does cartography data, and sold cargo show up for the wrong faction, but for the right station/system?
Because they only aid the controlling faction of the station.
### Why are some of my bounty vouchers missing?
Sometimes, due to a bug, the bounty vouchers in the journal have no faction information
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.

View File

@ -1,89 +0,0 @@
# EliteBGS
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.
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.3.7** at CodeBerg:
* [https://codeberg.org/nola/EDBGS/releases](https://codeberg.org/nola/EDBGS/releases)
Or alternatively from my server:
* [https://bgs.n0la.org/elitebgs-0.3.7.zip](https://bgs.n0la.org/elitebgs-0.3.7.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
"categories". These are based upon the star system, station and the faction for which the
action was taken. So for example if you contributed bounty vouchers for Nova Paresa in
Paresa, but also did some missions for Nova Paresa in Adachit, those actions will be
split into two categories.
You can then select which of the two actions goes into the final log.
### What it detects:
* Buying of cargo from stations (BGS relevant since Update 10)
* Completed missions
* Failed missions
* Murders
* Search and Rescue contributions
* Selling cartography data
* Selling of cargo to stations
* Selling of micro resources (Odyssey only)
* Vouchers, including bounty vouchers, combat bonds, and settlement vouchers (aka intel packages)
* Thargoid kills
* Combat zones (experimental feature)
The following transactions are recognised but not listed, because they do not affect BGS:
* Selling of organic data (Odyssey only)
### What it does not detect:
* Combat zone objectives
* Megaship scenarios
* On foot missions accepted by NPCs in stations (pre Update 13)
* Murders of NPCs you haven't fully scanned
## Open Source
The tool itself is Open Source, licenced unter the GPLv3.
The source code can be found here:
* [https://codeberg.org/nola/edbgs](https://codeberg.org/nola/edbgs)
## Contact
I can be reached over discord: `nola#2457`
Or by joining either the [Salus Invicta](https://discord.com/invite/FeEtjqBRkg) or the
[Nova Navy](https://discord.gg/WEJeFQw) discord.