using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using HarmonyLib; using Newtonsoft.Json; using Splatform; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Speedchoice")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Speedchoice")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("a1c0aac5-01e5-4957-99fe-6ae9edeafa78")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Speedchoice; [BepInPlugin("com.lukkster.Speedchoice", "Speedchoice", "1.0.0")] public class Speedchoice : BaseUnityPlugin { private struct Settings { public float boatSpeed; public float timeToRest; public float trophyOdds; public bool bossReveals; public bool bossSkills; public bool cheatDeath; public bool dropMaterials; public bool fastCrops; public bool fastFermenters; public bool harmlessPieces; public bool increasedExp; public bool instantUpgrades; public bool lootlessBosses; public bool noBuildStations; public bool noCraftCost; public bool noCraftLevels; public bool showDeaths; public bool showLogouts; public bool showTimer; public bool structureLoot; public bool wherePortal; public bool alwaysRocky; public float runSpeed; public float jumpForce; public float sailForce; public float restOverride; public float trophyOverride; public bool unlockPieces; public bool unlockRecipes; public int time; public bool isTimerRunning; public Settings() { boatSpeed = 0f; timeToRest = 0f; trophyOdds = 0f; bossReveals = false; bossSkills = false; cheatDeath = false; dropMaterials = false; fastCrops = false; fastFermenters = false; harmlessPieces = false; increasedExp = false; instantUpgrades = false; lootlessBosses = false; noBuildStations = false; noCraftCost = false; noCraftLevels = false; showDeaths = false; showLogouts = false; showTimer = false; structureLoot = false; wherePortal = false; alwaysRocky = false; runSpeed = 1f; jumpForce = 1f; sailForce = 1f; restOverride = -1f; trophyOverride = -1f; unlockPieces = false; unlockRecipes = false; time = 0; isTimerRunning = false; } } private struct Profile { public List keys; public string toolTip; public Dictionary ranges; public Dictionary checkBoxes; public Profile(List keys, string toolTip, Dictionary ranges, Dictionary checkBoxes) { this.keys = keys; this.toolTip = toolTip; this.ranges = ranges; this.checkBoxes = checkBoxes; } } private struct RangeOption { public string name; public string toolTip; public RangeOption(string name, string toolTip) { this.name = name; this.toolTip = toolTip; } } private struct Range { public Func Get; public Action Set; public string toolTip; public List rangeOptions; public Range(Func getter, Action setter, string toolTip, List rangeOptions) { Get = getter; Set = setter; this.toolTip = toolTip; this.rangeOptions = rangeOptions; } } private struct CheckBox { public Func Get; public Action Set; public string toolTip; public CheckBox(Func getter, Action setter, string toolTip) { Get = getter; Set = setter; this.toolTip = toolTip; } } [HarmonyPatch(typeof(FejdStartup), "OnServerOptions")] private class FejdStartup_OnServerOptions { private static float profileSep; private static float rangeSep; private static float checkBoxSep; private static GameObject serverOptions; private static void Postfix(FejdStartup __instance) { if ((Object)(object)GameObject.Find(checkBoxes.Keys.First()) == (Object)null) { serverOptions = GameObject.Find("StartGui_ServerOptions"); profileSep = GetSeperation("Presets/Easy", "Presets/Casual"); rangeSep = GetSeperation("Modifiers/Combat", "Modifiers/Death"); checkBoxSep = GetSeperation("Modifiers/NoBuildCost", "Modifiers/Passivemobs"); int num = 1; int num2 = 0; foreach (KeyValuePair profile in profiles) { num2++; if (num2 > 3) { num2 = 1; num++; } AddProfile(num, num2, profile); } float num3 = (float)num * profileSep; string[] array = new string[2] { "Presets/Default", "Modifiers" }; for (int i = 0; i < array.Length; i++) { MoveDown(array[i], num3); } num = 0; foreach (KeyValuePair range in ranges) { num++; AddRange(num, range); } array = new string[5] { "Modifiers/NoBuildCost", "Modifiers/PlayerBasedEvents", "Modifiers/Fire", "Modifiers/Passivemobs", "Modifiers/Nomap" }; for (int i = 0; i < array.Length; i++) { MoveDown(array[i], (float)num * rangeSep); } num3 += (float)num * rangeSep; num = 2; num2 = 0; foreach (KeyValuePair checkBox in checkBoxes) { num2++; if (num2 > 3) { num2 = 1; num++; } AddCheckBox(num, num2, checkBox); } ExpandPanel(num3 + (float)(num - 1) * checkBoxSep); } Load(__instance.m_world); foreach (KeyValuePair range2 in ranges) { GameObject.Find(range2.Key).GetComponentInChildren().value = range2.Value.Get(); } foreach (KeyValuePair checkBox2 in checkBoxes) { GameObject.Find(checkBox2.Key).GetComponentInChildren().isOn = checkBox2.Value.Get(); } } private static float GetSeperation(string a, string b) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) Transform val = serverOptions.transform.Find("panel/" + a); Transform obj = serverOptions.transform.Find("panel/" + b); float y = ((Component)val).GetComponent().anchoredPosition.y; float y2 = ((Component)obj).GetComponent().anchoredPosition.y; return Math.Abs(y - y2); } private static void AddProfile(int row, int col, KeyValuePair entry) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) Transform val = serverOptions.transform.Find("panel/Presets"); GameObject obj = Object.Instantiate(((Component)(col switch { 1 => ((Component)val).transform.Find("Casual"), 2 => ((Component)val).transform.Find("Hammer"), _ => ((Component)val).transform.Find("Immersive"), })).gameObject, val); Transform obj2 = obj.transform.Find("Text"); ((obj2 != null) ? ((Component)obj2).GetComponent() : null).text = entry.Key; ((Object)obj).name = entry.Key; KeyButton obj3 = ((obj != null) ? obj.GetComponent() : null); obj3.m_keys = entry.Value.keys; obj3.m_preset = (WorldPresets)0; obj3.m_toolTip = entry.Value.toolTip; MoveDown("Presets/" + entry.Key, profileSep * (float)row); } private static void AddRange(int row, KeyValuePair entry) { //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown Transform val = serverOptions.transform.Find("panel/Modifiers"); GameObject obj = Object.Instantiate(((Component)((Component)val).transform.Find("Portals")).gameObject, val); Transform obj2 = obj.transform.Find("label"); ((TMP_Text)((obj2 != null) ? ((Component)obj2).GetComponent() : null)).text = entry.Key; ((Object)obj).name = entry.Key; MoveDown("Modifiers/" + entry.Key, rangeSep * (float)row); Transform obj3 = obj.transform.Find("slider"); Slider obj4 = ((obj3 != null) ? ((Component)obj3).GetComponent() : null); obj4.maxValue = entry.Value.rangeOptions.Count() - 1; obj4.value = 0f; KeySlider val2 = ((obj3 != null) ? ((Component)obj3).GetComponent() : null); val2.m_toolTip = entry.Value.toolTip; val2.m_settings = new List(); foreach (RangeOption rangeOption in entry.Value.rangeOptions) { val2.m_settings.Add(new SliderSetting { m_name = rangeOption.name, m_toolTip = rangeOption.toolTip }); } } private static void AddCheckBox(int row, int col, KeyValuePair entry) { Transform val = serverOptions.transform.Find("panel/Modifiers"); GameObject obj = Object.Instantiate(((Component)(col switch { 1 => ((Component)val).transform.Find("NoBuildCost"), 2 => ((Component)val).transform.Find("PlayerBasedEvents"), _ => ((Component)val).transform.Find("Fire"), })).gameObject, val); Transform obj2 = obj.transform.Find("Label"); ((TMP_Text)((obj2 != null) ? ((Component)obj2).GetComponent() : null)).text = entry.Key; ((Object)obj).name = entry.Key; MoveDown("Modifiers/" + entry.Key, checkBoxSep * (float)row); obj.GetComponent().m_toolTip = entry.Value.toolTip; } private static void MoveDown(string objectId, float distance) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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) RectTransform component = GameObject.Find("GuiRoot/GUI/StartGui/StartGame/StartGui_ServerOptions/panel/" + objectId).GetComponent(); component.anchoredPosition -= new Vector2(0f, distance); } private static void ExpandPanel(float distance, int max = -10, int min = -1070) { //IL_001c: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //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) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_00c8: Unknown result type (might be due to invalid IL or missing references) RectTransform component = ((Component)serverOptions.transform.Find("panel")).GetComponent(); component.offsetMax += new Vector2(0f, distance / 2f); float num = 0f; if (component.offsetMax.y > (float)max) { num = component.offsetMax.y - (float)max; component.offsetMax = new Vector2(component.offsetMax.x, (float)max); } component.offsetMin -= new Vector2(0f, distance / 2f + num); if (component.offsetMin.y < (float)min) { num = (float)min - component.offsetMin.y; component.offsetMin = new Vector2(component.offsetMin.x, (float)min); } MoveDown("Modifiers", -1f * distance - num / 2f); } } [HarmonyPatch(typeof(FejdStartup), "OnServerOptionsDone")] private class FejdStartup_OnServerOptionsDone { private static void Prefix(FejdStartup __instance) { bool isUpdated = false; foreach (KeyValuePair range in ranges) { Assign(range, ref isUpdated); } foreach (KeyValuePair checkBox in checkBoxes) { Assign(checkBox, ref isUpdated); } if (isUpdated) { Save(__instance.m_world); } } private static void Assign(KeyValuePair entry, ref bool isUpdated) { float value = GameObject.Find(entry.Key).GetComponentInChildren().value; isUpdated = isUpdated || value != entry.Value.Get(); entry.Value.Set(value); } private static void Assign(KeyValuePair entry, ref bool isUpdated) { bool isOn = GameObject.Find(entry.Key).GetComponentInChildren().isOn; isUpdated = isUpdated || isOn != entry.Value.Get(); entry.Value.Set(isOn); } } [HarmonyPatch(typeof(ServerOptionsGUI), "OnPresetButton")] private class ServerOptionsGUI_OnPresetButton { private static void Postfix(KeyButton button) { foreach (KeyValuePair range in ranges) { GameObject.Find(range.Key).GetComponentInChildren().value = 0f; } foreach (KeyValuePair checkBox in checkBoxes) { GameObject.Find(checkBox.Key).GetComponentInChildren().isOn = false; } if (!profiles.TryGetValue(button.GetName(), out var value)) { return; } foreach (KeyValuePair range2 in value.ranges) { GameObject.Find(range2.Key).GetComponentInChildren().value = range2.Value; } foreach (KeyValuePair checkBox2 in value.checkBoxes) { GameObject.Find(checkBox2.Key).GetComponentInChildren().isOn = checkBox2.Value; } } } [HarmonyPatch(typeof(FejdStartup), "UpdateWorldList")] private class FejdStartup_UpdateWorldList { private static void UpdateToolTip(UITooltip toolTip, string add) { toolTip.m_topic = "$menu_serveroptions"; if (toolTip.m_text != "") { toolTip.m_text += "\n"; } toolTip.m_text += add; } private static void Postfix(FejdStartup __instance) { for (int i = 0; i < __instance.m_worlds.Count; i++) { Load(__instance.m_worlds[i]); List list = profiles.Keys.ToList(); HashSet hashSet = new HashSet(__instance.m_worlds[i].m_startingGlobalKeys); hashSet.Remove("noworkbench"); hashSet.RemoveWhere((string x) => x.StartsWith("preset ")); for (int num = list.Count - 1; num >= 0; num--) { if (!profiles[list[num]].keys.ToHashSet().SetEquals(hashSet)) { list.RemoveAt(num); } } bool flag = false; UITooltip component = __instance.m_worldListElements[i].GetComponent(); foreach (KeyValuePair range in ranges) { float num2 = range.Value.Get(); for (int num3 = list.Count - 1; num3 >= 0; num3--) { if (profiles[list[num3]].ranges[range.Key] != num2) { list.RemoveAt(num3); } } if (num2 != 0f) { flag = true; UpdateToolTip(component, range.Key + ": " + range.Value.rangeOptions[(int)num2].name); } } foreach (KeyValuePair checkBox in checkBoxes) { for (int num4 = list.Count - 1; num4 >= 0; num4--) { if (profiles[list[num4]].checkBoxes[checkBox.Key] != checkBox.Value.Get()) { list.RemoveAt(num4); } } if (checkBox.Value.Get()) { flag = true; UpdateToolTip(component, checkBox.Key); } } TextMeshProUGUI component2 = ((Component)__instance.m_worldListElements[i].transform.Find("modifiers")).GetComponent(); if (list.Count > 0) { ((TMP_Text)component2).text = list[0]; } else if (flag) { ((TMP_Text)component2).text = Localization.instance.Localize("$menu_modifier_custom"); } } } } [HarmonyPatch(typeof(World), "RemoveWorld")] private class World_RemoveWorld { private static void Postfix(string name) { File.Delete(GetSavePath(name)); } } private struct Prefab { public string name; public string aoe; public DamageTypes damage; public Prefab(string name, string aoe, DamageTypes damage) { //IL_000f: 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) this.name = name; this.aoe = aoe; this.damage = damage; } } [HarmonyPatch(typeof(ZoneSystem), "Start")] private class ZoneSystem_Start { private static void Postfix(ZoneSystem __instance) { if (ZNet.instance.IsServer()) { Load(ZNet.m_world); HarmlessPieces(); if (settings.noBuildStations) { __instance.SetGlobalKey((GlobalKeys)22); } else { __instance.RemoveGlobalKey((GlobalKeys)22); } if (settings.unlockPieces) { __instance.SetGlobalKey((GlobalKeys)21); } else { __instance.RemoveGlobalKey((GlobalKeys)21); } } ZRoutedRpc.instance.Register("FromServer", (Action)FromServer); ZRoutedRpc.instance.Register("StartTimer", (Action)StartTimer); ZRoutedRpc.instance.Register("GetTimer", (Action)GetTimer); ZRoutedRpc.instance.Register("SetTimer", (Action)SetTimer); ZRoutedRpc.instance.Register("RequestPois", (Action)RequestPois); ZRoutedRpc.instance.Register("RevealPois", (Action)RevealPois); ZRoutedRpc.instance.Register("LevelUp", (Action)LevelUp); ZRoutedRpc.instance.Register("PlacePortal", (Action)PlacePortal); } private static void HarmlessPieces() { //IL_0079: 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_004b: Unknown result type (might be due to invalid IL or missing references) foreach (Prefab harmingPrefab in harmingPrefabs) { if (settings.harmlessPieces) { ((Component)ZNetScene.instance.GetPrefab(harmingPrefab.name).transform.Find(harmingPrefab.aoe)).GetComponent().m_damage = default(DamageTypes); } else { ((Component)ZNetScene.instance.GetPrefab(harmingPrefab.name).transform.Find(harmingPrefab.aoe)).GetComponent().m_damage = harmingPrefab.damage; } } } private static void FromServer(long sender, string json) { ToSettings(json); HarmlessPieces(); if (settings.isTimerRunning) { ((MonoBehaviour)speedchoice).StartCoroutine(TimerUpdate()); } } private static void StartTimer(long sender, string json) { if (!settings.isTimerRunning) { settings.isTimerRunning = true; ((MonoBehaviour)speedchoice).StartCoroutine(TimerUpdate()); } } private static void GetTimer(long sender, string json) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SetTimer", new object[1] { settings.time }); } private static void SetTimer(long sender, int time) { settings.time = time; } private static void RequestPois(long sender, string json) { //IL_003c: 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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_0083: Unknown result type (might be due to invalid IL or missing references) List list = JsonConvert.DeserializeObject>(json); List list2 = new List(); foreach (Poi item in list) { foreach (KeyValuePair locationInstance in ZoneSystem.instance.m_locationInstances) { if (locationInstance.Value.m_location.m_prefabName == item.prefabName) { list2.Add(new Poi(item, locationInstance.Value.m_position.x, locationInstance.Value.m_position.y, locationInstance.Value.m_position.z)); } } } ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RevealPois", new object[1] { JsonConvert.SerializeObject((object)list2) }); } private static void RevealPois(long sender, string json) { //IL_0034: 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_004d: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); foreach (Poi item in JsonConvert.DeserializeObject>(json)) { ((Vector3)(ref val))..ctor(item.x, item.y, item.z); Minimap.instance.DiscoverLocation(val, item.pinType, item.name, false); Minimap.instance.Explore(val, item.radius); } } private static void LevelUp(long sender, int level) { if (!((Object)(object)Player.m_localPlayer != (Object)null)) { return; } foreach (KeyValuePair skillDatum in ((Character)Player.m_localPlayer).GetSkills().m_skillData) { if (skillDatum.Value.m_level < (float)level) { skillDatum.Value.m_level = level; } } } private static void PlacePortal(long sender, string json) { //IL_002d: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) PortalPin portalPin = JsonConvert.DeserializeObject(json); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(portalPin.x, portalPin.y, portalPin.z); if (portalPin.remove) { Minimap.instance.RemovePin(val, 0.1f); } if (portalPin.add) { Minimap.instance.AddPin(val, (PinType)6, portalPin.text, true, false, 0L, default(PlatformUserID)); } } } [HarmonyPatch(typeof(ZRoutedRpc), "AddPeer")] private class ZRoutedRpc_AddPeer { private static void Postfix(ZRoutedRpc __instance, ZNetPeer peer) { if (__instance.m_server) { __instance.InvokeRoutedRPC(peer.m_uid, "FromServer", new object[1] { FromSettings() }); } } } [HarmonyPatch(typeof(ZRoutedRpc), "RemovePeer")] private class ZRoutedRpc_RemovePeer { private static void Postfix(ZRoutedRpc __instance) { if (__instance.m_server && ZNet.instance.IsDedicated() && __instance.m_peers.Count < 1) { ((MonoBehaviour)speedchoice).StopAllCoroutines(); settings.isTimerRunning = false; } } } [HarmonyPatch(typeof(Ship), "GetSailForce")] public class Ship_GetSailForce { private static void Postfix(ref Vector3 __result) { //IL_002c: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (boatSpeeds.TryGetValue(settings.boatSpeed, out var value)) { __result *= value; } __result *= settings.sailForce; } } [HarmonyPatch(typeof(Ship), "Awake")] public class Ship_Awake { private static void Postfix(Ship __instance) { if (boatSpeeds.TryGetValue(settings.boatSpeed, out var value)) { __instance.m_backwardForce *= value * 0.8f; } __instance.m_backwardForce *= settings.sailForce; } } [HarmonyPatch(typeof(SE_Cozy), "Setup", new Type[] { typeof(Character) })] public static class SE_Cozy_Setup { private static void Postfix(SE_Cozy __instance) { float value; if (settings.restOverride >= 0f) { __instance.m_delay = settings.restOverride; } else if (restDelays.TryGetValue(settings.timeToRest, out value)) { __instance.m_delay = value; } } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] private class CharacterDrop_GenerateDropList { private static void Postfix(CharacterDrop __instance, ref List> __result) { float value; if (settings.lootlessBosses && levels.ContainsKey(((Component)__instance).GetComponent().m_name)) { __result = new List>(); } else if (settings.trophyOverride >= 0f) { AddTrophy(__instance, ref __result, settings.trophyOverride / 100f); } else if (trophyOdds.TryGetValue(settings.trophyOdds, out value)) { AddTrophy(__instance, ref __result, value); } } private static void AddTrophy(CharacterDrop __instance, ref List> __result, float odds) { if (trophies.TryGetValue(((Component)__instance).GetComponent().m_name, out var trophy) && !GotTrophy(trophy, __result) && Random.value <= odds) { Drop val = __instance.m_drops.Find((Drop drop) => ((Object)drop.m_prefab).name == trophy); __result.Add(new KeyValuePair(val.m_prefab, 1)); } } private static bool GotTrophy(string trophy, List> __result) { foreach (KeyValuePair item in __result) { if (trophy == ((Object)item.Key).name) { return true; } } return false; } } [HarmonyPatch(typeof(Trader), "GetAvailableItems")] private class Trader_GetAvailableItems { private static bool Prefix(Trader __instance, ref List __result) { if (settings.lootlessBosses) { __result = new List(); foreach (TradeItem item in __instance.m_items) { if (string.IsNullOrEmpty(item.m_requiredGlobalKey)) { __result.Add(item); } } return false; } return true; } } private struct Poi { public string prefabName; public PinType pinType; public string name; public float radius; public float x; public float y; public float z; public Poi(string prefabName, PinType pinType, string name, float radius) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) this.prefabName = prefabName; this.pinType = pinType; this.name = name; this.radius = radius; x = 0f; y = 0f; z = 0f; } public Poi(Poi poi, float x, float y, float z) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) prefabName = poi.prefabName; pinType = poi.pinType; name = poi.name; radius = poi.radius; this.x = x; this.y = y; this.z = z; } } [HarmonyPatch(typeof(Character), "OnDeath")] private class Character_OnDeath { private static void Postfix(Character __instance) { if (settings.bossReveals && reveals.TryGetValue(__instance.m_name, out var value)) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "RequestPois", new object[1] { JsonConvert.SerializeObject((object)value) }); } if (settings.bossSkills && levels.TryGetValue(__instance.m_name, out var value2)) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "LevelUp", new object[1] { value2 }); } } } [HarmonyPatch(typeof(Skill), "Raise")] private class Skills_Skill_Raise { private static void Prefix(ref float factor) { if (settings.increasedExp) { factor *= 6f; } } private static void Postfix(Skill __instance, ref bool __result) { if (!settings.bossSkills) { return; } foreach (KeyValuePair level in levels) { if (ZoneSystem.instance.GetGlobalKey("defeated_" + level.Key.Substring(7))) { if (__instance.m_level < (float)level.Value) { __instance.m_level = level.Value; __instance.m_accumulator = 0f; __result = true; } break; } } } } [HarmonyPatch(typeof(Game), "Shutdown")] private class Game_Shutdown { private static void Prefix(Game __instance) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer != (Object)null) { if (settings.cheatDeath && ((Character)Player.m_localPlayer).IsDead()) { __instance.GetPlayerProfile().SetLogoutPoint(((Component)Player.m_localPlayer).transform.position); } Dictionary customData = Player.m_localPlayer.m_customData; int result = 1; if (customData.TryGetValue(logoutsKey, out var value)) { int.TryParse(value, out result); result++; } customData[logoutsKey] = result.ToString(); } ((MonoBehaviour)speedchoice).StopAllCoroutines(); settings.isTimerRunning = false; rockyied = false; isSynced = false; if (ZNet.instance.IsServer()) { Save(ZNet.m_world); } } } [HarmonyPatch(typeof(Humanoid), "Pickup")] private class Humanoid_Pickup { private static void Postfix(Humanoid __instance, GameObject go) { if (((Character)__instance).IsPlayer()) { RemoveItem(__instance.m_inventory, go.GetComponent().m_itemData); } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] private class Inventory_AddItem { private static void Postfix(Inventory __instance, ItemData item) { if ((Object)(object)Player.m_localPlayer != (Object)null && ((Humanoid)Player.m_localPlayer).GetInventory() == __instance) { RemoveItem(__instance, item); } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(Vector2i) })] private class Inventory_AddItem_2 { private static void Postfix(Inventory __instance, ItemData item) { if ((Object)(object)Player.m_localPlayer != (Object)null && ((Humanoid)Player.m_localPlayer).GetInventory() == __instance) { RemoveItem(__instance, item); } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(int), typeof(int), typeof(int) })] private class Inventory_AddItem_4 { private static void Postfix(Inventory __instance, ItemData item) { if ((Object)(object)Player.m_localPlayer != (Object)null && ((Humanoid)Player.m_localPlayer).GetInventory() == __instance) { RemoveItem(__instance, item); } } } [HarmonyPatch(typeof(Plant), "TimeSincePlanted")] private static class Plant_TimeSincePlanted { private static void Postfix(Plant __instance, ref double __result) { if (settings.fastCrops) { __result = (double)__instance.m_growTimeMax + 1.0; } } } [HarmonyPatch(typeof(Fermenter), "Awake")] private static class Fermenter_Awake { private static void Postfix(Fermenter __instance) { if (settings.fastFermenters) { __instance.m_fermentationDuration = 10f; } } } [HarmonyPatch(typeof(Fermenter), "DelayedTap")] private static class Fermenter_DelayedTap { private static void Prefix(Fermenter __instance) { if (settings.fastFermenters) { __instance.GetItemConversion(__instance.m_delayedTapItem).m_producedItems = 10; } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private class ObjectDB_Awake { private static void Postfix() { upgradeAbles.Clear(); foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if ((Object)(object)recipe.m_item != (Object)null && recipe.m_item.m_itemData.m_shared.m_maxQuality > 1) { upgradeAbles.Add(recipe.m_item.m_itemData.m_shared.m_name, recipe); } } } } [HarmonyPatch(typeof(InventoryGui), "SetupCrafting")] private class InventoryGui_SetupCrafting { private static void Prefix() { UpgradeInventory(Player.m_localPlayer); } } [HarmonyPatch(typeof(Hud), "SetupPieceInfo")] private class Hud_SetupPieceInfo { private static void Postfix(Hud __instance, Piece piece) { //IL_0046: 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) if (settings.noBuildStations) { GameObject obj = __instance.m_requirementItems[piece.m_resources.Length]; Image component = ((Component)obj.transform.Find("res_icon")).GetComponent(); TMP_Text component2 = ((Component)obj.transform.Find("res_amount")).GetComponent(); ((Graphic)component).color = Color.white; component2.text = ""; ((Graphic)component2).color = Color.white; } } } [HarmonyPatch(typeof(Player), "HaveRequirementItems")] private class Player_HaveRequirementItems { private static void Postfix(bool discover, ref bool __result) { if (settings.noCraftCost && !discover) { __result = true; } } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] private class InventoryGui_SetupRequirement { private static void Postfix(Transform elementRoot) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (settings.noCraftCost) { ((Graphic)((Component)((Component)elementRoot).transform.Find("res_amount")).GetComponent()).color = Color.white; } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] private class InventoryGui_DoCrafting { private static IEnumerable Transpiler(IEnumerable instructions) { MethodInfo targetMethod = typeof(Player).GetMethod("NoCostCheat"); MethodInfo replacementMethod = typeof(InventoryGui_DoCrafting).GetMethod("NoCostCheat"); foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, targetMethod)) { yield return new CodeInstruction(OpCodes.Call, (object)replacementMethod); } else { yield return instruction; } } } public bool NoCostCheat() { if (settings.noCraftCost) { return true; } return Player.m_localPlayer.m_noPlacementCost; } private static void Postfix(Player player) { UpgradeInventory(player); } } [HarmonyPatch(typeof(Player), "RequiredCraftingStation")] private class Player_RequiredCraftingStation { private static void Prefix(ref bool checkLevel) { if (settings.noCraftLevels) { checkLevel = false; } } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] private class InventoryGui_UpdateRecipe { private static void Postfix(InventoryGui __instance) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (settings.noCraftLevels) { ((Graphic)__instance.m_minStationLevelText).color = __instance.m_minStationLevelBasecolor; } } } [HarmonyPatch(typeof(FejdStartup), "Start")] private class FejdStartup_Start { private static void Postfix() { GameObject obj = GameObject.Find("Topic"); font = ((obj != null) ? ((TMP_Text)obj.GetComponent()).font : null); } } [HarmonyPatch(typeof(Player), "OnSpawned")] private class Player_OnSpawned { private static Transform healthpanel; private static GameObject LeftOf(string name, Transform parent, RectTransform from) { //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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0041: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown GameObject val = new GameObject(name); val.transform.SetParent(parent); RectTransform obj = val.AddComponent(); obj.sizeDelta = from.sizeDelta; obj.anchoredPosition = from.anchoredPosition - new Vector2(from.sizeDelta.x + 1f, 0f); obj.anchorMax = from.anchorMax; obj.anchorMin = from.anchorMin; return val; } private static void DefaultFont(ref TextMeshProUGUI tmpGui, Color color, float ratio) { //IL_001f: 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) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) ((TMP_Text)tmpGui).font = font; ((Graphic)tmpGui).material = ((TMP_Asset)font).material; ((Graphic)tmpGui).color = color; ((TMP_Text)tmpGui).alignment = (TextAlignmentOptions)514; ((TMP_Text)tmpGui).fontMaterial.EnableKeyword("OUTLINE_ON"); ((TMP_Text)tmpGui).outlineColor = Color32.op_Implicit(Color.black); ((TMP_Text)tmpGui).outlineWidth = 0.1f; ((TMP_Text)tmpGui).fontStyle = (FontStyles)1; ((TMP_Text)tmpGui).fontSize = ((Component)((Component)Hud.instance).transform.Find("hudroot/healthpanel/food0")).GetComponent().sizeDelta.x * ratio; } private static TextMeshProUGUI AddCounter(string name, string item, int y) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)Hud.instance).transform.Find("hudroot/healthpanel"); RectTransform component = ((Component)((Component)val).transform.Find("food" + y)).GetComponent(); GameObject val2 = LeftOf(name + "Bkg", val, component); JsonUtility.FromJsonOverwrite(JsonUtility.ToJson((object)((Component)component).GetComponent()), (object)val2.AddComponent()); LeftOf(name + "Icon", val, component).AddComponent().sprite = GetItemIcon(item); TextMeshProUGUI tmpGui = LeftOf(name + "Text", val, component).AddComponent(); DefaultFont(ref tmpGui, Color.white, 0.5f); ((TMP_Text)tmpGui).alignment = (TextAlignmentOptions)1028; return tmpGui; } private static TextMeshProUGUI AddTimer() { //IL_002b: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)Hud.instance).transform.Find("hudroot"); RectTransform component = ((Component)val.Find("healthpanel")).GetComponent(); GameObject val2 = new GameObject("timer"); val2.transform.SetParent(val); RectTransform obj = val2.AddComponent(); obj.sizeDelta = new Vector2(1000f, 0f); obj.anchoredPosition = component.anchoredPosition + new Vector2(71f * component.sizeDelta.x / 100f, -112f * component.sizeDelta.y / 100f); obj.anchorMax = component.anchorMax; obj.anchorMin = component.anchorMin; TextMeshProUGUI tmpGui = val2.AddComponent(); DefaultFont(ref tmpGui, new Color(1f, 0.717f, 0.36f, 1f), 2f / 3f); ((TMP_Text)tmpGui).text = $"{TimeSpan.FromSeconds(settings.time)}"; return tmpGui; } private static void Postfix(Player __instance) { healthpanel = ((Component)Hud.instance).transform.Find("hudroot/healthpanel"); int y = 0; if (settings.showDeaths && (Object)(object)deaths == (Object)null) { deaths = AddCounter("deaths", "Charredskull", y); UpdateDeaths(); y = 1; } if (settings.showLogouts && (Object)(object)logouts == (Object)null) { logouts = AddCounter("logouts", "RoundLog", y); UpdateLogouts(); } if (settings.showTimer && (Object)(object)timer == (Object)null) { timer = AddTimer(); } if (settings.unlockRecipes && !unlockedRecipes) { unlockedRecipes = true; foreach (GameObject item in ObjectDB.instance.m_items) { ItemDrop component = item.GetComponent(); if (!((Object)(object)component == (Object)null) && component.m_itemData != null) { string name = component.m_itemData.m_shared.m_name; if (!__instance.m_knownMaterial.Contains(name)) { __instance.m_knownMaterial.Add(name); } } } __instance.UpdateKnownRecipesList(); MessageHud.instance.m_unlockMsgQueue.Clear(); MessageHud.instance.m_unlockMsgCount = 0; } ((Character)__instance).m_runSpeed = ((Character)__instance).m_runSpeed * settings.runSpeed; ((Character)__instance).m_jumpForce = ((Character)__instance).m_jumpForce * settings.jumpForce; } } [HarmonyPatch(typeof(Player), "OnDeath")] private class Player_OnDeath { private static void Postfix() { UpdateDeaths(); } } [HarmonyPatch(typeof(Player), "Update")] private class Player_Update { private static void Postfix(Player __instance) { if (Object.op_Implicit((Object)(object)Game.instance) && ((Character)__instance).TakeInput() && Input.anyKeyDown) { if (!ZRoutedRpc.instance.m_server && !isSynced) { isSynced = true; ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "GetTimer", new object[1] { "GetTimer" }); } if (!settings.isTimerRunning) { settings.isTimerRunning = true; ((MonoBehaviour)speedchoice).StartCoroutine(TimerUpdate()); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "StartTimer", new object[1] { "StartTimer" }); } } } } private struct PortalPin { public float x; public float y; public float z; public string text; public bool add; public bool remove; public PortalPin(Vector3 vector, string text, bool add, bool remove) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) x = vector.x; y = vector.y; z = vector.z; this.text = text; this.add = add; this.remove = remove; } } [HarmonyPatch(typeof(Player), "PlacePiece", new Type[] { typeof(Piece), typeof(Vector3), typeof(Quaternion), typeof(bool) })] private class Player_PlacePiece { private static void Postfix(Piece piece, Vector3 pos) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (settings.wherePortal && (Object)(object)piece != (Object)null && (((Object)piece).name == "portal_wood" || ((Object)piece).name == "portal_stone")) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "PlacePortal", new object[1] { PortalPinJson(pos, "", add: true, remove: false) }); } } } [HarmonyPatch(typeof(TeleportWorld), "SetText")] private class TeleportWorld_SetText { private static void Postfix(TeleportWorld __instance, string text) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (settings.wherePortal) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "PlacePortal", new object[1] { PortalPinJson(((Component)__instance).transform.position, text, add: true, remove: true) }); } } } [HarmonyPatch(typeof(Piece), "DropResources")] private class Piece_DropResources { private static void Prefix(Piece __instance) { if (settings.structureLoot && !__instance.IsPlacedByPlayer()) { overridePieceDrops = true; } } private static void Postfix(Piece __instance) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) overridePieceDrops = false; if (settings.wherePortal && (Object)(object)((Component)__instance).GetComponent() != (Object)null) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "PlacePortal", new object[1] { PortalPinJson(((Component)__instance).transform.position, "", add: false, remove: true) }); } } } [HarmonyPatch(typeof(Piece), "FreeBuildKey")] private class Piece_FreeBuildKey { private static bool Prefix(Piece __instance, ref GlobalKeys __result) { if (settings.structureLoot && overridePieceDrops && !__instance.IsPlacedByPlayer()) { __result = (GlobalKeys)2; return false; } return true; } } [HarmonyPatch(typeof(ZoneSystem), "PlaceVegetation")] private class ZoneSystem_PlaceVegetation { private static void Prefix(ZoneSystem __instance) { if (!settings.alwaysRocky || rockyied) { return; } foreach (ZoneVegetation item in __instance.m_vegetation) { if ((Object)(object)item.m_prefab != (Object)null && ((Object)item.m_prefab).name == "Pickable_Stone") { item.m_prefab = ZNetScene.instance.GetPrefab("Pickable_StoneRock"); } } rockyied = true; } } [HarmonyPatch(typeof(Pickable), "Awake")] private class Pickable_Awake { private static void Prefix(Pickable __instance) { if (settings.alwaysRocky && ((Object)__instance.m_itemPrefab).name == "Stone") { __instance.m_itemPrefab = ObjectDB.instance.GetItemPrefab("StoneRock"); } } } public const string PluginGUID = "com.lukkster.Speedchoice"; public const string PluginName = "Speedchoice"; public const string PluginVersion = "1.0.0"; private readonly Harmony harmony = new Harmony("com.lukkster.Speedchoice"); private static Speedchoice speedchoice; private static Settings settings = new Settings(); private static readonly Dictionary profiles = new Dictionary { { "Speedchoice", new Profile(new List { "eventrate 0", "teleportall", "nobuildcost" }, "Recommended Speedchoice settings. Faster gameplay, no grinding required, and Boss Reveals make the whole game completable in one sitting.", new Dictionary { { "Boat Speed", 2f }, { "Time to Rest", 1f }, { "Trophy Odds", 2f } }, new Dictionary { { "Boss Reveals", true }, { "Boss Skills", true }, { "Cheat Death", true }, { "Drop Materials", true }, { "Fast Crops", true }, { "Fast Fermenters", true }, { "Harmless Pieces", true }, { "Increased Exp", false }, { "Instant Upgrades", true }, { "Lootless Bosses", false }, { "No Build Stations", true }, { "No Craft Cost", true }, { "No Craft Levels", false }, { "Show Deaths", true }, { "Show Logouts", true }, { "Show Timer", true }, { "Structure Loot", true }, { "Where's my Portal?", true } }) }, { "Trailblazer", new Profile(new List { "deathkeepequip", "skillreductionrate 15", "resourcerate 200", "eventrate 0", "teleportall", "nobuildcost" }, "OatHorse's Trailblazer settings, without the trophy hunt aspect.", new Dictionary { { "Boat Speed", 2f }, { "Time to Rest", 1f }, { "Trophy Odds", 4f } }, new Dictionary { { "Boss Reveals", true }, { "Boss Skills", true }, { "Cheat Death", true }, { "Drop Materials", false }, { "Fast Crops", true }, { "Fast Fermenters", true }, { "Harmless Pieces", false }, { "Increased Exp", true }, { "Instant Upgrades", false }, { "Lootless Bosses", false }, { "No Build Stations", true }, { "No Craft Cost", true }, { "No Craft Levels", true }, { "Show Deaths", true }, { "Show Logouts", true }, { "Show Timer", true }, { "Structure Loot", true }, { "Where's my Portal?", true } }) }, { "Blazing", new Profile(new List { "eventrate 0", "teleportall", "nobuildcost" }, "Accelerated version of a Reverse Boss playthrough. Defeat the bosses in order, and get rewarded in Skill Levels. However, the bosses have no drops. Thus no Forsaken Powers, or Moder's Tears for late game crafting.", new Dictionary { { "Boat Speed", 2f }, { "Time to Rest", 2f }, { "Trophy Odds", 2f } }, new Dictionary { { "Boss Reveals", true }, { "Boss Skills", true }, { "Cheat Death", true }, { "Drop Materials", true }, { "Fast Crops", true }, { "Fast Fermenters", true }, { "Harmless Pieces", true }, { "Increased Exp", false }, { "Instant Upgrades", true }, { "Lootless Bosses", true }, { "No Build Stations", true }, { "No Craft Cost", true }, { "No Craft Levels", false }, { "Show Deaths", true }, { "Show Logouts", true }, { "Show Timer", true }, { "Structure Loot", true }, { "Where's my Portal?", true } }) } }; private static readonly SortedDictionary ranges = new SortedDictionary { { "Boat Speed", new Range(() => settings.boatSpeed, delegate(float val) { settings.boatSpeed = val; }, "Changes the speed at which ships sail.", new List { new RangeOption("Normal", "Boats travel normally."), new RangeOption("Fast", "Boats are 2.5 times faster, 2 times faster while paddling."), new RangeOption("Dangerous", "Boats are 10 times faster, 8 times faster while paddling."), new RangeOption("Capsize", "Boats travel ... faster.") }) }, { "Time to Rest", new Range(() => settings.timeToRest, delegate(float val) { settings.timeToRest = val; }, "Adjusts how long it takes to become rested.", new List { new RangeOption("Normal", "The default of 20 seconds."), new RangeOption("Fast", "Spend 10 seconds to become rested."), new RangeOption("Instant", "Resting happens instantly.") }) }, { "Trophy Odds", new Range(() => settings.trophyOdds, delegate(float val) { settings.trophyOdds = val; }, "Adds an extra reroll for trophy drops to all enemies.", new List { new RangeOption("Normal", "Vanilla drop rates."), new RangeOption("More", "Trophies drop 25%, multiplicity, more often. Thus a Deer trophy would have 62.5% drop rate, boosted from it's vanilla 50%. A Deathsquito trophy would have 28.75%, from 5%."), new RangeOption("Often", "Trophies drop 50%, multiplicity, more often. Thus 50% -> 75%, and 5% -> 52.5"), new RangeOption("Frequently", "Trophies drop 75%, multiplicity, more often. Thus 50% -> 87.5%, and 5% -> 76.25%"), new RangeOption("Always", "All creatures that can drop trophies, will drop trophies.") }) } }; private static readonly Dictionary checkBoxes = new Dictionary { { "Boss Reveals", new CheckBox(() => settings.bossReveals, delegate(bool val) { settings.bossReveals = val; }, "Upon defeating a Forsaken, the next Forsaken's locations are revealed.") }, { "Boss Skills", new CheckBox(() => settings.bossSkills, delegate(bool val) { settings.bossSkills = val; }, "Upon defeating a Forsaken, all skills will be leveled up.") }, { "Lootless Bosses", new CheckBox(() => settings.lootlessBosses, delegate(bool val) { settings.lootlessBosses = val; }, "Forsaken do not drop items, including both their Trophies, and their \"progressive\" materials.") }, { "Cheat Death", new CheckBox(() => settings.cheatDeath, delegate(bool val) { settings.cheatDeath = val; }, "If one logs out shortly after dying, they'll log in where they died rather than their spawn point.") }, { "Drop Materials", new CheckBox(() => settings.dropMaterials, delegate(bool val) { settings.dropMaterials = val; }, "Materials, items used for crafting exclusively, are immediately removed from the inventory.") }, { "Harmless Pieces", new CheckBox(() => settings.harmlessPieces, delegate(bool val) { settings.harmlessPieces = val; }, "Player built structures, such as campfires or spikes, do no damage to creatures.") }, { "Fast Crops", new CheckBox(() => settings.fastCrops, delegate(bool val) { settings.fastCrops = val; }, "Crops grow quickly.") }, { "Fast Fermenters", new CheckBox(() => settings.fastFermenters, delegate(bool val) { settings.fastFermenters = val; }, "Fermenters brew quickly.") }, { "Increased Exp", new CheckBox(() => settings.increasedExp, delegate(bool val) { settings.increasedExp = val; }, "Increases Skill experience gains by 500%.") }, { "Instant Upgrades", new CheckBox(() => settings.instantUpgrades, delegate(bool val) { settings.instantUpgrades = val; }, "Instantly upgrades any upgradeable tool or armor.") }, { "Structure Loot", new CheckBox(() => settings.structureLoot, delegate(bool val) { settings.structureLoot = val; }, "Naturally occurring structures, such as houses, will drop into materials when deconstructed with a hammer in \"No Build Cost\".") }, { "Where's my Portal?", new CheckBox(() => settings.wherePortal, delegate(bool val) { settings.wherePortal = val; }, "Adds a portal pin to the map upon placing a portal.") }, { "No Build Stations", new CheckBox(() => settings.noBuildStations, delegate(bool val) { settings.noBuildStations = val; }, "Player built pieces can be constructed without the required nearby crafting stations. For instance a Portal can be built without a nearby Workbench.") }, { "No Craft Cost", new CheckBox(() => settings.noCraftCost, delegate(bool val) { settings.noCraftCost = val; }, "Items can be crafted without consuming or requiring the materials to do so.") }, { "No Craft Levels", new CheckBox(() => settings.noCraftLevels, delegate(bool val) { settings.noCraftLevels = val; }, "Items can be crafted without the prerequisite Crafting Station Level to do so.") }, { "Show Deaths", new CheckBox(() => settings.showDeaths, delegate(bool val) { settings.showDeaths = val; }, "Adds an UI element showing the number of Deaths.") }, { "Show Logouts", new CheckBox(() => settings.showLogouts, delegate(bool val) { settings.showLogouts = val; }, "Adds an UI element showing the number of Logouts.") }, { "Show Timer", new CheckBox(() => settings.showTimer, delegate(bool val) { settings.showTimer = val; }, "Adds an UI element showing how long there has been activity in the world. Starts on first input, and pauses when the game pauses.") } }; private static readonly List harmingPrefabs = new List { new Prefab("piece_sharpstakes", "HIT AREA", new DamageTypes { m_pierce = 15f }), new Prefab("piece_dvergr_sharpstakes", "Colliders/HIT AREA", new DamageTypes { m_pierce = 15f }), new Prefab("piece_stakewall_blackwood", "HIT AREA", new DamageTypes { m_pierce = 120f }), new Prefab("piece_brazierfloor02", "_enabled_high/FireBurn", new DamageTypes { m_fire = 10f }), new Prefab("bonfire", "_enabled/FireBurn", new DamageTypes { m_fire = 20f }), new Prefab("fire_pit", "_enabled_high/FireBurn", new DamageTypes { m_fire = 10f }), new Prefab("piece_brazierceiling01", "_enabled_high/FireBurn", new DamageTypes { m_fire = 10f }), new Prefab("hearth", "_enabled_high/FireBurn", new DamageTypes { m_fire = 10f }), new Prefab("fire_pit_iron", "_enabled_high/FireBurn", new DamageTypes { m_fire = 10f }), new Prefab("piece_brazierfloor01", "_enabled_high/FireBurn", new DamageTypes { m_fire = 10f }), new Prefab("piece_trap_troll", "Damage Area", new DamageTypes { m_blunt = 50f, m_pierce = 50f, m_chop = 50f }) }; private static readonly Dictionary boatSpeeds = new Dictionary { { 1f, 2.5f }, { 2f, 10f }, { 3f, 100f } }; private static readonly Dictionary restDelays = new Dictionary { { 1f, 10f }, { 2f, 0f } }; private static readonly Dictionary trophies = new Dictionary { { "$enemy_abomination", "TrophyAbomination" }, { "$enemy_asksvin", "TrophyAsksvin" }, { "$enemy_bjorn", "TrophyBjorn" }, { "$enemy_blob", "TrophyBlob" }, { "$enemy_blobelite", "TrophyBlob" }, { "$enemy_blobtar", "TrophyGrowth" }, { "$enemy_boar", "TrophyBoar" }, { "$enemy_bonemass", "TrophyBonemass" }, { "$enemy_bonemawserpent", "TrophyBonemawSerpent" }, { "$enemy_charred_archer", "TrophyCharredArcher" }, { "$enemy_charred_mage", "TrophyCharredMage" }, { "$enemy_charred_melee", "TrophyCharredMelee" }, { "$enemy_deathsquito", "TrophyDeathsquito" }, { "$enemy_deer", "TrophyDeer" }, { "$enemy_dragon", "TrophyDragonQueen" }, { "$enemy_drake", "TrophyHatchling" }, { "$enemy_draugr", "TrophyDraugr" }, { "$enemy_draugrelite", "TrophyDraugrElite" }, { "$enemy_dvergr", "TrophyDvergr" }, { "$enemy_dvergr_mage", "TrophyDvergr" }, { "$enemy_eikthyr", "TrophyEikthyr" }, { "$enemy_fader", "TrophyFader" }, { "$enemy_fallenvalkyrie", "TrophyFallenValkyrie" }, { "$enemy_fenring", "TrophyFenring" }, { "$enemy_fenringcultist", "TrophyCultist" }, { "$enemy_fenringcultist_hildir", "TrophyCultist_Hildir" }, { "$enemy_gdking", "TrophyTheElder" }, { "$enemy_ghost", "TrophyGhost" }, { "$enemy_gjall", "TrophyGjall" }, { "$enemy_goblin", "TrophyGoblin" }, { "$enemy_goblin_hildir", "TrophyGoblinBruteBrosShaman" }, { "$enemy_goblinbrute", "TrophyGoblinBrute" }, { "$enemy_goblinbrute_hildircombined", "TrophyGoblinBruteBrosBrute" }, { "$enemy_goblinking", "TrophyGoblinKing" }, { "$enemy_goblinshaman", "TrophyGoblinShaman" }, { "$enemy_greydwarf", "TrophyGreydwarf" }, { "$enemy_greydwarfbrute", "TrophyGreydwarfBrute" }, { "$enemy_greydwarfshaman", "TrophyGreydwarfShaman" }, { "$enemy_hare", "TrophyHare" }, { "$enemy_kvastur", "TrophyKvastur" }, { "$enemy_leech", "TrophyLeech" }, { "$enemy_lox", "TrophyLox" }, { "$enemy_morgen", "TrophyMorgen" }, { "$enemy_neck", "TrophyNeck" }, { "$enemy_seeker", "TrophySeeker" }, { "$enemy_seekerbrute", "TrophySeekerBrute" }, { "$enemy_seekerqueen", "TrophySeekerQueen" }, { "$enemy_serpent", "TrophySerpent" }, { "$enemy_skeleton", "TrophySkeleton" }, { "$enemy_skeletonfire", "TrophySkeletonHildir" }, { "$enemy_skeletonpoison", "TrophySkeletonPoison" }, { "$enemy_stonegolem", "TrophySGolem" }, { "$enemy_surtling", "TrophySurtling" }, { "$enemy_thehive,", "TrophyHatchling" }, { "$enemy_tick", "TrophyTick" }, { "$enemy_troll", "TrophyFrostTroll" }, { "$enemy_ulv", "TrophyUlv" }, { "$enemy_unbjorn", "TrophyBjornUndead" }, { "$enemy_volture", "TrophyVolture" }, { "$enemy_wolf", "TrophyWolf" }, { "$enemy_wraith", "TrophyWraith" } }; private static readonly Dictionary trophyOdds = new Dictionary { { 1f, 0.25f }, { 2f, 0.5f }, { 3f, 0.75f }, { 4f, 1f } }; private const float bossRadius = 500f; private const float vendorRadius = 100f; private static readonly Dictionary> reveals = new Dictionary> { { "$enemy_eikthyr", new List { new Poi("GDKing", (PinType)9, "$enemy_gdking", 500f), new Poi("Vendor_BlackForest", (PinType)3, "Haldor", 100f) } }, { "$enemy_gdking", new List { new Poi("Bonemass", (PinType)9, "$enemy_bonemass", 500f), new Poi("BogWitch_Camp", (PinType)3, "BogWitch", 100f) } }, { "$enemy_bonemass", new List { new Poi("Dragonqueen", (PinType)9, "$enemy_dragon", 500f) } }, { "$enemy_dragon", new List { new Poi("GoblinKing", (PinType)9, "$enemy_goblinking", 500f), new Poi("Hildir_camp", (PinType)3, "Hildir", 100f) } }, { "$enemy_goblinking", new List { new Poi("Mistlands_DvergrBossEntrance1", (PinType)9, "$enemy_seekerqueen", 500f) } }, { "$enemy_seekerqueen", new List { new Poi("FaderLocation", (PinType)9, "$enemy_fader_codename", 500f), new Poi("PlaceofMystery1", (PinType)3, "Mysterious Location", 100f) } } }; private static readonly Dictionary levels = new Dictionary { { "$enemy_fader", 100 }, { "$enemy_seekerqueen", 80 }, { "$enemy_goblinking", 60 }, { "$enemy_dragon", 50 }, { "$enemy_bonemass", 40 }, { "$enemy_gdking", 30 }, { "$enemy_eikthyr", 20 } }; private static readonly List drops = new List { (ItemType)1, (ItemType)13 }; private static readonly List exhausts = new List { "$item_barberkit", "$item_barleyflour", "$item_barrelrings", "$item_dragontear", "$item_scythehandle", "$item_yagluththing" }; private static readonly List retains = new List { "$item_catapult_ammo", "$item_bonefragments", "$item_catapult_training_ammo", "$item_charredbone", "$item_eitr", "$item_asksvin_meat", "$item_barley", "$item_bjorn_meat", "$item_bonemawmeat", "$item_breaddough", "$item_bug_meat", "$item_chicken_meat", "$item_deer_meat", "$item_fishandbreaduncooked", "$item_fish_raw", "$item_fish_raw", "$item_hare_meat", "$item_honeyglazedchickenuncooked", "$item_loxmeat", "$item_loxpie_uncooked", "$item_magicallystuffedmushroomuncooked", "$item_meatplatteruncooked", "$item_mistharesupremeuncooked", "$item_necktail", "$item_piquantpie_uncooked", "$item_boar_meat", "$item_roastedcrustpie_uncooked", "$item_serpentmeat", "$item_vikingcupcake_uncooked", "$item_volture_meat", "$item_wolf_meat", "$item_blackcore", "$item_fireworkrocket_blue", "$item_fireworkrocket_cyan", "$item_fireworkrocket_green", "$item_fireworkrocket_purple", "$item_fireworkrocket_red", "$item_fireworkrocket_white", "$item_fireworkrocket_yellow", "$item_resin", "$item_surtlingcore", "$item_thunderstone", "$item_trophy_bonemass", "$item_trophy_deer", "$item_trophy_dragonqueen", "$item_trophy_eikthyr", "$item_trophy_fader", "$item_trophy_goblinking", "$item_trophy_seeker_brute", "$item_trophy_seekerqueen", "$item_trophy_elder", "$item_witheredbone", "$item_barleywinebase", "$item_meadbasebugrepellent", "$item_meadbasebzerker", "$item_meadbaseeitr_lingering", "$item_meadbaseeitr", "$item_meadbasefrostresist", "$item_meadbasehasty", "$item_meadbasehealth_lingering", "$item_meadbasehealth_major", "$item_meadbasehealth_medium", "$item_meadbasehealth", "$item_meadbaselightfoot", "$item_meadbasepoisonresist", "$item_meadbasestamina_lingering", "$item_meadbasestamina_medium", "$item_meadbasestamina", "$item_meadbasestrength", "$item_meadbaseswimmer", "$item_meadbasetamer", "$item_meadbasetasty", "$item_amber", "$item_amberpearl", "$item_coins", "$item_ruby", "$item_silvernecklace", "$item_blackmetalscrap", "$item_bronzescrap", "$item_coal", "$item_copperore", "$item_copperscrap", "$item_finewood", "$item_flametalore_old", "$item_flametalore", "$item_flax", "$item_ironore", "$item_ironscrap", "$item_roundlog", "$item_sap", "$item_silverore", "$item_softtissue", "$item_tinore", "$item_wood", "$item_beechseeds", "$item_birchseeds", "$item_carrotseeds", "$item_dandelion", "$item_onionseeds", "$item_turnip", "$item_turnipseeds" }; private static Dictionary upgradeAbles = new Dictionary(); private static TMP_FontAsset font; private static TextMeshProUGUI deaths; private static readonly string logoutsKey = "logouts"; private static TextMeshProUGUI logouts; private static TextMeshProUGUI timer; private static bool unlockedRecipes = false; private static bool isSynced = false; private static bool overridePieceDrops = false; private static bool rockyied = false; private void Start() { harmony.PatchAll(); speedchoice = this; } private static string GetSavePath(World world) { return GetSavePath(world.m_name); } private static string GetSavePath(string name) { return Path.Combine(Path.Combine(Utils.GetSaveDataPath((FileSource)1), "worlds"), name + "_speedchoice.json"); } private static string FromSettings() { return JsonConvert.SerializeObject((object)settings, (Formatting)1); } private static void ToSettings(string json) { settings = JsonConvert.DeserializeObject(json); } private static void Save(World world) { File.WriteAllText(GetSavePath(world), FromSettings()); } private static void Load(World world) { if (File.Exists(GetSavePath(world))) { ToSettings(File.ReadAllText(GetSavePath(world))); } else { settings = new Settings(); } } private static void RemoveItem(Inventory inventory, ItemData itemData) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (settings.dropMaterials && (drops.Contains(itemData.m_shared.m_itemType) || exhausts.Contains(itemData.m_shared.m_name)) && !retains.Contains(itemData.m_shared.m_name)) { inventory.RemoveItem(itemData); } } private static void UpgradeInventory(Player player) { if (!settings.instantUpgrades) { return; } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation == (Object)null) { return; } foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (upgradeAbles.TryGetValue(allItem.m_shared.m_name, out var value) && (((Object)(object)value.m_craftingStation != (Object)null && currentCraftingStation.m_name == value.m_craftingStation.m_name) || ((Object)(object)value.m_craftingStation == (Object)null && currentCraftingStation.m_name == "$piece_workbench"))) { int num = MaxLevel(currentCraftingStation, value); if (allItem.m_quality < num) { allItem.m_quality = num; allItem.m_durability = allItem.m_shared.m_maxDurability + allItem.m_shared.m_durabilityPerLevel * (float)allItem.m_quality; } } } } private static int MaxLevel(CraftingStation station, Recipe recipe) { if (settings.noCraftLevels) { return 4; } int num = 1; if ((Object)(object)station != (Object)null) { num = station.GetLevel(true); } int num2 = num - recipe.m_minStationLevel; if (recipe.m_minStationLevel != 0) { num2++; } if (num2 > 4) { num2 = 4; } return num2; } private static Sprite GetItemIcon(string itemPrefab) { return ObjectDB.instance.GetItemPrefab(itemPrefab).GetComponent().m_itemData.m_shared.m_icons[0]; } private static void UpdateDeaths() { if ((Object)(object)deaths != (Object)null) { ((TMP_Text)deaths).text = Game.instance.GetPlayerProfile().m_playerStats[(PlayerStatType)0].ToString(); } } private static void UpdateLogouts() { if (Player.m_localPlayer.m_customData.TryGetValue(logoutsKey, out var value)) { ((TMP_Text)logouts).text = value; } else { ((TMP_Text)logouts).text = "0"; } } private static IEnumerator TimerUpdate() { while (true) { if (!Game.IsPaused()) { if ((Object)(object)timer != (Object)null) { ((TMP_Text)timer).text = $"{TimeSpan.FromSeconds(settings.time)}"; } settings.time++; } yield return (object)new WaitForSeconds(1f); } } private static string PortalPinJson(Vector3 vector, string text, bool add, bool remove) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return JsonConvert.SerializeObject((object)new PortalPin(vector, text, add, remove)); } }