Decompiled source of PostalExpansion v1.1.2
BepInEx/plugins/PostalExpansion/PostalExpansion.dll
Decompiled 24 minutes ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("PostalExpansion")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.1.0")] [assembly: AssemblyInformationalVersion("1.1.1")] [assembly: AssemblyProduct("PostalExpansion")] [assembly: AssemblyTitle("PostalExpansion")] [assembly: AssemblyVersion("1.1.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PostalExpansion { internal sealed class AestraAbbeyGraveRobberTableMission : RegisteredLetterMissionDefinition { internal static readonly AestraAbbeyGraveRobberTableMission Instance = new AestraAbbeyGraveRobberTableMission(); private AestraAbbeyGraveRobberTableMission() : base("aestra_abbey_grave_robber_table", "Aestra Abbey", 26, new Vector3(232.158f, -0.924f, 194.327f), new Vector3(0f, 136.291f, 0f), new Vector3(2f, 2f, 2f), LetterDeliveryWindow.Day, new int[2] { 18, 6 }, "Table of grave robber") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { int originPortIndex = LetterMissionDefinition.GetOriginPortIndex(mission); if (originPortIndex == 6 || originPortIndex == 18) { return "(You put the letter under the table)"; } return UnexpectedOrigin(mission); } } internal sealed class AestraAbbeyMainAbbeyMission : RegisteredLetterMissionDefinition { internal static readonly AestraAbbeyMainAbbeyMission Instance = new AestraAbbeyMainAbbeyMission(); private AestraAbbeyMainAbbeyMission() : base("aestra_abbey_main_abbey", "Aestra Abbey", 26, new Vector3(-117.4f, 56.962f, -81.718f), new Vector3(0f, 220.653f, 0f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Day, new int[3] { 28, 21, 10 }, "Abbey") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { return LetterMissionDefinition.GetOriginPortIndex(mission) switch { 28 => "Castigo corpus meum.", 21 => "A solis ortus cardine.", 10 => "Pacem in terries.", _ => UnexpectedOrigin(mission), }; } } internal sealed class AestraAbbeyOracleBenchMission : AnonymousLetterMissionDefinition { internal static readonly AestraAbbeyOracleBenchMission Instance = new AestraAbbeyOracleBenchMission(); private AestraAbbeyOracleBenchMission() : base("aestra_abbey_oracle_bench", "Aestra Abbey", 26, new Vector3(-129.328f, -1.928f, 1355.791f), new Vector3(0f, 257.793f, 0f), new Vector3(2.5f, 2.5f, 2.5f), 1362.3f, new LetterDeliveryWindow(19f, 7f, "19-07"), new int[3] { 24, 29, 27 }, "Oracle bench") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { return LetterMissionDefinition.GetOriginPortIndex(mission) switch { 24 => "(Letter open by itself once you approach one of the shrooms, showing totemic pattern before flying away. Closest shroom is gone)", 29 => "(The letter tries to let out the light but it got put out by shrooms quickly.)", 27 => "(You place the letter on bench. You heard a pleasent chime.)", _ => UnexpectedOrigin(mission), }; } } internal sealed class AlAnkhAcademyKeyKeeperMission : RegisteredLetterMissionDefinition { internal static readonly AlAnkhAcademyKeyKeeperMission Instance = new AlAnkhAcademyKeyKeeperMission(); private AlAnkhAcademyKeyKeeperMission() : base("al_ankh_academy_key_keeper", "Al'Ankh Academy", 5, new Vector3(-0.173f, 0.833f, 1.175f), new Vector3(0f, 170.709f, 0f), new Vector3(2f, 2f, 2f), LetterDeliveryWindow.Day, new int[11] { 0, 6, 32, 16, 9, 10, 25, 22, 23, 15, 21 }, "Key Keeper") { }//IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 0: case 6: case 9: case 15: case 22: case 23: return "Endless applications... I need a day off."; case 32: return "Oh! Ibn Doraid will be interested in this!"; case 16: return "These glasses cost a big fortune for sure."; case 10: case 25: return "These ideas are... interesting."; case 21: return "(Whistles) Your journey must have been eventful."; default: return UnexpectedOrigin(mission); } } } internal sealed class AlbacoreTownCreepyGuyMission : RegisteredLetterMissionDefinition { internal static readonly AlbacoreTownCreepyGuyMission Instance = new AlbacoreTownCreepyGuyMission(); private AlbacoreTownCreepyGuyMission() : base("albacore_town_creepy_guy", "Albacore Town", 3, new Vector3(40.721f, 3.318f, -50.81f), new Vector3(0f, 55.492f, 0f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Night, new int[3] { 15, 12, 25 }, "Creepy guy") { }//IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 12: case 15: return "Were you seen? You'd better not."; case 25: return "This makes me homesick... but I need to know where the fishing ground is."; default: return UnexpectedOrigin(mission); } } } internal sealed class AlchemistsIslandApprenticeMission : RegisteredLetterMissionDefinition { internal static readonly AlchemistsIslandApprenticeMission Instance = new AlchemistsIslandApprenticeMission(); private AlchemistsIslandApprenticeMission() : base("alchemists_island_apprentice", "Alchemist's Island", 4, new Vector3(-0.235f, 0.336f, 14.538f), new Vector3(0f, 35.018f, 0f), new Vector3(3f, 3f, 3f), LetterDeliveryWindow.Day, new int[12] { 0, 6, 32, 5, 20, 9, 10, 25, 22, 19, 28, 21 }, "Alchemist's apprentice") { }//IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 0: case 6: case 9: case 20: case 22: case 32: return "I will inform my mentor about this. Thank you."; case 5: return "This again... When will they stop trying?"; case 10: case 25: return "That's... a brilliant idea! I need to tell my mentor now!"; case 19: case 28: return "Your God cannot help the exhausted miners? Heh."; case 21: return "...Really?"; default: return UnexpectedOrigin(mission); } } } internal sealed class AlNilemLionsFangObeliskMission : AnonymousLetterMissionDefinition { internal static readonly AlNilemLionsFangObeliskMission Instance = new AlNilemLionsFangObeliskMission(); private AlNilemLionsFangObeliskMission() : base("al_nilem_lions_fang_obelisk", "Al'Nilem", 1, new Vector3(807.097f, 4.672f, 1451.161f), new Vector3(0f, 318.985f, 0f), new Vector3(5f, 5f, 5f), 1659.3f, new LetterDeliveryWindow(11f, 13f, "11-13"), new int[6] { 2, 31, 32, 29, 24, 28 }, "Isle of Clear Mind Obelisk") { }//IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 2: case 31: case 32: return "(Letter burns away after you place it on ground, you feel hotter)"; case 29: return "(Letter open by itself once you approach the obelisk, showing totemic pattern before flying away)"; case 24: case 28: return "(Letter got eject away before you can approach, falls into the seas)"; default: return UnexpectedOrigin(mission); } } } [HarmonyPatch(typeof(ShipItem), "UpdateLookText")] internal static class AnonymousLetterItemLookTextPatch { private static bool Prefix(ShipItem __instance) { if ((Object)(object)__instance == (Object)null || !PostalMail.IsRegisteredLetter(((Component)__instance).GetComponent<SaveablePrefab>())) { return true; } Good component = ((Component)__instance).GetComponent<Good>(); int num = (((Object)(object)component != (Object)null) ? component.GetMissionIndex() : (-1)); if (num < 0 || PlayerMissions.missions == null || num >= PlayerMissions.missions.Length) { return true; } Mission val = PlayerMissions.missions[num]; if (!AnonymousLetterMissions.TryGetDefinition(val, out var _)) { return true; } ((GoPointerButton)__instance).lookText = "due: " + val.GetDueText(); return false; } } internal abstract class AnonymousLetterMissionDefinition : LetterMissionDefinition { internal sealed override float DistanceToOffice { get; } internal sealed override bool UsePersistentWorldAnchor => true; internal sealed override bool UseDeliveryLocationForRoute => true; internal sealed override bool ShowDeliveryCoordinates => true; internal sealed override bool HideDestination => true; protected AnonymousLetterMissionDefinition(string id, string destinationPortName, int destinationPortIndex, Vector3 localPosition, Vector3 localEulerAngles, Vector3 triggerSize, float distanceToOffice, LetterDeliveryWindow deliveryWindow, int[] spawnPortIndices, string locationDescription) : base(id, destinationPortName, destinationPortIndex, localPosition, localEulerAngles, triggerSize, deliveryWindow, spawnPortIndices, locationDescription) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) DistanceToOffice = distanceToOffice; } } internal static class AnonymousLetterMissionRegistry { private static readonly LetterMissionRegistry<AnonymousLetterMissionDefinition> Registry = new LetterMissionRegistry<AnonymousLetterMissionDefinition>("Anonymous Letter", OasisPirateHideoutMission.Instance, HappyBayUnnamedGraveMission.Instance, EastwindLighthouseMission.Instance, SaffronIslandTraderMission.Instance, AlNilemLionsFangObeliskMission.Instance, OldAnkhTownClearMindMission.Instance, AestraAbbeyOracleBenchMission.Instance, TurtleIslandPonderingPeakMission.Instance, DeadCoveNamelessRockMission.Instance); internal static IReadOnlyList<AnonymousLetterMissionDefinition> All => Registry.All; } internal static class AnonymousLetterMissions { internal const int RequiredReputation = 8; internal const float DueDayBaseSpeed = 3f; internal const float ReputationMultiplier = 10f; internal const int FixedGoldReward = 5; internal const int OneDayLateGoldReward = 1; internal const int SeverelyLatePenalty = -8000; private static readonly LetterMissionSaveKeys SaveKeys = new LetterMissionSaveKeys("PostalExpansion.AnonymousLetter.Active.v1", "PostalExpansion.AnonymousLetter.Claimed.v1"); private static readonly LetterMissionSaveKeys LegacyPirateHideoutSaveKeys = new LetterMissionSaveKeys("PostalExpansion.RegisteredLetter.Active.v1", "PostalExpansion.RegisteredLetter.Claimed.v1"); private static readonly LetterMissionSet<AnonymousLetterMissionDefinition> Missions = new LetterMissionSet<AnonymousLetterMissionDefinition>("Anonymous Letter", AnonymousLetterMissionRegistry.All, SaveKeys, 8, 3f, 5, (Port destination) => "Anonymous letter"); internal static void AddMissions(Port origin, List<Mission> missions) { Missions.AddMissions(origin, missions); } internal static int GetGoldReward(int daysLate) { if (daysLate <= 0) { return 5; } return (daysLate == 1) ? 1 : 0; } internal static List<string> GetDebugStatusLines() { return Missions.GetDebugStatusLines(); } internal static bool TryGetDefinition(Mission mission, out AnonymousLetterMissionDefinition definition) { return Missions.TryGetDefinition(mission, out definition); } internal static void MissionAccepted(Mission mission) { Missions.MissionAccepted(mission); } internal static void MissionDelivered(Mission mission) { Missions.MissionDelivered(mission); } internal static void SavePersistentState() { Missions.SavePersistentState(); } internal static void LoadPersistentState() { Missions.LoadPersistentState(LegacyPirateHideoutSaveKeys); } internal static void ResetRuntimeState() { Missions.ResetRuntimeState(); } } internal sealed class ChronosChurchHouseMission : RegisteredLetterMissionDefinition { internal static readonly ChronosChurchHouseMission Instance = new ChronosChurchHouseMission(); private ChronosChurchHouseMission() : base("chronos_church_house", "Chronos", 21, new Vector3(-19.175f, 31.109f, -62.909f), new Vector3(0f, 17.783f, 0f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Day, new int[5] { 26, 28, 5, 0, 9 }, "Church house") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 26: case 28: return "There is little common ground after the schism."; case 5: return "We appreciate the knowledge seeking."; case 0: case 9: return "The Church is under maintenance thus not open for visiting."; default: return UnexpectedOrigin(mission); } } } internal sealed class ConfigurationManagerAttributes { public Action<ConfigEntryBase> CustomDrawer; public object DefaultValue; } internal sealed class CrabBeachHouseMission : RegisteredLetterMissionDefinition { internal static readonly CrabBeachHouseMission Instance = new CrabBeachHouseMission(); private CrabBeachHouseMission() : base("crab_beach_house", "Crab Beach", 11, new Vector3(-100.447f, 4.35f, 30.655f), new Vector3(0f, 188.793f, 0f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Day, new int[5] { 9, 0, 15, 22, 21 }, "House at beach") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 0: case 9: case 15: case 22: return "I SAID I DON'T BUILD SHIPS ANYMORE! GO AWAY!"; case 21: return "...Where?"; default: return UnexpectedOrigin(mission); } } } internal sealed class DailySpecialMissionState { private sealed class Marker { } private readonly string activeMissionDataKey; private readonly string claimedOfferDataKey; private readonly Func<int, Mission, string> serializeActiveMission; private readonly Func<Mission, string[], bool> matchesSavedMission; private readonly Action<Mission> onMissionRestored; private ConditionalWeakTable<Mission, Marker> markedMissions = new ConditionalWeakTable<Mission, Marker>(); private readonly HashSet<string> claimedOffers = new HashSet<string>(StringComparer.Ordinal); internal DailySpecialMissionState(string activeMissionDataKey, string claimedOfferDataKey, Func<int, Mission, string> serializeActiveMission, Func<Mission, string[], bool> matchesSavedMission, Action<Mission> onMissionRestored) { this.activeMissionDataKey = activeMissionDataKey; this.claimedOfferDataKey = claimedOfferDataKey; this.serializeActiveMission = serializeActiveMission; this.matchesSavedMission = matchesSavedMission; this.onMissionRestored = onMissionRestored; } internal bool IsMarked(Mission mission) { Marker value; if (mission != null) { return markedMissions.TryGetValue(mission, out value); } return false; } internal void Mark(Mission mission) { if (mission != null) { markedMissions.GetValue(mission, (Mission _) => new Marker()); } } internal bool CanOfferAt(Port origin) { if ((Object)(object)origin == (Object)null) { return false; } PruneClaimsForCurrentDay(); return !claimedOffers.Contains(GetClaimKey(GameState.day, origin.portIndex)); } internal void MissionAccepted(Mission mission) { if (IsMarked(mission) && !((Object)(object)mission.originPort == (Object)null) && mission.missionIndex >= 0 && PlayerMissions.missions != null && mission.missionIndex < PlayerMissions.missions.Length && PlayerMissions.missions[mission.missionIndex] == mission) { PruneClaimsForCurrentDay(); claimedOffers.Add(GetClaimKey(GameState.day, mission.originPort.portIndex)); } } internal void SavePersistentState() { if (GameState.modData == null) { GameState.modData = new Dictionary<string, string>(); } List<string> list = new List<string>(); if (PlayerMissions.missions != null) { for (int i = 0; i < PlayerMissions.missions.Length; i++) { Mission val = PlayerMissions.missions[i]; if (IsMarked(val) && !((Object)(object)val.originPort == (Object)null) && !((Object)(object)val.destinationPort == (Object)null)) { string text = serializeActiveMission(i, val); if (!string.IsNullOrEmpty(text)) { list.Add(text); } } } } GameState.modData[activeMissionDataKey] = string.Join(";", list); PruneClaimsForCurrentDay(); List<string> list2 = new List<string>(claimedOffers); list2.Sort(StringComparer.Ordinal); GameState.modData[claimedOfferDataKey] = string.Join(";", list2); } internal void LoadPersistentState() { ResetRuntimeState(); if (GameState.modData != null) { LoadClaims(); LoadActiveMissions(); } } internal void ResetRuntimeState() { markedMissions = new ConditionalWeakTable<Mission, Marker>(); claimedOffers.Clear(); } private void LoadClaims() { if (!GameState.modData.TryGetValue(claimedOfferDataKey, out var value)) { return; } string value2 = GameState.day + ","; string[] array = value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { if (text.StartsWith(value2, StringComparison.Ordinal)) { claimedOffers.Add(text); } } } private void LoadActiveMissions() { if (PlayerMissions.missions == null || !GameState.modData.TryGetValue(activeMissionDataKey, out var value)) { return; } string[] array = value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ',' }); if (array2.Length != 0 && int.TryParse(array2[0], out var result) && result >= 0 && result < PlayerMissions.missions.Length) { Mission val = PlayerMissions.missions[result]; if (val != null && val.missionIndex == result && (Object)(object)val.originPort != (Object)null && (Object)(object)val.destinationPort != (Object)null && matchesSavedMission(val, array2)) { Mark(val); onMissionRestored?.Invoke(val); } } } } private static string GetClaimKey(int day, int originPortIndex) { return day + "," + originPortIndex; } private void PruneClaimsForCurrentDay() { string currentDayPrefix = GameState.day + ","; claimedOffers.RemoveWhere((string claim) => !claim.StartsWith(currentDayPrefix, StringComparison.Ordinal)); } } internal sealed class DeadCoveNamelessRockMission : AnonymousLetterMissionDefinition { internal static readonly DeadCoveNamelessRockMission Instance = new DeadCoveNamelessRockMission(); private DeadCoveNamelessRockMission() : base("dead_cove_nameless_rock", "Dead Cove", 30, new Vector3(-852.584f, 2.539f, -826.316f), new Vector3(0f, 26.327f, 0f), new Vector3(8f, 8f, 8f), 1195.2f, LetterDeliveryWindow.Night, new int[3] { 1, 19, 11 }, "Nameless rock southren tip") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { int originPortIndex = LetterMissionDefinition.GetOriginPortIndex(mission); if (originPortIndex == 1 || originPortIndex == 11 || originPortIndex == 19) { return "(There is no remarkable landmark so you just throw the letter on the rock randomly. You have no idea what you are doing.)"; } return UnexpectedOrigin(mission); } } internal sealed class DragonCliffsBrownTobaccoVendorMission : RegisteredLetterMissionDefinition { internal static readonly DragonCliffsBrownTobaccoVendorMission Instance = new DragonCliffsBrownTobaccoVendorMission(); private DragonCliffsBrownTobaccoVendorMission() : base("dragon_cliffs_brown_tobacco_vendor", "Dragon Cliffs", 9, new Vector3(47.025f, 1.993f, -11.703f), new Vector3(0f, 106.371f, 0f), new Vector3(3f, 3f, 3f), LetterDeliveryWindow.Day, new int[5] { 0, 15, 12, 20, 28 }, "Brown Tobacco Vendor") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 12: case 15: case 20: case 28: return "(Sigh) How much longer do I need to stay here...?"; case 0: return "Hmm..."; default: return UnexpectedOrigin(mission); } } } internal sealed class DragonCliffsChimesHutMission : RegisteredLetterMissionDefinition { internal static readonly DragonCliffsChimesHutMission Instance = new DragonCliffsChimesHutMission(); private DragonCliffsChimesHutMission() : base("dragon_cliffs_small_hut_beside_chimes", "Dragon Cliffs", 9, new Vector3(-45.037f, 0.07f, -119.983f), new Vector3(0f, 148.902f, 0f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Day, new int[10] { 13, 29, 24, 16, 1, 25, 22, 28, 10, 21 }, "Small hut beside chimes") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 1: case 10: case 13: case 16: case 22: case 24: case 25: case 28: case 29: return "(Gasp) It finally arrived! Thanks!"; case 21: return "What took you so long?"; default: return UnexpectedOrigin(mission); } } } internal sealed class DragonCliffsTeaMerchantHouseMission : RegisteredLetterMissionDefinition { internal static readonly DragonCliffsTeaMerchantHouseMission Instance = new DragonCliffsTeaMerchantHouseMission(); private DragonCliffsTeaMerchantHouseMission() : base("dragon_cliffs_house_behind_tea_merchant", "Dragon Cliffs", 9, new Vector3(-6.196f, 2.711f, -52.022f), new Vector3(0f, 101.025f, 0f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Night, new int[5] { 6, 20, 22, 18, 0 }, "House behind tea merchant") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 6: if (!VanillaQuestState.IsHideoutQuestComplete()) { return "Thank you."; } return "New order, matey?"; case 0: case 18: case 20: case 22: if (!VanillaQuestState.IsHideoutQuestComplete()) { return "...You can leave now."; } return "Which scurvy dog brings ye 'ere?"; default: return UnexpectedOrigin(mission); } } } internal sealed class EastwindLighthouseMission : AnonymousLetterMissionDefinition { internal static readonly EastwindLighthouseMission Instance = new EastwindLighthouseMission(); private EastwindLighthouseMission() : base("eastwind_lighthouse", "Eastwind", 19, new Vector3(3070.795f, 8.574f, -4694.155f), new Vector3(0f, 266.217f, 0f), new Vector3(1.5f, 1.5f, 1.5f), 5610.9f, new LetterDeliveryWindow(22f, 2f, "22-02"), new int[6] { 2, 10, 26, 21, 23, 6 }, "Light house") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 6: return "Aye matey, Me belong 'ere now."; case 2: case 10: case 21: case 23: case 26: return "YER GODS 'AVE NO POWER 'ERE LANDLUBBER!"; default: return UnexpectedOrigin(mission); } } } internal sealed class FeyValleyWaterfallManorVendorMission : RegisteredLetterMissionDefinition { internal static readonly FeyValleyWaterfallManorVendorMission Instance = new FeyValleyWaterfallManorVendorMission(); private FeyValleyWaterfallManorVendorMission() : base("fey_valley_waterfall_manor_vendor", "Fey Valley", 27, new Vector3(-126.239f, 51.409f, 42.779f), new Vector3(0f, 300.007f, 0f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Day, new int[6] { 15, 0, 9, 20, 12, 26 }, "Waterfall manor vendor") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 26: return "Gods be praised! This year should be a good harvest year!"; case 12: case 20: return "We're supposed to bring their fruit back, not the other way around!"; case 0: case 9: case 15: return "I will let the Abbot know about the orders."; default: return UnexpectedOrigin(mission); } } } internal sealed class FireFishTownPainterMission : RegisteredLetterMissionDefinition { internal static readonly FireFishTownPainterMission Instance = new FireFishTownPainterMission(); private FireFishTownPainterMission() : base("fire_fish_town_painter", "Fire Fish Town", 23, new Vector3(7.186f, 3.075f, 216.135f), new Vector3(0f, 190.815f, 0f), new Vector3(3f, 3f, 3f), LetterDeliveryWindow.Day, new int[5] { 15, 0, 9, 21, 20 }, "Painter") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 0: case 15: return "Always happy to hear from fellow painters!"; case 9: return "Ugh! I escape there for a reason!"; case 20: return "Daddy..."; case 21: return "I would like to visit there one day!"; default: return UnexpectedOrigin(mission); } } } internal sealed class FireFishTownTempleHouseMission : RegisteredLetterMissionDefinition { internal static readonly FireFishTownTempleHouseMission Instance = new FireFishTownTempleHouseMission(); private FireFishTownTempleHouseMission() : base("fire_fish_town_temple_house", "Fire Fish Town", 23, new Vector3(-5.519f, 7.688f, 82.87f), new Vector3(0f, 35.728f, 0f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Day, new int[1] { 10 }, "Temple house") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { if (LetterMissionDefinition.GetOriginPortIndex(mission) != 10) { return UnexpectedOrigin(mission); } return "All is well."; } } internal sealed class FireflyGrottoChurchMission : RegisteredLetterMissionDefinition { internal static readonly FireflyGrottoChurchMission Instance = new FireflyGrottoChurchMission(); private FireflyGrottoChurchMission() : base("firefly_grotto_church", "Firefly Grotto", 28, new Vector3(128.273f, 5.458f, 37.452f), new Vector3(0f, 107.82f, 0f), new Vector3(2.5f, 2.5f, 2.5f), LetterDeliveryWindow.Day, new int[4] { 26, 12, 20, 9 }, "Chruch") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 26: return "Ora et Labora."; case 9: case 12: case 20: return "We must continued our missionary work."; default: return UnexpectedOrigin(mission); } } } internal sealed class FortAestrinUpperTownGateMission : RegisteredLetterMissionDefinition { internal static readonly FortAestrinUpperTownGateMission Instance = new FortAestrinUpperTownGateMission(); private FortAestrinUpperTownGateMission() : base("fort_aestrin_upper_town_gate", "Fort Aestrin", 15, new Vector3(112.355f, 35.876f, -61.713f), new Vector3(359.526f, 116.915f, 359.692f), new Vector3(3f, 3f, 3f), LetterDeliveryWindow.Day, new int[10] { 0, 6, 22, 9, 12, 20, 26, 28, 19, 21 }, "Upper Town Gate") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 0: case 6: case 9: case 19: case 22: return "Your job here is done, courier. Now move along."; case 12: case 20: return "I wonder when we'll get the next shipment of that colorful tobacco."; case 26: case 28: return "God be praised!"; case 21: return "You've come a long way, my friend!"; default: return UnexpectedOrigin(mission); } } } internal sealed class FortAestrinWesternmostPierHouseMission : RegisteredLetterMissionDefinition { internal static readonly FortAestrinWesternmostPierHouseMission Instance = new FortAestrinWesternmostPierHouseMission(); private FortAestrinWesternmostPierHouseMission() : base("fort_aestrin_westernmost_house_at_pier", "Fort Aestrin", 15, new Vector3(-144.465f, -1.242f, -99.124f), new Vector3(359.794f, 152.539f, 359.474f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Night, new int[4] { 0, 2, 32, 31 }, "Westernmost house on the pier") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { int originPortIndex = LetterMissionDefinition.GetOriginPortIndex(mission); if (originPortIndex == 0 || originPortIndex == 2 || (uint)(originPortIndex - 31) <= 1u) { return "Sabbih Ash-shams!"; } return UnexpectedOrigin(mission); } } internal static class GoldenDeliveryMissions { private readonly struct DestinationCandidate { internal Port Destination { get; } internal float Distance { get; } internal DestinationCandidate(Port destination, float distance) { Destination = destination; Distance = distance; } } internal const string DisplayName = "Golden Delivery"; internal const int RequiredReputation = 9; internal const float MoneyMultiplier = 10f; internal const float ReputationMultiplier = 15f; internal const int SeverelyLatePenalty = -50000; private const float SpawnChance = 0.5f; private const float MinimumDistance = 288f; private const float DueDayBaseSpeed = 4f; private const float ComparableRegularMailPackageMultiplier = 2f; private const string ActiveMissionDataKey = "PostalExpansion.GoldenDelivery.Active.v1"; private const string ClaimedOfferDataKey = "PostalExpansion.GoldenDelivery.Claimed.v1"; private static readonly DailySpecialMissionState State = new DailySpecialMissionState("PostalExpansion.GoldenDelivery.Active.v1", "PostalExpansion.GoldenDelivery.Claimed.v1", SerializeActiveMission, MatchesSavedMission, ApplyMissionName); internal static bool IsGolden(Mission mission) { return State.IsMarked(mission); } internal static void AddMission(Port origin, List<Mission> missions) { if (!CanOfferAt(origin) || missions == null || !PostalExpressMail.EnsureRegistered(PrefabsDirectory.instance)) { return; } Random random = new Random(GetDailySeed(origin)); if (!(random.NextDouble() >= 0.5)) { List<DestinationCandidate> candidates = GetCandidates(origin); if (candidates.Count != 0) { DestinationCandidate candidate = candidates[random.Next(candidates.Count)]; Mission val = GenerateMission(origin, candidate); MarkRuntime(val); missions.Add(val); } } } internal static void MissionAccepted(Mission mission) { State.MissionAccepted(mission); } internal static void SavePersistentState() { State.SavePersistentState(); } internal static void LoadPersistentState() { State.LoadPersistentState(); } internal static void ResetRuntimeState() { State.ResetRuntimeState(); } private static bool CanOfferAt(Port origin) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)origin == (Object)null || origin.portIndex == 33 || origin.portIndex == 7 || PlayerReputation.GetRepLevel(origin.region) < 9) { return false; } return State.CanOfferAt(origin); } private static List<DestinationCandidate> GetCandidates(Port origin) { List<DestinationCandidate> list = new List<DestinationCandidate>(); if (Port.ports == null) { return list; } Port[] ports = Port.ports; foreach (Port val in ports) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)origin) && val.portIndex != 7 && !PlayerAlreadyHasGoldenMission(origin, val)) { float distance = Mission.GetDistance(origin, val); if (distance > 288f) { list.Add(new DestinationCandidate(val, distance)); } } } return list; } private static Mission GenerateMission(Port origin, DestinationCandidate candidate) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown Good component = PostalExpressMail.Prefab.GetComponent<Good>(); int num = Mathf.RoundToInt(candidate.Distance * DebugMarketTracker.instance.missionDistanceFee * 2f * Plugin.RegularMailRewardMultiplier.Value * 10f); num = CurrencyMarket.instance.GetSellPriceInCurrency((Currency)candidate.Destination.region, (float)num, false); int num2 = MailDueDateCalculator.Calculate(origin, candidate.Destination, component, 4f); Mission val = new Mission(origin, candidate.Destination, PostalExpressMail.Prefab, 1, num, 1f, 0, num2); val.pricePerKm = (float)val.totalPrice / val.distance; return val; } private static void MarkRuntime(Mission mission) { State.Mark(mission); ApplyMissionName(mission); } private static void ApplyMissionName(Mission mission) { mission.missionName = "Golden Delivery to " + mission.destinationPort.GetPortName(); } private static bool IsExpressMission(Mission mission) { if (mission == null || (Object)(object)mission.goodPrefab == (Object)null) { return false; } return PostalMail.IsExpressMail(mission.goodPrefab.GetComponent<SaveablePrefab>()); } private static bool PlayerAlreadyHasGoldenMission(Port origin, Port destination) { if (PlayerMissions.missions == null) { return false; } Mission[] missions = PlayerMissions.missions; foreach (Mission val in missions) { if (IsGolden(val) && (Object)(object)val.originPort == (Object)(object)origin && (Object)(object)val.destinationPort == (Object)(object)destination) { return true; } } return false; } private static int GetDailySeed(Port origin) { return ((1907 + GameState.day) * 31 + origin.portIndex) * 31 + 9; } private static string SerializeActiveMission(int slot, Mission mission) { return string.Join(",", slot, mission.originPort.portIndex, mission.destinationPort.portIndex, mission.dueDay, mission.totalPrice); } private static bool MatchesSavedMission(Mission mission, string[] fields) { if (fields.Length == 5 && int.TryParse(fields[1], out var result) && int.TryParse(fields[2], out var result2) && int.TryParse(fields[3], out var result3) && int.TryParse(fields[4], out var result4) && IsExpressMission(mission) && mission.goodCount == 1 && mission.originPort.portIndex == result && mission.destinationPort.portIndex == result2 && mission.dueDay == result3) { return mission.totalPrice == result4; } return false; } } internal sealed class GoldRockCityPalaceFishVendorMission : RegisteredLetterMissionDefinition { internal static readonly GoldRockCityPalaceFishVendorMission Instance = new GoldRockCityPalaceFishVendorMission(); private GoldRockCityPalaceFishVendorMission() : base("gold_rock_city_palace_fish_vendor", "Gold Rock City", 0, new Vector3(-130.644f, 2.269f, 70.875f), new Vector3(0f, 226.858f, 0f), new Vector3(2f, 2f, 2f), LetterDeliveryWindow.Day, new int[7] { 15, 3, 23, 22, 9, 20, 6 }, "Fish vendor at palace") { }//IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 3: case 15: case 22: case 23: return "People love exotic fish!"; case 9: case 20: return "Eels... not sure about that."; case 6: if (!VanillaQuestState.IsHideoutQuestComplete()) { return "I will need a fast boat for this delivery."; } return "Our mutual friend has come up with some new stuff, eh?"; default: return UnexpectedOrigin(mission); } } } internal sealed class GoldRockCityPalaceGateMission : RegisteredLetterMissionDefinition { internal static readonly GoldRockCityPalaceGateMission Instance = new GoldRockCityPalaceGateMission(); private GoldRockCityPalaceGateMission() : base("gold_rock_city_palace_gate", "Gold Rock City", 0, new Vector3(-94.099f, 7.512f, -36.68f), new Vector3(0f, 261.509f, 0f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Day, new int[8] { 15, 5, 6, 32, 9, 22, 20, 21 }, "Palace Gate") { }//IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { return "Letter Received. Leave."; } } internal sealed class HappyBayLocalPrinceMission : RegisteredLetterMissionDefinition { internal static readonly HappyBayLocalPrinceMission Instance = new HappyBayLocalPrinceMission(); private HappyBayLocalPrinceMission() : base("happy_bay_local_prince", "Happy Bay", 20, new Vector3(102.092f, 17.839f, -23.281f), new Vector3(0f, 81.201f, 0f), new Vector3(3f, 3f, 3f), LetterDeliveryWindow.Day, new int[10] { 0, 12, 15, 9, 22, 26, 28, 21, 2, 6 }, "Local Prince") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { switch (LetterMissionDefinition.GetOriginPortIndex(mission)) { case 12: case 15: return "More demands..."; case 2: case 26: case 28: return "Take your god or whatever somewhere else."; case 9: case 22: return "These merchants only care about gold."; case 0: return "A surprise, but a welcome one."; case 21: return "At least they stay away from this."; case 6: if (!VanillaQuestState.IsHideoutQuestComplete()) { return "You're going to have a hard time on the return trip."; } return "Nice doing business with you."; default: return UnexpectedOrigin(mission); } } } internal sealed class HappyBayUnnamedGraveMission : AnonymousLetterMissionDefinition { internal static readonly HappyBayUnnamedGraveMission Instance = new HappyBayUnnamedGraveMission(); private HappyBayUnnamedGraveMission() : base("happy_bay_unnamed_grave", "Happy Bay", 20, new Vector3(-6791.194f, 55.928f, -5663.258f), new Vector3(0f, 355.344f, 0f), new Vector3(2.5f, 2.5f, 2.5f), 8844.2f, new LetterDeliveryWindow(5f, 7f, "05-07"), new int[1] { 2 }, "Unnamed grave") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { if (LetterMissionDefinition.GetOriginPortIndex(mission) != 2) { return UnexpectedOrigin(mission); } return "(You place the letter on the grave. It fades into light when sun raise up)"; } } internal sealed class KiciaBayWesternmostHouseMission : RegisteredLetterMissionDefinition { internal static readonly KiciaBayWesternmostHouseMission Instance = new KiciaBayWesternmostHouseMission(); private KiciaBayWesternmostHouseMission() : base("kicia_bay_westernmost_house", "Kicia Bay", 22, new Vector3(204.082f, 3.362f, -107.532f), new Vector3(0f, 74.864f, 0f), new Vector3(1.5f, 1.5f, 1.5f), LetterDeliveryWindow.Night, new int[5] { 6, 9, 0, 18, 20 }, "Western most house") { }//IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) internal override string GetDeliveryDialogue(Mission mission) { int originPortIndex = LetterMissionDefinition.GetOriginPortIndex(mission); if (!VanillaQuestState.IsHideoutQuestComplete()) { switch (originPortIndex) { case 0: case 6: return "I wish for a dryer air..."; case 9: case 18: case 20: return "Oranges...Always oranges..."; default: return UnexpectedOrigin(mission); } } switch (originPortIndex) { case 6: return "Aye...more work! Ye should be shipwreck in the fog!"; case 0: case 9: case 18: case 20: return "They just want me blue tobacco, feck off!"; default: return UnexpectedOrigin(mission); } } } internal static class Letter { internal const int LetterGoodIndex = 68; private const int QuestLetterItemIndex = 330; private const string LetterName = "Registered Letter"; private const string InheritedLabelObjectName = "label"; private const string LetterSealTextureFile = "registered_letter_seal.png"; private const string LetterSealObjectName = "postal_expansion_registered_letter_seal"; private const float LetterSealSize = 0.11f; private const float LetterSealSurfaceOffset = 0.002f; private static GameObject letterPrefab; private static readonly PostalSealVisual LetterSeal = new PostalSealVisual("postal_expansion_registered_letter_seal", "registered_letter_seal.png", "registered_letter_seal", 0.11f); internal static GameObject Prefab => letterPrefab; internal static bool EnsureRegistered(PrefabsDirectory directory) { if ((Object)(object)directory == (Object)null || directory.directory == null) { return false; } if (PostalPrefabRegistration.IsRegistered(directory, 238, letterPrefab)) { return true; } if (!HasPrefab(directory, 221)) { Debug.LogWarning((object)"Postal Expansion: regular mail prefab 221 was not found."); return false; } if (!HasPrefab(directory, 330)) { Debug.LogWarning((object)"Postal Expansion: vanilla quest letter prefab 330 was not found."); return false; } if (PostalPrefabRegistration.IsSlotOccupiedByAnotherPrefab(directory, 238, letterPrefab)) { Debug.LogError((object)"Postal Expansion: prefab index 238 is already occupied."); return false; } GameObject val = directory.directory[221]; GameObject questLetterPrefab = directory.directory[330]; if (!HasRequiredComponents(val, questLetterPrefab) || !PostalPrefabRegistration.EnsureCapacity(directory, 238)) { Debug.LogError((object)"Postal Expansion: Registered Letter prefab components could not be prepared."); return false; } if ((Object)(object)letterPrefab == (Object)null) { letterPrefab = Object.Instantiate<GameObject>(val); ((Object)letterPrefab).name = string.Format("{0} ({1}) {2}", 238, 68, "Registered Letter"); Object.DontDestroyOnLoad((Object)(object)letterPrefab); } ConfigurePrefab(letterPrefab, questLetterPrefab); if (!PostalPrefabRegistration.RegisterShipItem(directory, 238, letterPrefab)) { Debug.LogError((object)"Postal Expansion: Registered Letter prefab could not be registered as a ship item."); return false; } directory.directory[238] = letterPrefab; return true; } private static bool HasPrefab(PrefabsDirectory directory, int prefabIndex) { if (directory.directory.Length > prefabIndex) { return (Object)(object)directory.directory[prefabIndex] != (Object)null; } return false; } private static bool HasRequiredComponents(GameObject regularMailPrefab, GameObject questLetterPrefab) { if ((Object)(object)regularMailPrefab.GetComponent<SaveablePrefab>() != (Object)null && (Object)(object)regularMailPrefab.GetComponent<ShipItem>() != (Object)null && (Object)(object)regularMailPrefab.GetComponent<Good>() != (Object)null && (Object)(object)regularMailPrefab.GetComponent<MeshFilter>() != (Object)null && (Object)(object)regularMailPrefab.GetComponent<MeshRenderer>() != (Object)null && (Object)(object)regularMailPrefab.GetComponent<BoxCollider>() != (Object)null && (Object)(object)questLetterPrefab.GetComponent<ShipItem>() != (Object)null && (Object)(object)questLetterPrefab.GetComponent<MeshFilter>() != (Object)null && (Object)(object)questLetterPrefab.GetComponent<MeshRenderer>() != (Object)null) { return (Object)(object)questLetterPrefab.GetComponent<BoxCollider>() != (Object)null; } return false; } private static void ConfigurePrefab(GameObject prefab, GameObject questLetterPrefab) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) prefab.SetActive(true); ((Object)prefab).name = string.Format("{0} ({1}) {2}", 238, 68, "Registered Letter"); prefab.GetComponent<SaveablePrefab>().prefabIndex = 238; ShipItem component = prefab.GetComponent<ShipItem>(); ShipItem component2 = questLetterPrefab.GetComponent<ShipItem>(); component.name = "Registered Letter"; component.mass = 1f; ((PickupableItem)component).big = ((PickupableItem)component2).big; ((PickupableItem)component).holdDistance = ((PickupableItem)component2).holdDistance; ((PickupableItem)component).holdHeight = ((PickupableItem)component2).holdHeight; ((PickupableItem)component).heldRotationOffset = ((PickupableItem)component2).heldRotationOffset; component.inventoryScale = component2.inventoryScale; component.inventoryRotation = component2.inventoryRotation; component.inventoryRotationX = component2.inventoryRotationX; prefab.GetComponent<Good>().requiredRepLevel = 7; MeshFilter component3 = questLetterPrefab.GetComponent<MeshFilter>(); MeshRenderer component4 = questLetterPrefab.GetComponent<MeshRenderer>(); BoxCollider component5 = questLetterPrefab.GetComponent<BoxCollider>(); prefab.GetComponent<MeshFilter>().sharedMesh = component3.sharedMesh; ((Renderer)prefab.GetComponent<MeshRenderer>()).sharedMaterials = ((Renderer)component4).sharedMaterials; BoxCollider component6 = prefab.GetComponent<BoxCollider>(); component6.center = component5.center; component6.size = component5.size; Transform val = prefab.transform.Find("label"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)val).gameObject); } Vector3 center = component6.center; center.z += component6.size.z / 2f + 0.002f; LetterSeal.Ensure(prefab, center, Quaternion.identity); } } internal sealed class LetterDeliveryArea : MonoBehaviour { private Port port; private LetterMissionDefinition definition; private LetterDialoguePresenceArea dialogueArea; private Good waitingLetter; private bool closedNoticeShown; internal void Initialize(Port destinationPort, LetterMissionDefinition missionDefinition, LetterDialoguePresenceArea presenceArea) { port = destinationPort; definition = missionDefinition; dialogueArea = presenceArea; } private void OnTriggerEnter(Collider other) { Good componentInParent = ((Component)other).GetComponentInParent<Good>(); if (IsLetter(componentInParent)) { if (!TryGetMatchingMission(componentInParent, out var _)) { ShowNotification("Wrong Letter!"); return; } waitingLetter = componentInParent; closedNoticeShown = false; TryDeliver(); } } private void OnTriggerExit(Collider other) { if ((Object)(object)((Component)other).GetComponentInParent<Good>() == (Object)(object)waitingLetter) { waitingLetter = null; closedNoticeShown = false; } } private void Update() { if ((Object)(object)waitingLetter != (Object)null && LetterDeliveryHours.IsOpen(definition.DeliveryWindow)) { TryDeliver(); } } private void TryDeliver() { if ((Object)(object)waitingLetter == (Object)null || !TryGetMatchingMission(waitingLetter, out var mission)) { waitingLetter = null; } else if (!LetterDeliveryHours.IsOpen(definition.DeliveryWindow)) { if (!closedNoticeShown) { closedNoticeShown = true; ShowNotification("Wrong Time!"); } } else { Good obj = waitingLetter; waitingLetter = null; closedNoticeShown = false; string deliveryDialogue = definition.GetDeliveryDialogue(mission); LetterMissions.MissionDelivered(mission); obj.Deliver(); dialogueArea?.ShowForDelivery(deliveryDialogue); } } private bool TryGetMatchingMission(Good letter, out Mission mission) { mission = null; if ((Object)(object)letter == (Object)null || PlayerMissions.missions == null) { return false; } int missionIndex = letter.GetMissionIndex(); if (missionIndex < 0 || missionIndex >= PlayerMissions.missions.Length) { return false; } mission = PlayerMissions.missions[missionIndex]; if (mission != null && mission.missionIndex == missionIndex && (Object)(object)mission.destinationPort == (Object)(object)port && LetterMissions.TryGetDefinition(mission, out var letterMissionDefinition)) { return string.Equals(letterMissionDefinition.Id, definition.Id, StringComparison.Ordinal); } return false; } private static bool IsLetter(Good good) { return PostalMail.IsRegisteredLetter(((Object)(object)good != (Object)null) ? ((Component)good).GetComponent<SaveablePrefab>() : null); } private static void ShowNotification(string message) { if ((Object)(object)NotificationUi.instance != (Object)null) { NotificationUi.instance.ShowNotification(message); } } } [HarmonyPatch(typeof(PortDude), "Awake")] internal static class LetterDeliveryAreaCreationPatch { private const string AreaRootPrefix = "postal_expansion_letter_"; private static void Postfix(PortDude __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.GetPort() == (Object)null) { return; } foreach (LetterMissionDefinition item in LetterMissionDefinitions.All) { if (item.DestinationPortIndex == __instance.GetPort().portIndex) { EnsureArea(__instance, item); } } } private static void EnsureArea(PortDude portDude, LetterMissionDefinition definition) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) string text = "postal_expansion_letter_" + definition.Id; Transform areaParent = GetAreaParent(portDude, definition); if (!((Object)(object)areaParent == (Object)null) && !((Object)(object)areaParent.Find(text) != (Object)null)) { GameObject val = new GameObject(text); if (definition.UsePersistentWorldAnchor) { val.transform.position = ((Component)portDude).transform.TransformPoint(definition.LocalPosition); val.transform.rotation = ((Component)portDude).transform.rotation * Quaternion.Euler(definition.LocalEulerAngles); val.transform.SetParent(areaParent, true); } else { val.transform.SetParent(areaParent, false); val.transform.localPosition = definition.LocalPosition; val.transform.localRotation = Quaternion.Euler(definition.LocalEulerAngles); } LetterDialoguePresenceArea dialogueArea = CreateDialogueArea(val, definition); CreateDeliveryArea(val, portDude.GetPort(), definition, dialogueArea); if (definition.UsePersistentWorldAnchor) { val.AddComponent<PersistentLetterDeliveryAnchor>().Initialize(((Component)portDude).transform, definition.LocalPosition, definition.LocalEulerAngles); } } } private static Transform GetAreaParent(PortDude portDude, LetterMissionDefinition definition) { if (!definition.UsePersistentWorldAnchor) { return ((Component)portDude).transform; } if ((Object)(object)Refs.shiftingWorld != (Object)null) { return Refs.shiftingWorld; } FloatingOriginManager val = Object.FindObjectOfType<FloatingOriginManager>(); if ((Object)(object)val != (Object)null) { return ((Component)val).transform; } Debug.LogWarning((object)("Postal Expansion: Cannot create persistent delivery area " + definition.Id + "; shifting world is unavailable.")); return null; } internal static bool TryGetAreaTransform(LetterMissionDefinition definition, out Transform areaTransform) { areaTransform = null; if (definition == null) { return false; } Transform val = null; if (definition.UsePersistentWorldAnchor) { val = Refs.shiftingWorld; } else if (Port.ports != null && definition.DestinationPortIndex >= 0 && definition.DestinationPortIndex < Port.ports.Length) { Port val2 = Port.ports[definition.DestinationPortIndex]; PortDude val3 = (((Object)(object)val2 != (Object)null) ? val2.GetDude() : null); val = (((Object)(object)val3 != (Object)null) ? ((Component)val3).transform : null); } areaTransform = (((Object)(object)val != (Object)null) ? val.Find("postal_expansion_letter_" + definition.Id) : null); return (Object)(object)areaTransform != (Object)null; } private static LetterDialoguePresenceArea CreateDialogueArea(GameObject root, LetterMissionDefinition definition) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown GameObject val = new GameObject("postal_expansion_letter_dialogue_" + definition.Id) { layer = 2 }; val.transform.SetParent(root.transform, false); BoxCollider obj = val.AddComponent<BoxCollider>(); ((Collider)obj).isTrigger = true; obj.size = definition.TriggerSize * 5f; AddTriggerRigidbody(val); LetterDialoguePresenceArea letterDialoguePresenceArea = val.AddComponent<LetterDialoguePresenceArea>(); letterDialoguePresenceArea.Initialize(definition); return letterDialoguePresenceArea; } private static void CreateDeliveryArea(GameObject root, Port port, LetterMissionDefinition definition, LetterDialoguePresenceArea dialogueArea) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown GameObject val = new GameObject("postal_expansion_letter_delivery_" + definition.Id) { layer = 2 }; val.transform.SetParent(root.transform, false); BoxCollider obj = val.AddComponent<BoxCollider>(); ((Collider)obj).isTrigger = true; obj.size = definition.TriggerSize; AddTriggerRigidbody(val); val.AddComponent<LetterDeliveryArea>().Initialize(port, definition, dialogueArea); } private static void AddTriggerRigidbody(GameObject areaObject) { Rigidbody obj = areaObject.AddComponent<Rigidbody>(); obj.isKinematic = true; obj.useGravity = false; } } internal sealed class LetterDeliveryDialogue { private const string BubbleGraphicsName = "gfx"; private const string BubbleReferenceText = "Share a drink with a fellow sailor?"; private const int DialogueWrapCharacterLimit = 40; private const float ObserverOffset = 0.75f; private const float HeadHeightOffset = 0.5f; private const float MinimumBubbleWidthMultiplier = 0.35f; private const float MaximumBubbleWidthMultiplier = 1.8f; private static bool missingBubbleGraphicsWarningLogged; private readonly Transform anchor; private readonly int portIndex; private bool missingTemplateWarningLogged; private GameObject panel; private TextMesh text; private Transform bubbleGraphics; private Vector3 baseBubbleScale; private float baseTextWidth; internal LetterDeliveryDialogue(Transform dialogueAnchor, int destinationPortIndex) { anchor = dialogueAnchor; portIndex = destinationPortIndex; } internal bool Show(string dialogueText) { if (!EnsureCreated()) { return false; } string dialogueText2 = Wrap(dialogueText, 40); text.text = dialogueText2; ResizeBubble(dialogueText2); PositionTowardObserver(); panel.SetActive(true); FaceObserver(); return true; } internal void Hide() { if ((Object)(object)panel != (Object)null) { panel.SetActive(false); } } internal void FaceObserver() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)panel == (Object)null) && panel.activeInHierarchy && !((Object)(object)Refs.observerMirror == (Object)null)) { PositionTowardObserver(); panel.transform.rotation = ((Component)Refs.observerMirror).transform.rotation; } } private void PositionTowardObserver() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)panel == (Object)null) && !((Object)(object)Refs.observerMirror == (Object)null)) { Vector3 val = ((Component)Refs.observerMirror).transform.position - anchor.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = -anchor.forward; } else { ((Vector3)(ref val)).Normalize(); } Vector3 position = anchor.position + val * 0.75f; position.y = ((Component)Refs.observerMirror).transform.position.y + 0.5f; panel.transform.position = position; } } private bool EnsureCreated() { if ((Object)(object)panel != (Object)null && (Object)(object)text != (Object)null) { return true; } panel = LetterDialogueTemplate.Create(anchor, out text); if ((Object)(object)panel == (Object)null || (Object)(object)text == (Object)null) { if (!missingTemplateWarningLogged) { missingTemplateWarningLogged = true; int num = portIndex; Debug.LogWarning((object)("Postal Expansion: the letter dialogue template is unavailable at port " + num + ".")); } return false; } InitializeBubbleLayout(); panel.SetActive(false); return true; } private void InitializeBubbleLayout() { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) Transform val = (((Object)(object)text != (Object)null) ? ((Component)text).transform.parent : null); bubbleGraphics = (((Object)(object)val != (Object)null) ? val.Find("gfx") : null); if ((Object)(object)bubbleGraphics == (Object)null || (Object)(object)text == (Object)null || (Object)(object)text.font == (Object)null) { if (!missingBubbleGraphicsWarningLogged) { missingBubbleGraphicsWarningLogged = true; Debug.LogWarning((object)"Postal Expansion: letter dialogue bubble graphics could not be found; dynamic sizing is disabled."); } } else { baseBubbleScale = bubbleGraphics.localScale; baseTextWidth = MeasureMaximumLineWidth("Share a drink with a fellow sailor?"); } } private void ResizeBubble(string dialogueText) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)bubbleGraphics == (Object)null) && !((Object)(object)text == (Object)null) && !((Object)(object)text.font == (Object)null) && !(baseTextWidth <= 0f)) { bubbleGraphics.localScale = baseBubbleScale; float num = MeasureMaximumLineWidth(dialogueText); if (!(num <= 0f)) { float num2 = Mathf.Clamp(num / baseTextWidth, 0.35f, 1.8f); Vector3 localScale = baseBubbleScale; localScale.x *= num2; bubbleGraphics.localScale = localScale; } } } private float MeasureMaximumLineWidth(string value) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) text.font.RequestCharactersInTexture(value, text.fontSize, text.fontStyle); float num = 0f; float num2 = 0f; CharacterInfo val = default(CharacterInfo); foreach (char c in value) { if (c == '\n') { num2 = Mathf.Max(num2, num); num = 0f; } else if (text.font.GetCharacterInfo(c, ref val, text.fontSize, text.fontStyle)) { num += (float)((CharacterInfo)(ref val)).advance; } } return Mathf.Max(num2, num); } private static string Wrap(string value, int size) { value = value.TrimStart(Array.Empty<char>()); if (value.Length <= size) { return value; } int num = value.LastIndexOf(' ', size); if (num == -1) { num = Mathf.Min(value.Length, size); } return value.Substring(0, num) + ((num >= value.Length) ? string.Empty : ("\n" + Wrap(value.Substring(num), size))); } } internal readonly struct LetterDeliveryWindow { internal static readonly LetterDeliveryWindow Day = new LetterDeliveryWindow(7f, 18f, "07-18"); internal static readonly LetterDeliveryWindow Night = new LetterDeliveryWindow(19f, 5f, "19 - 05"); internal float StartHour { get; } internal float EndHour { get; } internal string DisplayHours { get; } internal LetterDeliveryWindow(float startHour, float endHour, string displayHours) { StartHour = startHour; EndHour = endHour; DisplayHours = displayHours; } } internal static class LetterDeliveryHours { internal static bool IsOpen(LetterDeliveryWindow window) { if ((Object)(object)Sun.sun == (Object)null) { return false; } float localTime = Sun.sun.localTime; if (!(window.StartHour <= window.EndHour)) { if (!(localTime >= window.StartHour)) { return localTime <= window.EndHour; } return true; } if (localTime >= window.StartHour) { return localTime <= window.EndHour; } return false; } internal static string GetDisplayHours(LetterDeliveryWindow window) { return window.DisplayHours; } } internal sealed class LetterDialoguePresenceArea : MonoBehaviour { private const float DialogueRetryInterval = 0.5f; private readonly HashSet<Collider> playerColliders = new HashSet<Collider>(); private LetterDeliveryDialogue dialogue; private string pendingText; private bool shown; private bool consumed; private float nextDialogueRetryTime; internal void Initialize(LetterMissionDefinition missionDefinition) { dialogue = new LetterDeliveryDialogue(((Component)this).transform, missionDefinition.DestinationPortIndex); } internal void ShowForDelivery(string text) { if (!string.IsNullOrEmpty(text) && !shown && pendingText == null) { consumed = false; pendingText = text; nextDialogueRetryTime = 0f; TryShow(); } } private void OnTriggerEnter(Collider other) { if (((Component)other).CompareTag("Player")) { playerColliders.Add(other); TryShow(); } } private void OnTriggerExit(Collider other) { if (!((Component)other).CompareTag("Player")) { return; } playerColliders.Remove(other); if (playerColliders.Count == 0) { if (shown) { dialogue.Hide(); } shown = false; consumed = true; pendingText = null; nextDialogueRetryTime = 0f; } } private void Update() { if (shown) { dialogue.FaceObserver(); } else if (pendingText != null && playerColliders.Count > 0 && Time.time >= nextDialogueRetryTime) { nextDialogueRetryTime = Time.time + 0.5f; TryShow(); } } private void TryShow() { if (!shown && !consumed && pendingText != null && playerColliders.Count != 0) { shown = dialogue.Show(pendingText); } } } internal static class LetterDialogueTemplate { private const string TemplateObjectName = "postal_expansion_letter_dialogue_template"; private static GameObject template; private static string textRelativePath; internal static bool TryCapture(TavernRumorsDude source) { if ((Object)(object)template != (Object)null) { return true; } if ((Object)(object)source == (Object)null || (Object)(object)source.speechUI == (Object)null || (Object)(object)source.text == (Object)null) { return false; } string relativePath = GetRelativePath(source.speechUI.transform, ((Component)source.text).transform); if (relativePath == null) { return false; } GameObject val = Object.Instantiate<GameObject>(source.speechUI); ((Object)val).name = "postal_expansion_letter_dialogue_template"; val.transform.SetParent((Transform)null, true); if ((Object)(object)source.drinkButton != (Object)null) { string relativePath2 = GetRelativePath(source.speechUI.transform, source.drinkButton.transform); Transform val2 = FindRelativeTransform(val.transform, relativePath2); if ((Object)(object)val2 != (Object)null) { ((Component)val2).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)val2).gameObject); } } val.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val); template = val; textRelativePath = relativePath; return true; } internal static GameObject Create(Transform parent, out TextMesh dialogueText) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) dialogueText = null; if ((Object)(object)parent == (Object)null || (!EnsureCaptured() && (Object)(object)template == (Object)null)) { return null; } GameObject val = Object.Instantiate<GameObject>(template); ((Object)val).name = "postal_expansion_letter_dialogue"; val.transform.SetParent(parent, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; Transform val2 = FindRelativeTransform(val.transform, textRelativePath); dialogueText = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<TextMesh>() : null); val.SetActive(false); if ((Object)(object)dialogueText != (Object)null) { return val; } Object.Destroy((Object)(object)val); return null; } internal static void Dispose() { if ((Object)(object)template != (Object)null) { Object.Destroy((Object)(object)template); } template = null; textRelativePath = null; } private static bool EnsureCaptured() { if ((Object)(object)template != (Object)null) { return true; } TavernRumorsDude[] array = Object.FindObjectsOfType<TavernRumorsDude>(); for (int i = 0; i < array.Length; i++) { if (TryCapture(array[i])) { return true; } } array = Resources.FindObjectsOfTypeAll<TavernRumorsDude>(); for (int i = 0; i < array.Length; i++) { if (TryCapture(array[i])) { return true; } } return false; } private static Transform FindRelativeTransform(Transform root, string relativePath) { if ((Object)(object)root == (Object)null || relativePath == null) { return null; } if (relativePath.Length != 0) { return root.Find(relativePath); } return root; } private static string GetRelativePath(Transform root, Transform child) { if ((Object)(object)root == (Object)null || (Object)(object)child == (Object)null) { return null; } List<string> list = new List<string>(); Transform val = child; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { list.Add(((Object)val).name); val = val.parent; } if ((Object)(object)val != (Object)(object)root) { return null; } list.Reverse(); return string.Join("/", list.ToArray()); } } [HarmonyPatch(typeof(TavernRumorsDude), "Awake")] internal static class LetterDialogueTemplateCapturePatch { private static void Postfix(TavernRumorsDude __instance) { LetterDialogueTemplate.TryCapture(__instance); } } internal static class LetterMissionDebug { private const int EntriesPerPage = 5; private static int page; internal static void ShowSpawnLocations() { List<string> list = new List<string>(); list.AddRange(RegisteredLetterMissions.GetDebugStatusLines()); list.AddRange(AnonymousLetterMissions.GetDebugStatusLines()); int num = Mathf.Max(1, Mathf.CeilToInt((float)list.Count / 5f)); page = Mathf.Clamp(page, 0, num - 1); int num2 = page * 5; int num3 = Mathf.Min(5, list.Count - num2); List<string> list2 = new List<string>(); list2.Add("Letter mission spawns (" + (page + 1) + "/" + num + "):"); List<string> list3 = list2; for (int i = 0; i < num3; i++) { list3.Add(list[num2 + i]); } Debug.Log((object)("Postal Expansion: letter mission spawns: | " + string.Join(" | ", list))); if ((Object)(object)NotificationUi.instance != (Object)null) { NotificationUi.instance.ShowNotification(string.Join("\n", list3)); } page = (page + 1) % num; } internal static void Reset() { page = 0; } } internal abstract class LetterMissionDefinition { internal string Id { get; } internal string DestinationPortName { get; } internal int DestinationPortIndex { get; } internal Vector3 LocalPosition { get; } internal Vector3 LocalEulerAngles { get; } internal Vector3 TriggerSize { get; } internal LetterDeliveryWindow DeliveryWindow { get; } internal int[] SpawnPortIndices { get; } internal string LocationDescription { get; } internal virtual float DistanceToOffice { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) Vector2 val = new Vector2(LocalPosition.x, LocalPosition.z); return ((Vector2)(ref val)).magnitude; } } internal virtual bool UsePersistentWorldAnchor => false; internal virtual bool UseDeliveryLocationForRoute => false; internal virtual bool ShowDeliveryCoordinates => false; internal virtual bool HideDestination => false; protected LetterMissionDefinition(string id, string destinationPortName, int destinationPortIndex, Vector3 localPosition, Vector3 localEulerAngles, Vector3 triggerSize, LetterDeliveryWindow deliveryWindow, int[] spawnPortIndices, string locationDescription) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) Id = id; DestinationPortName = destinationPortName; DestinationPortIndex = destinationPortIndex; LocalPosition = localPosition; LocalEulerAngles = localEulerAngles; TriggerSize = triggerSize; DeliveryWindow = deliveryWindow; SpawnPortIndices = spawnPortIndices; LocationDescription = locationDescription; } internal abstract string GetDeliveryDialogue(Mission mission); protected static int GetOriginPortIndex(Mission mission) { return mission?.originPort?.portIndex ?? (-1); } protected string UnexpectedOrigin(Mission mission) { Port val = mission?.originPort; string text = (((Object)(object)val != (Object)null) ? (val.GetPortName() + " (" + val.portIndex + ")") : "missing origin"); Debug.LogWarning((object)("Postal Expansion: letter mission " + Id + " received unexpected origin " + text + ".")); return string.Empty; } } [HarmonyPatch(typeof(MissionDetailsUI), "InsertMissionData")] internal static class LetterMissionDetailsPatch { private const float LocationLabelPosition = 0.45f; private const float LocationValuePosition = 0.8f; private const float DeliveryHoursValueOffset = 0.5f; private const string LocationLabelObjectName = "postal_expansion_letter_location_label"; private const string LocationValueObjectName = "postal_expansion_letter_location_value"; private const string DeliveryHoursLabelObjectName = "postal_expansion_letter_delivery_hours_label"; private const string DeliveryHoursValueObjectName = "postal_expansion_letter_delivery_hours_value"; private static readonly FieldInfo LocationTextField = AccessTools.Field(typeof(MissionDetailsUI), "locationText"); private static readonly FieldInfo DestinationTextField = AccessTools.Field(typeof(MissionDetailsUI), "destination"); private static readonly FieldInfo DueTextField = AccessTools.Field(typeof(MissionDetailsUI), "due"); private static readonly FieldInfo DistanceTextField = AccessTools.Field(typeof(MissionDetailsUI), "distance"); private static readonly FieldInfo TotalGoldTextField = AccessTools.Field(typeof(MissionDetailsUI), "totalGold"); private static readonly FieldInfo MapRendererField = AccessTools.Field(typeof(MissionDetailsUI), "mapRenderer"); private static void Postfix(MissionDetailsUI __instance, Mission mission) { //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || LocationTextField == null || DestinationTextField == null || DueTextField == null || DistanceTextField == null || TotalGoldTextField == null) { return; } object? value = DestinationTextField.GetValue(__instance); TextMesh val = (TextMesh)((value is TextMesh) ? value : null); object? value2 = DueTextField.GetValue(__instance); TextMesh val2 = (TextMesh)((value2 is TextMesh) ? value2 : null); object? value3 = DistanceTextField.GetValue(__instance); TextMesh val3 = (TextMesh)((value3 is TextMesh) ? value3 : null); object? value4 = TotalGoldTextField.GetValue(__instance); TextMesh val4 = (TextMesh)((value4 is TextMesh) ? value4 : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null) { return; } Transform parent = ((Component)val).transform.parent; Transform parent2 = ((Component)val3).transform.parent; TextMesh val5 = FindText(parent, "postal_expansion_letter_location_label"); TextMesh val6 = FindText(parent, "postal_expansion_letter_location_value"); TextMesh val7 = FindText(parent2, "postal_expansion_letter_delivery_hours_label"); TextMesh val8 = FindText(parent2, "postal_expansion_letter_delivery_hours_value"); TextMesh val9 = FindTextByContent(parent, "Destination:"); TextMesh val10 = FindTextStartingWith(parent, "Cargo:"); if (!LetterMissions.TryGetDefinition(mission, out var definition)) { SetActive(val9, active: true); SetActive(val, active: true); SetActive(val5, active: false); SetActive(val6, active: false); SetActive(val7, active: false); SetActive(val8, active: false); return; } val4.text = LetterMissions.GetFixedGoldReward(mission) + " " + PlayerGold.GetCurrencyName(3); if ((Object)(object)val9 == (Object)null || (Object)(object)val10 == (Object)null) { Debug.LogWarning((object)"Postal Expansion: mission detail labels were not found."); return; } val5 = val5 ?? CloneText(val9, "postal_expansion_letter_location_label"); val6 = val6 ?? CloneText(val, "postal_expansion_letter_location_value"); if ((Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null) { return; } if (definition.HideDestination) { ((Component)val5).transform.localPosition = ((Component)val9).transform.localPosition; ((Component)val6).transform.localPosition = ((Component)val).transform.localPosition; } else { float y = ((Component)val).transform.localPosition.y; float y2 = ((Component)val10).transform.localPosition.y; SetLocalY(((Component)val5).transform, Mathf.Lerp(y, y2, 0.45f)); SetLocalY(((Component)val6).transform, Mathf.Lerp(y, y2, 0.8f)); } val5.text = "Location:"; val6.text = definition.LocationDescription; SetActive(val9, !definition.HideDestination); SetActive(val, !definition.HideDestination); SetActive(val5, active: true); SetActive(val6, active: true); val7 = val7 ?? CloneText(val3, "postal_expansion_letter_delivery_hours_label"); val8 = val8 ?? CloneText(val2, "postal_expansion_letter_delivery_hours_value"); if ((Object)(object)val7 != (Object)null && (Object)(object)val8 != (Object)null) { float y3 = Mathf.Lerp(((Component)val2).transform.localPosition.y, ((Component)val3).transform.localPosition.y, 0.5f); SetLocalY(((Component)val7).transform, y3); SetLocalY(((Component)val8).transform, y3); val7.text = "Delivery hours:"; val8.text = LetterDeliveryHours.GetDisplayHours(definition.DeliveryWindow); SetActive(val7, active: true); SetActive(val8, active: true); PositionDeliveryHoursValue(val7, val8); } object? value5 = LocationTextField.GetValue(__instance); TextMesh val11 = (TextMesh)((value5 is TextMesh) ? value5 : null); object? obj = MapRendererField?.GetValue(__instance); Renderer val12 = (Renderer)((obj is Renderer) ? obj : null); if (definition.ShowDeliveryCoordinates) { if ((Object)(object)val12 != (Object)null) { ((Component)val12).gameObject.SetActive(false); } if ((Object)(object)val11 != (Object)null) { val11.text = (((Object)(object)FloatingOriginManager.instance != (Object)null && LetterDeliveryAreaCreationPatch.TryGetAreaTransform(definition, out var areaTransform)) ? GetVanillaLocationText(areaTransform) : "approximate location:\nunavailable"); } } else if ((Object)(object)val11 != (Object)null) { val11.text = string.Empty; } } private static string GetVanillaLocationText(Transform deliveryArea) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Vector3 globeCoords = FloatingOriginManager.instance.GetGlobeCoords(deliveryArea); int num = Mathf.RoundToInt(globeCoords.x); int num2 = Mathf.RoundToInt(globeCoords.z); string text = ((num < 0) ? "W" : "E"); string text2 = ((num2 < 0) ? "S" : "N"); return "approximate location:\n" + num2 + " " + text2 + ", " + num + " " + text; } private static TextMesh CloneText(TextMesh source, string objectName) { if ((Object)(object)source == (Object)null || (Object)(object)((Component)source).transform.parent == (Object)null) { return null; } GameObject obj = Object.Instantiate<GameObject>(((Component)source).gameObject, ((Component)source).transform.parent); ((Object)obj).name = objectName; return obj.GetComponent<TextMesh>(); } private static TextMesh FindText(Transform root, string objectName) { Transform val = (((Object)(object)root != (Object)null) ? root.Find(objectName) : null); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponent<TextMesh>(); } private static TextMesh FindTextByContent(Transform root, string content) { return FindText(root, (string text) => string.Equals(text.Trim(), content, StringComparison.Ordinal)); } private static TextMesh FindTextStartingWith(Transform root, string content) { return FindText(root, (string text) => text.TrimStart(Array.Empty<char>()).StartsWith(content, StringComparison.Ordinal)); } private static TextMesh FindText(Transform root, Func<string, bool> predicate) { if ((Object)(object)root == (Object)null) { return null; } TextMesh[] componentsInChildren = ((Component)root).GetComponentsInChildren<TextMesh>(true); foreach (TextMesh val in componentsInChildren) { if ((Object)(object)val != (Object)null && predicate(val.text ?? string.Empty)) { return val; } } return null; } private static void SetLocalY(Transform target, float y) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Vector3 localPosition = target.localPosition; localPosition.y = y; target.localPosition = localPosition; } private static void PositionDeliveryHoursValue(TextMesh label, TextMesh value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)label).transform.localRotation * Vector3.right; Vector3 localPosition = ((Component)label).transform.localPosition + ((Vector3)(ref val)).normalized * 0.5f; localPosition.y = ((Component)value).transform.localPosition.y; localPosition.z = ((Component)value).transform.localPosition.z; ((Component)value).transform.localPosition = localPosition; } private static void SetActive(TextMesh text, bool active) { if ((Object)(object)text != (Object)null) { ((Component)text).gameObject.SetActive(active); } } } internal sealed class LetterMissionRegistry<TDefinition> where TDefinition : LetterMissionDefinition { private readonly List<TDefinition> definitions = new List<TDefinition>(); internal IReadOnlyList<TDefinition> All => definitions; internal LetterMissionRegistry(string categoryName, params TDefinition[] candidates) { HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); foreach (TDefinition val in candidates) { if (val == null || string.IsNullOrEmpty(val.Id)) { Debug.LogError((object)("Postal Expansion: ignored a " + categoryName + " mission without an ID.")); } else if (!hashSet.Add(val.Id)) { Debug.LogError((object)("Postal Expansion: ignored duplicate " + categoryName + " mission ID " + val.Id + ".")); } else { definitions.Add(val); } } } } internal static class LetterMissionDefinitions { private static readonly IReadOnlyList<LetterMissionDefinition> Definitions = BuildDefinitions(); internal static IReadOnlyList<LetterMissionDefinition> All => Definitions; private static IReadOnlyList<LetterMissionDefinition> BuildDefinitions() { List<LetterMissionDefinition> list = new List<LetterMissionDefinition>(); foreach (RegisteredLetterMissionDefinition item in RegisteredLetterMissionRegistry.All) { list.Add(item); } foreach (AnonymousLetterMissionDefinition item2 in AnonymousLetterMissionRegistry.All) { list.Add(item2); } return list.AsReadOnly(); } } internal static class LetterMissionRoute { internal static float GetMissionDistance(Port origin, Port destination, LetterMissionDefinition definition) { float distance = Mission.GetDistance(origin, destination); if (!definition.UseDeliveryLocationForRoute || (Object)(object)destination == (Object)null || destination.portIndex != definition.DestinationPortIndex) { return distance; } return distance + definition.DistanceToOffice / 100f; } } internal static class LetterMissions { internal static bool TryGetDefinition(Mission mission, out LetterMissionDefinition definition) { if (AnonymousLetterMissions.TryGetDefinition(mission, out var definition2)) { definition = definition2; return true; } if (RegisteredLetterMissions.TryGetDefinition(mission, out var definition3)) { definition = definition3; return true; } definition = null; return false; } internal static void MissionDelivered(Mission mission) { AnonymousLetterMissions.MissionDelivered(mission); RegisteredLetterMissions.MissionDelivered(mission); } internal static int GetFixedGoldReward(Mission mission) { if (!AnonymousLetterMissions.TryGetDefinition(mission, out var _)) { return 1; } return 5; } internal static float GetReputationMultiplier(Mission mission) { if (!AnonymousLetterMissions.TryGetDefinition(mission, out var _)) { return 8f; } return 10f; } internal static int GetSeverelyLatePenalty(Mission mission) { if (!AnonymousLetterMissions.TryGetDefinition(mission, out var _)) { return -5000; } return -8000; } } internal readonly struct LetterMissionSaveKeys { internal string ActiveMissions { get; } internal string ClaimedOffers { get; } internal LetterMissionSaveKeys(string activeMissions, string claimedOffers) { ActiveMissions = activeMissions; ClaimedOffers = claimedOffers; } } internal sealed class LetterMissionSet<TDefinition> where TDefinition : LetterMissionDefinition { private sealed class MissionData { internal TDefinition Definition { get; } internal MissionData(TDefinition definition) { Definition = definition; } } private readonly string categoryName; private readonly IReadOnlyList<TDefinition> definitions; private readonly Dictionary<string, TDefinition> definitionsById; private readonly LetterMissionSaveKeys saveKeys; private readonly int requiredReputation; private readonly float dueDayBaseSpeed; private readonly int fixedGoldReward; private readonly Func<Port, string> getMissionName; private ConditionalWeakTable<Mission, MissionData> missionData = new ConditionalWeakTable<Mission, MissionData>(); private readonly Dictionary<string, Mission> dailyOffers = new Dictionary<string, Mission>(StringComparer.Ordinal); private readonly HashSet<string> claimedOffers = new HashSet<string>(StringComparer.Ordinal); private int dailyOfferDay = int.MinValue; internal LetterMissionSet(string categoryName, IReadOnlyList<TDefinition> definitions, LetterMissionSaveKeys saveKeys, int requiredReputation, float dueDayBaseSpeed, int fixedGoldReward, Func<Port, string> getMissionName) { this.categoryName = categoryName; this.definitions = definitions; this.saveKeys = saveKeys; this.requiredReputation = requiredReputation; this.dueDayBaseSpeed = dueDayBaseSpeed; this.fixedGoldReward = fixedGoldReward; this.getMissionName = getMissionName; definitionsById = new Dictionary<string, TDefinition>(StringComparer.Ordinal); foreach (TDefinition definition in definitions) { definitionsById.Add(definition.Id, definition); } } internal void AddMissions(Port origin, List<Mission> missions) { if ((Object)(object)origin == (Object)null || missions == null) { return; } EnsureDailyOffers(); foreach (TDefinition definition in definitions) { if (dailyOffers.TryGetValue(definition.Id, out var value) && value != null && !((Object)(object)value.originPort != (Object)(object)origin) && CanOfferFrom(origin, value.destinationPort) && value.missionIndex == -1 && !IsClaimed(definition.Id) && !HasActiveMission(definition.Id)) { missions.Add(value); } } } internal List<string> GetDebugStatusLines() { EnsureDailyOffers(); List<string> list = new List<string>(); foreach (TDefinition definition in definitions) { Mission activeMission; Mission value; string text = ((!TryGetActiveMission(definition.Id, out activeMission)) ? ((!IsClaimed(definition.Id)) ? ((!dailyOffers.TryGetValue(definition.Id, out value) || value == null || value.missionIndex != -1 || !CanOfferFrom(value.originPort, value.destinationPort)) ? "not available today" : GetPortName(value.originPort)) : "already claimed today") : ("active from " + GetPortName(activeMission.originPort))); list.Add(categoryName + " | " + definition.LocationDescription + ": " + text); } return list; } internal bool TryGetDefinition(Mission mission, out TDefinition definition) { if (mission != null && missionData.TryGetValue(mission, out var value)) { definition = value.Definition; return true; } definition = null; return false; } internal void MissionAccepted(Mission mission) { if (TryGetDefinition(mission, out var definition) && mission.missionIndex >= 0 && PlayerMissions.missions != null && mission.missionIndex < PlayerMissions.missions.Length && PlayerMissions.missions[mission.missionIndex] == mission) { claimedOffers.Add(GetClaimKey(GameState.day, definition.Id)); } } internal void MissionDelivered(Mission mission) { if (TryGetDefinition(mission, out var definition)) { claimedOffers.Add(GetClaimKey(GameState.day, definition.Id)); } } internal void SavePersistentState() { if (GameState.modData == null) { GameState.modData = new Dictionary<string, string>(); } List<string> list = new List<string>(); if (PlayerMissions.missions != null) { for (int i = 0; i < PlayerMissions.missions.Length; i++) { Mission val = PlayerMissions.missions[i]; if (TryGetDefinition(val, out var definition) && !((Object)(object)val.originPort == (Object)null) && !((Object)(object)val.destinationPort == (Object)null)) { list.Add(string.Join(",", i, val.originPort.portIndex, val.destinationPort.portIndex, definition.Id)); } } } GameState.modData[saveKeys.ActiveMissions] = string.Join(";", list); PruneClaimsForCurrentDay(); List<string> list2 = new List<string>(claimedOffers); list2.Sort(StringComparer.Ordinal); GameState.modData[saveKeys.ClaimedOffers] = string.Join(";", list2); } internal void LoadPersistentState(params LetterMissionSaveKeys[] legacySaveKeys) { ResetRuntimeState(); if (GameState.modData != null) { LoadClaims(saveKeys); LoadActiveMissions(saveKeys); foreach (LetterMissionSaveKeys sourceKeys in legacySaveKeys) { LoadClaims(sourceKeys); LoadActiveMissions(sourceKeys); } } } internal void ResetRuntimeState() { missionData = new ConditionalWeakTable<Mission, MissionData>(); dailyOffers.Clear(); claimedOffers.Clear(); dailyOfferDay = int.MinValue; } private void LoadClaims(LetterMissionSaveKeys sourceKeys) { if (!GameState.modData.TryGetValue(sourceKeys.ClaimedOffers, out var value)) { return; } string text = GameState.day + ","; string[] array = value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { if (text2.StartsWith(text, StringComparison.Ordinal)) { string key = text2.Substring(text.Length); if (definitionsById.ContainsKey(key)) { claimedOffers.Add(text2); } } } } private void LoadActiveMissions(LetterMissionSaveKeys sourceKeys) { if (PlayerMissions.missions == null || !GameState.modData.TryGetValue(sourceKeys.ActiveMissions, out var value)) { return; } string[] array = value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ',' }); if (array2.Length == 4 && int.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2) && int.TryParse(array2[2], out var result3) && result >= 0 && result < PlayerMissions.missions.Length && definitionsByI