Compare commits
82 Commits
Author | SHA1 | Date | |
---|---|---|---|
4cefc393b5 | |||
693d49be14 | |||
32dbde2c82 | |||
894918b5ba | |||
41fca4fa8c | |||
2acb63025c | |||
eaa4bda098 | |||
9d8f0c1b9a | |||
88b770e5ec | |||
d9dd2cc524 | |||
2905696641 | |||
aeaa6b5220 | |||
cdbca10f2d | |||
1da6f41ec8 | |||
2c6eb9190a | |||
8a92cac02a | |||
4fe77e6946 | |||
912e8b602f | |||
be3bceb880 | |||
6cbe54ff73 | |||
6fd5bbc582 | |||
262182cfaf | |||
007b391dc2 | |||
9918c7d559 | |||
2bf8d9018d | |||
8eaf94f634 | |||
20adf93d39 | |||
fd3e5f61cb | |||
e617c3852b | |||
9f013bed38 | |||
916afb2348 | |||
6eb892151c | |||
6a9e4978aa | |||
0203008202 | |||
03621721b8 | |||
ccba55ac35 | |||
0708880284 | |||
18c3073635 | |||
c43d2ff1d3 | |||
a3b7623557 | |||
1c2fc1e2e6 | |||
53da6b4bc2 | |||
bc44ceb205 | |||
4d3048a37d | |||
463598c779 | |||
bf56f3a2d5 | |||
450824733d | |||
110f909c6f | |||
a1099628a0 | |||
7e85159fd5 | |||
2e8daca61c | |||
05b714a607 | |||
3b0492c70f | |||
c20280eb13 | |||
dd863c326e | |||
2012aab7b3 | |||
abb7954614 | |||
0f44a6a9a7 | |||
34e0a0c8ba | |||
b0b82811cc | |||
4855d78823 | |||
5ea288ee86 | |||
f3fc99a3f3 | |||
2bee03dbc2 | |||
16b579688d | |||
9994a45d06 | |||
d6e2280a00 | |||
160f4f8370 | |||
4400418d30 | |||
43037b0a5b | |||
afc831cf31 | |||
4ab54ee576 | |||
d6842115c5 | |||
acb60e0a08 | |||
dac9b7b8c7 | |||
3338f573c8 | |||
204d6b8914 | |||
4c75515a70 | |||
c43c6f742a | |||
c7a70598c4 | |||
cdd7eb33de | |||
dab39b9a4e |
@ -35,10 +35,10 @@ public class Cartographics : Transaction {
|
|||||||
/* add multi sell and normal ones together */
|
/* add multi sell and normal ones together */
|
||||||
long total =
|
long total =
|
||||||
Entries.OfType<MultiSellExplorationDataEntry>()
|
Entries.OfType<MultiSellExplorationDataEntry>()
|
||||||
.Sum(x => x.TotalEarnings)
|
.Sum(x => x.Total)
|
||||||
+
|
+
|
||||||
Entries.OfType<SellExplorationDataEntry>()
|
Entries.OfType<SellExplorationDataEntry>()
|
||||||
.Sum(x => x.TotalEarnings)
|
.Sum(x => x.Total)
|
||||||
;
|
;
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,12 @@ public class CombatZone : Transaction {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? CapitalShip { get; set; }
|
public bool? CapitalShip { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If we have a combat zone, this might point to the settlement
|
||||||
|
/// in question.
|
||||||
|
/// </summary>
|
||||||
|
public string? Settlement { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How many optional objectives were completed?
|
/// How many optional objectives were completed?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -86,6 +92,13 @@ public class CombatZone : Transaction {
|
|||||||
get { return string.Compare(Type, CombatZones.AXCombatZone) == 0; }
|
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) {
|
public override int CompareTo(Transaction? obj) {
|
||||||
if (obj == null || obj.GetType() != typeof(CombatZone)) {
|
if (obj == null || obj.GetType() != typeof(CombatZone)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -9,7 +9,7 @@ namespace EDPlayerJournal.BGS;
|
|||||||
/// faction to another. Both sometimes gain influence.
|
/// faction to another. Both sometimes gain influence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class InfluenceSupport : Transaction {
|
public class InfluenceSupport : Transaction {
|
||||||
public string Influence { get; set; } = "";
|
public MissionInfluence? Influence { get; set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Relevant mission completed entry
|
/// Relevant mission completed entry
|
||||||
@ -46,7 +46,7 @@ public class InfluenceSupport : Transaction {
|
|||||||
|
|
||||||
builder.AppendFormat("Influence gained from \"{0}\": \"{1}\"",
|
builder.AppendFormat("Influence gained from \"{0}\": \"{1}\"",
|
||||||
missionname,
|
missionname,
|
||||||
string.IsNullOrEmpty(Influence) ? "NONE" : Influence
|
Influence == null ? "NONE" : Influence.TrendAdjustedInfluence
|
||||||
);
|
);
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
|
32
EDPlayerJournal/BGS/MeritsGained.cs
Normal file
32
EDPlayerJournal/BGS/MeritsGained.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -38,7 +38,14 @@ public class MissionCompleted : Transaction {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (CompletedEntry.Mission.GetInfluenceForFaction(Faction, SystemAddress) ?? "");
|
return string.Join("",
|
||||||
|
CompletedEntry
|
||||||
|
.Mission
|
||||||
|
.GetInfluenceForFaction(Faction, SystemAddress)
|
||||||
|
.Select(x => x.Influence)
|
||||||
|
.ToArray()
|
||||||
|
)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,8 +77,10 @@ public class MissionCompleted : Transaction {
|
|||||||
var influence = CompletedEntry.Mission.GetInfluenceForFaction(Faction, SystemAddress);
|
var influence = CompletedEntry.Mission.GetInfluenceForFaction(Faction, SystemAddress);
|
||||||
|
|
||||||
builder.AppendFormat("{0}", MissionName);
|
builder.AppendFormat("{0}", MissionName);
|
||||||
if (influence != "") {
|
if (influence != null && influence.Length > 0) {
|
||||||
builder.AppendFormat(", Influence: {0}", influence);
|
builder.AppendFormat(", Influence: {0}",
|
||||||
|
influence.Select(x => x.InfluenceAmount).Sum()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
|
@ -13,6 +13,21 @@ public class MissionFailed : Transaction {
|
|||||||
Failed = failed;
|
Failed = failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the amount of influence generated by failing this mission. The
|
||||||
|
/// system returns no influence for one INF missions, but sadly also for
|
||||||
|
/// when the influence had no affect at all (i.e. during a war).
|
||||||
|
/// </summary>
|
||||||
|
public long InfluenceAmount {
|
||||||
|
get {
|
||||||
|
if (Mission == null || string.IsNullOrEmpty(Mission.Influence)) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return Mission.Influence.Length * -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override int CompareTo(Transaction? other) {
|
public override int CompareTo(Transaction? other) {
|
||||||
if (other == null || other.GetType() != typeof(MissionFailed)) {
|
if (other == null || other.GetType() != typeof(MissionFailed)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
15
EDPlayerJournal/BGS/Parsers/ApproachSettlementParser.cs
Normal file
15
EDPlayerJournal/BGS/Parsers/ApproachSettlementParser.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS.Parsers;
|
||||||
|
|
||||||
|
internal class ApproachSettlementParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
ApproachSettlementEntry? approach = entry as ApproachSettlementEntry;
|
||||||
|
if (approach == null || string.IsNullOrEmpty(approach.Name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Settlement = approach.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
30
EDPlayerJournal/BGS/Parsers/CarrierJumpParser.cs
Normal file
30
EDPlayerJournal/BGS/Parsers/CarrierJumpParser.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS.Parsers;
|
||||||
|
|
||||||
|
internal class CarrierJumpParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
CarrierJump? jump = entry as CarrierJump;
|
||||||
|
|
||||||
|
if (jump == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jump.Docked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.CurrentSystem = jump.StarSystem;
|
||||||
|
context.CurrentSystemAddress = jump.SystemAddress;
|
||||||
|
|
||||||
|
context.SystemsByID.TryAdd(jump.SystemAddress, jump.StarSystem);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(jump.SystemFaction)) {
|
||||||
|
context.ControllingFaction = jump.SystemFaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jump.SystemFactions != null && jump.SystemFactions.Count > 0) {
|
||||||
|
context.SystemFactions[jump.StarSystem] = jump.SystemFactions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
EDPlayerJournal/BGS/Parsers/CommanderParser.cs
Normal file
17
EDPlayerJournal/BGS/Parsers/CommanderParser.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using EDPlayerJournal.BGS;
|
||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
internal class CommanderParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
CommanderEntry commanderEntry = (CommanderEntry)entry;
|
||||||
|
if (commanderEntry != null && !string.IsNullOrEmpty(commanderEntry.FullName)) {
|
||||||
|
if (!context.Commanders.Contains(commanderEntry.FullName)) {
|
||||||
|
context.Commanders.Add(commanderEntry.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
17
EDPlayerJournal/BGS/Parsers/MusicParser.cs
Normal file
17
EDPlayerJournal/BGS/Parsers/MusicParser.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS.Parsers;
|
||||||
|
|
||||||
|
internal class MusicParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
MusicEntry? entryMusic = (MusicEntry)entry;
|
||||||
|
|
||||||
|
if (entryMusic == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Compare(entryMusic.MusicTrack, "Combat_CapitalShip") == 0) {
|
||||||
|
context.HaveSeenCapShip = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
EDPlayerJournal/BGS/Parsers/PowerplayMeritsParser.cs
Normal file
31
EDPlayerJournal/BGS/Parsers/PowerplayMeritsParser.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
84
EDPlayerJournal/BGS/Parsers/RedeemVoucherParser.cs
Normal file
84
EDPlayerJournal/BGS/Parsers/RedeemVoucherParser.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS.Parsers;
|
||||||
|
|
||||||
|
internal class RedeemVoucherParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
RedeemVoucherEntry? entry = e as RedeemVoucherEntry;
|
||||||
|
if (entry == null) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.CurrentSystem == null) {
|
||||||
|
transactions.AddIncomplete(new Vouchers(),
|
||||||
|
"Could not find out where the vouchers were redeemed", e
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string faction in entry.Factions) {
|
||||||
|
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) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var voucher = new Vouchers(entry) {
|
||||||
|
System = context.CurrentSystem,
|
||||||
|
Station = context.CurrentStation,
|
||||||
|
Faction = relevantFaction,
|
||||||
|
ControllingFaction = context.ControllingFaction,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.FilterDoubleRedeemVouchers) {
|
||||||
|
// To filter out doubly redeemed vouchers, find another redeem voucher
|
||||||
|
// event that happened in the same system, same total sum, and also the
|
||||||
|
// same faction. If there is one, filter this one out.
|
||||||
|
var doubledEntry = transactions
|
||||||
|
.OfType<Vouchers>()
|
||||||
|
.Where(x => x.TotalSum == voucher.TotalSum &&
|
||||||
|
x.System == voucher.System &&
|
||||||
|
x.Faction == voucher.Faction)
|
||||||
|
.ToList()
|
||||||
|
;
|
||||||
|
if (doubledEntry.Count > 0) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
voucher,
|
||||||
|
string.Format("A doubled redeem voucher for {0} valued {1} was detected",
|
||||||
|
voucher.Faction, Credits.FormatMillions(voucher.TotalSum)),
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transactions.Add(voucher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -49,10 +49,11 @@ public class SellCargo : Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (MarketSellEntry sell in sold) {
|
foreach (MarketSellEntry sell in sold) {
|
||||||
builder.AppendFormat("Sold {0} {1} to the {2}",
|
builder.AppendFormat("Sold {0} {1} to the {2} of {3}",
|
||||||
sell.Count,
|
sell.Count,
|
||||||
Cargo,
|
Cargo,
|
||||||
Market
|
Market,
|
||||||
|
Station
|
||||||
);
|
);
|
||||||
|
|
||||||
if (Profit != 0) {
|
if (Profit != 0) {
|
||||||
|
@ -16,6 +16,12 @@ public class TransactionParserOptions {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IgnoreInfluenceSupport { get; set; } = false;
|
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>
|
/// <summary>
|
||||||
/// Whether to ignore market buy. Buying from a market gives a small amount
|
/// 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
|
/// of INF if it is sold to a high demand market, but generally one buys from
|
||||||
@ -28,6 +34,14 @@ public class TransactionParserOptions {
|
|||||||
/// Whether we should ignore things done for the fleet carrier faction.
|
/// Whether we should ignore things done for the fleet carrier faction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IgnoreFleetCarrierFaction { get; set; } = true;
|
public bool IgnoreFleetCarrierFaction { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filter out double redeem vouchers that happen when you redeem a specific
|
||||||
|
/// voucher, and then redeem the rest of your vouchers (say from a KWS) in
|
||||||
|
/// bulk. The bulk redeem will also list the first voucher redeem again in
|
||||||
|
/// its bulk list.
|
||||||
|
/// </summary>
|
||||||
|
public bool FilterDoubleRedeemVouchers { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TransactionList : List<Transaction> {
|
public class TransactionList : List<Transaction> {
|
||||||
@ -298,20 +312,20 @@ internal class MissionCompletedParser : ITransactionParserPart {
|
|||||||
if (context.CurrentSystemAddress == null) {
|
if (context.CurrentSystemAddress == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
other.Value.Add(context.CurrentSystemAddress.Value, "");
|
other.Value.Add(context.CurrentSystemAddress.Value, new MissionInfluence());
|
||||||
// Mission gave no influence to the target faction, so we assume
|
// Mission gave no influence to the target faction, so we assume
|
||||||
// the target faction was in the same system.
|
// the target faction was in the same system.
|
||||||
} else if (string.Compare(source_faction_name, faction, true) == 0) {
|
} else if (string.Compare(source_faction_name, faction, true) == 0) {
|
||||||
// This happens if the source faction is not getting any influence
|
// This happens if the source faction is not getting any influence
|
||||||
// This could be if the source faction is in a conflict, and thus does
|
// This could be if the source faction is in a conflict, and thus does
|
||||||
// not gain any influence at all.
|
// not gain any influence at all.
|
||||||
other.Value.Add(accepted_location.SystemAddress, "");
|
other.Value.Add(accepted_location.SystemAddress, new MissionInfluence());
|
||||||
|
|
||||||
// Just check if the target/source faction are the same, in which case
|
// Just check if the target/source faction are the same, in which case
|
||||||
// we also have to make an additional entry
|
// we also have to make an additional entry
|
||||||
if (string.Compare(source_faction_name, target_faction_name, true) == 0 &&
|
if (string.Compare(source_faction_name, target_faction_name, true) == 0 &&
|
||||||
context.CurrentSystemAddress != null) {
|
context.CurrentSystemAddress != null) {
|
||||||
other.Value.Add(context.CurrentSystemAddress.Value, "");
|
other.Value.Add(context.CurrentSystemAddress.Value, new MissionInfluence());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -422,63 +436,6 @@ internal class MissionFailedParser : ITransactionParserPart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class RedeemVoucherParser : ITransactionParserPart {
|
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
|
||||||
RedeemVoucherEntry? entry = e as RedeemVoucherEntry;
|
|
||||||
if (entry == null) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.CurrentSystem == null) {
|
|
||||||
transactions.AddIncomplete(new Vouchers(),
|
|
||||||
"Could not find out where the vouchers were redeemed", e
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string faction in entry.Factions) {
|
|
||||||
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 = relevantFaction,
|
|
||||||
ControllingFaction = context.ControllingFaction,
|
|
||||||
IsLegacy = context.IsLegacy,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class SellMicroResourcesParser : ITransactionParserPart {
|
internal class SellMicroResourcesParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
SellMicroResourcesEntry? entry = e as SellMicroResourcesEntry;
|
SellMicroResourcesEntry? entry = e as SellMicroResourcesEntry;
|
||||||
@ -630,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 {
|
internal class DiedParser : ITransactionParserPart {
|
||||||
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
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.
|
// Death only matters in ship. On foot you can just redeploy with the dropship.
|
||||||
if (context.IsOnFoot) {
|
if (context.IsOnFoot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// You can't complete a combat zone if you die in it. Others might keep it open
|
if (context.SelfDestruct != null && context.SelfDestruct == true) {
|
||||||
// for you, but still you will not have completed it unless you jump back in.
|
// 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();
|
context.ResetCombatZone();
|
||||||
// Dying also moves you back to another instance
|
// Dying also moves you back to another instance
|
||||||
context.LeftInstance();
|
context.LeftInstance();
|
||||||
@ -651,19 +619,12 @@ internal class DropshipDeployParser : ITransactionParserPart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class CommanderParser : ITransactionParserPart {
|
|
||||||
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, 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 {
|
public class TransactionParser {
|
||||||
private static Dictionary<string, ITransactionParserPart> ParserParts { get; } = new()
|
private static Dictionary<string, ITransactionParserPart> ParserParts { get; } = new()
|
||||||
{
|
{
|
||||||
|
{ Events.ApproachSettlement, new ApproachSettlementParser() },
|
||||||
{ Events.CapShipBond, new CapShipBondParser() },
|
{ Events.CapShipBond, new CapShipBondParser() },
|
||||||
|
{ Events.CarrierJump, new CarrierJumpParser() },
|
||||||
{ Events.Commander, new CommanderParser() },
|
{ Events.Commander, new CommanderParser() },
|
||||||
{ Events.CommitCrime, new CommitCrimeParser() },
|
{ Events.CommitCrime, new CommitCrimeParser() },
|
||||||
{ Events.Died, new DiedParser() },
|
{ Events.Died, new DiedParser() },
|
||||||
@ -682,9 +643,12 @@ public class TransactionParser {
|
|||||||
{ Events.MissionFailed, new MissionFailedParser() },
|
{ Events.MissionFailed, new MissionFailedParser() },
|
||||||
{ Events.Missions, new MissionsParser() },
|
{ Events.Missions, new MissionsParser() },
|
||||||
{ Events.MultiSellExplorationData, new MultiSellExplorationDataParser() },
|
{ Events.MultiSellExplorationData, new MultiSellExplorationDataParser() },
|
||||||
|
{ Events.Music, new MusicParser() },
|
||||||
|
{ Events.PowerplayMerits, new PowerplayMeritsParser() },
|
||||||
{ Events.ReceiveText, new ReceiveTextParser() },
|
{ Events.ReceiveText, new ReceiveTextParser() },
|
||||||
{ Events.RedeemVoucher, new RedeemVoucherParser() },
|
{ Events.RedeemVoucher, new RedeemVoucherParser() },
|
||||||
{ Events.SearchAndRescue, new SearchAndRescueParser() },
|
{ Events.SearchAndRescue, new SearchAndRescueParser() },
|
||||||
|
{ Events.SelfDestruct, new SelfDestructParser() },
|
||||||
{ Events.SellExplorationData, new SellExplorationDataParser() },
|
{ Events.SellExplorationData, new SellExplorationDataParser() },
|
||||||
{ Events.SellMicroResources, new SellMicroResourcesParser() },
|
{ Events.SellMicroResources, new SellMicroResourcesParser() },
|
||||||
{ Events.SellOrganicData, new SellOrganicDataParser() },
|
{ Events.SellOrganicData, new SellOrganicDataParser() },
|
||||||
@ -715,6 +679,11 @@ public class TransactionParser {
|
|||||||
return Parse(entries, defaultOptions);
|
return Parse(entries, defaultOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of commanders seen during parsing.
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Commanders { get; set; } = new();
|
||||||
|
|
||||||
public List<Transaction>? Parse(IEnumerable<Entry> entries, TransactionParserOptions options) {
|
public List<Transaction>? Parse(IEnumerable<Entry> entries, TransactionParserOptions options) {
|
||||||
TransactionList transactions = new();
|
TransactionList transactions = new();
|
||||||
TransactionParserContext context = new();
|
TransactionParserContext context = new();
|
||||||
@ -732,6 +701,9 @@ public class TransactionParser {
|
|||||||
transactionParserPart.Parse(entry, context, options, transactions);
|
transactionParserPart.Parse(entry, context, options, transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy out list of commanders seen
|
||||||
|
Commanders = context.Commanders;
|
||||||
|
|
||||||
return transactions.ToList();
|
return transactions.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
namespace EDPlayerJournal.BGS;
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
internal class TransactionParserContext {
|
internal class TransactionParserContext {
|
||||||
|
/// <summary>
|
||||||
|
/// List of commander names seen in the logs. May be empty.
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Commanders { get; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Name of the current system the player is in.
|
/// Name of the current system the player is in.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -57,6 +62,23 @@ internal class TransactionParserContext {
|
|||||||
public bool HaveSeenAlliedCorrespondent { get; set; } = false;
|
public bool HaveSeenAlliedCorrespondent { get; set; } = false;
|
||||||
public bool HaveSeenEnemyCorrespondent { 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>
|
/// <summary>
|
||||||
/// Returns true if the current session is legacy
|
/// Returns true if the current session is legacy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -115,6 +137,23 @@ internal class TransactionParserContext {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void LeftInstance() {
|
public void LeftInstance() {
|
||||||
CurrentInstanceType = null;
|
CurrentInstanceType = null;
|
||||||
|
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) {
|
public void DiscernCombatZone(TransactionList transactions, Entry e) {
|
||||||
@ -123,10 +162,7 @@ internal class TransactionParserContext {
|
|||||||
ulong highest = HighestCombatBond ?? 0;
|
ulong highest = HighestCombatBond ?? 0;
|
||||||
string? faction = LastRecordedAwardingFaction;
|
string? faction = LastRecordedAwardingFaction;
|
||||||
|
|
||||||
if (HighestCombatBond == null &&
|
if (!HadCombatZone()) {
|
||||||
LastRecordedAwardingFaction == null &&
|
|
||||||
HaveSeenAXWarzoneNPC == false &&
|
|
||||||
CurrentInstanceType == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +182,8 @@ internal class TransactionParserContext {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (LastRecordedAwardingFaction == null &&
|
if (LastRecordedAwardingFaction == null &&
|
||||||
Instances.IsHumanWarzone(CurrentInstanceType)) {
|
(Instances.IsHumanWarzone(CurrentInstanceType) ||
|
||||||
|
Instances.IsPowerWarzone(CurrentInstanceType))) {
|
||||||
transactions.AddIncomplete(new CombatZone(),
|
transactions.AddIncomplete(new CombatZone(),
|
||||||
"Could not discern for whom you fought for, " +
|
"Could not discern for whom you fought for, " +
|
||||||
"as it seems you haven't killed anyone in the ship combat zone.",
|
"as it seems you haven't killed anyone in the ship combat zone.",
|
||||||
@ -176,6 +213,9 @@ internal class TransactionParserContext {
|
|||||||
} else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidVeryHigh)) {
|
} else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidVeryHigh)) {
|
||||||
cztype = CombatZones.AXCombatZone;
|
cztype = CombatZones.AXCombatZone;
|
||||||
grade = CombatZones.DifficultyVeryHigh;
|
grade = CombatZones.DifficultyVeryHigh;
|
||||||
|
} else if (Instances.IsInstance(CurrentInstanceType, Instances.PowerWarzoneMedium)) {
|
||||||
|
cztype = CombatZones.PowerCombatZone;
|
||||||
|
grade = CombatZones.DifficultyMedium;
|
||||||
} else {
|
} else {
|
||||||
transactions.AddIncomplete(new CombatZone(),
|
transactions.AddIncomplete(new CombatZone(),
|
||||||
"Unknown conflict zone difficulty",
|
"Unknown conflict zone difficulty",
|
||||||
@ -223,6 +263,7 @@ internal class TransactionParserContext {
|
|||||||
System = CurrentSystem,
|
System = CurrentSystem,
|
||||||
Faction = faction,
|
Faction = faction,
|
||||||
IsLegacy = IsLegacy,
|
IsLegacy = IsLegacy,
|
||||||
|
Settlement = Settlement,
|
||||||
Grade = grade,
|
Grade = grade,
|
||||||
Type = cztype,
|
Type = cztype,
|
||||||
// Sad truth is, if HaveSeenXXX is false, we just don't know for certain
|
// Sad truth is, if HaveSeenXXX is false, we just don't know for certain
|
||||||
|
@ -14,6 +14,11 @@ public class CombatZones {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string ShipCombatZone = "Ship";
|
public static readonly string ShipCombatZone = "Ship";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Power combat zones, new in Ascendancy update.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string PowerCombatZone = "Power";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AX combat zone
|
/// AX combat zone
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -44,6 +44,6 @@ public class Credits {
|
|||||||
return string.Format("{0:0.00}M", millions);
|
return string.Format("{0:0.00}M", millions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return string.Format("{0}", amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
EDPlayerJournal/Entries/ApproachSettlementEntry.cs
Normal file
48
EDPlayerJournal/Entries/ApproachSettlementEntry.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class ApproachSettlementEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Settlement name
|
||||||
|
/// </summary>
|
||||||
|
public string? Name { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Market ID of the settlement
|
||||||
|
/// </summary>
|
||||||
|
public long? MarketID { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System ID
|
||||||
|
/// </summary>
|
||||||
|
public long? SystemAddress { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body ID
|
||||||
|
/// </summary>
|
||||||
|
public long? BodyID { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the planet
|
||||||
|
/// </summary>
|
||||||
|
public string? BodyName { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Planet latitude
|
||||||
|
/// </summary>
|
||||||
|
public double Latitude { get; set; } = 0.0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Planet longitude
|
||||||
|
/// </summary>
|
||||||
|
public double Longitude { get; set; } = 0.0;
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
Name = JSON.Value<string?>("Name");
|
||||||
|
MarketID = JSON.Value<long?>("MarketID");
|
||||||
|
SystemAddress = JSON.Value<long?>("SystemID");
|
||||||
|
BodyID = JSON.Value<long?>("BodyID");
|
||||||
|
BodyName = JSON.Value<string?>("BodyName");
|
||||||
|
Longitude = JSON.Value<double?>("Longitude") ?? 0.0;
|
||||||
|
Latitude = JSON.Value<double?>("Latitude") ?? 0.0;
|
||||||
|
}
|
||||||
|
}
|
44
EDPlayerJournal/Entries/CarrierJump.cs
Normal file
44
EDPlayerJournal/Entries/CarrierJump.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class CarrierJump : Entry {
|
||||||
|
public bool Docked { get; set; } = false;
|
||||||
|
|
||||||
|
public string? StationName { get; set; } = null;
|
||||||
|
|
||||||
|
public string? StationType { get; set; } = null;
|
||||||
|
|
||||||
|
public string? StarSystem { get; set; } = null;
|
||||||
|
|
||||||
|
public ulong SystemAddress { get; set; } = 0;
|
||||||
|
|
||||||
|
public string? SystemFaction { get; set; } = null;
|
||||||
|
|
||||||
|
public List<Faction> SystemFactions { get; set; } = new List<Faction>();
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
Docked = JSON.Value<bool?>("Docked") ?? false;
|
||||||
|
|
||||||
|
StarSystem = JSON.Value<string>("StarSystem");
|
||||||
|
SystemAddress = JSON.Value<ulong?>("SystemAddress") ?? 0;
|
||||||
|
|
||||||
|
StationName = JSON.Value<string?>("StationName");
|
||||||
|
StationType = JSON.Value<string?>("StationType");
|
||||||
|
|
||||||
|
var faction = JSON.Value<JObject>("SystemFaction");
|
||||||
|
if (faction != null) {
|
||||||
|
SystemFaction = faction.Value<string>("Name");
|
||||||
|
}
|
||||||
|
|
||||||
|
var factions = JSON.Value<JArray>("Factions");
|
||||||
|
if (factions != null) {
|
||||||
|
foreach (JObject system_faction in factions) {
|
||||||
|
Faction? f = Faction.FromJSON(system_faction);
|
||||||
|
if (f != null) {
|
||||||
|
SystemFactions.Add(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,4 +8,13 @@ public class CommanderEntry : Entry {
|
|||||||
Name = JSON.Value<string>("Name") ?? "";
|
Name = JSON.Value<string>("Name") ?? "";
|
||||||
FID = JSON.Value<string>("FID") ?? "";
|
FID = JSON.Value<string>("FID") ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string FullName {
|
||||||
|
get {
|
||||||
|
if (string.IsNullOrEmpty(Name)) {
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
return "CMDR " + Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,10 @@ namespace EDPlayerJournal.Entries;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Entry {
|
public class Entry {
|
||||||
private static readonly Dictionary<string, Type> classes = new Dictionary<string, Type> {
|
private static readonly Dictionary<string, Type> classes = new Dictionary<string, Type> {
|
||||||
|
{ Events.ApproachSettlement, typeof(ApproachSettlementEntry) },
|
||||||
{ Events.Bounty, typeof(BountyEntry) },
|
{ Events.Bounty, typeof(BountyEntry) },
|
||||||
{ Events.CapShipBond, typeof(CapShipBondEntry) },
|
{ Events.CapShipBond, typeof(CapShipBondEntry) },
|
||||||
|
{ Events.CarrierJump, typeof(CarrierJump) },
|
||||||
{ Events.Commander, typeof(CommanderEntry) },
|
{ Events.Commander, typeof(CommanderEntry) },
|
||||||
{ Events.CommitCrime, typeof(CommitCrimeEntry) },
|
{ Events.CommitCrime, typeof(CommitCrimeEntry) },
|
||||||
{ Events.Died, typeof(DiedEntry) },
|
{ Events.Died, typeof(DiedEntry) },
|
||||||
@ -36,9 +38,16 @@ public class Entry {
|
|||||||
{ Events.MissionRedirected, typeof(MissionRedirectedEntry) },
|
{ Events.MissionRedirected, typeof(MissionRedirectedEntry) },
|
||||||
{ Events.Missions, typeof(MissionsEntry) },
|
{ Events.Missions, typeof(MissionsEntry) },
|
||||||
{ Events.MultiSellExplorationData, typeof(MultiSellExplorationDataEntry) },
|
{ 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.ReceiveText, typeof(ReceiveTextEntry) },
|
||||||
{ Events.RedeemVoucher, typeof(RedeemVoucherEntry) },
|
{ Events.RedeemVoucher, typeof(RedeemVoucherEntry) },
|
||||||
{ Events.SearchAndRescue, typeof(SearchAndRescueEntry) },
|
{ Events.SearchAndRescue, typeof(SearchAndRescueEntry) },
|
||||||
|
{ Events.SelfDestruct, typeof(SelfDestructEntry) },
|
||||||
{ Events.SellExplorationData, typeof(SellExplorationDataEntry) },
|
{ Events.SellExplorationData, typeof(SellExplorationDataEntry) },
|
||||||
{ Events.SellMicroResources, typeof(SellMicroResourcesEntry) },
|
{ Events.SellMicroResources, typeof(SellMicroResourcesEntry) },
|
||||||
{ Events.SellOrganicData, typeof(SellOrganicDataEntry) },
|
{ Events.SellOrganicData, typeof(SellOrganicDataEntry) },
|
||||||
@ -63,7 +72,15 @@ public class Entry {
|
|||||||
public static Entry? Parse(string journalline) {
|
public static Entry? Parse(string journalline) {
|
||||||
using (JsonReader reader = new JsonTextReader(new StringReader(journalline))) {
|
using (JsonReader reader = new JsonTextReader(new StringReader(journalline))) {
|
||||||
reader.DateParseHandling = DateParseHandling.None;
|
reader.DateParseHandling = DateParseHandling.None;
|
||||||
var json = JObject.Load(reader);
|
JObject? json = null;
|
||||||
|
try {
|
||||||
|
json = JObject.Load(reader);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidJournalEntryException(
|
||||||
|
"invalid JSON journal entry: " + journalline,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
if (json == null) {
|
if (json == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
namespace EDPlayerJournal.Entries;
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
public class Events {
|
public class Events {
|
||||||
|
public static readonly string ApproachSettlement = "ApproachSettlement";
|
||||||
public static readonly string Bounty = "Bounty";
|
public static readonly string Bounty = "Bounty";
|
||||||
public static readonly string CapShipBond = "CapShipBond";
|
public static readonly string CapShipBond = "CapShipBond";
|
||||||
|
public static readonly string CarrierJump = "CarrierJump";
|
||||||
public static readonly string Commander = "Commander";
|
public static readonly string Commander = "Commander";
|
||||||
public static readonly string CommitCrime = "CommitCrime";
|
public static readonly string CommitCrime = "CommitCrime";
|
||||||
public static readonly string Died = "Died";
|
public static readonly string Died = "Died";
|
||||||
@ -26,9 +28,16 @@ public class Events {
|
|||||||
public static readonly string MissionRedirected = "MissionRedirected";
|
public static readonly string MissionRedirected = "MissionRedirected";
|
||||||
public static readonly string Missions = "Missions";
|
public static readonly string Missions = "Missions";
|
||||||
public static readonly string MultiSellExplorationData = "MultiSellExplorationData";
|
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 ReceiveText = "ReceiveText";
|
||||||
public static readonly string RedeemVoucher = "RedeemVoucher";
|
public static readonly string RedeemVoucher = "RedeemVoucher";
|
||||||
public static readonly string SearchAndRescue = "SearchAndRescue";
|
public static readonly string SearchAndRescue = "SearchAndRescue";
|
||||||
|
public static readonly string SelfDestruct = "SelfDestruct";
|
||||||
public static readonly string SellExplorationData = "SellExplorationData";
|
public static readonly string SellExplorationData = "SellExplorationData";
|
||||||
public static readonly string SellMicroResources = "SellMicroResources";
|
public static readonly string SellMicroResources = "SellMicroResources";
|
||||||
public static readonly string SellOrganicData = "SellOrganicData";
|
public static readonly string SellOrganicData = "SellOrganicData";
|
||||||
|
@ -1,8 +1,23 @@
|
|||||||
namespace EDPlayerJournal.Entries;
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
public class MultiSellExplorationDataEntry : Entry {
|
public class MultiSellExplorationDataEntry : Entry {
|
||||||
protected override void Initialise() {
|
protected override void Initialise() {
|
||||||
TotalEarnings = (JSON.Value<int?>("TotalEarnings") ?? 0);
|
TotalEarnings = JSON.Value<long?>("TotalEarnings") ?? 0;
|
||||||
|
BaseValue = JSON.Value<long?>("BaseValue") ?? 0;
|
||||||
|
Bonus = JSON.Value<long?>("Bonus") ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int TotalEarnings { get; set; } = 0;
|
public long Total {
|
||||||
|
get { return BaseValue + Bonus; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public long BaseValue { get; set; } = 0;
|
||||||
|
|
||||||
|
public long Bonus { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total Earnings are the actual earnings without bonus. So this
|
||||||
|
/// value is BaseValue minus any percent a crew pilot takes.
|
||||||
|
/// </summary>
|
||||||
|
public long TotalEarnings { get; set; } = 0;
|
||||||
}
|
}
|
||||||
|
9
EDPlayerJournal/Entries/MusicEntry.cs
Normal file
9
EDPlayerJournal/Entries/MusicEntry.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class MusicEntry : Entry {
|
||||||
|
public string? MusicTrack { get; set; } = null;
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
MusicTrack = JSON.Value<string?>("MusicTrack");
|
||||||
|
}
|
||||||
|
}
|
7
EDPlayerJournal/Entries/PowerplayCollectEntry.cs
Normal file
7
EDPlayerJournal/Entries/PowerplayCollectEntry.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class PowerplayCollectEntry : Entry {
|
||||||
|
protected override void Initialise() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
7
EDPlayerJournal/Entries/PowerplayDeliverEntry.cs
Normal file
7
EDPlayerJournal/Entries/PowerplayDeliverEntry.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class PowerplayDeliverEntry : Entry {
|
||||||
|
protected override void Initialise() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
32
EDPlayerJournal/Entries/PowerplayEntry.cs
Normal file
32
EDPlayerJournal/Entries/PowerplayEntry.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
EDPlayerJournal/Entries/PowerplayMeritsEntry.cs
Normal file
15
EDPlayerJournal/Entries/PowerplayMeritsEntry.cs
Normal 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;
|
||||||
|
}
|
7
EDPlayerJournal/Entries/PowerplayRankEntry.cs
Normal file
7
EDPlayerJournal/Entries/PowerplayRankEntry.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class PowerplayRankEntry : Entry {
|
||||||
|
protected override void Initialise() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
5
EDPlayerJournal/Entries/SelfDestructEntry.cs
Normal file
5
EDPlayerJournal/Entries/SelfDestructEntry.cs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
namespace EDPlayerJournal.Entries {
|
||||||
|
public class SelfDestructEntry : Entry {
|
||||||
|
// Has no data
|
||||||
|
}
|
||||||
|
}
|
@ -6,8 +6,17 @@ namespace EDPlayerJournal.Entries;
|
|||||||
public class SellExplorationDataEntry : Entry {
|
public class SellExplorationDataEntry : Entry {
|
||||||
public long BaseValue { get; set; }
|
public long BaseValue { get; set; }
|
||||||
public long Bonus { get; set; }
|
public long Bonus { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total Earnings are the actual earnings without bonus. So this
|
||||||
|
/// value is BaseValue minus any percent a crew pilot takes.
|
||||||
|
/// </summary>
|
||||||
public long TotalEarnings { get; set; }
|
public long TotalEarnings { get; set; }
|
||||||
|
|
||||||
|
public long Total {
|
||||||
|
get { return BaseValue + Bonus; }
|
||||||
|
}
|
||||||
|
|
||||||
public List<string> Systems { get; set; } = new List<string>();
|
public List<string> Systems { get; set; } = new List<string>();
|
||||||
public List<string> Discovered { get; set; } = new List<string>();
|
public List<string> Discovered { get; set; } = new List<string>();
|
||||||
|
|
||||||
|
@ -18,6 +18,11 @@ public class Instances {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string WarzoneHigh = "$Warzone_PointRace_High";
|
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>
|
/// <summary>
|
||||||
/// Low Thargoid combat zone
|
/// Low Thargoid combat zone
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -52,8 +57,17 @@ public class Instances {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsPowerWarzone(string type) {
|
||||||
|
return
|
||||||
|
IsInstance(type, PowerWarzoneMedium)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsWarzone(string type) {
|
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) {
|
public static bool IsInstance(string type, string instance) {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
public class InvalidJournalEntryException : Exception {
|
public class InvalidJournalEntryException : Exception {
|
||||||
public InvalidJournalEntryException() { }
|
public InvalidJournalEntryException() { }
|
||||||
public InvalidJournalEntryException(string message) : base(message) { }
|
public InvalidJournalEntryException(string message) : base(message) { }
|
||||||
|
public InvalidJournalEntryException(string message, Exception inner) : base(message, inner) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -17,6 +17,11 @@ public class JournalFile : IComparable<JournalFile>
|
|||||||
private static Regex update11regex = new Regex("Journal\\.([^\\.]+)\\.(\\d+).log");
|
private static Regex update11regex = new Regex("Journal\\.([^\\.]+)\\.(\\d+).log");
|
||||||
private static string iso8601 = "yyyyMMddTHHmmss";
|
private static string iso8601 = "yyyyMMddTHHmmss";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A public list of errors encountered while parsing the journal files
|
||||||
|
/// </summary>
|
||||||
|
public List<Exception> Errors { get; private set; } = new List<Exception>();
|
||||||
|
|
||||||
public static bool VerifyFile(string path) {
|
public static bool VerifyFile(string path) {
|
||||||
string filename = Path.GetFileName(path);
|
string filename = Path.GetFileName(path);
|
||||||
|
|
||||||
@ -125,15 +130,20 @@ public class JournalFile : IComparable<JournalFile>
|
|||||||
}
|
}
|
||||||
|
|
||||||
entries.Clear();
|
entries.Clear();
|
||||||
foreach(var line in lines) {
|
Errors.Clear();
|
||||||
|
foreach (var line in lines) {
|
||||||
// Skip empty lines
|
// Skip empty lines
|
||||||
if (line.Trim().Length == 0) {
|
if (line.Trim().Length == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
Entry? entry = Entry.Parse(line);
|
Entry? entry = Entry.Parse(line);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
entries.Add(entry);
|
entries.Add(entry);
|
||||||
}
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Errors.Add(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,31 @@ public class MissionInfluence {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Influence { get; set; } = string.Empty;
|
public string Influence { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public long InfluenceAmount {
|
||||||
|
get {
|
||||||
|
string trend = TrendAdjustedInfluence;
|
||||||
|
return (long)
|
||||||
|
(trend.Count(x => x == '-') * -1) +
|
||||||
|
trend.Count(x => x == '+')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns how much influence was made, represented in pluses for positive influence,
|
||||||
|
/// and minuses with negative influence. This takes Trend (up, bad etc.) into account.
|
||||||
|
/// </summary>
|
||||||
|
public string TrendAdjustedInfluence {
|
||||||
|
get {
|
||||||
|
if (!string.IsNullOrEmpty(Trend) &&
|
||||||
|
Trend.Contains("bad", StringComparison.OrdinalIgnoreCase)) {
|
||||||
|
return new string('-', Influence.Length);
|
||||||
|
} else {
|
||||||
|
return new string('+', Influence.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static MissionInfluence FromJSON(JObject obj) {
|
public static MissionInfluence FromJSON(JObject obj) {
|
||||||
MissionInfluence missionInfluence = new MissionInfluence();
|
MissionInfluence missionInfluence = new MissionInfluence();
|
||||||
|
|
||||||
@ -394,27 +419,29 @@ public class Mission : IComparable<Mission> {
|
|||||||
/// <param name="faction">Faction name in question.</param>
|
/// <param name="faction">Faction name in question.</param>
|
||||||
/// <param name="systemaddr">Star System address</param>
|
/// <param name="systemaddr">Star System address</param>
|
||||||
/// <returns>null if no entry was found, or a string denoting pluses for the amount influence gained.</returns>
|
/// <returns>null if no entry was found, or a string denoting pluses for the amount influence gained.</returns>
|
||||||
public string? GetInfluenceForFaction(string faction, ulong systemaddr) {
|
public MissionInfluence[]? GetInfluenceForFaction(string faction, ulong systemaddr) {
|
||||||
var results = FactionEffects
|
var results = FactionEffects
|
||||||
.Where(x => string.Compare(x.Faction, faction) == 0)
|
.Where(x => string.Compare(x.Faction, faction) == 0)
|
||||||
.SelectMany(x => x.Influences)
|
.SelectMany(x => x.Influences)
|
||||||
.Where(x => (x.SystemAddress != null && x.SystemAddress == systemaddr))
|
.Where(x => (x.SystemAddress != null && x.SystemAddress == systemaddr))
|
||||||
.Select(x => x.Influence)
|
.Select(x => x)
|
||||||
.ToArray()
|
.ToArray()
|
||||||
;
|
;
|
||||||
|
|
||||||
if (results == null || results.Length == 0) {
|
if (results == null || results.Length == 0) {
|
||||||
return null;
|
return new MissionInfluence[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Join("", results);
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A convenient Dictionary containing all influences given out by faction,
|
/// A convenient Dictionary containing all influences given out by faction,
|
||||||
/// then by system address and then by influence handed out.
|
/// then by system address and then by influence handed out. Influence can
|
||||||
|
/// be either a series of "+" for positive influence, or "-" for negative
|
||||||
|
/// influence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, Dictionary<ulong, string>> Influences {
|
public Dictionary<string, Dictionary<ulong, MissionInfluence>> Influences {
|
||||||
get {
|
get {
|
||||||
return FactionEffects
|
return FactionEffects
|
||||||
.Where(x => x.Faction != null)
|
.Where(x => x.Faction != null)
|
||||||
@ -422,7 +449,10 @@ public class Mission : IComparable<Mission> {
|
|||||||
x => (x.Faction ?? string.Empty),
|
x => (x.Faction ?? string.Empty),
|
||||||
x => x.Influences
|
x => x.Influences
|
||||||
.Where(x => x.SystemAddress != null)
|
.Where(x => x.SystemAddress != null)
|
||||||
.ToDictionary(x => (x.SystemAddress ?? 0), x => x.Influence)
|
.ToDictionary(
|
||||||
|
x => (x.SystemAddress ?? 0),
|
||||||
|
x => x
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,12 @@ public class PlayerJournal {
|
|||||||
ScanFiles();
|
ScanFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Exception> AllErrors {
|
||||||
|
get {
|
||||||
|
return Files.SelectMany(x => x.Errors).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<JournalFile> Files {
|
public List<JournalFile> Files {
|
||||||
get { return journalfiles; }
|
get { return journalfiles; }
|
||||||
}
|
}
|
||||||
|
101
EDPlayerJournal/PowerPlay/Powers.cs
Normal file
101
EDPlayerJournal/PowerPlay/Powers.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -8,11 +8,16 @@ public enum ThargoidVessel {
|
|||||||
Basilisk = 4,
|
Basilisk = 4,
|
||||||
Medusa = 5,
|
Medusa = 5,
|
||||||
Hydra = 6,
|
Hydra = 6,
|
||||||
Glaive = 7,
|
// Includes Glaive and Scythe
|
||||||
|
Hunter = 7,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Thargoid drone
|
/// Thargoid drone
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Revenant = 8,
|
Revenant = 8,
|
||||||
|
/// <summary>
|
||||||
|
/// New thargoid drone in U17
|
||||||
|
/// </summary>
|
||||||
|
Banshee = 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Thargoid {
|
public class Thargoid {
|
||||||
@ -23,8 +28,10 @@ public class Thargoid {
|
|||||||
{ 25000, ThargoidVessel.Revenant },
|
{ 25000, ThargoidVessel.Revenant },
|
||||||
{ 65000, ThargoidVessel.Scout },
|
{ 65000, ThargoidVessel.Scout },
|
||||||
{ 75000, ThargoidVessel.Scout },
|
{ 75000, ThargoidVessel.Scout },
|
||||||
|
// New in Update 17
|
||||||
|
{ 100000, ThargoidVessel.Banshee },
|
||||||
// New in Update 15
|
// New in Update 15
|
||||||
{ 4500000, ThargoidVessel.Glaive },
|
{ 4500000, ThargoidVessel.Hunter },
|
||||||
{ 6500000, ThargoidVessel.Cyclops },
|
{ 6500000, ThargoidVessel.Cyclops },
|
||||||
{ 20000000, ThargoidVessel.Basilisk },
|
{ 20000000, ThargoidVessel.Basilisk },
|
||||||
//{ 25000000, ThargoidVessel.Orthrus },
|
//{ 25000000, ThargoidVessel.Orthrus },
|
||||||
@ -46,7 +53,7 @@ public class Thargoid {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static Dictionary<ThargoidVessel, string?> VesselNames { get; } = new() {
|
public static Dictionary<ThargoidVessel, string?> VesselNames { get; } = new() {
|
||||||
{ ThargoidVessel.Unknown, null },
|
{ ThargoidVessel.Unknown, "(Unknown)" },
|
||||||
{ ThargoidVessel.Revenant, "Revenant" },
|
{ ThargoidVessel.Revenant, "Revenant" },
|
||||||
{ ThargoidVessel.Scout, "Scout" },
|
{ ThargoidVessel.Scout, "Scout" },
|
||||||
{ ThargoidVessel.Orthrus, "Orthrus" },
|
{ ThargoidVessel.Orthrus, "Orthrus" },
|
||||||
@ -54,7 +61,8 @@ public class Thargoid {
|
|||||||
{ ThargoidVessel.Basilisk, "Basilisk" },
|
{ ThargoidVessel.Basilisk, "Basilisk" },
|
||||||
{ ThargoidVessel.Medusa, "Medusa" },
|
{ ThargoidVessel.Medusa, "Medusa" },
|
||||||
{ ThargoidVessel.Hydra, "Hydra" },
|
{ ThargoidVessel.Hydra, "Hydra" },
|
||||||
{ ThargoidVessel.Glaive, "Glaive" },
|
{ ThargoidVessel.Hunter, "Hunter" },
|
||||||
|
{ ThargoidVessel.Banshee, "Banshee" },
|
||||||
};
|
};
|
||||||
|
|
||||||
public static ThargoidVessel GetVesselByPayout(ulong payout) {
|
public static ThargoidVessel GetVesselByPayout(ulong payout) {
|
||||||
|
@ -59,9 +59,9 @@ public class MissionTest {
|
|||||||
Assert.IsTrue(e.IsEmptyFaction);
|
Assert.IsTrue(e.IsEmptyFaction);
|
||||||
Assert.AreEqual(e.Faction, string.Empty);
|
Assert.AreEqual(e.Faction, string.Empty);
|
||||||
|
|
||||||
string? influence = m.GetInfluenceForFaction("", 251012319587UL);
|
var influence = m.GetInfluenceForFaction("", 251012319587UL);
|
||||||
Assert.IsNotNull(influence);
|
Assert.IsNotNull(influence);
|
||||||
Assert.AreEqual(influence, "+");
|
Assert.AreEqual(influence[0].Influence, "+");
|
||||||
|
|
||||||
e = m.FactionEffects[1];
|
e = m.FactionEffects[1];
|
||||||
Assert.AreEqual(e.Faction, "Social LHS 6103 Confederation");
|
Assert.AreEqual(e.Faction, "Social LHS 6103 Confederation");
|
||||||
@ -101,22 +101,25 @@ public class MissionTest {
|
|||||||
|
|
||||||
Assert.AreEqual(effect.Reputation, "++");
|
Assert.AreEqual(effect.Reputation, "++");
|
||||||
|
|
||||||
string? influence;
|
var influence = m.GetInfluenceForFaction("Salus Imperial Society", 1865919973739UL);
|
||||||
|
Assert.IsNotNull(influence);
|
||||||
influence = m.GetInfluenceForFaction("Salus Imperial Society", 1865919973739UL);
|
Assert.IsTrue(influence.Length > 0);
|
||||||
Assert.AreEqual(influence, "++");
|
Assert.AreEqual(influence[0].Influence, "++");
|
||||||
|
|
||||||
influence = m.GetInfluenceForFaction("Salus Imperial Society", 1733186884306UL);
|
influence = m.GetInfluenceForFaction("Salus Imperial Society", 1733186884306UL);
|
||||||
Assert.AreEqual(influence, "++");
|
Assert.IsNotNull(influence);
|
||||||
|
Assert.IsTrue(influence.Length > 0);
|
||||||
|
Assert.AreEqual(influence[0].Influence, "++");
|
||||||
|
|
||||||
influence = m.GetInfluenceForFaction("Saelishi Saxons", 1733186884306UL);
|
influence = m.GetInfluenceForFaction("Saelishi Saxons", 1733186884306UL);
|
||||||
Assert.IsNull(influence);
|
Assert.IsNotNull(influence);
|
||||||
|
Assert.AreEqual(influence.Length, 0);
|
||||||
|
|
||||||
// Only one entry are we only have Salus
|
// Only one entry are we only have Salus
|
||||||
Assert.AreEqual(m.Influences.Count, 1);
|
Assert.AreEqual(m.Influences.Count, 1);
|
||||||
Assert.AreEqual(m.Influences["Salus Imperial Society"].Count, 2);
|
Assert.AreEqual(m.Influences["Salus Imperial Society"].Count, 2);
|
||||||
Assert.AreEqual(m.Influences["Salus Imperial Society"][1865919973739UL], "++");
|
Assert.AreEqual(m.Influences["Salus Imperial Society"][1865919973739UL].Influence, "++");
|
||||||
Assert.AreEqual(m.Influences["Salus Imperial Society"][1733186884306UL], "++");
|
Assert.AreEqual(m.Influences["Salus Imperial Society"][1733186884306UL].Influence, "++");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -19,7 +19,13 @@ public class TestTransactionParser {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Transaction>? transactions = parser.Parse(entries);
|
var options = new TransactionParserOptions() {
|
||||||
|
IgnoreInfluenceSupport = false,
|
||||||
|
IgnoreExoBiology = false,
|
||||||
|
IgnoreFleetCarrierFaction = false,
|
||||||
|
IgnoreMarketBuy = false,
|
||||||
|
};
|
||||||
|
List<Transaction>? transactions = parser.Parse(entries, options);
|
||||||
Assert.IsNotNull(transactions, "could not parse entries");
|
Assert.IsNotNull(transactions, "could not parse entries");
|
||||||
Assert.AreEqual(transactions.Count, 3);
|
Assert.AreEqual(transactions.Count, 3);
|
||||||
|
|
||||||
@ -144,7 +150,14 @@ public class TestTransactionParser {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Transaction>? transactions = parser.Parse(entries);
|
var options = new TransactionParserOptions() {
|
||||||
|
IgnoreInfluenceSupport = false,
|
||||||
|
IgnoreExoBiology = false,
|
||||||
|
IgnoreFleetCarrierFaction = false,
|
||||||
|
IgnoreMarketBuy = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
List<Transaction>? transactions = parser.Parse(entries, options);
|
||||||
Assert.IsNotNull(transactions, "could not parse entries");
|
Assert.IsNotNull(transactions, "could not parse entries");
|
||||||
Assert.AreEqual(transactions.Count, 1);
|
Assert.AreEqual(transactions.Count, 1);
|
||||||
Assert.IsInstanceOfType(transactions[0], typeof(OrganicData), "result is not of type Organic Data");
|
Assert.IsInstanceOfType(transactions[0], typeof(OrganicData), "result is not of type Organic Data");
|
||||||
|
@ -22,14 +22,17 @@ public class ThargoidKills {
|
|||||||
Assert.IsNotNull(transactions, "could not parse entries");
|
Assert.IsNotNull(transactions, "could not parse entries");
|
||||||
Assert.AreEqual(transactions.Count, 3);
|
Assert.AreEqual(transactions.Count, 3);
|
||||||
|
|
||||||
|
// In recent updates the payout was changed, that's why this test reports unknown thargoid vessels
|
||||||
|
// This test makes sure the new parser does not conflict with legacy values
|
||||||
|
//
|
||||||
Assert.IsInstanceOfType(transactions[0], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
Assert.IsInstanceOfType(transactions[0], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
||||||
Assert.AreEqual(transactions[0].ThargoidType, EDPlayerJournal.ThargoidVessel.Scout);
|
Assert.AreEqual(transactions[0].ThargoidType, EDPlayerJournal.ThargoidVessel.Unknown);
|
||||||
|
|
||||||
Assert.IsInstanceOfType(transactions[1], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
Assert.IsInstanceOfType(transactions[1], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
||||||
Assert.AreEqual(transactions[1].ThargoidType, EDPlayerJournal.ThargoidVessel.Basilisk);
|
Assert.AreEqual(transactions[1].ThargoidType, EDPlayerJournal.ThargoidVessel.Unknown);
|
||||||
|
|
||||||
Assert.IsInstanceOfType(transactions[2], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
Assert.IsInstanceOfType(transactions[2], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
||||||
Assert.AreEqual(transactions[2].ThargoidType, EDPlayerJournal.ThargoidVessel.Scout);
|
Assert.AreEqual(transactions[2].ThargoidType, EDPlayerJournal.ThargoidVessel.Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
7
EDPlayerJournalTests/double-vouchers-2.txt
Normal file
7
EDPlayerJournalTests/double-vouchers-2.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{"timestamp":"2024-04-27T13:27:08Z","event":"Fileheader","part":1,"language":"English/UK","Odyssey":true,"gameversion":"4.0.0.1803","build":"r301470/r0 "}
|
||||||
|
{"timestamp":"2024-04-27T13:27:34Z","event":"Commander","FID":"F9183790","Name":"Jeremaya"}
|
||||||
|
{"timestamp":"2024-04-27T15:06:31Z","event":"FSDJump","Taxi":false,"Multicrew":false,"StarSystem":"HIP 3318","SystemAddress":525890177387,"StarPos":[50.21875,-190.6875,37.5],"SystemAllegiance":"Empire","SystemEconomy":"$economy_Refinery;","SystemEconomy_Localised":"Refinery","SystemSecondEconomy":"$economy_Extraction;","SystemSecondEconomy_Localised":"Extraction","SystemGovernment":"$government_Patronage;","SystemGovernment_Localised":"Patronage","SystemSecurity":"$SYSTEM_SECURITY_high;","SystemSecurity_Localised":"High Security","Population":239484,"Body":"HIP 3318 A","BodyID":2,"BodyType":"Star","JumpDist":27.495,"FuelUsed":3.115176,"FuelLevel":13.228082,"Factions":[{"Name":"HIP 3318 Autocracy","FactionState":"None","Government":"Dictatorship","Influence":0.119192,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"Chakho Gold Galactic Limited","FactionState":"None","Government":"Corporate","Influence":0.09798,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"HIP 3318 Interstellar","FactionState":"None","Government":"Corporate","Influence":0.075758,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"HIP 3318 Values Party","FactionState":"None","Government":"Democracy","Influence":0.032323,"Allegiance":"Independent","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"Nationalists of HIP 3318","FactionState":"None","Government":"Dictatorship","Influence":0.035354,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"Nova Paresa","FactionState":"Boom","Government":"Patronage","Influence":0.434343,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","SquadronFaction":true,"MyReputation":100.0,"PendingStates":[{"State":"Expansion","Trend":0}]},{"Name":"Empire Consulate Ltd","FactionState":"None","Government":"Patronage","Influence":0.20505,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":94.474998}],"SystemFaction":{"Name":"Nova Paresa","FactionState":"Boom"}}
|
||||||
|
{"timestamp":"2024-04-27T15:12:23Z","event":"ApproachSettlement","Name":"Koh Biological Installation","MarketID":3803792128,"StationFaction":{"Name":"Nova Paresa","FactionState":"Boom"},"StationGovernment":"$government_Patronage;","StationGovernment_Localised":"Patronage","StationAllegiance":"Empire","StationServices":["dock","autodock","commodities","contacts","exploration","missions","refuel","repair","engineer","missionsgenerated","flightcontroller","stationoperations","searchrescue","stationMenu"],"StationEconomy":"$economy_HighTech;","StationEconomy_Localised":"High Tech","StationEconomies":[{"Name":"$economy_HighTech;","Name_Localised":"High Tech","Proportion":1.0}],"SystemAddress":525890177387,"BodyID":26,"BodyName":"HIP 3318 D 3","Latitude":-0.893061,"Longitude":-62.928345}
|
||||||
|
{"timestamp":"2024-04-27T15:14:08Z","event":"Docked","StationName":"Koh Biological Installation","StationType":"OnFootSettlement","Taxi":false,"Multicrew":false,"StarSystem":"HIP 3318","SystemAddress":525890177387,"MarketID":3803792128,"StationFaction":{"Name":"Nova Paresa","FactionState":"Boom"},"StationGovernment":"$government_Patronage;","StationGovernment_Localised":"Patronage","StationAllegiance":"Empire","StationServices":["dock","autodock","commodities","contacts","exploration","missions","refuel","repair","engineer","missionsgenerated","flightcontroller","stationoperations","searchrescue","stationMenu"],"StationEconomy":"$economy_HighTech;","StationEconomy_Localised":"High Tech","StationEconomies":[{"Name":"$economy_HighTech;","Name_Localised":"High Tech","Proportion":1.0}],"DistFromStarLS":11972.63409,"LandingPads":{"Small":1,"Medium":0,"Large":1}}
|
||||||
|
{"timestamp":"2024-04-27T15:15:10Z","event":"RedeemVoucher","Type":"bounty","Amount":9449329,"Factions":[{"Faction":"Nova Paresa","Amount":9449329}]}
|
||||||
|
{"timestamp":"2024-04-27T15:15:51Z","event":"RedeemVoucher","Type":"bounty","Amount":18780130,"Factions":[{"Faction":"","Amount":224449},{"Faction":"","Amount":730880},{"Faction":"","Amount":1272764},{"Faction":"","Amount":580384},{"Faction":"","Amount":10180261},{"Faction":"","Amount":1413153},{"Faction":"","Amount":1365934},{"Faction":"","Amount":202193},{"Faction":"Nova Paresa","Amount":9449329},{"Faction":"","Amount":104412},{"Faction":"","Amount":2453443},{"Faction":"","Amount":252257}]}
|
@ -1,5 +1,71 @@
|
|||||||
# EliteBGS changelog
|
# 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.
|
||||||
|
Logs are automatically split to fit discord length, and you can choose the
|
||||||
|
name of the Commander to post it as. There are some restrictions, so for
|
||||||
|
ultra long logs the one line log format might be necessary.
|
||||||
|
* Fix cartographics data value by igonring `TotalEarnings`. Total earnings
|
||||||
|
is the same as `BaseValue`, except any percentages taken by crew members
|
||||||
|
is deducted. Actual total value is `BaseValue` plus `Bonus`.
|
||||||
|
|
||||||
|
## 0.4.2 on 02.05.2024
|
||||||
|
|
||||||
|
* Add a bot header for all generated logs that shows the tool version, as
|
||||||
|
well as the name of of the log format used. This makes it easier for bots
|
||||||
|
to parse these logs. Since the different formats have become popular, its
|
||||||
|
always good to make it easier for bots to parse the logs.
|
||||||
|
|
||||||
|
## 0.4.1 on 28.04.2024
|
||||||
|
|
||||||
|
* Filter out vouchers that are redeemed twice, due to bulk turn-in. If you
|
||||||
|
redeem a singular voucher for value X, and then redeem the rest of your
|
||||||
|
vouchers - say KWS vouchers - in bulk, the first voucher of value X will
|
||||||
|
appear again in the logs. It appears twice in the logs, but only counts
|
||||||
|
once.
|
||||||
|
* Add the market name to the trading log entries.
|
||||||
|
|
||||||
|
## 0.4.0 on 13.04.2024
|
||||||
|
|
||||||
|
* Change layout of the results into System -> Faction -> Transaction.
|
||||||
|
Many people who contribute *a lot* of things to the BGS have preferred such
|
||||||
|
a layout to find the right things to post to various discord guilds/threads.
|
||||||
|
* Sort all systems in the new overview by name. It just makes them easier to
|
||||||
|
find when there are a lot of entries.
|
||||||
|
* Add a button to deselect/select all buttons.
|
||||||
|
|
||||||
|
## 0.3.7 on 29.01.2024
|
||||||
|
|
||||||
|
* Fix wrong locations of BGS action if you remain on your carrier while its
|
||||||
|
jumping to a new system.
|
||||||
|
* Identify a capital ship in a high CZ by its music.
|
||||||
|
|
||||||
|
## 0.3.6 on 25.10.2023
|
||||||
|
|
||||||
|
* U17 introduced invalid JSON into the player journal. EliteBGS can now skip over
|
||||||
|
those and keep processing. This way players won't have to delete lines in their
|
||||||
|
journals anymore to keep using the tool.
|
||||||
|
* Banshee has been added.
|
||||||
|
|
||||||
|
## 0.3.5 on 11.09.2023
|
||||||
|
|
||||||
|
* Small bounty voucher formats are no longer suppressed.
|
||||||
|
* Glaive has been renamed to "Hunter" since Scythe has the same bounty
|
||||||
|
and they cannot be distinguished.
|
||||||
|
* Mission influence can now also be negative. Failed missions now properly
|
||||||
|
report the amount of negative influence given to a faction.
|
||||||
|
* Mission secondary influences now also support negative influences. This
|
||||||
|
for example happens if you take a mission to murder another faction's
|
||||||
|
civlians, which causes negative INF.
|
||||||
|
|
||||||
## 0.3.4 on 18.06.2023
|
## 0.3.4 on 18.06.2023
|
||||||
|
|
||||||
* Added possibility to specify allied, as well as enemy captain and correspondent.
|
* Added possibility to specify allied, as well as enemy captain and correspondent.
|
@ -4,14 +4,12 @@ using System.Collections.Generic;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using EliteBGS.LogGenerator;
|
using EliteBGS.LogGenerator;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace EliteBGS;
|
namespace EliteBGS;
|
||||||
|
|
||||||
public class DiscordLogGenerator {
|
public class DiscordLogGenerator {
|
||||||
protected List<LogFormatter> formatters = new List<LogFormatter>() {
|
protected List<LogFormatter> formatters = new List<LogFormatter>() {
|
||||||
new MissionFormat(),
|
new MissionFormat(),
|
||||||
new FailedMissionFormat(),
|
|
||||||
new MurderFormat(),
|
new MurderFormat(),
|
||||||
new VoucherFormat(),
|
new VoucherFormat(),
|
||||||
new ThargoidFormatter(),
|
new ThargoidFormatter(),
|
||||||
@ -23,6 +21,7 @@ public class DiscordLogGenerator {
|
|||||||
new CargoSoldFormatter(),
|
new CargoSoldFormatter(),
|
||||||
new VistaGenomicsFormat(),
|
new VistaGenomicsFormat(),
|
||||||
new SearchAndRescueFormat(),
|
new SearchAndRescueFormat(),
|
||||||
|
new MeritsGainedFormat(),
|
||||||
};
|
};
|
||||||
|
|
||||||
protected virtual string GetToolVersion() {
|
protected virtual string GetToolVersion() {
|
||||||
@ -113,10 +112,6 @@ public class DiscordLogGenerator {
|
|||||||
|
|
||||||
string summary = GenerateSummary(objective);
|
string summary = GenerateSummary(objective);
|
||||||
|
|
||||||
log.AppendFormat("**Log Generated:** {0} by {1}\n",
|
|
||||||
DateTime.Now.ToString("dd/MM/yyyy"),
|
|
||||||
GetToolVersion()
|
|
||||||
);
|
|
||||||
var earliest = GetDateOfEarliestEntry(objective);
|
var earliest = GetDateOfEarliestEntry(objective);
|
||||||
var latest = GetDateOfLatestEntry(objective);
|
var latest = GetDateOfLatestEntry(objective);
|
||||||
if (earliest != null && latest != null) {
|
if (earliest != null && latest != null) {
|
||||||
@ -127,7 +122,7 @@ public class DiscordLogGenerator {
|
|||||||
}
|
}
|
||||||
log.AppendFormat("**Target:** {0}\n", location);
|
log.AppendFormat("**Target:** {0}\n", location);
|
||||||
if (!string.IsNullOrEmpty(summary)) {
|
if (!string.IsNullOrEmpty(summary)) {
|
||||||
log.AppendFormat("**Summary**: {0}\n", summary);
|
log.AppendFormat("**Summary:** {0}\n", summary);
|
||||||
}
|
}
|
||||||
if (legacycount > 0) {
|
if (legacycount > 0) {
|
||||||
log.AppendFormat("**Warning:** Some actions were performed on ED Legacy\n");
|
log.AppendFormat("**Warning:** Some actions were performed on ED Legacy\n");
|
||||||
@ -151,6 +146,16 @@ public class DiscordLogGenerator {
|
|||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual string Name {
|
||||||
|
get { return "GenericLog"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string BotHeader() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendFormat("**Bot-Header:** {0}; {1}\n", GetToolVersion(), this.Name);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual string GenerateDiscordLog(Report report) {
|
public virtual string GenerateDiscordLog(Report report) {
|
||||||
StringBuilder log = new StringBuilder();
|
StringBuilder log = new StringBuilder();
|
||||||
|
|
||||||
@ -166,6 +171,7 @@ public class DiscordLogGenerator {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.AppendFormat("{0}", BotHeader());
|
||||||
log.AppendFormat("{0}", GenerateHeader());
|
log.AppendFormat("{0}", GenerateHeader());
|
||||||
|
|
||||||
foreach (Objective objective in objectives) {
|
foreach (Objective objective in objectives) {
|
||||||
@ -193,4 +199,65 @@ public class DiscordLogGenerator {
|
|||||||
|
|
||||||
return log.ToString().Trim();
|
return log.ToString().Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual string[] SplitLog(string log, int maxcount = 2000) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string[] SplitLogWithHeader(string log, string header, int maxcount = 2000) {
|
||||||
|
string[] lines = log.Split("\n");
|
||||||
|
List<string> chunks = new();
|
||||||
|
string chunk = string.Empty;
|
||||||
|
|
||||||
|
// Optimisation
|
||||||
|
if (log.Length <= maxcount) {
|
||||||
|
return new string[] { log };
|
||||||
|
}
|
||||||
|
|
||||||
|
// First split the log into its headers
|
||||||
|
// skip first bot header line
|
||||||
|
for (int i = 1; i < lines.Length; i++) {
|
||||||
|
string line = lines[i];
|
||||||
|
|
||||||
|
if (line.StartsWith(header) && !string.IsNullOrEmpty(chunk)) {
|
||||||
|
chunks.Add(chunk.Trim());
|
||||||
|
chunk = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = chunk + "\n" + line;
|
||||||
|
}
|
||||||
|
|
||||||
|
int curchunk = 0;
|
||||||
|
string botheader = BotHeader().Trim() + "\n";
|
||||||
|
// Leave room for botheader and some leeway
|
||||||
|
int maxlength = (2000 - botheader.Length - 10);
|
||||||
|
|
||||||
|
// Then try to collate chunks
|
||||||
|
for (curchunk = 0; curchunk < chunks.Count; ++curchunk) {
|
||||||
|
int count = chunks[curchunk].Length;
|
||||||
|
while (count < maxlength && (curchunk+1) < chunks.Count) {
|
||||||
|
count += chunks[curchunk + 1].Length + 2;
|
||||||
|
if (count < maxlength) {
|
||||||
|
chunks[curchunk] += "\n";
|
||||||
|
chunks[curchunk] += chunks[curchunk + 1];
|
||||||
|
chunks.RemoveAt(curchunk + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Readd bott headers
|
||||||
|
for (int i = 0; i < chunks.Count; i++) {
|
||||||
|
chunks[i] = chunks[i].Insert(0, botheader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now finally check if any one chunk is bigger than max length
|
||||||
|
for (int i = 0; i < chunks.Count; i++) {
|
||||||
|
if (chunks[i].Length > maxcount) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
string.Format("a chunk turned out bigger than {0}", maxcount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks.ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
32
EliteBGS/DiscordPoster.cs
Normal file
32
EliteBGS/DiscordPoster.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using EliteBGS.Util;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
|
namespace EliteBGS;
|
||||||
|
|
||||||
|
public class DiscordPoster {
|
||||||
|
public static readonly int DiscordLimit = 2000;
|
||||||
|
|
||||||
|
public static void PostToDiscord(DiscordWebhook webhook, string log, string username = "EDBGS") {
|
||||||
|
JsonObject obj = new();
|
||||||
|
obj.Add("content", log);
|
||||||
|
obj.Add("username", username);
|
||||||
|
|
||||||
|
using (var client = new HttpClient()) {
|
||||||
|
var content = new StringContent(obj.ToString(), Encoding.UTF8, "application/json");
|
||||||
|
var response = client.PostAsync(webhook.Webhook, content);
|
||||||
|
if (response == null) {
|
||||||
|
throw new Exception("failed to post content to Discord webhook");
|
||||||
|
}
|
||||||
|
response.Wait();
|
||||||
|
var resp = response.Result;
|
||||||
|
if (!resp.IsSuccessStatusCode) {
|
||||||
|
throw new Exception(string.Format(
|
||||||
|
"failed to post content to webhook {0}: {1} / {2}",
|
||||||
|
webhook.Name, resp.StatusCode, resp.Content.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
|
@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<Version>0.3.4</Version>
|
<Version>0.4.3</Version>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
@ -18,12 +18,15 @@
|
|||||||
<Copyright>Copyright 2019 by Florian Stinglmayr</Copyright>
|
<Copyright>Copyright 2019 by Florian Stinglmayr</Copyright>
|
||||||
<RepositoryUrl>https://codeberg.org/nola/EDBGS</RepositoryUrl>
|
<RepositoryUrl>https://codeberg.org/nola/EDBGS</RepositoryUrl>
|
||||||
<PackageTags>ED;Elite Dangerous;BGS</PackageTags>
|
<PackageTags>ED;Elite Dangerous;BGS</PackageTags>
|
||||||
<PackageProjectUrl>https://bgs.n0la.org</PackageProjectUrl>
|
<PackageProjectUrl>https://salusinvicta.org/bgstool/</PackageProjectUrl>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Description>Elite: Dangerous BGS logging and reporting tool
|
<Description>Elite: Dangerous BGS logging and reporting tool
|
||||||
</Description>
|
</Description>
|
||||||
<PackageIcon>logo_v5.png</PackageIcon>
|
<PackageIcon>logo_v5.png</PackageIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="main-page.png" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="main-page.png">
|
<Resource Include="main-page.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
@ -37,15 +40,10 @@
|
|||||||
<Pack>True</Pack>
|
<Pack>True</Pack>
|
||||||
<PackagePath>\</PackagePath>
|
<PackagePath>\</PackagePath>
|
||||||
</None>
|
</None>
|
||||||
<None Update="docs\CHANGELOG.md">
|
<None Update="CHANGELOG.md">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Resource Include="docs\main-page.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Resource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="LICENCE.txt">
|
<Content Include="LICENCE.txt">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
@ -55,12 +53,12 @@
|
|||||||
<Resource Include="Salus.ico" />
|
<Resource Include="Salus.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MahApps.Metro" Version="2.4.9" />
|
<PackageReference Include="MahApps.Metro" Version="2.4.10" />
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<PackageReference Include="Microsoft.Windows.Compatibility" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Windows.Compatibility" Version="8.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,7 +1,18 @@
|
|||||||
namespace EliteBGS;
|
using System.Collections.Generic;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
|
||||||
|
namespace EliteBGS;
|
||||||
|
|
||||||
public class GenericDiscordLog : DiscordLogGenerator {
|
public class GenericDiscordLog : DiscordLogGenerator {
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return "Generic Log";
|
return "Generic";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name {
|
||||||
|
get { return "Generic"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string[] SplitLog(string log, int maxcount = 2000) {
|
||||||
|
return SplitLogWithHeader(log, "**Date:**", maxcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ public partial class LoadEntriesWindow : Window {
|
|||||||
dialog.DefaultExt = ".log";
|
dialog.DefaultExt = ".log";
|
||||||
dialog.Filter = "Log files (*.log)|*.log|All files (*.*)|*";
|
dialog.Filter = "Log files (*.log)|*.log|All files (*.*)|*";
|
||||||
|
|
||||||
var location = config.Global.DefaultJournalLocation;
|
var location = AppConfig.DefaultJournalLocation;
|
||||||
if (Directory.Exists(location)) {
|
if (Directory.Exists(location)) {
|
||||||
dialog.InitialDirectory = location;
|
dialog.InitialDirectory = location;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ class CombatZoneFormat : LogFormatter {
|
|||||||
var logs = objective
|
var logs = objective
|
||||||
.EnabledOfType<CombatZone>()
|
.EnabledOfType<CombatZone>()
|
||||||
.OrderBy(x => (CombatZones.DifficultyRank(x.Grade) ?? 0))
|
.OrderBy(x => (CombatZones.DifficultyRank(x.Grade) ?? 0))
|
||||||
.GroupBy(x => new { x.Type, x.Grade })
|
.GroupBy(x => new { x.Type, x.Grade, x.Settlement })
|
||||||
.ToDictionary(x => x.Key, x => x.ToList())
|
.ToDictionary(x => x.Key, x => x.ToList())
|
||||||
;
|
;
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
@ -23,6 +23,11 @@ class CombatZoneFormat : LogFormatter {
|
|||||||
int optionals = log.Value
|
int optionals = log.Value
|
||||||
.Sum(x => x.OptionalObjectivesCompleted)
|
.Sum(x => x.OptionalObjectivesCompleted)
|
||||||
;
|
;
|
||||||
|
var settlements = log.Value
|
||||||
|
.Select(x => x.Settlement)
|
||||||
|
.Distinct()
|
||||||
|
;
|
||||||
|
string settl = string.Join(", ", settlements);
|
||||||
if (!string.IsNullOrEmpty(log.Key.Grade)) {
|
if (!string.IsNullOrEmpty(log.Key.Grade)) {
|
||||||
builder.AppendFormat("Won {0}x {1} {2} Combat Zone(s)",
|
builder.AppendFormat("Won {0}x {1} {2} Combat Zone(s)",
|
||||||
log.Value.Count,
|
log.Value.Count,
|
||||||
@ -39,6 +44,9 @@ class CombatZoneFormat : LogFormatter {
|
|||||||
if (optionals > 0) {
|
if (optionals > 0) {
|
||||||
builder.AppendFormat(" (with {0} optional objectives)", optionals);
|
builder.AppendFormat(" (with {0} optional objectives)", optionals);
|
||||||
}
|
}
|
||||||
|
if (!string.IsNullOrEmpty(settl)) {
|
||||||
|
builder.AppendFormat(" (at {0})", settl);
|
||||||
|
}
|
||||||
builder.Append("\n");
|
builder.Append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using EDPlayerJournal.BGS;
|
|
||||||
|
|
||||||
namespace EliteBGS.LogGenerator;
|
|
||||||
|
|
||||||
public class FailedMissionFormat : LogFormatter {
|
|
||||||
public string GenerateLog(Objective objective) {
|
|
||||||
var missions = objective.EnabledOfType<MissionFailed>();
|
|
||||||
|
|
||||||
if (missions.Count <= 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GenerateSummary(Objective objective) {
|
|
||||||
var missions = objective.EnabledOfType<MissionFailed>();
|
|
||||||
|
|
||||||
if (missions.Count <= 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder sb = new();
|
|
||||||
|
|
||||||
int onFootFails = missions.Where(x => x.Mission.IsOnFoot).Count();
|
|
||||||
int shipFails = missions.Where(x => !x.Mission.IsOnFoot).Count();
|
|
||||||
|
|
||||||
sb.Append("Fails: ");
|
|
||||||
if (onFootFails > 0) {
|
|
||||||
sb.AppendFormat("{0} Ground", onFootFails);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shipFails > 0) {
|
|
||||||
if (onFootFails > 0) {
|
|
||||||
sb.Append(", ");
|
|
||||||
}
|
|
||||||
sb.AppendFormat("{0} Ship", shipFails);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
47
EliteBGS/LogGenerator/MeritsGainedFormat.cs
Normal file
47
EliteBGS/LogGenerator/MeritsGainedFormat.cs
Normal 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(';');
|
||||||
|
}
|
||||||
|
}
|
@ -6,17 +6,73 @@ using EDPlayerJournal.BGS;
|
|||||||
namespace EliteBGS.LogGenerator;
|
namespace EliteBGS.LogGenerator;
|
||||||
|
|
||||||
public class MissionFormat : LogFormatter {
|
public class MissionFormat : LogFormatter {
|
||||||
|
private string GenerateFailedLog(Objective objective) {
|
||||||
|
var missions = objective.EnabledOfType<MissionFailed>();
|
||||||
|
|
||||||
|
if (missions.Count <= 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateFailedSummary(Objective objective) {
|
||||||
|
var missions = objective.EnabledOfType<MissionFailed>();
|
||||||
|
|
||||||
|
if (missions.Count <= 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new();
|
||||||
|
|
||||||
|
int onFootFails = missions.Where(x => x.Mission.IsOnFoot).Count();
|
||||||
|
int shipFails = missions.Where(x => !x.Mission.IsOnFoot).Count();
|
||||||
|
|
||||||
|
sb.Append("Fails: ");
|
||||||
|
if (onFootFails > 0) {
|
||||||
|
sb.AppendFormat("{0} Ground", onFootFails);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shipFails > 0) {
|
||||||
|
if (onFootFails > 0) {
|
||||||
|
sb.Append(", ");
|
||||||
|
}
|
||||||
|
sb.AppendFormat("{0} Ship", shipFails);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
public string GenerateLog(Objective objective) {
|
public string GenerateLog(Objective objective) {
|
||||||
Dictionary<string, Dictionary<string, int>> collated = new();
|
Dictionary<string, Dictionary<string, int>> collated = new();
|
||||||
Dictionary<string, ulong> passengers = new();
|
Dictionary<string, ulong> passengers = new();
|
||||||
StringBuilder output = new StringBuilder();
|
StringBuilder output = new StringBuilder();
|
||||||
int total_influence = 0;
|
long total_influence = 0;
|
||||||
|
bool hadmissions = false;
|
||||||
|
|
||||||
var missions = objective.EnabledOfType<MissionCompleted>();
|
var missions = objective.EnabledOfType<MissionCompleted>();
|
||||||
var support = objective.EnabledOfType<InfluenceSupport>();
|
var support = objective.EnabledOfType<InfluenceSupport>();
|
||||||
|
var failed = objective.EnabledOfType<MissionFailed>();
|
||||||
|
|
||||||
if ((missions == null || missions.Count == 0) &&
|
if ((missions == null || missions.Count == 0) &&
|
||||||
(support == null || support.Count == 0)) {
|
(support == null || support.Count == 0) &&
|
||||||
|
(failed == null || failed.Count == 0)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +86,7 @@ public class MissionFormat : LogFormatter {
|
|||||||
|
|
||||||
++collated[m.MissionName][m.Influence];
|
++collated[m.MissionName][m.Influence];
|
||||||
|
|
||||||
|
hadmissions = true;
|
||||||
total_influence += m.Influence.Length;
|
total_influence += m.Influence.Length;
|
||||||
|
|
||||||
if (m.AcceptedEntry != null &&
|
if (m.AcceptedEntry != null &&
|
||||||
@ -60,17 +117,29 @@ public class MissionFormat : LogFormatter {
|
|||||||
|
|
||||||
output.Append("\n");
|
output.Append("\n");
|
||||||
|
|
||||||
|
// Handle failed missions, and add them to the log and influence tally
|
||||||
|
string failedlog = GenerateFailedLog(objective);
|
||||||
|
if (!string.IsNullOrEmpty(failedlog)) {
|
||||||
|
output.Append(failedlog);
|
||||||
|
output.Append("\n");
|
||||||
|
}
|
||||||
|
if (failed.Count > 0) {
|
||||||
|
hadmissions = true;
|
||||||
|
}
|
||||||
|
total_influence += failed.Sum(x => x.InfluenceAmount);
|
||||||
|
|
||||||
foreach (InfluenceSupport inf in support) {
|
foreach (InfluenceSupport inf in support) {
|
||||||
output.Append(inf.ToString());
|
output.Append(inf.ToString());
|
||||||
output.Append("\n");
|
output.Append("\n");
|
||||||
total_influence += inf.Influence.Length;
|
hadmissions = true;
|
||||||
|
total_influence += inf.Influence.InfluenceAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (support.Count() > 0) {
|
if (support.Count > 0) {
|
||||||
output.Append("\n");
|
output.Append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total_influence > 0) {
|
if (hadmissions) {
|
||||||
output.AppendFormat("Total Influence: {0}", total_influence);
|
output.AppendFormat("Total Influence: {0}", total_influence);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,19 +147,34 @@ public class MissionFormat : LogFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public string GenerateSummary(Objective objective) {
|
public string GenerateSummary(Objective objective) {
|
||||||
|
bool hadmissions = objective
|
||||||
|
.EnabledOfType<MissionCompleted>()
|
||||||
|
.Count > 0
|
||||||
|
;
|
||||||
long influence = objective
|
long influence = objective
|
||||||
.EnabledOfType<MissionCompleted>()
|
.EnabledOfType<MissionCompleted>()
|
||||||
.Sum(x => x.Influence.Length)
|
.Sum(x => x.Influence.Length)
|
||||||
;
|
;
|
||||||
long support = objective
|
long support = objective
|
||||||
.EnabledOfType<InfluenceSupport>()
|
.EnabledOfType<InfluenceSupport>()
|
||||||
.Sum(x => x.Influence.Length)
|
.Sum(x => x.Influence.InfluenceAmount)
|
||||||
|
;
|
||||||
|
long failed = objective
|
||||||
|
.EnabledOfType<MissionFailed>()
|
||||||
|
.Sum(x => x.InfluenceAmount)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (influence + support <= 0) {
|
if (influence == 0 && support == 0 && failed == 0 && !hadmissions) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Format("INF: {0}", influence + support);
|
string failedsummary = GenerateFailedSummary(objective);
|
||||||
|
string summary = string.Format("INF: {0}", influence + support + failed);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(failedsummary)) {
|
||||||
|
string.Join("; ", summary, failedsummary);
|
||||||
|
}
|
||||||
|
|
||||||
|
return summary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,19 +5,138 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:EliteBGS"
|
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"
|
xmlns:Util="clr-namespace:EliteBGS.Util"
|
||||||
|
d:DataContext="{d:DesignInstance Type=Util:AppConfig}"
|
||||||
|
x:Name="window"
|
||||||
|
x:Class="EliteBGS.MainWindow"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Elite: Dangerous BGS Helper" Height="520" Width="950" Icon="Salus.ico" Closing="window_Closing">
|
Title="Elite: Dangerous BGS Helper" Height="620" Width="950" Icon="Salus.ico" Closing="window_Closing"
|
||||||
|
>
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
|
<local:MinusFortyFiveConverter x:Key="MinusFortyFiveConverter" />
|
||||||
<Style x:Key="StretchingTreeViewStyle" TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
|
<Style x:Key="StretchingTreeViewStyle" TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||||
</Style>
|
</Style>
|
||||||
<local:MinusFortyFiveConverter x:Key="MinusFortyFiveConverter" />
|
|
||||||
|
<local:Report x:Key="ObjectivesBasedOnSystem" />
|
||||||
|
<Util:Config x:Key="Config" />
|
||||||
|
|
||||||
|
<DataTemplate DataType="{x:Type Util:DiscordWebhook}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Text="Name: " Grid.Column="0" Margin="2,0,0,0"/>
|
||||||
|
<TextBox Text="{Binding Name}" Grid.Column="1"/>
|
||||||
|
|
||||||
|
<TextBlock Text="Webhook URL: " Grid.Column="2" Margin="2,0,0,0"/>
|
||||||
|
<TextBox Text="{Binding Webhook}" Grid.Column="3"/>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
|
<HierarchicalDataTemplate DataType="{x:Type local:SystemObjectives}" ItemsSource="{Binding Path=Objectives}">
|
||||||
|
<Grid
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Width="{Binding ActualWidth, ElementName=entries, Converter={StaticResource MinusFortyFiveConverter}}"
|
||||||
|
>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<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="System: " Margin="2,0,0,0"/>
|
||||||
|
<TextBlock Text="{Binding SystemName}" FontWeight="DemiBold"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</HierarchicalDataTemplate>
|
||||||
|
|
||||||
|
<HierarchicalDataTemplate DataType="{x:Type local:Objective}"
|
||||||
|
ItemsSource="{Binding Path=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="Faction: " Margin="2,0,0,0"/>
|
||||||
|
<TextBlock Text="{Binding Faction}" FontWeight="DemiBold"/>
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<DataTemplate DataType="{x:Type local:UITransaction}">
|
||||||
|
<!-- This will stretch out the width of the item-->
|
||||||
|
<Grid Initialized="Transaction_Initialized"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
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="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="AlliedCaptain" Margin="2,0,2,0" Content="Allied Captain" IsChecked="{Binding HasAlliedCaptain, Mode=TwoWay}" IsThreeState="False"/>
|
||||||
|
<ToggleButton x:Name="EnemyCaptain" Margin="2,0,2,0" Content="Enemy Captain" IsChecked="{Binding HasEnemyCaptain, Mode=TwoWay}" IsThreeState="False"/>
|
||||||
|
<ToggleButton x:Name="AlliedCorrespondent" Margin="2,0,2,0" Content="Allied Correspondent" IsChecked="{Binding HasAlliedCorrespondent, Mode=TwoWay}" IsThreeState="False"/>
|
||||||
|
<ToggleButton x:Name="EnemyCorrespondent" Margin="2,0,2,0" Content="Enemy Correspondent" IsChecked="{Binding HasEnemyCorrespondent, 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"/>
|
||||||
|
<Button Content="Power" x:Name="Power" Click="Power_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>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
<mah:MetroWindow.RightWindowCommands>
|
<mah:MetroWindow.RightWindowCommands>
|
||||||
<mah:WindowCommands ShowSeparators="False">
|
<mah:WindowCommands ShowSeparators="False">
|
||||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,5,0">
|
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,5,0">
|
||||||
<Hyperlink x:Name="URL" NavigateUri="https://bgs.n0la.org/" RequestNavigate="URL_RequestNavigate">Homepage</Hyperlink>
|
<Hyperlink x:Name="URL" NavigateUri="https://salusinvicta.org/bgstool/" RequestNavigate="URL_RequestNavigate">Homepage</Hyperlink>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,15,0">
|
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,15,0">
|
||||||
<Hyperlink x:Name="SRC" NavigateUri="https://codeberg.org/nola/EDBGS" RequestNavigate="URL_RequestNavigate">Source</Hyperlink>
|
<Hyperlink x:Name="SRC" NavigateUri="https://codeberg.org/nola/EDBGS" RequestNavigate="URL_RequestNavigate">Source</Hyperlink>
|
||||||
@ -63,95 +182,24 @@
|
|||||||
<Button x:Name="GenerateDiscord" Content="Generate Discord Report" VerticalAlignment="Stretch" Margin="0,0,0,0" VerticalContentAlignment="Center" Click="GenerateDiscord_Click"/>
|
<Button x:Name="GenerateDiscord" Content="Generate Discord Report" VerticalAlignment="Stretch" Margin="0,0,0,0" VerticalContentAlignment="Center" Click="GenerateDiscord_Click"/>
|
||||||
<Separator />
|
<Separator />
|
||||||
<ComboBox x:Name="LogType" VerticalAlignment="Stretch" Margin="0,3,0,3" Width="140" SelectionChanged="LogType_SelectionChanged" />
|
<ComboBox x:Name="LogType" VerticalAlignment="Stretch" Margin="0,3,0,3" Width="140" SelectionChanged="LogType_SelectionChanged" />
|
||||||
|
<Separator />
|
||||||
|
<CheckBox x:Name="SelectAll" Content="Select All" IsChecked="True" Click="SelectAll_Click"/>
|
||||||
|
<Separator />
|
||||||
|
<Label Content="Post log as" VerticalAlignment="Center" Margin="0,3,0,3" />
|
||||||
|
<ComboBox x:Name="Commanders" VerticalAlignment="Stretch" Margin="0,3,0,3" Width="180" />
|
||||||
|
<Label Content="to" VerticalAlignment="Center" Margin="0,3,0,3" />
|
||||||
|
<mah:DropDownButton x:Name="PostToDiscord" Content="Discord" />
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
<TreeView CheckBox.Checked="TreeView_CheckBox_Updated"
|
<TreeView CheckBox.Checked="TreeView_CheckBox_Updated"
|
||||||
CheckBox.Unchecked="TreeView_CheckBox_Updated"
|
CheckBox.Unchecked="TreeView_CheckBox_Updated"
|
||||||
x:Name="entries" Margin="0,0,0,0"
|
x:Name="entries" Margin="0,0,0,0"
|
||||||
Grid.ColumnSpan="3" Grid.Row="2"
|
Grid.ColumnSpan="3"
|
||||||
|
Grid.Row="2"
|
||||||
KeyUp="entries_KeyUp"
|
KeyUp="entries_KeyUp"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
|
ItemsSource="{Binding Source={StaticResource ObjectivesBasedOnSystem}}"
|
||||||
>
|
>
|
||||||
<TreeView.ItemTemplate>
|
|
||||||
<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="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>
|
|
||||||
<!-- This will stretch out the width of the item-->
|
|
||||||
<Grid Initialized="Transaction_Initialized"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
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="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="AlliedCaptain" Margin="2,0,2,0" Content="Allied Captain" IsChecked="{Binding HasAlliedCaptain, Mode=TwoWay}" IsThreeState="False"/>
|
|
||||||
<ToggleButton x:Name="EnemyCaptain" Margin="2,0,2,0" Content="Enemy Captain" IsChecked="{Binding HasEnemyCaptain, Mode=TwoWay}" IsThreeState="False"/>
|
|
||||||
<ToggleButton x:Name="AlliedCorrespondent" Margin="2,0,2,0" Content="Allied Correspondent" IsChecked="{Binding HasAlliedCorrespondent, Mode=TwoWay}" IsThreeState="False"/>
|
|
||||||
<ToggleButton x:Name="EnemyCorrespondent" Margin="2,0,2,0" Content="Enemy Correspondent" IsChecked="{Binding HasEnemyCorrespondent, 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>
|
|
||||||
</TreeView.ItemTemplate>
|
|
||||||
<TreeView.ItemContainerStyle>
|
<TreeView.ItemContainerStyle>
|
||||||
<Style TargetType="TreeViewItem">
|
<Style TargetType="TreeViewItem">
|
||||||
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
|
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
|
||||||
@ -168,6 +216,7 @@
|
|||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@ -213,6 +262,7 @@
|
|||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
@ -221,6 +271,36 @@
|
|||||||
<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="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="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="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">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<DataGrid x:Name="Webhooks"
|
||||||
|
Grid.Row="0"
|
||||||
|
ItemsSource="{Binding Webhooks}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
ScrollViewer.CanContentScroll="True"
|
||||||
|
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||||
|
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||||
|
MaxHeight="100"
|
||||||
|
MinHeight="100"
|
||||||
|
KeyUp="Webhooks_KeyUp"
|
||||||
|
CellEditEnding="Webhooks_CellEditEnding"
|
||||||
|
>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
|
||||||
|
<DataGridTextColumn Header="Webhook URL" Binding="{Binding Webhook}" Width="*"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Left" Margin="5,10,5,0">
|
||||||
|
<Button x:Name="AddWebHook" Content="Add" Click="AddWebHook_Click"/>
|
||||||
|
<Button x:Name="RemoveWebHook" Content="Remove" Click="RemoveWebHook_Click" />
|
||||||
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -32,8 +32,8 @@ public partial class MainWindow : MetroWindow {
|
|||||||
private LoadEntriesWindow loadentries = null;
|
private LoadEntriesWindow loadentries = null;
|
||||||
|
|
||||||
private static readonly List<DiscordLogGenerator> logtypes = new List<DiscordLogGenerator>() {
|
private static readonly List<DiscordLogGenerator> logtypes = new List<DiscordLogGenerator>() {
|
||||||
new NonaDiscordLog(),
|
|
||||||
new GenericDiscordLog(),
|
new GenericDiscordLog(),
|
||||||
|
new NonaDiscordLog(),
|
||||||
new OneLineDiscordLog(),
|
new OneLineDiscordLog(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -46,6 +46,9 @@ public partial class MainWindow : MetroWindow {
|
|||||||
/* ignored */
|
/* ignored */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Webhooks.ItemsSource = Config.Global.Webhooks;
|
||||||
|
RefreshPostMenu();
|
||||||
|
|
||||||
foreach (DiscordLogGenerator type in logtypes) {
|
foreach (DiscordLogGenerator type in logtypes) {
|
||||||
LogType.Items.Add(type);
|
LogType.Items.Add(type);
|
||||||
}
|
}
|
||||||
@ -61,6 +64,7 @@ public partial class MainWindow : MetroWindow {
|
|||||||
this.NoInfluenceSupport.IsOn = Config.Global.IgnoreInfluenceSupport;
|
this.NoInfluenceSupport.IsOn = Config.Global.IgnoreInfluenceSupport;
|
||||||
this.NoMarketBuy.IsOn = Config.Global.IgnoreMarketBuy;
|
this.NoMarketBuy.IsOn = Config.Global.IgnoreMarketBuy;
|
||||||
this.NoFleetCarrier.IsOn = Config.Global.IgnoreFleetCarrier;
|
this.NoFleetCarrier.IsOn = Config.Global.IgnoreFleetCarrier;
|
||||||
|
this.NoPowerplay.IsOn = Config.Global.IgnorePowerplay;
|
||||||
|
|
||||||
// Apply theme
|
// Apply theme
|
||||||
try {
|
try {
|
||||||
@ -107,6 +111,10 @@ public partial class MainWindow : MetroWindow {
|
|||||||
//{ "HouseSalus", Color.FromRgb(0xBC, 0x94, 0x39) },
|
//{ "HouseSalus", Color.FromRgb(0xBC, 0x94, 0x39) },
|
||||||
{ "HouseSalus", Color.FromRgb(0xED, 0xDA, 0x70) },
|
{ "HouseSalus", Color.FromRgb(0xED, 0xDA, 0x70) },
|
||||||
{ "NovaNavy", Color.FromRgb(0xA1, 0xA4, 0xDB) },
|
{ "NovaNavy", Color.FromRgb(0xA1, 0xA4, 0xDB) },
|
||||||
|
// Official Red of the Polish Flag
|
||||||
|
{ "PolskaGurom", Color.FromRgb(0xD4, 0x21, 0x3D) },
|
||||||
|
// Official Blue in the Armenian Flag
|
||||||
|
{ "ArmeniaBlue", Color.FromRgb(0x00, 0x33, 0xA0) },
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var colourtheme in colorThemes) {
|
foreach (var colourtheme in colorThemes) {
|
||||||
@ -175,9 +183,15 @@ public partial class MainWindow : MetroWindow {
|
|||||||
options.IgnoreInfluenceSupport = Config.Global.IgnoreInfluenceSupport;
|
options.IgnoreInfluenceSupport = Config.Global.IgnoreInfluenceSupport;
|
||||||
options.IgnoreMarketBuy = Config.Global.IgnoreMarketBuy;
|
options.IgnoreMarketBuy = Config.Global.IgnoreMarketBuy;
|
||||||
options.IgnoreFleetCarrierFaction = Config.Global.IgnoreFleetCarrier;
|
options.IgnoreFleetCarrierFaction = Config.Global.IgnoreFleetCarrier;
|
||||||
|
options.IgnorePowerplay = Config.Global.IgnorePowerplay;
|
||||||
|
|
||||||
List<Transaction> transactions = parser.Parse(entries, options);
|
List<Transaction> transactions = parser.Parse(entries, options);
|
||||||
|
|
||||||
|
Commanders.ItemsSource = parser.Commanders;
|
||||||
|
if (Commanders.Items.Count > 0) {
|
||||||
|
Commanders.SelectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Filter the transactions down to the given time frame
|
// Filter the transactions down to the given time frame
|
||||||
transactions = transactions
|
transactions = transactions
|
||||||
.Where(t => t.CompletedAtDateTime >= start && t.CompletedAtDateTime <= end)
|
.Where(t => t.CompletedAtDateTime >= start && t.CompletedAtDateTime <= end)
|
||||||
@ -192,7 +206,7 @@ public partial class MainWindow : MetroWindow {
|
|||||||
transactions.RemoveAll(x => incompletes.Contains(x));
|
transactions.RemoveAll(x => incompletes.Contains(x));
|
||||||
|
|
||||||
report = new Report(transactions);
|
report = new Report(transactions);
|
||||||
this.entries.ItemsSource = report.Objectives;
|
this.entries.ItemsSource = report.SystemObjectives;
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
Log("Something went terribly wrong while parsing the E:D player journal.");
|
Log("Something went terribly wrong while parsing the E:D player journal.");
|
||||||
Log("Please send this to CMDR Hekateh:");
|
Log("Please send this to CMDR Hekateh:");
|
||||||
@ -233,6 +247,12 @@ public partial class MainWindow : MetroWindow {
|
|||||||
|
|
||||||
HandleEntries(entries, start, end);
|
HandleEntries(entries, start, end);
|
||||||
GenerateLog();
|
GenerateLog();
|
||||||
|
|
||||||
|
var errors = journal.AllErrors;
|
||||||
|
foreach (var error in errors) {
|
||||||
|
Log("An error has occured in the Journal file, please send this to CMDR Hekateh:");
|
||||||
|
Log(error.ToString());
|
||||||
|
}
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
Log("Something went terribly wrong while parsing the E:D player journal.");
|
Log("Something went terribly wrong while parsing the E:D player journal.");
|
||||||
Log("Please send this to CMDR Hekateh:");
|
Log("Please send this to CMDR Hekateh:");
|
||||||
@ -265,15 +285,27 @@ public partial class MainWindow : MetroWindow {
|
|||||||
object obj = entries.SelectedItem;
|
object obj = entries.SelectedItem;
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
|
|
||||||
if (obj.GetType() == typeof(Objective)) {
|
if (obj.GetType() == typeof(SystemObjectives)) {
|
||||||
removed = report.Objectives.Remove(obj as Objective);
|
removed = report.SystemObjectives.Remove(obj as SystemObjectives);
|
||||||
} else if (obj.GetType() == typeof(UITransaction) ||
|
} else if (obj.GetType() == typeof(Objective)) {
|
||||||
obj.GetType().IsSubclassOf(typeof(UITransaction))) {
|
report
|
||||||
foreach (Objective parent in report.Objectives) {
|
.SystemObjectives
|
||||||
if (parent.UITransactions.Remove(obj as UITransaction)) {
|
.ForEach(x => {
|
||||||
|
if (x.Objectives.Remove(obj as Objective)) {
|
||||||
removed = true;
|
removed = true;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
} else if (obj.GetType() == typeof(UITransaction) ||
|
||||||
|
obj.GetType().IsSubclassOf(typeof(UITransaction))) {
|
||||||
|
report
|
||||||
|
.SystemObjectives
|
||||||
|
.SelectMany(x =>
|
||||||
|
x.Objectives
|
||||||
|
.Where(x => x.UITransactions.Contains(obj as UITransaction))
|
||||||
|
)
|
||||||
|
.ToList()
|
||||||
|
.ForEach(x => removed = x.UITransactions.Remove(obj as UITransaction))
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (removed) {
|
if (removed) {
|
||||||
@ -446,6 +478,16 @@ public partial class MainWindow : MetroWindow {
|
|||||||
RefreshView();
|
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) {
|
private void Thargoid_Click(object sender, RoutedEventArgs e) {
|
||||||
CombatZone transaction = GetTransaction<CombatZone>(sender);
|
CombatZone transaction = GetTransaction<CombatZone>(sender);
|
||||||
if (transaction == null) {
|
if (transaction == null) {
|
||||||
@ -543,6 +585,10 @@ public partial class MainWindow : MetroWindow {
|
|||||||
Config.Global.IgnoreFleetCarrier = this.NoFleetCarrier.IsOn;
|
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) {
|
private void OpenInExplorer_Click(object sender, RoutedEventArgs e) {
|
||||||
try {
|
try {
|
||||||
Process.Start(new ProcessStartInfo(Config.Global.JournalLocation) {
|
Process.Start(new ProcessStartInfo(Config.Global.JournalLocation) {
|
||||||
@ -551,4 +597,136 @@ public partial class MainWindow : MetroWindow {
|
|||||||
} catch (Exception) {
|
} catch (Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SelectAll_Click(object sender, RoutedEventArgs e) {
|
||||||
|
if (report == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
report.SystemObjectives.ForEach(t => { t.IsEnabled = (bool)SelectAll.IsChecked; });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddWebHook_Click(object sender, RoutedEventArgs e) {
|
||||||
|
Config.Global.Webhooks.Add(new DiscordWebhook {
|
||||||
|
Name = "Discord Server Name",
|
||||||
|
Webhook = "..."
|
||||||
|
});
|
||||||
|
Webhooks.Items.Refresh();
|
||||||
|
RefreshPostMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveWebHook_Click(object sender, RoutedEventArgs e) {
|
||||||
|
if (Webhooks.SelectedItems.Count <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selection = Webhooks.SelectedItems
|
||||||
|
.OfType<DiscordWebhook>()
|
||||||
|
.ToList()
|
||||||
|
;
|
||||||
|
foreach (var item in selection) {
|
||||||
|
Config.Global.Webhooks.Remove(item);
|
||||||
|
}
|
||||||
|
Webhooks.Items.Refresh();
|
||||||
|
RefreshPostMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Webhooks_KeyUp(object sender, KeyEventArgs e) {
|
||||||
|
DataGridCell cell = e.OriginalSource as DataGridCell;
|
||||||
|
/* We also get keypresses from DataGridCells that are currently
|
||||||
|
* editing their content. Filter those out. We don't want to delete
|
||||||
|
* the row when the user presses DEL while editing the cells content
|
||||||
|
*/
|
||||||
|
if (cell == null || cell.IsEditing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e.Key == Key.Delete) {
|
||||||
|
RemoveWebHook_Click(this, new RoutedEventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Webhooks_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) {
|
||||||
|
try {
|
||||||
|
Config.SaveGlobal();
|
||||||
|
} catch (Exception) { }
|
||||||
|
e.Cancel = false;
|
||||||
|
RefreshPostMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshPostMenu() {
|
||||||
|
MenuItem menu;
|
||||||
|
PostToDiscord.Items.Clear();
|
||||||
|
if (Config.Global.Webhooks.Count <= 0) {
|
||||||
|
PostToDiscord.IsEnabled = false;
|
||||||
|
} else {
|
||||||
|
PostToDiscord.IsEnabled = true;
|
||||||
|
foreach (var item in Config.Global.Webhooks) {
|
||||||
|
menu = new MenuItem();
|
||||||
|
menu.Header = item.Name;
|
||||||
|
menu.Click += DiscordWebhook_Click;
|
||||||
|
PostToDiscord.Items.Add(menu);
|
||||||
|
}
|
||||||
|
PostToDiscord.Items.Add(new Separator());
|
||||||
|
|
||||||
|
menu = new MenuItem();
|
||||||
|
menu.Header = "All";
|
||||||
|
menu.Click += PostToAll_Click;
|
||||||
|
PostToDiscord.Items.Add(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PostToDiscordWebhook(IEnumerable<DiscordWebhook> hooks) {
|
||||||
|
if (string.IsNullOrEmpty(DiscordLog.Text)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DiscordLogGenerator discord = LogType.SelectedItem as DiscordLogGenerator;
|
||||||
|
string[] chunks;
|
||||||
|
|
||||||
|
try {
|
||||||
|
chunks = discord.SplitLog(DiscordLog.Text);
|
||||||
|
} catch (Exception) {
|
||||||
|
MessageBox.Show(
|
||||||
|
"The log could not be split into discord appropriate length.\n" +
|
||||||
|
"This happens with the bigger logs formats if you do lots of things in one system.\n" +
|
||||||
|
"Try posting the log in the OneLine format.",
|
||||||
|
"Sorry!", MessageBoxButton.OK, MessageBoxImage.Error
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string commander = "EDBGS";
|
||||||
|
if (Commanders.SelectedIndex >= 0) {
|
||||||
|
commander = Commanders.SelectedItem.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var hook in hooks) {
|
||||||
|
try {
|
||||||
|
foreach (var chunk in chunks) {
|
||||||
|
DiscordPoster.PostToDiscord(hook, chunk, commander);
|
||||||
|
}
|
||||||
|
Log(string.Format("successfully posted to discord webhook `{0}`", hook.Name));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log(string.Format("failed to post to discord webhook `{0}`: {1}",
|
||||||
|
hook.Name, ex.Message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DiscordWebhook_Click(object sender, RoutedEventArgs e) {
|
||||||
|
MenuItem item = sender as MenuItem;
|
||||||
|
if (item == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DiscordWebhook hook = Config.Global.Webhooks
|
||||||
|
.Find(x => string.Compare(x.Name, item.Header.ToString()) == 0)
|
||||||
|
;
|
||||||
|
if (hook == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PostToDiscordWebhook(new DiscordWebhook[] { hook });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PostToAll_Click(object sender, RoutedEventArgs e) {
|
||||||
|
PostToDiscordWebhook(Config.Global.Webhooks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ public class MinusFortyFiveConverter : IValueConverter {
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public object Convert(
|
public object Convert(
|
||||||
object value, Type targetType, object parameter, CultureInfo culture) {
|
object value, Type targetType, object parameter, CultureInfo culture) {
|
||||||
return (double)value - 80;
|
return (double)value - 110;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
@ -7,6 +7,12 @@ using System.Linq;
|
|||||||
namespace EliteBGS.BGS;
|
namespace EliteBGS.BGS;
|
||||||
|
|
||||||
public class NonaDiscordLog : DiscordLogGenerator {
|
public class NonaDiscordLog : DiscordLogGenerator {
|
||||||
|
protected override string BotHeader() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendFormat(":robot: `Bot-Header:` {0}; {1}\n", GetToolVersion(), this.Name);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
private string FormatDate() {
|
private string FormatDate() {
|
||||||
CultureInfo cultureInfo = CultureInfo.InvariantCulture;
|
CultureInfo cultureInfo = CultureInfo.InvariantCulture;
|
||||||
StringBuilder date = new StringBuilder();
|
StringBuilder date = new StringBuilder();
|
||||||
@ -79,6 +85,14 @@ public class NonaDiscordLog : DiscordLogGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return "Nova Navy Log";
|
return "Nova Navy";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name {
|
||||||
|
get { return "NovaNavy"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string[] SplitLog(string log, int maxcount = 2000) {
|
||||||
|
return SplitLogWithHeader(log, ":clock2: `Date:`", maxcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,9 @@ public class UITransaction : INotifyPropertyChanged {
|
|||||||
return Visibility.Hidden;
|
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;
|
return Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +244,7 @@ public class UITransaction : INotifyPropertyChanged {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class Objective : IComparable<Objective> {
|
public class Objective : IComparable<Objective> {
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; } = true;
|
||||||
|
|
||||||
public List<UITransaction> UITransactions { get; } = new List<UITransaction>();
|
public List<UITransaction> UITransactions { get; } = new List<UITransaction>();
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
using EliteBGS.LogGenerator;
|
using EliteBGS.LogGenerator;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
|
||||||
namespace EliteBGS;
|
namespace EliteBGS;
|
||||||
|
|
||||||
@ -25,6 +28,30 @@ public class OneLineDiscordLog : DiscordLogGenerator {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string[] SplitLog(string log, int maxcount = 2000) {
|
||||||
|
string[] lines = log.Split('\n');
|
||||||
|
List<string> chunks = new();
|
||||||
|
string chunk = string.Empty;
|
||||||
|
|
||||||
|
// Optimisation
|
||||||
|
if (log.Length <= maxcount) {
|
||||||
|
return new string[] { log };
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < lines.Length; i++) {
|
||||||
|
string line = lines[i];
|
||||||
|
if ((chunk.Length + line.Length) > maxcount || i == lines.Length - 1) {
|
||||||
|
chunks.Add(chunk.Trim());
|
||||||
|
chunk = string.Empty;
|
||||||
|
chunk = chunk.Insert(0, BotHeader()).Trim();
|
||||||
|
} else {
|
||||||
|
chunk = chunk + "\n" + line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
public override string GenerateDiscordLog(Report report) {
|
public override string GenerateDiscordLog(Report report) {
|
||||||
StringBuilder log = new StringBuilder();
|
StringBuilder log = new StringBuilder();
|
||||||
|
|
||||||
@ -40,6 +67,8 @@ public class OneLineDiscordLog : DiscordLogGenerator {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.AppendFormat("{0}", BotHeader());
|
||||||
|
|
||||||
foreach (Objective objective in objectives) {
|
foreach (Objective objective in objectives) {
|
||||||
log.AppendFormat("{0}", GenerateObjectiveHeader(objective));
|
log.AppendFormat("{0}", GenerateObjectiveHeader(objective));
|
||||||
|
|
||||||
@ -60,6 +89,10 @@ public class OneLineDiscordLog : DiscordLogGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return "One Line Report";
|
return "One Line";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name {
|
||||||
|
get { return "OneLine"; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Resources;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
@ -51,5 +49,5 @@ using System.Windows;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.3.4.0")]
|
[assembly: AssemblyVersion("0.4.3.0")]
|
||||||
[assembly: AssemblyFileVersion("0.3.4.0")]
|
[assembly: AssemblyFileVersion("0.4.3.0")]
|
||||||
|
@ -7,7 +7,7 @@ been parsed, you may then generate a BGS report you can copy/paste into Discord.
|
|||||||
|
|
||||||
Source code is available at [https://codeberg.org/nola/edbgs](https://codeberg.org/nola/edbgs).
|
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/).
|
Binary downloads can be found here: [https://salusinvicta.org/bgstool/](https://salusinvicta.org/bgstool/).
|
||||||
|
|
||||||
## How To
|
## How To
|
||||||
|
|
||||||
|
@ -1,10 +1,38 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
using EDPlayerJournal.BGS;
|
using EDPlayerJournal.BGS;
|
||||||
|
|
||||||
namespace EliteBGS;
|
namespace EliteBGS;
|
||||||
|
|
||||||
|
public class SystemObjectives : INotifyPropertyChanged, IComparable<SystemObjectives> {
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
private bool isenabled = true;
|
||||||
|
|
||||||
|
public bool IsEnabled {
|
||||||
|
get { return isenabled; }
|
||||||
|
set {
|
||||||
|
isenabled = value;
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsEnabled"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsExpanded { get; set; } = false;
|
||||||
|
|
||||||
|
public string SystemName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public List<Objective> Objectives { get; set; } = new();
|
||||||
|
|
||||||
|
public int CompareTo(SystemObjectives other) {
|
||||||
|
if (other == null) return 1;
|
||||||
|
return string.Compare(SystemName, other.SystemName, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class Report {
|
public class Report {
|
||||||
public List<Objective> Objectives { get; set; } = new List<Objective>();
|
public List<SystemObjectives> SystemObjectives { get; set; } = new();
|
||||||
|
|
||||||
public Report() { }
|
public Report() { }
|
||||||
|
|
||||||
@ -12,29 +40,35 @@ public class Report {
|
|||||||
Populate(transactions);
|
Populate(transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Objective> Objectives {
|
||||||
|
get {
|
||||||
|
return SystemObjectives
|
||||||
|
.Where(t => t.IsEnabled)
|
||||||
|
.SelectMany(x => x.Objectives)
|
||||||
|
.ToList()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Populate(List<Transaction> transactions) {
|
private void Populate(List<Transaction> transactions) {
|
||||||
if (transactions == null || transactions.Count == 0) {
|
if (transactions == null || transactions.Count == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Transaction t in transactions) {
|
foreach (Transaction t in transactions) {
|
||||||
Objective o;
|
var o = SystemObjectives.Find(x => string.Compare(x.SystemName, t.System) == 0);
|
||||||
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 (o == null) {
|
||||||
if (t.SystemContribution) {
|
o = new SystemObjectives() { SystemName = t.System };
|
||||||
o = new Objective() { System = t.System };
|
SystemObjectives.Add(o);
|
||||||
} else {
|
|
||||||
o = new Objective() { Faction = t.Faction, System = t.System };
|
|
||||||
}
|
}
|
||||||
Objectives.Add(o);
|
var objective = o.Objectives.Find(x => x.Matches(t.System, t.Faction));
|
||||||
|
if (objective == null) {
|
||||||
|
objective = new Objective() { Faction = t.Faction, System = t.System };
|
||||||
|
o.Objectives.Add(objective);
|
||||||
|
}
|
||||||
|
objective.UITransactions.Add(new UITransaction(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
o.UITransactions.Add(new UITransaction(t));
|
SystemObjectives.Sort();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace EliteBGS.Util {
|
namespace EliteBGS.Util;
|
||||||
public class AppConfig {
|
|
||||||
|
public class AppConfig {
|
||||||
private static readonly string default_journal_location = "%UserProfile%\\Saved Games\\Frontier Developments\\Elite Dangerous";
|
private static readonly string default_journal_location = "%UserProfile%\\Saved Games\\Frontier Developments\\Elite Dangerous";
|
||||||
private string journal_location = default_journal_location;
|
private string journal_location = default_journal_location;
|
||||||
public string DefaultJournalLocation => default_journal_location;
|
|
||||||
private string colour = "Amber";
|
private string colour = "Amber";
|
||||||
private string theme = "Dark";
|
private string theme = "Dark";
|
||||||
|
|
||||||
|
public static string DefaultJournalLocation => default_journal_location;
|
||||||
|
|
||||||
public string LastUsedDiscordTemplate { get; set; }
|
public string LastUsedDiscordTemplate { get; set; }
|
||||||
|
|
||||||
public string JournalLocation {
|
public string JournalLocation {
|
||||||
@ -63,9 +67,18 @@ namespace EliteBGS.Util {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IgnoreFleetCarrier { get; set; } = true;
|
public bool IgnoreFleetCarrier { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore power play?
|
||||||
|
/// </summary>
|
||||||
|
public bool IgnorePowerplay { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of Webhooks configured
|
||||||
|
/// </summary>
|
||||||
|
public List<DiscordWebhook> Webhooks { get; set; } = new List<DiscordWebhook>();
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string FullTheme {
|
public string FullTheme {
|
||||||
get { return Theme + "." + Colour; }
|
get { return Theme + "." + Colour; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace EliteBGS.Util {
|
namespace EliteBGS.Util {
|
||||||
public class Config {
|
public class Config {
|
||||||
|
13
EliteBGS/Util/DiscordWebhook.cs
Normal file
13
EliteBGS/Util/DiscordWebhook.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace EliteBGS.Util;
|
||||||
|
|
||||||
|
public class DiscordWebhook {
|
||||||
|
/// <summary>
|
||||||
|
/// Webhook URL
|
||||||
|
/// </summary>
|
||||||
|
public string Webhook { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Human readable name for easier identification
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
BIN
EliteBGS/combatzone.png
Normal file
BIN
EliteBGS/combatzone.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
Binary file not shown.
Before Width: | Height: | Size: 68 KiB |
@ -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:
|
|
||||||
|
|
||||||

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

|
|
||||||
|
|
||||||
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.
|
|
@ -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
|
|
||||||
hip. 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.
|
|
@ -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.4** 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.4.zip](https://bgs.n0la.org/elitebgs-0.3.4.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.
|
|
Binary file not shown.
Before Width: | Height: | Size: 67 KiB |
Binary file not shown.
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 74 KiB |
@ -1,15 +0,0 @@
|
|||||||
site_name: EliteBGS
|
|
||||||
|
|
||||||
markdown_extensions:
|
|
||||||
- pymdownx.snippets:
|
|
||||||
check_paths: true
|
|
||||||
|
|
||||||
theme:
|
|
||||||
name: lumen
|
|
||||||
|
|
||||||
nav:
|
|
||||||
- Overview: 'index.md'
|
|
||||||
- "Detailed Description": 'description.md'
|
|
||||||
- "Combat Zones": 'combatzones.md'
|
|
||||||
- FAQ: 'faq.md'
|
|
||||||
- Changelog: 'CHANGELOG.md'
|
|
@ -3,7 +3,7 @@
|
|||||||
EDBGS is a project containing the EliteBGS BGS application. It also contains the dotnet
|
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.
|
class library EDPlayerJournal, which reads and parses Elite Dangerous player journals.
|
||||||
|
|
||||||
See [https://bgs.n0la.org/](https://bgs.n0la.org) for further details.
|
See [https://salusinvicta.org/bgstool/](https://salusinvicta.org/bgstool/) for further details.
|
||||||
|
|
||||||
The tool helps with creating BGS reports for squadrons that support factions in
|
The tool helps with creating BGS reports for squadrons that support factions in
|
||||||
Elite: Dangerous that can be copy and pasted into a Discord server. It finds all BGS
|
Elite: Dangerous that can be copy and pasted into a Discord server. It finds all BGS
|
||||||
|
Loading…
x
Reference in New Issue
Block a user