using EDPlayerJournal.Entries; namespace EDPlayerJournal.BGS; internal class TransactionParserContext { /// <summary> /// Name of the current system the player is in. /// </summary> public string? CurrentSystem { get; set; } /// <summary> /// 64 bit address of the current system. /// </summary> public ulong? CurrentSystemAddress { get; set; } /// <summary> /// Controlling faction of the current system. /// </summary> public string? ControllingFaction { get; set; } /// <summary> /// Name of the current station the player is docked at. /// </summary> public string? CurrentStation { get; set; } /// <summary> /// Faction that owns the current station. /// </summary> public string? StationOwner { get; set; } /// <summary> /// Whether the player is currently on foot, or in an SRV/ship. /// </summary> public bool IsOnFoot { get; set; } = false; /// <summary> /// Type of the current instance after a SupercruiseDestinationDropEntry. /// This is null if there is no current instance, or the current instance /// is not known. /// </summary> public string? CurrentInstanceType { get; set; } = null; /// <summary> /// Last faction that awarded the player with combat bonds. /// </summary> public string? LastRecordedAwardingFaction { get; set; } /// <summary> /// Highest combat bond seen so far. /// </summary> public ulong? HighestCombatBond { get; set; } public bool HaveSeenCapShip { get; set; } = false; public bool HaveSeenAlliedCaptain { get; set; } = false; public bool HaveSeenEnemyCaptain { get; set; } = false; public bool HaveSeenSpecOps { get; set; } = false; public bool HaveSeenAlliedCorrespondent { get; set; } = false; public bool HaveSeenEnemyCorrespondent { get; set; } = false; /// <summary> /// Current Odyssey settlement. /// </summary> public string? Settlement { get; set; } = null; /// <summary> /// Returns true if the current session is legacy /// </summary> public bool IsLegacy { get; set; } = false; /// <summary> /// How many on foot kills were done. /// </summary> public ulong OnFootKills { get; set; } = 0; /// <summary> /// How many ship kills were done. /// </summary> public ulong ShipKills { get; set; } = 0; /// <summary> /// Thargoid scouts killed /// </summary> public ulong ThargoidScoutKills { get; set; } = 0; /// <summary> /// Thargoid interceptor kills /// </summary> public ulong ThargoidInterceptorKills { get; set; } = 0; /// <summary> /// Whether we have seen an AX warzone NPC talk to us with ReceiveText /// </summary> public bool HaveSeenAXWarzoneNPC { get; set; } = false; /// <summary> /// A list of accepted missions index by their mission ID /// </summary> public Dictionary<ulong, Mission> AcceptedMissions { get; } = new(); public Dictionary<ulong, Location> AcceptedMissionLocation { get; } = new(); /// <summary> /// A way to lookup a system by its system id /// </summary> public Dictionary<ulong, string> SystemsByID { get; } = new(); /// <summary> /// A list of factions present in the given star system /// </summary> public Dictionary<string, List<Faction>> SystemFactions { get; } = new(); /// <summary> /// To which faction a given named NPC belonged to. /// </summary> public Dictionary<string, string> NPCFaction { get; } = new(); /// <summary> /// Buy costs for a given commodity /// </summary> public Dictionary<string, long> BuyCost = new(); /// <summary> /// Called when the player leaves an instance, either through logout, FSD jump or /// supercruise instance. /// </summary> public void LeftInstance() { CurrentInstanceType = null; Settlement = null; } public void DiscernCombatZone(TransactionList transactions, Entry e) { string? grade = CombatZones.DifficultyLow; string cztype; ulong highest = HighestCombatBond ?? 0; string? faction = LastRecordedAwardingFaction; if (HighestCombatBond == null && LastRecordedAwardingFaction == null && HaveSeenAXWarzoneNPC == false && CurrentInstanceType == null) { return; } if (OnFootKills > 0 || IsOnFoot == true) { cztype = CombatZones.GroundCombatZone; // High on foot combat zones have enforcers that bring 80k a pop if (highest >= 60000) { grade = CombatZones.DifficultyHigh; } else if (highest >= 30000) { // In medium conflict zones, the enforcers are worth 30k grade = CombatZones.DifficultyMedium; } else { grade = CombatZones.DifficultyLow; } } else if (CurrentInstanceType != null) { if (!Instances.IsWarzone(CurrentInstanceType)) { return; } if (LastRecordedAwardingFaction == null && Instances.IsHumanWarzone(CurrentInstanceType)) { transactions.AddIncomplete(new CombatZone(), "Could not discern for whom you fought for, " + "as it seems you haven't killed anyone in the ship combat zone.", e); return; } // If we have information about the current instance being a warship use that // information to determine the warzone. if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneLow)) { cztype = CombatZones.ShipCombatZone; grade = CombatZones.DifficultyLow; } else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneMedium)) { cztype = CombatZones.ShipCombatZone; grade = CombatZones.DifficultyMedium; } else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneHigh)) { cztype = CombatZones.ShipCombatZone; grade = CombatZones.DifficultyHigh; } else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidLow)) { cztype = CombatZones.AXCombatZone; grade = CombatZones.DifficultyLow; } else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidMedium)) { cztype = CombatZones.AXCombatZone; grade = CombatZones.DifficultyMedium; } else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidHigh)) { cztype = CombatZones.AXCombatZone; grade = CombatZones.DifficultyHigh; } else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidVeryHigh)) { cztype = CombatZones.AXCombatZone; grade = CombatZones.DifficultyVeryHigh; } else { transactions.AddIncomplete(new CombatZone(), "Unknown conflict zone difficulty", e); return; } } else if (ShipKills > 0 && !IsOnFoot) { // Ship combat zones can be identified by the amount of kills if (ShipKills > 20) { grade = CombatZones.DifficultyHigh; } else if (ShipKills > 10) { grade = CombatZones.DifficultyMedium; } // Cap ship, means a high conflict zone if (HaveSeenCapShip) { grade = CombatZones.DifficultyHigh; } else { int warzoneNpcs = new List<bool>() { HaveSeenEnemyCaptain, HaveSeenEnemyCorrespondent, HaveSeenSpecOps } .Where(x => x == true) .Count() ; if (warzoneNpcs >= 1 && grade == CombatZones.DifficultyLow) { grade = CombatZones.DifficultyMedium; } } cztype = CombatZones.ShipCombatZone; } else if ((ThargoidScoutKills > 0 && ThargoidInterceptorKills > 0) || HaveSeenAXWarzoneNPC == true) { // Could be a thargoid combat zones if interceptors and scouts are there cztype = CombatZones.AXCombatZone; // Still unknown grade = null; } else { transactions.AddIncomplete(new CombatZone(), "Failed to discern combat zone type", e); return; } CombatZone zone = new CombatZone() { System = CurrentSystem, Faction = faction, IsLegacy = IsLegacy, Settlement = Settlement, Grade = grade, Type = cztype, // Sad truth is, if HaveSeenXXX is false, we just don't know for certain CapitalShip = HaveSeenCapShip ? true : null, SpecOps = HaveSeenSpecOps ? true : null, EnemyCorrespondent = HaveSeenEnemyCorrespondent ? true : null, AlliedCorrespondent = HaveSeenAlliedCorrespondent ? true : null, EnemyCaptain = HaveSeenEnemyCaptain ? true : null, AlliedCaptain = HaveSeenAlliedCaptain ? true : null, }; zone.Entries.Add(e); transactions.Add(zone); } public void RecordCombatBond(FactionKillBondEntry e) { if (HighestCombatBond == null || e.Reward > HighestCombatBond) { HighestCombatBond = e.Reward; } LastRecordedAwardingFaction = e.AwardingFaction; if (IsOnFoot) { ++OnFootKills; } else { ++ShipKills; } } public void ResetCombatZone() { HighestCombatBond = null; HaveSeenCapShip = false; HaveSeenAlliedCaptain = false; HaveSeenEnemyCaptain = false; HaveSeenAlliedCorrespondent = false; HaveSeenEnemyCorrespondent = false; HaveSeenSpecOps = false; LastRecordedAwardingFaction = null; OnFootKills = 0; ShipKills = 0; ThargoidInterceptorKills = 0; ThargoidScoutKills = 0; HaveSeenAXWarzoneNPC = false; } public void BoughtCargo(string? cargo, long? cost) { if (cargo == null || cost == null) { return; } BuyCost[cargo] = cost.Value; } public List<Faction>? GetFactions(string? system) { if (system == null || !SystemFactions.ContainsKey(system)) { return null; } return SystemFactions[system]; } public void MissionAccepted(MissionAcceptedEntry? entry) { if (entry == null) { return; } MissionAccepted(entry.Mission); } public void MissionAccepted(Mission? mission) { if (CurrentSystem == null || CurrentSystemAddress == null) { throw new Exception("Mission accepted without knowing where."); } if (mission == null) { throw new Exception("Mission is null"); } AcceptedMissions.TryAdd(mission.MissionID, mission); Location location = new() { StarSystem = CurrentSystem, SystemAddress = CurrentSystemAddress.Value, Station = (CurrentStation ?? ""), }; AcceptedMissionLocation.TryAdd(mission.MissionID, location); } }