2021-07-09 11:03:30 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2021-08-25 16:36:57 +02:00
|
|
|
|
using EDJournal;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
|
2021-11-10 21:24:39 +01:00
|
|
|
|
namespace EliteBGS.BGS {
|
2021-07-09 11:03:30 +02:00
|
|
|
|
public class Report {
|
|
|
|
|
private List<Objective> objectives = new List<Objective>();
|
|
|
|
|
|
|
|
|
|
public delegate void OnLogDelegate(string log);
|
|
|
|
|
|
|
|
|
|
public event OnLogDelegate OnLog;
|
|
|
|
|
|
|
|
|
|
public List<Objective> Objectives {
|
|
|
|
|
get { return objectives; }
|
|
|
|
|
set { objectives = value; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool AddObjective(Objective objective) {
|
2021-07-09 11:30:11 +02:00
|
|
|
|
var found = objectives.Find(x => x.CompareTo(objective) == 0);
|
2021-07-09 11:03:30 +02:00
|
|
|
|
bool added = false;
|
|
|
|
|
|
|
|
|
|
if (found == null) {
|
|
|
|
|
objectives.Add(objective);
|
|
|
|
|
added = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return added;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-14 18:11:11 +01:00
|
|
|
|
public static bool IsRelevant(Entry e) {
|
2022-02-11 13:26:10 +01:00
|
|
|
|
return e.Is(Events.CommitCrime) ||
|
2021-07-09 11:03:30 +02:00
|
|
|
|
e.Is(Events.Docked) ||
|
2022-02-11 13:26:10 +01:00
|
|
|
|
e.Is(Events.FactionKillBond) ||
|
2021-07-09 11:03:30 +02:00
|
|
|
|
e.Is(Events.FSDJump) ||
|
2021-11-15 19:54:04 +01:00
|
|
|
|
e.Is(Events.Location) ||
|
2022-02-11 13:26:10 +01:00
|
|
|
|
e.Is(Events.MarketBuy) ||
|
|
|
|
|
e.Is(Events.MarketSell) ||
|
|
|
|
|
e.Is(Events.MissionAccepted) ||
|
|
|
|
|
e.Is(Events.MissionFailed) ||
|
2021-07-09 11:03:30 +02:00
|
|
|
|
e.Is(Events.MultiSellExplorationData) ||
|
2022-02-11 13:26:10 +01:00
|
|
|
|
e.Is(Events.RedeemVoucher) ||
|
2022-02-09 09:44:25 +01:00
|
|
|
|
e.Is(Events.SearchAndRescue) ||
|
2022-01-22 13:18:24 +01:00
|
|
|
|
e.Is(Events.SellExplorationData) ||
|
2021-07-09 11:03:30 +02:00
|
|
|
|
e.Is(Events.SellMicroResources) ||
|
2022-02-07 16:47:00 +01:00
|
|
|
|
e.Is(Events.SellOrganicData) ||
|
2022-02-11 13:26:10 +01:00
|
|
|
|
e.Is(Events.ShipTargeted) ||
|
|
|
|
|
e.Is(Events.MissionCompleted)
|
2021-07-09 11:03:30 +02:00
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Scan(PlayerJournal journal, DateTime start, DateTime end) {
|
2022-06-07 19:00:38 +02:00
|
|
|
|
/* Log files only get rotated if you restart the game client. This means that there might
|
|
|
|
|
* be - say - entries from the 4th of May in the file with a timestamp of 3rd of May. This
|
|
|
|
|
* happens if you happen to play a session late into the night.
|
|
|
|
|
* At first I tried extracting the first and last line of a file to see the date range, but
|
|
|
|
|
* if you have a lot of files this becomes quite slow, and quite the memory hog (as journal
|
|
|
|
|
* files have to be read in their entirety to check this). So we assume that you can't play
|
|
|
|
|
* three days straight, and keep the code fast.
|
|
|
|
|
*/
|
|
|
|
|
DateTime actualstart = start.AddDays(-3);
|
|
|
|
|
List<Entry> entries = journal.Files
|
|
|
|
|
.Where(f => f.NormalisedDateTime >= actualstart && f.NormalisedDateTime <= end)
|
|
|
|
|
.SelectMany(e => e.Entries)
|
|
|
|
|
.ToList()
|
|
|
|
|
;
|
|
|
|
|
// Now further sort the list down to entries that are actually within the given datetime
|
|
|
|
|
// Note that entry datetimes are not normalised, so we have to sort until end + 1 day
|
|
|
|
|
DateTime actualend = end.AddDays(1);
|
|
|
|
|
|
|
|
|
|
entries = entries
|
|
|
|
|
.Where(e => e.Timestamp >= start && e.Timestamp < actualend)
|
|
|
|
|
.ToList()
|
|
|
|
|
;
|
|
|
|
|
Scan(entries);
|
2022-01-23 15:52:19 +01:00
|
|
|
|
}
|
2021-07-09 11:03:30 +02:00
|
|
|
|
|
2022-01-23 15:52:19 +01:00
|
|
|
|
public void Scan(List<Entry> entries) {
|
|
|
|
|
if (entries.Count <= 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-11-12 22:23:40 +01:00
|
|
|
|
|
2022-02-11 13:26:10 +01:00
|
|
|
|
List<Entry> relevant = entries
|
|
|
|
|
.Where(x => IsRelevant(x))
|
|
|
|
|
.ToList()
|
|
|
|
|
;
|
|
|
|
|
|
2022-02-14 18:11:11 +01:00
|
|
|
|
Dictionary<ulong, MissionAcceptedEntry> acceptedMissions = new Dictionary<ulong, MissionAcceptedEntry>();
|
2022-01-26 09:58:23 +01:00
|
|
|
|
Dictionary<string, long> buyCost = new Dictionary<string, long>();
|
2022-01-27 23:21:34 +01:00
|
|
|
|
Dictionary<ulong, string> systems = new Dictionary<ulong, string>();
|
2022-02-11 13:26:10 +01:00
|
|
|
|
Dictionary<string, string> npcfactions = new Dictionary<string, string>();
|
2022-02-12 19:50:26 +01:00
|
|
|
|
Dictionary<string, List<Faction>> system_factions = new Dictionary<string, List<Faction>>();
|
2022-01-12 17:29:58 +01:00
|
|
|
|
|
2022-02-14 18:11:11 +01:00
|
|
|
|
// A dictionary resolving to a station at which each mission was accepted
|
|
|
|
|
Dictionary<ulong, string> acceptedStations = new Dictionary<ulong, string>();
|
|
|
|
|
// A dictionary resolving to a system at which each mission was accepted
|
|
|
|
|
Dictionary<ulong, ulong> acceptedSystems = new Dictionary<ulong, ulong>();
|
|
|
|
|
|
2021-07-09 11:03:30 +02:00
|
|
|
|
string current_system = null;
|
2022-01-27 23:21:34 +01:00
|
|
|
|
ulong current_system_address = 0;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
string current_station = null;
|
|
|
|
|
string controlling_faction = null;
|
|
|
|
|
|
2021-09-30 13:28:52 +02:00
|
|
|
|
objectives.ForEach(x => x.Clear());
|
2021-07-09 11:03:30 +02:00
|
|
|
|
|
2022-02-11 13:26:10 +01:00
|
|
|
|
foreach (Entry e in relevant) {
|
2022-01-21 20:03:17 +01:00
|
|
|
|
List<LogEntry> results = new List<LogEntry>();
|
2021-08-04 17:50:46 +02:00
|
|
|
|
bool collate = false;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
|
|
|
|
|
if (e.Is(Events.Docked)) {
|
2021-11-17 21:01:35 +01:00
|
|
|
|
DockedEntry docked = e as DockedEntry;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
/* gleem the current station from this message
|
|
|
|
|
*/
|
2021-11-17 21:01:35 +01:00
|
|
|
|
current_station = docked.StationName;
|
|
|
|
|
current_system = docked.StarSystem;
|
|
|
|
|
controlling_faction = docked.StationFaction;
|
2022-01-27 23:21:34 +01:00
|
|
|
|
current_system_address = docked.SystemAddress;
|
|
|
|
|
|
|
|
|
|
if (!systems.ContainsKey(docked.SystemAddress)) {
|
|
|
|
|
systems.Add(docked.SystemAddress, docked.StarSystem);
|
|
|
|
|
}
|
2021-07-09 11:03:30 +02:00
|
|
|
|
} else if (e.Is(Events.FSDJump)) {
|
2021-07-09 11:39:09 +02:00
|
|
|
|
/* Gleem current system and controlling faction from this message.
|
|
|
|
|
*/
|
2022-01-27 23:21:34 +01:00
|
|
|
|
FSDJumpEntry fsd = e as FSDJumpEntry;
|
|
|
|
|
current_system_address = fsd.SystemAddress;
|
|
|
|
|
current_system = fsd.StarSystem;
|
|
|
|
|
controlling_faction = fsd.SystemFaction;
|
|
|
|
|
|
|
|
|
|
if (!systems.ContainsKey(fsd.SystemAddress)) {
|
|
|
|
|
systems.Add(fsd.SystemAddress, fsd.StarSystem);
|
|
|
|
|
}
|
2022-02-12 19:50:26 +01:00
|
|
|
|
|
|
|
|
|
if (!system_factions.ContainsKey(fsd.StarSystem) &&
|
|
|
|
|
fsd.SystemFactions.Count > 0) {
|
|
|
|
|
system_factions[fsd.StarSystem] = fsd.SystemFactions;
|
|
|
|
|
}
|
2021-11-15 19:54:04 +01:00
|
|
|
|
} else if (e.Is(Events.Location)) {
|
|
|
|
|
/* Get current system, faction name and station from Location message
|
|
|
|
|
*/
|
|
|
|
|
LocationEntry location = e as LocationEntry;
|
|
|
|
|
|
|
|
|
|
current_system = location.StarSystem;
|
2022-01-27 23:21:34 +01:00
|
|
|
|
current_system_address = location.SystemAddress;
|
|
|
|
|
|
|
|
|
|
if (!systems.ContainsKey(location.SystemAddress)) {
|
|
|
|
|
systems.Add(location.SystemAddress, location.StarSystem);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-15 19:54:04 +01:00
|
|
|
|
if (!string.IsNullOrEmpty(location.SystemFaction)) {
|
|
|
|
|
controlling_faction = location.SystemFaction;
|
|
|
|
|
}
|
|
|
|
|
if (!string.IsNullOrEmpty(location.StationName)) {
|
|
|
|
|
current_station = location.StationName;
|
|
|
|
|
}
|
2022-02-12 19:50:26 +01:00
|
|
|
|
|
|
|
|
|
if (!system_factions.ContainsKey(location.StarSystem) &&
|
|
|
|
|
location.SystemFactions.Count > 0) {
|
|
|
|
|
system_factions[location.StarSystem] = location.SystemFactions;
|
|
|
|
|
}
|
2022-02-11 13:26:10 +01:00
|
|
|
|
} else if (e.Is(Events.ShipTargeted)) {
|
|
|
|
|
ShipTargetedEntry targeted = e as ShipTargetedEntry;
|
|
|
|
|
|
2022-02-12 16:22:08 +01:00
|
|
|
|
if (string.IsNullOrEmpty(targeted.PilotNameLocalised) ||
|
2022-02-11 13:26:10 +01:00
|
|
|
|
string.IsNullOrEmpty(targeted.Faction)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-12 16:22:08 +01:00
|
|
|
|
npcfactions[targeted.PilotNameLocalised] = targeted.Faction;
|
2022-01-23 17:05:43 +01:00
|
|
|
|
} else if (e.Is(Events.CommitCrime)) {
|
|
|
|
|
CommitCrimeEntry crime = e as CommitCrimeEntry;
|
2022-02-11 13:26:10 +01:00
|
|
|
|
string faction = crime.Faction;
|
2022-01-23 17:05:43 +01:00
|
|
|
|
|
|
|
|
|
if (!crime.IsMurder) {
|
|
|
|
|
/* we don't care about anything but murder for now */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-12 16:22:08 +01:00
|
|
|
|
/* use localised victim name if we have it, otherwise use normal name */
|
|
|
|
|
string victim = crime.VictimLocalised;
|
|
|
|
|
if (string.IsNullOrEmpty(victim)) {
|
|
|
|
|
victim = crime.Victim;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!npcfactions.ContainsKey(victim)) {
|
2022-02-11 13:26:10 +01:00
|
|
|
|
/* The faction in the crime report is the faction that issues the bounty,
|
|
|
|
|
* and not the faction of the victim.
|
|
|
|
|
*/
|
|
|
|
|
OnLog?.Invoke(string.Format(
|
|
|
|
|
"No faction found for victim \"{0}\", using faction that issued the bounty instead.",
|
2022-02-12 16:22:08 +01:00
|
|
|
|
victim, crime.Faction
|
2022-02-11 13:26:10 +01:00
|
|
|
|
));
|
|
|
|
|
} else {
|
2022-02-12 16:22:08 +01:00
|
|
|
|
faction = npcfactions[victim];
|
2022-02-11 13:26:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-23 17:05:43 +01:00
|
|
|
|
results.Add(new FoulMurder(crime) {
|
|
|
|
|
System = current_system,
|
2022-02-11 13:26:10 +01:00
|
|
|
|
Faction = faction,
|
2022-01-23 17:05:43 +01:00
|
|
|
|
});
|
|
|
|
|
collate = true;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
} else if (e.Is(Events.MissionCompleted)) {
|
2022-02-14 18:11:11 +01:00
|
|
|
|
MissionCompletedEntry completed = e as MissionCompletedEntry;
|
2022-02-14 19:12:46 +01:00
|
|
|
|
MissionAcceptedEntry accepted = null;
|
|
|
|
|
MissionCompleted main_mission = null;
|
2022-02-26 10:58:09 +01:00
|
|
|
|
ulong accepted_address;
|
|
|
|
|
string accepted_system;
|
|
|
|
|
|
|
|
|
|
string target_faction_name = completed.TargetFaction;
|
|
|
|
|
string source_faction_name = completed.Faction;
|
2022-02-14 18:11:11 +01:00
|
|
|
|
|
|
|
|
|
if (!acceptedMissions.TryGetValue(completed.MissionID, out accepted)) {
|
|
|
|
|
OnLog?.Invoke(string.Format(
|
|
|
|
|
"Unable to find mission acceptance for mission \"{0}\". " +
|
|
|
|
|
"Please extend range to include the mission acceptance.", completed.HumanReadableName
|
|
|
|
|
));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-26 10:58:09 +01:00
|
|
|
|
if (!acceptedSystems.TryGetValue(completed.MissionID, out accepted_address)) {
|
|
|
|
|
OnLog?.Invoke(string.Format(
|
|
|
|
|
"Unable to figure out in which system mission \"{0}\" was accepted.", completed.HumanReadableName
|
|
|
|
|
));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!systems.TryGetValue(accepted_address, out accepted_system)) {
|
|
|
|
|
OnLog?.Invoke(string.Format(
|
|
|
|
|
"Unable to figure out in which system mission \"{0}\" was accepted.", completed.HumanReadableName
|
|
|
|
|
));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 11:03:30 +02:00
|
|
|
|
if (completed.HumanReadableNameWasGenerated) {
|
2021-07-09 11:39:09 +02:00
|
|
|
|
/* If the human readable name was generated, we send a log message. Because the
|
|
|
|
|
* generated names all sort of suck, we should have more human readable names in
|
|
|
|
|
* in the lookup dictionary.
|
|
|
|
|
*/
|
2021-07-09 11:03:30 +02:00
|
|
|
|
OnLog?.Invoke("Human readable name for mission \"" +
|
|
|
|
|
completed.Name +
|
|
|
|
|
"\" was generated, please report this.");
|
|
|
|
|
}
|
2022-01-21 20:34:56 +01:00
|
|
|
|
|
2022-01-29 10:48:49 +01:00
|
|
|
|
foreach (var other in completed.Influences) {
|
|
|
|
|
string faction = other.Key;
|
|
|
|
|
if (string.IsNullOrEmpty(faction)) {
|
2022-02-24 22:40:00 +01:00
|
|
|
|
OnLog?.Invoke(string.Format(
|
|
|
|
|
"Mission \"{0}\" has empty faction name in influence block, "+
|
|
|
|
|
"so this influence support was ignored. " +
|
|
|
|
|
"Please check the README on why this happens.", completed.HumanReadableName)
|
|
|
|
|
);
|
2022-01-29 10:48:49 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-02-24 22:40:00 +01:00
|
|
|
|
|
|
|
|
|
/* Now comes the fun part. Sometimes the influence list is empty for a faction.
|
|
|
|
|
* This happens if the faction in question
|
|
|
|
|
*/
|
|
|
|
|
if (other.Value.Count() == 0) {
|
|
|
|
|
OnLog?.Invoke(string.Format(
|
|
|
|
|
"Mission \"{0}\" gave no influence to \"{1}\", so we assume this is because the " +
|
|
|
|
|
"faction is in a conflict and cannot gain influence right now. " +
|
|
|
|
|
"If this assessment is wrong, just remove the entry from the objective list.",
|
|
|
|
|
completed.HumanReadableName, faction
|
|
|
|
|
));
|
2022-02-14 18:11:11 +01:00
|
|
|
|
|
2022-02-26 10:58:09 +01:00
|
|
|
|
if (string.Compare(target_faction_name, faction, true) == 0) {
|
|
|
|
|
/* here we assume that if the faction in question is the target faction,
|
|
|
|
|
* that we gave said target faction no influence in the target system, aka
|
|
|
|
|
* current system
|
|
|
|
|
*/
|
|
|
|
|
other.Value.Add(current_system_address, "");
|
2022-02-14 18:11:11 +01:00
|
|
|
|
OnLog?.Invoke(string.Format(
|
2022-02-26 10:58:09 +01:00
|
|
|
|
"Mission \"{0}\" gave no influence to \"{1}\". Since \"{1}\" is the target faction " +
|
|
|
|
|
"of the mission, we assume the influence was gained in \"{2}\". " +
|
|
|
|
|
"Please remove the entry if this assumption is wrong.",
|
|
|
|
|
completed.HumanReadableName, faction, current_system
|
2022-02-14 18:11:11 +01:00
|
|
|
|
));
|
2022-02-26 10:58:09 +01:00
|
|
|
|
} else if (string.Compare(source_faction_name, faction, true) == 0) {
|
|
|
|
|
/* source faction of the mission is not getting any influence. This could be because
|
|
|
|
|
* the source faction is in an election state in its home system and cannot gain any
|
|
|
|
|
* influence. It may also very well be that the source and target faction are the same
|
|
|
|
|
* since the faction is present in both target and source system. In which case we add
|
|
|
|
|
* both and hope for the best.
|
|
|
|
|
*/
|
|
|
|
|
other.Value.Add(accepted_address, "");
|
2022-02-14 18:11:11 +01:00
|
|
|
|
OnLog?.Invoke(string.Format(
|
2022-02-26 10:58:09 +01:00
|
|
|
|
"Mission \"{0}\" gave no influence to \"{1}\". Since \"{1}\" is the source faction " +
|
|
|
|
|
"of the mission, we assume the influence was gained in \"{2}\". " +
|
|
|
|
|
"Please remove the entry if this assumption is wrong.",
|
|
|
|
|
completed.HumanReadableName, faction, accepted_system
|
2022-02-14 18:11:11 +01:00
|
|
|
|
));
|
2022-02-26 10:58:09 +01:00
|
|
|
|
|
|
|
|
|
/* check if source/target faction are equal, in which case we also need an entry
|
|
|
|
|
* for the target system. As said factions can be present in two systems, and can
|
|
|
|
|
* give missions that target each other.
|
|
|
|
|
*/
|
|
|
|
|
if (string.Compare(source_faction_name, target_faction_name, true) == 0) {
|
|
|
|
|
other.Value.Add(current_system_address, "");
|
|
|
|
|
OnLog?.Invoke(string.Format(
|
|
|
|
|
"Mission \"{0}\" gave no influence to \"{1}\". Since \"{1}\" is the source and target faction " +
|
|
|
|
|
"of the mission, we assume the influence was also gained in target system \"{2}\". " +
|
|
|
|
|
"Please remove the entry if this assumption is wrong.",
|
|
|
|
|
completed.HumanReadableName, faction, current_system
|
|
|
|
|
));
|
|
|
|
|
}
|
2022-02-14 18:11:11 +01:00
|
|
|
|
}
|
2022-02-26 10:58:09 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var influences in other.Value) {
|
|
|
|
|
ulong system_address = influences.Key;
|
|
|
|
|
string system, accepted_station;
|
2022-02-14 18:11:11 +01:00
|
|
|
|
|
2022-02-26 10:58:09 +01:00
|
|
|
|
if (!systems.TryGetValue(system_address, out system)) {
|
2022-02-14 18:11:11 +01:00
|
|
|
|
OnLog?.Invoke(string.Format(
|
2022-02-26 10:58:09 +01:00
|
|
|
|
"Unknown system \"{0}\" unable to assign that mission a target.", system_address
|
2022-02-14 18:11:11 +01:00
|
|
|
|
));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!acceptedStations.TryGetValue(completed.MissionID, out accepted_station)) {
|
|
|
|
|
OnLog?.Invoke(string.Format(
|
2022-02-18 13:38:47 +01:00
|
|
|
|
"Unable to figure out in which station mission \"{0}\" was accepted.", completed.HumanReadableName
|
2022-02-14 18:11:11 +01:00
|
|
|
|
));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-26 10:58:09 +01:00
|
|
|
|
if (faction.Equals(source_faction_name) && system_address == accepted_address) {
|
2022-02-14 18:11:11 +01:00
|
|
|
|
/* This is the influence block for the origin of the mission.
|
|
|
|
|
*/
|
2022-02-14 19:12:46 +01:00
|
|
|
|
main_mission = new MissionCompleted(completed) {
|
2022-02-14 18:11:11 +01:00
|
|
|
|
System = accepted_system,
|
2022-02-26 10:58:09 +01:00
|
|
|
|
Faction = source_faction_name,
|
2022-02-14 18:11:11 +01:00
|
|
|
|
SystemAddress = accepted_address,
|
|
|
|
|
Station = accepted_station,
|
2022-02-14 19:12:46 +01:00
|
|
|
|
};
|
|
|
|
|
results.Add(main_mission);
|
2022-02-26 10:58:09 +01:00
|
|
|
|
} else if (!faction.Equals(source_faction_name) ||
|
|
|
|
|
(faction.Equals(source_faction_name) && system_address != accepted_address)) {
|
2022-02-14 18:11:11 +01:00
|
|
|
|
/* This block is for secondary factions (first if), or if the secondary faction
|
|
|
|
|
* is the same as the mission giver, but in another system (second if).
|
|
|
|
|
*/
|
2022-01-29 10:48:49 +01:00
|
|
|
|
results.Add(new InfluenceSupport() {
|
|
|
|
|
Faction = faction,
|
|
|
|
|
Influence = influences.Value,
|
|
|
|
|
System = system,
|
|
|
|
|
SystemAddress = system_address,
|
2022-02-26 10:58:09 +01:00
|
|
|
|
RelevantMission = completed
|
2022-01-29 10:48:49 +01:00
|
|
|
|
});
|
2022-01-27 23:21:34 +01:00
|
|
|
|
}
|
2022-01-26 09:32:23 +01:00
|
|
|
|
}
|
2022-01-21 20:34:56 +01:00
|
|
|
|
}
|
2021-11-12 22:23:40 +01:00
|
|
|
|
} else if (e.Is(Events.MissionAccepted)) {
|
|
|
|
|
MissionAcceptedEntry accepted = e as MissionAcceptedEntry;
|
2022-02-14 18:11:11 +01:00
|
|
|
|
ulong id = accepted.MissionID;
|
|
|
|
|
if (!acceptedMissions.ContainsKey(id)) {
|
|
|
|
|
acceptedMissions[id] = accepted;
|
|
|
|
|
}
|
|
|
|
|
if (!acceptedStations.ContainsKey(id)) {
|
|
|
|
|
acceptedStations[id] = current_station;
|
|
|
|
|
}
|
|
|
|
|
if (!acceptedSystems.ContainsKey(id)) {
|
|
|
|
|
acceptedSystems[id] = current_system_address;
|
|
|
|
|
}
|
2021-11-12 22:23:40 +01:00
|
|
|
|
} else if (e.Is(Events.MissionFailed)) {
|
2022-02-18 13:38:47 +01:00
|
|
|
|
MissionFailedEntry failed = e as MissionFailedEntry;
|
2022-01-06 16:15:13 +01:00
|
|
|
|
MissionAcceptedEntry accepted = null;
|
2022-02-18 13:38:47 +01:00
|
|
|
|
ulong accepted_address = 0;
|
|
|
|
|
string accepted_system;
|
|
|
|
|
string accepted_station;
|
|
|
|
|
|
2022-01-06 16:15:13 +01:00
|
|
|
|
if (!acceptedMissions.TryGetValue(failed.MissionID, out accepted)) {
|
2022-01-09 13:11:53 +01:00
|
|
|
|
OnLog?.Invoke("A mission failed which wasn't accepted in the given time frame. " +
|
|
|
|
|
"Please adjust start date to when the mission was accepted to include it in the list.");
|
2021-11-12 22:23:40 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-02-18 13:38:47 +01:00
|
|
|
|
|
|
|
|
|
if (!acceptedSystems.TryGetValue(failed.MissionID, out accepted_address)) {
|
|
|
|
|
OnLog?.Invoke(string.Format(
|
|
|
|
|
"Unable to figure out in which system mission \"{0}\" was accepted.", accepted.Name
|
|
|
|
|
));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!systems.TryGetValue(accepted_address, out accepted_system)) {
|
|
|
|
|
OnLog?.Invoke(string.Format(
|
|
|
|
|
"Unable to figure out in which system mission \"{0}\" was accepted.", accepted.Name
|
|
|
|
|
));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!acceptedStations.TryGetValue(failed.MissionID, out accepted_station)) {
|
|
|
|
|
OnLog?.Invoke(string.Format(
|
|
|
|
|
"Unable to figure out in which station mission \"{0}\" was accepted.", accepted.Name
|
|
|
|
|
));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
results.Add(new MissionFailed(accepted) {
|
|
|
|
|
Failed = failed,
|
|
|
|
|
System = accepted_system,
|
|
|
|
|
Station = accepted_station,
|
|
|
|
|
Faction = accepted.Faction,
|
|
|
|
|
SystemAddress = accepted_address,
|
|
|
|
|
});
|
|
|
|
|
|
2021-11-12 22:23:40 +01:00
|
|
|
|
if (failed.HumanReadableName == null) {
|
|
|
|
|
OnLog?.Invoke("Human readable name for mission \"" +
|
|
|
|
|
failed.Name +
|
|
|
|
|
"\" was not recognised");
|
|
|
|
|
}
|
2022-01-10 18:58:50 +01:00
|
|
|
|
|
|
|
|
|
/* Mission failed should be collated if they are in the same system/station
|
|
|
|
|
*/
|
|
|
|
|
collate = true;
|
2022-01-22 13:18:24 +01:00
|
|
|
|
} else if (e.Is(Events.SellExplorationData)) {
|
|
|
|
|
results.Add(new Cartographics(e as SellExplorationDataEntry) {
|
|
|
|
|
System = current_system,
|
|
|
|
|
Station = current_station,
|
|
|
|
|
Faction = controlling_faction,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/* colate single cartographic selling into one */
|
2022-02-07 16:47:00 +01:00
|
|
|
|
collate = true;
|
|
|
|
|
} else if (e.Is(Events.SellOrganicData)) {
|
|
|
|
|
/* organic data sold to Vista Genomics */
|
|
|
|
|
results.Add(new OrganicData(e as SellOrganicDataEntry) {
|
|
|
|
|
System = current_system,
|
|
|
|
|
Station = current_station,
|
|
|
|
|
Faction = controlling_faction,
|
|
|
|
|
});
|
|
|
|
|
|
2022-01-22 13:18:24 +01:00
|
|
|
|
collate = true;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
} else if (e.Is(Events.MultiSellExplorationData)) {
|
2021-07-09 11:39:09 +02:00
|
|
|
|
/* For multi-sell-exploraton-data only the controlling faction of the station sold to matters.
|
|
|
|
|
*/
|
2022-01-21 20:03:17 +01:00
|
|
|
|
results.Add(new Cartographics(e as MultiSellExplorationDataEntry) {
|
|
|
|
|
System = current_system,
|
|
|
|
|
Station = current_station,
|
|
|
|
|
Faction = controlling_faction
|
|
|
|
|
});
|
2022-01-22 13:18:24 +01:00
|
|
|
|
|
|
|
|
|
collate = true;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
} else if (e.Is(Events.RedeemVoucher)) {
|
2022-02-12 19:50:26 +01:00
|
|
|
|
RedeemVoucherEntry voucher = e as RedeemVoucherEntry;
|
|
|
|
|
List<Faction> current_factions = new List<Faction>();
|
|
|
|
|
|
|
|
|
|
if (system_factions.ContainsKey(current_system)) {
|
|
|
|
|
current_factions = system_factions[current_system];
|
|
|
|
|
} else {
|
|
|
|
|
OnLog?.Invoke("There are no current system factions, so turned in vouchers were ignored.");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (string faction in voucher.Factions) {
|
|
|
|
|
if (current_factions.Find(x => x.Name == faction) == null) {
|
|
|
|
|
OnLog?.Invoke(
|
|
|
|
|
string.Format("Vouchers for \"{0}\" were ignored in \"{1}\" since said " +
|
|
|
|
|
"faction is not present there.", faction, current_system)
|
|
|
|
|
);
|
|
|
|
|
continue; /* faction is not present, so it is ignored */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Same for selling combat vouchers. Only the current controlling faction matters here.
|
|
|
|
|
*/
|
|
|
|
|
results.Add(new Vouchers(voucher) {
|
|
|
|
|
System = current_system,
|
|
|
|
|
Station = current_station,
|
|
|
|
|
Faction = faction,
|
|
|
|
|
ControllingFaction = controlling_faction,
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-09-28 13:20:59 +02:00
|
|
|
|
|
2021-08-04 17:50:46 +02:00
|
|
|
|
collate = true;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
} else if (e.Is(Events.SellMicroResources)) {
|
2022-01-21 20:03:17 +01:00
|
|
|
|
results.Add(new SellMicroResources(e as SellMicroResourcesEntry) {
|
2021-10-07 09:02:34 +02:00
|
|
|
|
Faction = controlling_faction,
|
|
|
|
|
Station = current_station,
|
|
|
|
|
System = current_system
|
2022-01-21 20:03:17 +01:00
|
|
|
|
});
|
2022-01-12 17:29:58 +01:00
|
|
|
|
} else if (e.Is(Events.MarketBuy)) {
|
|
|
|
|
MarketBuyEntry buy = e as MarketBuyEntry;
|
|
|
|
|
if (string.IsNullOrEmpty(buy.Type) || buy.BuyPrice == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
buyCost[buy.Type] = buy.BuyPrice;
|
2022-01-26 09:58:23 +01:00
|
|
|
|
|
|
|
|
|
results.Add(new BuyCargo(buy) {
|
|
|
|
|
Faction = controlling_faction,
|
2022-02-09 09:44:25 +01:00
|
|
|
|
Station = current_station,
|
|
|
|
|
System = current_system,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
collate = true;
|
|
|
|
|
} else if (e.Is(Events.SearchAndRescue)) {
|
|
|
|
|
results.Add(new SearchAndRescue(e as SearchAndRescueEntry) {
|
|
|
|
|
Faction = controlling_faction,
|
2022-01-26 09:58:23 +01:00
|
|
|
|
Station = current_station,
|
|
|
|
|
System = current_system,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
collate = true;
|
2021-09-28 14:41:09 +02:00
|
|
|
|
} else if (e.Is(Events.MarketSell)) {
|
2022-01-12 17:29:58 +01:00
|
|
|
|
MarketSellEntry sell = e as MarketSellEntry;
|
2022-01-26 09:58:23 +01:00
|
|
|
|
long profit = 0;
|
2022-01-12 17:29:58 +01:00
|
|
|
|
|
|
|
|
|
if (!buyCost.ContainsKey(sell.Type)) {
|
|
|
|
|
OnLog?.Invoke("Could not find buy order for the given commodity. Please adjust profit manually.");
|
|
|
|
|
} else {
|
2022-01-26 09:58:23 +01:00
|
|
|
|
long avg = buyCost[sell.Type];
|
|
|
|
|
profit = (long)sell.TotalSale - (avg * sell.Count);
|
2022-01-12 17:29:58 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-21 20:03:17 +01:00
|
|
|
|
results.Add(new SellCargo(e as MarketSellEntry) {
|
2021-09-28 14:41:09 +02:00
|
|
|
|
Faction = controlling_faction,
|
|
|
|
|
Station = current_station,
|
2022-01-12 17:29:58 +01:00
|
|
|
|
System = current_system,
|
|
|
|
|
Profit = profit
|
2022-01-21 20:03:17 +01:00
|
|
|
|
});
|
2021-07-09 11:03:30 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-21 20:03:17 +01:00
|
|
|
|
if (results == null || results.Count <= 0) {
|
2021-07-09 11:03:30 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-21 20:03:17 +01:00
|
|
|
|
foreach (LogEntry entry in results) {
|
|
|
|
|
/* Find all objectives that generally match.
|
2021-11-15 19:54:04 +01:00
|
|
|
|
*/
|
2022-01-21 20:03:17 +01:00
|
|
|
|
var matches = objectives
|
2022-01-29 16:18:28 +01:00
|
|
|
|
.Where(x => x.Matches(entry) >= 2)
|
2021-11-15 19:54:04 +01:00
|
|
|
|
.OrderBy(x => x.Matches(entry))
|
|
|
|
|
;
|
2021-08-04 17:50:46 +02:00
|
|
|
|
|
2022-01-21 20:03:17 +01:00
|
|
|
|
Objective objective = null;
|
|
|
|
|
if (matches != null && matches.Count() > 0) {
|
|
|
|
|
/* Then select the one that matches the most.
|
|
|
|
|
*/
|
|
|
|
|
objective = matches
|
|
|
|
|
.OrderBy(x => x.Matches(entry))
|
|
|
|
|
.Reverse()
|
|
|
|
|
.First()
|
|
|
|
|
;
|
|
|
|
|
} else {
|
|
|
|
|
/* create a new objective if we don't have one */
|
|
|
|
|
objective = new Objective() {
|
|
|
|
|
Station = entry.Station,
|
|
|
|
|
Faction = entry.Faction,
|
|
|
|
|
System = entry.System,
|
|
|
|
|
};
|
|
|
|
|
objectives.Add(objective);
|
2021-11-10 21:24:39 +01:00
|
|
|
|
}
|
2021-09-30 13:32:31 +02:00
|
|
|
|
|
2022-01-21 20:03:17 +01:00
|
|
|
|
LogEntry existing = null;
|
|
|
|
|
|
|
|
|
|
existing = objective.LogEntries.Find(x => {
|
|
|
|
|
try {
|
|
|
|
|
return x.CompareTo(entry) == 0;
|
|
|
|
|
} catch (NotImplementedException) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (collate && existing != null) {
|
|
|
|
|
existing.Entries.Add(e);
|
|
|
|
|
} else if (!collate || existing == null) {
|
|
|
|
|
objective.LogEntries.Add(entry);
|
|
|
|
|
}
|
2021-07-09 11:03:30 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Scan(PlayerJournal journal) {
|
|
|
|
|
Scan(journal, DateTime.Now, DateTime.Now);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|