Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Valheim Mastery v0.18.25
plugins/ValheimMastery/MasteryHuntingPhysics.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using ValheimMastery.Runtime; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] [BepInPlugin("org.valheim.mastery.huntingphysics", "Mastery Hunting Physics", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class HuntingPhysics : BaseUnityPlugin { internal static ManualLogSource Log; private void Awake() { //IL_0011: 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_004a: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; new Harmony("org.valheim.mastery.test.huntingphysics").Patch((MethodBase)AccessTools.Method(typeof(HuntRemains), "CreateVisual", (Type[])null, (Type[])null), new HarmonyMethod(typeof(HuntingPhysics), "Create", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"HUNT_PHYSICS_READY owner-simulated bodies; original rewards and expiry retained"); } private static bool Create(HuntRemains __instance, string species) { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return true; } GameObject val = null; GameObject val2 = null; try { GameObject prefab = ZNetScene.instance.GetPrefab(species); Character val3 = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<Character>()); GameObject val4 = null; if ((Object)(object)val3 != (Object)null) { EffectData[] effectPrefabs = val3.m_deathEffects.m_effectPrefabs; foreach (EffectData val5 in effectPrefabs) { if ((Object)(object)val5.m_prefab != (Object)null && (Object)(object)val5.m_prefab.GetComponentInChildren<Ragdoll>(true) != (Object)null) { val4 = val5.m_prefab; break; } } } bool flag = (Object)(object)val4 == (Object)null; if (flag) { val4 = prefab; } if ((Object)(object)val4 == (Object)null) { Log.LogWarning((object)("HUNT_PHYSICS_FALLBACK missing source for " + species)); return true; } val = new GameObject("HuntingPhysicsInactive"); val.SetActive(false); val2 = Object.Instantiate<GameObject>(val4, val.transform, false); val2.SetActive(false); Ragdoll componentInChildren = val2.GetComponentInChildren<Ragdoll>(true); bool shouldFloat = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.m_float : IsWaterSpecies(species)); float offset = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.m_floatOffset : 0f); LevelEffects[] componentsInChildren = val2.GetComponentsInChildren<LevelEffects>(true); foreach (LevelEffects val6 in componentsInChildren) { val6.SetupLevelVisualization(component.GetZDO().GetInt("MasteryHuntStars", 1)); } MonoBehaviour[] componentsInChildren2 = val2.GetComponentsInChildren<MonoBehaviour>(true); MonoBehaviour[] array = componentsInChildren2; foreach (MonoBehaviour val7 in array) { if (!(val7 is ZNetView)) { Object.DestroyImmediate((Object)(object)val7); } } array = val2.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val7 in array) { Object.DestroyImmediate((Object)(object)val7); } if (val2.GetComponentsInChildren<MonoBehaviour>(true).Length != 0) { throw new InvalidOperationException("Native scripts survived stripping"); } Animator[] componentsInChildren3 = val2.GetComponentsInChildren<Animator>(true); foreach (Animator val8 in componentsInChildren3) { Object.DestroyImmediate((Object)(object)val8); } AudioSource[] componentsInChildren4 = val2.GetComponentsInChildren<AudioSource>(true); foreach (AudioSource val9 in componentsInChildren4) { Object.DestroyImmediate((Object)(object)val9); } ParticleSystem[] componentsInChildren5 = val2.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val10 in componentsInChildren5) { Object.DestroyImmediate((Object)(object)((Component)val10).gameObject); } Light[] componentsInChildren6 = val2.GetComponentsInChildren<Light>(true); foreach (Light val11 in componentsInChildren6) { Object.DestroyImmediate((Object)(object)val11); } if (flag) { HuntingSkeletonBuilder.Build(val2, species); } List<Rigidbody> list = new List<Rigidbody>(); Rigidbody[] componentsInChildren7 = val2.GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody val12 in componentsInChildren7) { if (ActiveBranch(((Component)val12).transform, val2.transform)) { list.Add(val12); } } Rigidbody[] array2 = list.ToArray(); Collider[] componentsInChildren8 = val2.GetComponentsInChildren<Collider>(true); if (array2.Length == 0 || array2.Length > 48 || componentsInChildren8.Length == 0) { throw new InvalidOperationException("Unsupported native body layout"); } val2.transform.SetParent((Transform)null, false); val2.transform.position = ((Component)__instance).transform.position + Vector3.up * 0.15f; val2.transform.rotation = ((Component)__instance).transform.rotation * Quaternion.Euler(0f, 0f, 85f); Collider[] array3 = componentsInChildren8; foreach (Collider val13 in array3) { ((Component)val13).gameObject.layer = LayerMask.NameToLayer("piece"); if (!val13.isTrigger && (Object)(object)((Component)val13).GetComponentInParent<Rigidbody>(true) != (Object)null) { val13.enabled = true; HuntingCorpseUse huntingCorpseUse = ((Component)val13).gameObject.GetComponent<HuntingCorpseUse>(); if ((Object)(object)huntingCorpseUse == (Object)null) { huntingCorpseUse = ((Component)val13).gameObject.AddComponent<HuntingCorpseUse>(); } huntingCorpseUse.Target = __instance; } else { val13.enabled = false; } } componentsInChildren7 = array2; foreach (Rigidbody val12 in componentsInChildren7) { HuntingCorpseUse huntingCorpseUse = ((Component)val12).gameObject.GetComponent<HuntingCorpseUse>(); if ((Object)(object)huntingCorpseUse == (Object)null) { huntingCorpseUse = ((Component)val12).gameObject.AddComponent<HuntingCorpseUse>(); } huntingCorpseUse.Target = __instance; } HuntingCorpsePhysics huntingCorpsePhysics = ((Component)__instance).gameObject.AddComponent<HuntingCorpsePhysics>(); huntingCorpsePhysics.Initialize(val2, array2, component, shouldFloat, offset); array3 = ((Component)__instance).GetComponents<Collider>(); foreach (Collider val14 in array3) { Object.DestroyImmediate((Object)(object)val14); } val2.SetActive(true); if (flag) { HuntingSkeletonBuilder.IgnoreSelfCollisions(val2); } if (component.IsOwner()) { huntingCorpsePhysics.PlaceAboveTerrain(); } Log.LogInfo((object)("HUNT_PHYSICS_CREATED species=" + species + " bodies=" + array2.Length + " source=" + (flag ? "articulated-skeleton" : "native-ragdoll"))); val2 = null; return false; } catch (Exception ex) { Log.LogWarning((object)("HUNT_PHYSICS_FALLBACK " + species + ": " + ex.Message)); return true; } finally { if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); } if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } } private static bool IsWaterSpecies(string species) { int result; switch (species) { default: result = ((species == "Seal_Pup") ? 1 : 0); break; case "Leech": case "Leech_cave": case "Serpent": case "BonemawSerpent": case "Seal": result = 1; break; } return (byte)result != 0; } internal static bool ActiveBranch(Transform node, Transform root) { Transform val = node; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root) { if (!((Component)val).gameObject.activeSelf) { return false; } val = val.parent; } return (Object)(object)node == (Object)(object)root || node.IsChildOf(root); } } internal static class HuntingSkeletonBuilder { private static bool Segment(string species, string raw) { string text = raw.ToLowerInvariant(); switch (species) { case "Deathsquito": { int result2; switch (text) { default: if (!text.Contains("leg")) { result2 = (text.Contains("wing") ? 1 : 0); break; } goto case "thorax"; case "thorax": case "head": case "abdomen": result2 = 1; break; } return (byte)result2 != 0; } case "Gjall": return text == "hip" || text == "forehead" || text.Contains("tentacle"); default: if (!(species == "BonemawSerpent")) { if (species == "Leech" || species == "Leech_cave") { return text.StartsWith("spine") || text == "head"; } if (text.Contains("ctrl") || text.Contains("toe") || text.Contains("jaw") || text.Contains("mandible") || text.Contains("tooth")) { return false; } int result; switch (text) { default: if (!text.StartsWith("spine") && !text.StartsWith("thorax") && !text.Contains("upperarm") && !text.Contains("lowerarm") && !text.Contains("frontarm") && !text.Contains("backleg") && !text.Contains("upperleg") && !text.Contains("middleleg") && !text.Contains("lowerleg") && !text.Contains("uleg") && !text.Contains("lleg")) { result = (text.EndsWith("wing") ? 1 : 0); break; } goto case "hip"; case "hip": case "head": case "neck": case "abdomen": case "tail": result = 1; break; } return (byte)result != 0; } goto case "Serpent"; case "Serpent": return text == "main" || text == "head" || text.StartsWith("tail"); } } internal static void Build(GameObject model, string species) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_04ff: Unknown result type (might be due to invalid IL or missing references) //IL_0506: Unknown result type (might be due to invalid IL or missing references) //IL_050b: Unknown result type (might be due to invalid IL or missing references) //IL_0510: Unknown result type (might be due to invalid IL or missing references) //IL_0634: Unknown result type (might be due to invalid IL or missing references) //IL_05e7: Unknown result type (might be due to invalid IL or missing references) //IL_063a: Unknown result type (might be due to invalid IL or missing references) //IL_063e: Unknown result type (might be due to invalid IL or missing references) //IL_0643: Unknown result type (might be due to invalid IL or missing references) //IL_05ff: Unknown result type (might be due to invalid IL or missing references) //IL_0606: Unknown result type (might be due to invalid IL or missing references) //IL_060b: Unknown result type (might be due to invalid IL or missing references) //IL_0610: Unknown result type (might be due to invalid IL or missing references) //IL_0614: Unknown result type (might be due to invalid IL or missing references) //IL_05f6: Unknown result type (might be due to invalid IL or missing references) //IL_0677: Unknown result type (might be due to invalid IL or missing references) //IL_067e: Expected O, but got Unknown //IL_0697: Unknown result type (might be due to invalid IL or missing references) //IL_069c: Unknown result type (might be due to invalid IL or missing references) //IL_069e: Unknown result type (might be due to invalid IL or missing references) //IL_06a8: Unknown result type (might be due to invalid IL or missing references) //IL_061c: Unknown result type (might be due to invalid IL or missing references) //IL_0626: Unknown result type (might be due to invalid IL or missing references) //IL_062b: Unknown result type (might be due to invalid IL or missing references) //IL_0703: Unknown result type (might be due to invalid IL or missing references) //IL_0708: Unknown result type (might be due to invalid IL or missing references) //IL_06cc: Unknown result type (might be due to invalid IL or missing references) //IL_06d1: Unknown result type (might be due to invalid IL or missing references) //IL_06d5: Unknown result type (might be due to invalid IL or missing references) //IL_06da: Unknown result type (might be due to invalid IL or missing references) //IL_06df: Unknown result type (might be due to invalid IL or missing references) //IL_07bc: Unknown result type (might be due to invalid IL or missing references) //IL_07cd: Unknown result type (might be due to invalid IL or missing references) //IL_07d2: Unknown result type (might be due to invalid IL or missing references) //IL_07df: Unknown result type (might be due to invalid IL or missing references) //IL_07ec: Unknown result type (might be due to invalid IL or missing references) //IL_083a: Unknown result type (might be due to invalid IL or missing references) //IL_084d: Unknown result type (might be due to invalid IL or missing references) //IL_0859: Unknown result type (might be due to invalid IL or missing references) //IL_086c: Unknown result type (might be due to invalid IL or missing references) //IL_0878: Unknown result type (might be due to invalid IL or missing references) //IL_0892: Unknown result type (might be due to invalid IL or missing references) //IL_089e: Unknown result type (might be due to invalid IL or missing references) //IL_08b8: Unknown result type (might be due to invalid IL or missing references) Joint[] componentsInChildren = model.GetComponentsInChildren<Joint>(true); foreach (Joint val in componentsInChildren) { Object.DestroyImmediate((Object)(object)val); } Collider[] componentsInChildren2 = model.GetComponentsInChildren<Collider>(true); foreach (Collider val2 in componentsInChildren2) { Object.DestroyImmediate((Object)(object)val2); } Rigidbody[] componentsInChildren3 = model.GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody val3 in componentsInChildren3) { Object.DestroyImmediate((Object)(object)val3); } HashSet<Transform> hashSet = new HashSet<Transform>(); Bounds val4 = default(Bounds); bool flag = false; SkinnedMeshRenderer[] componentsInChildren4 = model.GetComponentsInChildren<SkinnedMeshRenderer>(true); Transform[] bones; foreach (SkinnedMeshRenderer val5 in componentsInChildren4) { if (!((Renderer)val5).enabled || (Object)(object)val5.sharedMesh == (Object)null) { continue; } bones = val5.bones; foreach (Transform val6 in bones) { if ((Object)(object)val6 != (Object)null && Segment(species, ((Object)val6).name)) { hashSet.Add(val6); } } Bounds localBounds = ((Renderer)val5).localBounds; for (int k = 0; k < 8; k++) { Vector3 val7 = ((Component)val5).transform.TransformPoint(((Bounds)(ref localBounds)).center + Vector3.Scale(((Bounds)(ref localBounds)).extents, new Vector3((float)(((k & 1) != 0) ? 1 : (-1)), (float)(((k & 2) != 0) ? 1 : (-1)), (float)(((k & 4) != 0) ? 1 : (-1))))); if (!flag) { val4 = new Bounds(val7, Vector3.zero); flag = true; } else { ((Bounds)(ref val4)).Encapsulate(val7); } } val5.updateWhenOffscreen = true; } Transform val8 = null; foreach (Transform item2 in hashSet) { if ((Object)(object)val8 == (Object)null) { val8 = item2; continue; } while ((Object)(object)val8 != (Object)null && (Object)(object)item2 != (Object)(object)val8 && !item2.IsChildOf(val8)) { val8 = val8.parent; } } if ((Object)(object)val8 != (Object)null) { hashSet.Add(val8); } List<Transform> list = new List<Transform>(); bones = model.GetComponentsInChildren<Transform>(true); foreach (Transform item in bones) { if (hashSet.Contains(item)) { list.Add(item); } } if (list.Count == 0 || list.Count > 32) { throw new InvalidOperationException("No supported bounded skeleton for " + species + " (" + list.Count + ")"); } float num = (flag ? Mathf.Min(((Bounds)(ref val4)).size.x, Mathf.Min(((Bounds)(ref val4)).size.y, ((Bounds)(ref val4)).size.z)) : 1f); float num2 = Mathf.Clamp(num * 0.22f, 0.06f, 0.8f); Dictionary<Transform, Rigidbody> dictionary = new Dictionary<Transform, Rigidbody>(); List<Collider> list2 = new List<Collider>(); foreach (Transform item3 in list) { Rigidbody val3 = ((Component)item3).gameObject.AddComponent<Rigidbody>(); val3.isKinematic = true; val3.mass = Mathf.Clamp(num2 * 8f, 0.2f, 8f); val3.linearDamping = 0.25f; val3.angularDamping = 0.8f; val3.solverIterations = ((species == "Tick") ? 32 : 8); val3.solverVelocityIterations = ((species == "Tick") ? 8 : 2); dictionary.Add(item3, val3); } foreach (Transform item4 in list) { Transform parent = item4.parent; while ((Object)(object)parent != (Object)null && !dictionary.ContainsKey(parent)) { parent = parent.parent; } Transform val9 = null; float num3 = float.MaxValue; Vector3 val10; foreach (Transform item5 in list) { if (!((Object)(object)item5 == (Object)(object)item4) && item5.IsChildOf(item4)) { val10 = item5.position - item4.position; float sqrMagnitude = ((Vector3)(ref val10)).sqrMagnitude; if (sqrMagnitude > 0.0001f && sqrMagnitude < num3) { num3 = sqrMagnitude; val9 = item5; } } } bool flag2 = ((Object)item4).name.ToLowerInvariant().Contains("leg") || ((Object)item4).name.ToLowerInvariant().Contains("arm") || ((Object)item4).name.ToLowerInvariant().Contains("wing") || ((Object)item4).name.ToLowerInvariant().Contains("tentacle"); float num4 = num2 * (flag2 ? 0.28f : 0.75f); Vector3 val12; if (!((Object)(object)val9 != (Object)null)) { Vector3 position = item4.position; Vector3 val11; if (!((Object)(object)parent != (Object)null)) { val11 = Vector3.up; } else { val10 = item4.position - parent.position; val11 = ((Vector3)(ref val10)).normalized; } val12 = position + val11 * num4 * 2f; } else { val12 = val9.position; } Vector3 val13 = val12; float num5 = Vector3.Distance(item4.position, val13); if (flag2) { num4 = Mathf.Min(num4, Mathf.Max(0.018f, num5 * 0.16f)); } GameObject val14 = new GameObject("Mastery corpse segment"); val14.transform.SetParent(item4, false); val14.transform.position = (item4.position + val13) * 0.5f; if (num5 > 0.001f) { val14.transform.rotation = Quaternion.FromToRotation(Vector3.up, val13 - item4.position); } CapsuleCollider val15 = val14.AddComponent<CapsuleCollider>(); val15.direction = 1; Vector3 lossyScale = val14.transform.lossyScale; val15.radius = num4 / Mathf.Max(0.001f, Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.z))); val15.height = Mathf.Max(num4 * 2f, num5 + num4 * 2f) / Mathf.Max(0.001f, Mathf.Abs(lossyScale.y)); list2.Add((Collider)(object)val15); if ((Object)(object)parent != (Object)null) { CharacterJoint val16 = ((Component)item4).gameObject.AddComponent<CharacterJoint>(); ((Joint)val16).connectedBody = dictionary[parent]; ((Joint)val16).autoConfigureConnectedAnchor = false; ((Joint)val16).anchor = Vector3.zero; ((Joint)val16).connectedAnchor = parent.InverseTransformPoint(item4.position); ((Joint)val16).axis = Vector3.right; val16.swingAxis = Vector3.up; ((Joint)val16).enableCollision = false; ((Joint)val16).enablePreprocessing = false; val16.enableProjection = species != "Tick"; val16.projectionDistance = 0.05f; val16.projectionAngle = 15f; SoftJointLimit lowTwistLimit = default(SoftJointLimit); ((SoftJointLimit)(ref lowTwistLimit)).limit = -25f; val16.lowTwistLimit = lowTwistLimit; SoftJointLimit highTwistLimit = default(SoftJointLimit); ((SoftJointLimit)(ref highTwistLimit)).limit = 25f; val16.highTwistLimit = highTwistLimit; SoftJointLimit swing1Limit = default(SoftJointLimit); ((SoftJointLimit)(ref swing1Limit)).limit = (flag2 ? 65 : 30); val16.swing1Limit = swing1Limit; SoftJointLimit swing2Limit = default(SoftJointLimit); ((SoftJointLimit)(ref swing2Limit)).limit = (flag2 ? 45 : 20); val16.swing2Limit = swing2Limit; } } } internal static void IgnoreSelfCollisions(GameObject model) { Collider[] componentsInChildren = model.GetComponentsInChildren<Collider>(); for (int i = 0; i < componentsInChildren.Length; i++) { for (int j = i + 1; j < componentsInChildren.Length; j++) { Physics.IgnoreCollision(componentsInChildren[i], componentsInChildren[j], true); } } } } public sealed class HuntingCorpseUse : MonoBehaviour, Hoverable, Interactable { public HuntRemains Target; public string GetHoverName() { return ((Object)(object)Target == (Object)null) ? "" : Target.GetHoverName(); } public string GetHoverText() { return ((Object)(object)Target == (Object)null) ? "" : Target.GetHoverText(); } public float GetHoverOffset() { return 0f; } public bool Interact(Humanoid user, bool hold, bool alt) { return (Object)(object)Target != (Object)null && Target.Interact(user, hold, alt); } public bool UseItem(Humanoid user, ItemData item) { return false; } } public sealed class HuntingCorpsePhysics : MonoBehaviour { private const string PoseCount = "MasteryHuntTestPoseCount"; private GameObject model; private Rigidbody[] bodies; private ZNetView view; private Collider originalCollider; private int[] positionKeys; private int[] rotationKeys; private Vector3[] lastPositions; private Quaternion[] lastRotations; private float nextSave; private bool frozen; private bool initialized; private bool floats; private bool wasOwner; private float floatOffset; private bool placed; private float nextGroundCheck; private float nextRangeCheck; private bool terrainReady; private bool nearPlayer; private static readonly RaycastHit[] SupportHits = (RaycastHit[])(object)new RaycastHit[96]; private static readonly RaycastHit[] CrowdedSupportHits = (RaycastHit[])(object)new RaycastHit[384]; private static bool warnedSupportSaturation; public void Initialize(GameObject visual, Rigidbody[] parts, ZNetView network, bool shouldFloat, float offset) { //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: 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_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) model = visual; bodies = parts; view = network; originalCollider = ((Component)this).GetComponent<Collider>(); floats = shouldFloat; floatOffset = offset; int num = bodies.Length; positionKeys = new int[num]; rotationKeys = new int[num]; lastPositions = (Vector3[])(object)new Vector3[num]; lastRotations = (Quaternion[])(object)new Quaternion[num]; ZDO zDO = view.GetZDO(); bool flag = zDO.GetInt("MasteryHuntTestPoseCount", 0) == num; for (int i = 0; i < num; i++) { positionKeys[i] = StringExtensionMethods.GetStableHashCode("MasteryHuntTestP" + i); rotationKeys[i] = StringExtensionMethods.GetStableHashCode("MasteryHuntTestR" + i); Rigidbody val = bodies[i]; val.isKinematic = true; val.useGravity = true; val.detectCollisions = true; val.collisionDetectionMode = (CollisionDetectionMode)3; val.interpolation = (RigidbodyInterpolation)1; val.maxAngularVelocity = 5f; if (flag) { Vector3 vec = zDO.GetVec3(positionKeys[i], val.position); if (Finite(vec)) { Vector3 val2 = vec - ((Component)this).transform.position; if (((Vector3)(ref val2)).sqrMagnitude < 900f) { val.position = vec; } } Quaternion quaternion = zDO.GetQuaternion(rotationKeys[i], val.rotation); if (Finite(quaternion)) { val.rotation = quaternion; } } ref Vector3 reference = ref lastPositions[i]; reference = new Vector3(float.PositiveInfinity, 0f, 0f); ref Quaternion reference2 = ref lastRotations[i]; reference2 = Quaternion.identity; } frozen = true; initialized = true; wasOwner = view.IsOwner(); HuntingCorpsePush.Install(((Component)this).gameObject, bodies, view); } public bool PlaceAboveTerrain() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_00a6: 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) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)model == (Object)null || !model.activeInHierarchy) { return false; } Physics.SyncTransforms(); float num = 0f; bool flag = false; Collider[] componentsInChildren = model.GetComponentsInChildren<Collider>(); foreach (Collider val in componentsInChildren) { if (val.enabled && !val.isTrigger && !((Object)(object)val.attachedRigidbody == (Object)null)) { Bounds bounds = val.bounds; if (Support(((Bounds)(ref bounds)).center, out var support)) { flag = true; num = Mathf.Max(num, ((RaycastHit)(ref support)).point.y + 0.08f - ((Bounds)(ref bounds)).min.y); } } } if (!flag && !WaterSupport()) { return false; } if (num > 0f) { Rigidbody[] array = bodies; foreach (Rigidbody val2 in array) { val2.position += Vector3.up * num; } } Physics.SyncTransforms(); placed = true; terrainReady = true; nextGroundCheck = Time.unscaledTime + 0.5f; return true; } internal static bool Finite(Vector3 v) { return Valid(v.x) && Valid(v.y) && Valid(v.z); } private static bool Finite(Quaternion q) { return Valid(q.x) && Valid(q.y) && Valid(q.z) && Valid(q.w) && q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w > 0.01f; } private static bool Valid(float f) { return !float.IsNaN(f) && !float.IsInfinity(f); } private bool WaterSupport() { //IL_004f: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (!floats || (Object)(object)ZoneSystem.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || !ZNetScene.instance.IsAreaReady(((Component)this).transform.position)) { return false; } Vector3 position = ((Component)this).transform.position; float waterLevel = ZoneSystem.instance.m_waterLevel; if (position.y > 3000f || position.y > waterLevel + 12f || position.y < waterLevel - 12f) { return false; } float liquidLevel = Floating.GetLiquidLevel(position, 1f, (LiquidType)0); return Valid(liquidLevel) && Mathf.Abs(liquidLevel - waterLevel) <= 12f; } private bool Support(Vector3 point, out RaycastHit support) { //IL_003b: 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_004b: 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_0105: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_0087: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) int mask = LayerMask.GetMask(new string[4] { "terrain", "static_solid", "piece", "Default" }); RaycastHit[] array = SupportHits; int num = Physics.RaycastNonAlloc(point + Vector3.up * 2f, Vector3.down, array, 12f, mask, (QueryTriggerInteraction)1); if (num == array.Length) { array = CrowdedSupportHits; num = Physics.RaycastNonAlloc(point + Vector3.up * 2f, Vector3.down, array, 12f, mask, (QueryTriggerInteraction)1); if (num == array.Length) { array = Physics.RaycastAll(point + Vector3.up * 2f, Vector3.down, 12f, mask, (QueryTriggerInteraction)1); num = array.Length; if (!warnedSupportSaturation) { warnedSupportSaturation = true; HuntingPhysics.Log.LogWarning((object)"HUNT_PHYSICS support query exceeded reusable buffer; full safety query used"); } } } support = default(RaycastHit); float num2 = float.MaxValue; for (int i = 0; i < num; i++) { RaycastHit val = array[i]; float num3 = (placed ? (point.y + 0.5f) : (((Component)this).transform.position.y + 0.5f)); if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && !(((RaycastHit)(ref val)).normal.y < 0.2f) && (((Component)((RaycastHit)(ref val)).collider).gameObject.layer == LayerMask.NameToLayer("terrain") || !(((RaycastHit)(ref val)).point.y > num3)) && !((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<HuntingCorpseUse>() != (Object)null) && !((Component)((RaycastHit)(ref val)).collider).transform.IsChildOf(model.transform) && !((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Character>() != (Object)null) && ((RaycastHit)(ref val)).distance < num2) { num2 = ((RaycastHit)(ref val)).distance; support = val; } } return num2 < float.MaxValue; } private bool PlayerNearby() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) Vector3 val; foreach (Player allPlayer in Player.GetAllPlayers()) { if ((Object)(object)allPlayer != (Object)null && !((Character)allPlayer).IsDead()) { val = ((Component)allPlayer).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude <= 3600f) { return true; } } } if ((Object)(object)ZNet.instance != (Object)null) { foreach (ZDO allCharacterZDO in ZNet.instance.GetAllCharacterZDOS()) { if (allCharacterZDO != null) { val = allCharacterZDO.GetPosition() - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude <= 3600f) { return true; } } } } return false; } private void FixedUpdate() { //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) if (!initialized || (Object)(object)model == (Object)null || !model.activeSelf || (Object)(object)view == (Object)null || !view.IsValid()) { return; } bool flag = view.IsOwner(); Rigidbody[] array; if (flag != wasOwner) { array = bodies; foreach (Rigidbody val in array) { val.isKinematic = true; } frozen = true; placed = false; terrainReady = false; wasOwner = flag; nextRangeCheck = 0f; ReadRemotePose(snap: true); if (flag) { PlaceAboveTerrain(); } } if (Time.unscaledTime >= nextRangeCheck) { nextRangeCheck = Time.unscaledTime + 0.5f; nearPlayer = PlayerNearby(); } bool flag2 = !nearPlayer; if (flag && !flag2 && Time.unscaledTime >= nextGroundCheck) { nextGroundCheck = Time.unscaledTime + 0.5f; terrainReady = Support(((Component)this).transform.position, out var _) || WaterSupport(); if (terrainReady && !placed) { PlaceAboveTerrain(); } } bool flag3 = !flag || flag2 || !terrainReady || !placed; if (flag3 != frozen) { frozen = flag3; array = bodies; foreach (Rigidbody val in array) { val.isKinematic = flag3; if (!flag3) { val.WakeUp(); } } } if (frozen) { return; } array = bodies; foreach (Rigidbody val in array) { if (floats && (Object)(object)ZoneSystem.instance != (Object)null && val.position.y < ZoneSystem.instance.m_waterLevel + 4f) { Vector3 val2 = val.worldCenterOfMass + Vector3.up * floatOffset; float num = Mathf.Clamp((Floating.GetLiquidLevel(val2, 1f, (LiquidType)10) - val2.y) / 0.5f, 0f, 6f); if (num > 0f) { val.AddForce(Vector3.up * (20f * num * Time.fixedDeltaTime), (ForceMode)2); Rigidbody obj = val; obj.linearVelocity *= 1f - 0.05f * num; } } Vector3 linearVelocity = val.linearVelocity; if (((Vector3)(ref linearVelocity)).sqrMagnitude > 36f) { val.linearVelocity = Vector3.ClampMagnitude(val.linearVelocity, 6f); } } } private void LateUpdate() { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: 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_0184: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) if (!initialized || (Object)(object)model == (Object)null || (Object)(object)view == (Object)null || !view.IsValid()) { return; } ZDO zDO = view.GetZDO(); bool flag = zDO.GetBool("MasteryHuntDone", false); if ((Object)(object)originalCollider != (Object)null) { originalCollider.enabled = false; } if (model.activeSelf == flag) { model.SetActive(!flag); } if (flag) { return; } if (!view.IsOwner()) { ReadRemotePose(snap: false); } else { if (frozen) { return; } Vector3 val = Vector3.zero; Rigidbody[] array = bodies; foreach (Rigidbody val2 in array) { val += val2.position; } val /= (float)bodies.Length; if (!Finite(val)) { return; } ((Component)this).transform.position = val; if (Time.unscaledTime < nextSave) { return; } nextSave = Time.unscaledTime + 0.5f; Vector3 val3 = zDO.GetPosition() - val; if (((Vector3)(ref val3)).sqrMagnitude > 0.0001f) { zDO.SetPosition(val); } for (int j = 0; j < bodies.Length; j++) { Rigidbody val2 = bodies[j]; val3 = val2.position - lastPositions[j]; if (!(((Vector3)(ref val3)).sqrMagnitude < 0.0001f) || !(Quaternion.Angle(val2.rotation, lastRotations[j]) < 0.5f)) { zDO.Set(positionKeys[j], val2.position); zDO.Set(rotationKeys[j], val2.rotation); ref Vector3 reference = ref lastPositions[j]; reference = val2.position; ref Quaternion reference2 = ref lastRotations[j]; reference2 = val2.rotation; } } zDO.Set("MasteryHuntTestPoseCount", bodies.Length); } } private void ReadRemotePose(bool snap) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = view.GetZDO(); if (zDO.GetInt("MasteryHuntTestPoseCount", 0) != bodies.Length) { return; } float num = (snap ? 1f : (1f - Mathf.Exp(-12f * Time.unscaledDeltaTime))); for (int i = 0; i < bodies.Length; i++) { Rigidbody val = bodies[i]; Vector3 vec = zDO.GetVec3(positionKeys[i], val.position); Quaternion quaternion = zDO.GetQuaternion(rotationKeys[i], val.rotation); if (!Finite(vec) || !Finite(quaternion)) { continue; } Vector3 val2 = vec - zDO.GetPosition(); if (((Vector3)(ref val2)).sqrMagnitude > 900f) { continue; } if (!snap) { val2 = vec - val.position; if (!(((Vector3)(ref val2)).sqrMagnitude > 25f)) { val.position = Vector3.Lerp(val.position, vec, num); val.rotation = Quaternion.Slerp(val.rotation, quaternion, num); continue; } } val.position = vec; val.rotation = quaternion; } } private void OnDisable() { if ((Object)(object)model != (Object)null) { model.SetActive(false); } } private void OnDestroy() { if ((Object)(object)model != (Object)null) { Object.Destroy((Object)(object)model); } } } public sealed class HuntingCorpsePush : MonoBehaviour { private const string Rpc = "MasteryHuntPushV1"; private ZNetView view; private Rigidbody[] bodies; private float nextSend; private float nextApply; private readonly Dictionary<long, float> senderUntil = new Dictionary<long, float>(); public static void Install(GameObject root, Rigidbody[] parts, ZNetView network) { if ((Object)(object)root == (Object)null || (Object)(object)network == (Object)null || !network.IsValid() || parts == null || parts.Length == 0) { return; } HuntingCorpsePush huntingCorpsePush = root.GetComponent<HuntingCorpsePush>(); if ((Object)(object)huntingCorpsePush == (Object)null) { huntingCorpsePush = root.AddComponent<HuntingCorpsePush>(); } huntingCorpsePush.view = network; huntingCorpsePush.bodies = parts; network.Register<long, int, Vector3, float>("MasteryHuntPushV1", (Method<long, int, Vector3, float>)huntingCorpsePush.Receive); for (int i = 0; i < parts.Length; i++) { if (!((Object)(object)parts[i] == (Object)null)) { HuntingCorpsePushContact huntingCorpsePushContact = ((Component)parts[i]).GetComponent<HuntingCorpsePushContact>(); if ((Object)(object)huntingCorpsePushContact == (Object)null) { huntingCorpsePushContact = ((Component)parts[i]).gameObject.AddComponent<HuntingCorpsePushContact>(); } huntingCorpsePushContact.Target = huntingCorpsePush; huntingCorpsePushContact.Part = i; } } } internal void Contact(int part, Collision collision) { //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)view == (Object)null || !view.IsValid() || view.IsOwner() || bodies == null || part < 0 || part >= bodies.Length || (Object)(object)bodies[part] == (Object)null || !bodies[part].isKinematic || Time.unscaledTime < nextSend || collision == null || collision.contactCount == 0) { return; } Player val = (((Object)(object)collision.collider == (Object)null) ? null : ((Component)collision.collider).GetComponentInParent<Player>()); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || ((Character)val).IsDead() || ((Character)val).IsTeleporting()) { return; } ZNetView component = ((Component)val).GetComponent<ZNetView>(); Rigidbody component2 = ((Component)val).GetComponent<Rigidbody>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner() && !((Object)(object)component2 == (Object)null)) { Vector3 linearVelocity = component2.linearVelocity; linearVelocity.y = 0f; Vector3 relativeVelocity = collision.relativeVelocity; relativeVelocity.y = 0f; float num = Mathf.Max(((Vector3)(ref linearVelocity)).magnitude, ((Vector3)(ref relativeVelocity)).magnitude); if (Finite(num) && !(num < 0.25f)) { ContactPoint contact = collision.GetContact(0); Vector3 point = ((ContactPoint)(ref contact)).point; nextSend = Time.unscaledTime + 0.2f; view.InvokeRPC("MasteryHuntPushV1", new object[4] { val.GetPlayerID(), part, point, Mathf.Min(num, 6f) }); } } } private void Receive(long sender, long character, int part, Vector3 point, float speed) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)view == (Object)null || !view.IsValid() || !view.IsOwner() || bodies == null || part < 0 || part >= bodies.Length || !Finite(point) || !Finite(speed) || speed < 0.25f || speed > 6f || Time.unscaledTime < nextApply || (Object)(object)ZNet.instance == (Object)null) { return; } ZDO zDO = view.GetZDO(); Rigidbody val = bodies[part]; if (zDO.GetBool("MasteryHuntDone", false) || !zDO.GetBool("MasteryHuntReady", false) || (Object)(object)val == (Object)null || val.isKinematic || !((Component)val).gameObject.activeInHierarchy) { return; } senderUntil.TryGetValue(sender, out var value); if (Time.unscaledTime < value) { return; } ZDO val2 = null; foreach (ZDO allCharacterZDO in ZNet.instance.GetAllCharacterZDOS()) { if (allCharacterZDO != null && allCharacterZDO.GetOwner() == sender && allCharacterZDO.GetLong(ZDOVars.s_playerID, 0L) == character && character != 0) { val2 = allCharacterZDO; break; } } if (val2 == null || (Object)(object)ZNetScene.instance == (Object)null) { return; } GameObject prefab = ZNetScene.instance.GetPrefab(val2.GetPrefab()); Player val3 = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<Player>()); if ((Object)(object)val3 == (Object)null || val2.GetFloat(ZDOVars.s_health, ((Character)val3).m_health) <= 0f) { return; } Vector3 val4 = val2.GetPosition() - point; if (((Vector3)(ref val4)).sqrMagnitude > 16f) { return; } bool flag = false; Collider[] componentsInChildren = ((Component)val).GetComponentsInChildren<Collider>(); foreach (Collider val5 in componentsInChildren) { if (!((Object)(object)val5 == (Object)null) && val5.enabled && !val5.isTrigger && !((Object)(object)val5.attachedRigidbody != (Object)(object)val)) { val4 = val5.ClosestPoint(point) - point; if (((Vector3)(ref val4)).sqrMagnitude <= 2.25f) { flag = true; break; } } } if (flag) { Vector3 p = val.worldCenterOfMass - val2.GetPosition(); p.y = 0f; if (((Vector3)(ref p)).sqrMagnitude < 0.01f) { p = point - val2.GetPosition(); p.y = 0f; } if (!(((Vector3)(ref p)).sqrMagnitude < 0.01f) && Finite(p)) { senderUntil[sender] = Time.unscaledTime + 0.2f; nextApply = Time.unscaledTime + 0.075f; val.WakeUp(); val.AddForceAtPosition(((Vector3)(ref p)).normalized * Mathf.Clamp(speed * 0.12f, 0.08f, 0.6f), point, (ForceMode)2); } } } private static bool Finite(float n) { return !float.IsNaN(n) && !float.IsInfinity(n); } private static bool Finite(Vector3 p) { return Finite(p.x) && Finite(p.y) && Finite(p.z); } } public sealed class HuntingCorpsePushContact : MonoBehaviour { internal HuntingCorpsePush Target; internal int Part; private void OnCollisionEnter(Collision collision) { if ((Object)(object)Target != (Object)null) { Target.Contact(Part, collision); } } private void OnCollisionStay(Collision collision) { if ((Object)(object)Target != (Object)null) { Target.Contact(Part, collision); } } }
plugins/ValheimMastery/MasteryWorldFeatures.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; using ValheimMastery.Progression; using ValheimMastery.Runtime; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace MasteryVoyagesTest; [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("org.valheim.mastery.worldfeatures", "Mastery World Features", "1.1.0")] [BepInDependency("org.valheim.mastery", "0.18.0")] public sealed class Voyages : BaseUnityPlugin { public static Voyages Instance; internal static readonly MasterySkill[] Skills = SkillRegistry.Implemented(); internal static ConfigEntry<KeyboardShortcut> BookKey; internal static ConfigEntry<bool> Animate; internal static readonly string Prefix = "org.valheim.mastery.voyages.test."; private static readonly Dictionary<MasterySkill, string> names = new Dictionary<MasterySkill, string> { { (MasterySkill)0, "Angriff" }, { (MasterySkill)1, "Stärke" }, { (MasterySkill)2, "Verteidigung" }, { (MasterySkill)3, "Lebenspunkte" }, { (MasterySkill)4, "Fernkampf" }, { (MasterySkill)5, "Magie" }, { (MasterySkill)6, "Gewandtheit" }, { (MasterySkill)7, "Bergbau" }, { (MasterySkill)8, "Holzfällen" }, { (MasterySkill)13, "Schmieden" }, { (MasterySkill)14, "Handwerk" }, { (MasterySkill)10, "Landwirtschaft" }, { (MasterySkill)11, "Sammeln" }, { (MasterySkill)15, "Kochen" }, { (MasterySkill)16, "Alchemie" }, { (MasterySkill)18, "Segeln" }, { (MasterySkill)19, "Slayer" }, { (MasterySkill)12, "Jagen" }, { (MasterySkill)17, "Baukunst" }, { (MasterySkill)9, "Angeln" }, { (MasterySkill)20, "Gebet" }, { (MasterySkill)21, "Tiermeister" } }; private static readonly MethodInfo areaAccess = AccessTools.Method(typeof(MasteryPlugin).Assembly.GetType("ValheimMastery.Runtime.ActivityAssets"), "Access", new Type[2] { typeof(long), typeof(Vector3) }, (Type[])null); private float next; private Player last; internal static bool Local => (Object)(object)ZNet.instance != (Object)null; internal static bool De => Localization.instance == null || Localization.instance.GetSelectedLanguage() == "German"; internal static string T(string de, string en) { return De ? de : en; } internal static string Name(MasterySkill s) { //IL_0017: 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) string value; return (De && names.TryGetValue(s, out value)) ? value : ((object)s).ToString(); } internal static int Level(Player p, MasterySkill s) { //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) try { return GeneralSkillStore.Read((IDictionary<string, string>)p.m_customData, s).Level; } catch { return 1; } } internal static Player Sender(long sender) { if ((Object)(object)Player.m_localPlayer != (Object)null && sender == ZNet.GetUID()) { return Player.m_localPlayer; } foreach (Player allPlayer in Player.GetAllPlayers()) { ZNetView component = ((Component)allPlayer).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid() && component.GetZDO().GetOwner() == sender) { return allPlayer; } } return null; } internal static long RequestCharacter(long sender, Vector3 point, float range) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0125: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) Player val = Sender(sender); if ((Object)(object)val != (Object)null) { return (!((Character)val).IsDead() && Vector3.Distance(((Component)val).transform.position, point) < range && Access(val, point)) ? val.GetPlayerID() : 0; } if ((Object)(object)ZNet.instance == (Object)null || areaAccess == null) { return 0L; } foreach (ZDO allCharacterZDO in ZNet.instance.GetAllCharacterZDOS()) { if (allCharacterZDO == null || allCharacterZDO.GetOwner() != sender) { continue; } GameObject prefab = ZNetScene.instance.GetPrefab(allCharacterZDO.GetPrefab()); Character val2 = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<Character>()); if (!((Object)(object)val2 == (Object)null) && !(allCharacterZDO.GetFloat(ZDOVars.s_health, val2.m_health) <= 0f)) { long num = allCharacterZDO.GetLong(ZDOVars.s_playerID, 0L); if (num != 0 && Vector3.Distance(allCharacterZDO.GetPosition(), point) < range && (bool)areaAccess.Invoke(null, new object[2] { num, point })) { return num; } } } return 0L; } internal static bool Access(Player p, Vector3 point) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)p == (Object)null) { return false; } if ((Object)(object)p == (Object)(object)Player.m_localPlayer) { return PrivateArea.CheckAccess(point, 0f, false, false); } return areaAccess != null && (bool)areaAccess.Invoke(null, new object[2] { p.GetPlayerID(), point }); } private void Awake() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown Instance = this; BookKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "AdventureBook", new KeyboardShortcut((KeyCode)291, (KeyCode[])(object)new KeyCode[0]), "Open the adventure book."); Animate = ((BaseUnityPlugin)this).Config.Bind<bool>("Sails", "AnimateApex", true, "Rising illuminated tree followed by fiery symbol rims over eight seconds. Disable for a static sail."); TestIcons.Load(); ConstructionHomeDestinations.Select = new SelectDestination(HomePoint.TryDestination); ConstructionHomeDestinations.Validate = new ResolveDestination(HomePoint.ResolveDestination); Harmony val = new Harmony("org.valheim.mastery.test.voyages"); val.PatchAll(typeof(Voyages).Assembly); Reserves.Install(val); ((BaseUnityPlugin)this).Logger.LogInfo((object)"MASTERY_WORLD_FEATURES loaded; visuals, sails, reserves, home marker and pickup radius"); } private void Update() { //IL_003e: 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) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)(object)last) { Window.Close(); last = localPlayer; } if ((Object)(object)localPlayer == (Object)null) { return; } KeyboardShortcut value = BookKey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && ((Object)(object)Chat.instance == (Object)null || !Chat.instance.IsChatDialogWindowVisible()) && !Console.IsVisible()) { Window.OpenBook(); } Window.Tick(); if (Time.time >= next) { next = Time.time + 2f; if (Local) { Adventure.Tick(localPlayer); } } } private void OnGUI() { Window.Draw(); } } public sealed class MasterySail : MonoBehaviour { public const string Key = "MasteryTestSail"; public Ship Ship; public ZNetView View; private Renderer[] renderers; private Material[][] originals; private Material[][] custom; private string applied = ""; private float next; private int lastFrame = -1; private static readonly Dictionary<string, Texture2D> cache = new Dictionary<string, Texture2D>(); private static Texture2D rough; private static Texture2D flatNormal; private static readonly Type coreArt = typeof(MasteryPlugin).Assembly.GetType("ValheimMastery.Runtime.BeastmasterArtRuntime"); private static readonly MethodInfo loadCoreTexture = AccessTools.Method(coreArt, "LoadTexture", new Type[1] { typeof(string) }, (Type[])null); private static readonly MethodInfo loadCoreApex = AccessTools.Method(coreArt, "LoadApex", new Type[1] { typeof(string) }, (Type[])null); public static Texture2D Texture(string name) { //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown if (name == "beastmaster" || name == "beastmaster_concept") { return CoreArt("LoadTexture", "sail.png"); } if (name != null && name.Length == 5 && name.StartsWith("apex", StringComparison.Ordinal) && name[4] >= '0' && name[4] <= '7') { return CoreArt("LoadApex", (name[4] == '0') ? "texture" : ("texture" + name[4])); } if (cache.TryGetValue(name, out var value)) { return value; } using Stream stream = typeof(Voyages).Assembly.GetManifestResourceStream("Sails." + name + ".png"); if (stream == null) { return null; } byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); value = new Texture2D(2, 2, (TextureFormat)3, true); ImageConversion.LoadImage(value, array, true); ((Texture)value).wrapMode = (TextureWrapMode)1; ((Object)value).name = "Mastery sail " + name; cache[name] = value; return value; } private static Texture2D CoreArt(string method, string name) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown MethodInfo methodInfo = ((method == "LoadApex") ? loadCoreApex : loadCoreTexture); if (methodInfo == null) { throw new MissingMethodException("Core22 shared art API: " + method); } return (Texture2D)methodInfo.Invoke(null, new object[1] { name }); } private static string BaseDesign(string design) { return design.EndsWith("_concept", StringComparison.Ordinal) ? design.Substring(0, design.Length - 8) : design; } public static bool Valid(string design) { return design != null && (design == "" || Voyages.Skills.Any((MasterySkill s) => SkillRegistry.Key(s) == BaseDesign(design)) || Enumerable.Range(0, 8).Any((int i) => design == "apex" + i)); } public static bool Unlocked(Player p, string design) { if ((Object)(object)p == (Object)null || !Valid(design)) { return false; } if (design == "") { return true; } if (design.StartsWith("apex")) { return Voyages.Skills.All((MasterySkill s) => Voyages.Level(p, s) == 100); } return Voyages.Skills.Any((MasterySkill s) => SkillRegistry.Key(s) == BaseDesign(design) && Voyages.Level(p, s) == 100); } private void Awake() { Ship = ((Component)this).GetComponent<Ship>(); View = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)Ship == (Object)null || (Object)(object)View == (Object)null || !View.IsValid()) { ((Behaviour)this).enabled = false; return; } View.Register<string>("MasterySailDesign", (Action<long, string>)ApplyDesign); renderers = (from r in ((Component)Ship).GetComponentsInChildren<Renderer>(true) where (r is MeshRenderer || r is SkinnedMeshRenderer) && ((Object)r).name.IndexOf("sail", StringComparison.OrdinalIgnoreCase) >= 0 && r.sharedMaterials.All((Material m) => (Object)(object)m != (Object)null && (Object)(object)m.mainTexture != (Object)null) select r).ToArray(); if (renderers.Length == 0) { ((Behaviour)this).enabled = false; return; } originals = renderers.Select((Renderer r) => r.sharedMaterials).ToArray(); custom = new Material[renderers.Length][]; } public bool Choose(Player p, string design) { //IL_0042: 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_0064: Unknown result type (might be due to invalid IL or missing references) if (!Voyages.Local || !((Behaviour)this).enabled || (Object)(object)View == (Object)null || !View.IsValid() || !Unlocked(p, design) || ((Character)p).IsDead() || Vector3.Distance(((Component)p).transform.position, ((Component)this).transform.position) > 25f || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { return false; } View.InvokeRPC("MasterySailDesign", new object[1] { design }); return true; } private void ApplyDesign(long sender, string design) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)View == (Object)null) && View.IsValid() && View.IsOwner() && design != null && design.Length <= 80 && Valid(design) && Voyages.RequestCharacter(sender, ((Component)this).transform.position, 25f) != 0) { View.GetZDO().Set("MasteryTestSail", design); Refresh(force: true); } } private void Update() { if (Time.time >= next) { next = Time.time + 0.25f; Refresh(force: false); } else { AnimateFrame(force: false); } } public void Refresh(bool force) { //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015c: 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_0281: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Expected O, but got Unknown //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Expected O, but got Unknown //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)View == (Object)null || !View.IsValid() || renderers == null) { return; } string text = View.GetZDO().GetString("MasteryTestSail", ""); if (!Valid(text)) { text = ""; } bool flag = text != applied; if (flag || force) { Restore(); applied = text; lastFrame = -1; if (text != "") { for (int i = 0; i < renderers.Length; i++) { custom[i] = ((IEnumerable<Material>)originals[i]).Select((Func<Material, Material>)((Material m) => new Material(m))).ToArray(); Renderer obj = renderers[i]; SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((obj is SkinnedMeshRenderer) ? obj : null); MeshFilter component = ((Component)renderers[i]).GetComponent<MeshFilter>(); Mesh val2 = (((Object)(object)val != (Object)null) ? val.sharedMesh : (((Object)(object)component == (Object)null) ? null : component.sharedMesh)); Vector2[] array = (Vector2[])(((Object)(object)val2 == (Object)null) ? ((Array)new Vector2[0]) : ((Array)val2.uv)); Vector2 one = Vector2.one; Vector2 zero = Vector2.zero; if (array.Length > 0) { float num = array.Min((Vector2 v) => v.x); float num2 = array.Max((Vector2 v) => v.x); float num3 = array.Min((Vector2 v) => v.y); float num4 = array.Max((Vector2 v) => v.y); ((Vector2)(ref one))..ctor(1f / Mathf.Max(0.01f, num2 - num), 1f / Mathf.Max(0.01f, num4 - num3)); ((Vector2)(ref zero))..ctor((0f - num) * one.x, (0f - num3) * one.y); } if ((Object)(object)rough == (Object)null) { rough = new Texture2D(1, 1, (TextureFormat)4, false); rough.SetPixel(0, 0, Color.clear); rough.Apply(); ((Object)rough).name = "Mastery sail matte cloth"; } if ((Object)(object)flatNormal == (Object)null) { flatNormal = new Texture2D(1, 1, (TextureFormat)4, false, true); flatNormal.SetPixel(0, 0, new Color(0.5f, 0.5f, 1f, 0.5f)); flatNormal.Apply(); ((Object)flatNormal).name = "Mastery sail woven normal"; } Material[] array2 = custom[i]; foreach (Material val3 in array2) { val3.mainTexture = (Texture)(object)Texture(text); val3.mainTextureScale = one; val3.mainTextureOffset = zero; if (val3.HasProperty("_Color")) { val3.color = Color.white; } string[] array3 = new string[2] { "_MetalTex", "_EmissiveTex" }; foreach (string text2 in array3) { if (val3.HasProperty(text2)) { val3.SetTexture(text2, (Texture)(object)rough); } } if (val3.HasProperty("_EmissiveTex")) { val3.SetTextureScale("_EmissiveTex", one); val3.SetTextureOffset("_EmissiveTex", zero); } if (val3.HasProperty("_EmissionColor")) { val3.SetColor("_EmissionColor", Color.black); } if (val3.HasProperty("_BumpMap")) { val3.SetTexture("_BumpMap", (Texture)(object)flatNormal); } array3 = new string[3] { "_Glossiness", "_Metallic", "_Smoothness" }; foreach (string text2 in array3) { if (val3.HasProperty(text2)) { val3.SetFloat(text2, 0f); } } } renderers[i].sharedMaterials = custom[i]; } } } AnimateFrame(flag || force); } private void AnimateFrame(bool force) { //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) if (applied == "" || custom == null) { return; } int num = ((applied.StartsWith("apex") && Voyages.Animate.Value) ? ApexAnimation.Frame : (-1)); if (num == lastFrame && !force) { return; } lastFrame = num; Texture2D mainTexture = Texture(applied); Texture2D val = ((num < 0) ? rough : ApexAnimation.Texture(num)); Material[][] array = custom; foreach (Material[] array2 in array) { if (array2 == null) { continue; } Material[] array3 = array2; foreach (Material val2 in array3) { val2.mainTexture = (Texture)(object)mainTexture; if (val2.HasProperty("_EmissiveTex")) { val2.SetTexture("_EmissiveTex", (Texture)(object)val); } if (val2.HasProperty("_EmissionColor")) { val2.SetColor("_EmissionColor", (num < 0) ? Color.black : (Color.white * 1.8f)); } } } } private void Restore() { if (renderers == null) { return; } for (int i = 0; i < renderers.Length; i++) { if ((Object)(object)renderers[i] != (Object)null) { renderers[i].sharedMaterials = originals[i]; } if (custom[i] != null) { Material[] array = custom[i]; foreach (Material val in array) { Object.Destroy((Object)(object)val); } custom[i] = null; } } } private void OnDestroy() { Restore(); } } [HarmonyPatch(typeof(Ship), "Awake")] internal static class ShipStart { private static void Postfix(Ship __instance) { if ((Object)(object)((Component)__instance).GetComponent<MasterySail>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<MasterySail>(); } } } [HarmonyPatch(typeof(ShipControlls), "GetHoverText")] internal static class SailHover { private static void Postfix(ShipControlls __instance, ref string __result) { MasterySail componentInParent = ((Component)__instance).GetComponentInParent<MasterySail>(); if ((Object)(object)componentInParent != (Object)null && ((Behaviour)componentInParent).enabled) { __result = __result + "\n[<color=yellow>Shift + E</color>] " + Voyages.T("Segel gestalten", "Customize sail"); } } } [HarmonyPatch(typeof(ShipControlls), "Interact")] internal static class SailUse { private static bool Prefix(ShipControlls __instance, Humanoid __0, bool __1, bool __2, ref bool __result) { if (__1 || (Object)(object)__0 != (Object)(object)Player.m_localPlayer || (!__2 && !Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303))) { return true; } MasterySail componentInParent = ((Component)__instance).GetComponentInParent<MasterySail>(); if ((Object)(object)componentInParent == (Object)null || !((Behaviour)componentInParent).enabled) { return true; } Window.OpenSail(componentInParent); __result = true; return false; } } [HarmonyPatch(typeof(Player), "TakeInput")] internal static class BlockPlayer { private static void Postfix(ref bool __result) { if (Window.Blocks) { __result = false; } } } [HarmonyPatch(typeof(PlayerController), "TakeInput", new Type[] { typeof(bool) })] internal static class BlockController { private static void Postfix(ref bool __result) { if (Window.Blocks) { __result = false; } } } [HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")] internal static class CursorPatch { private static bool Prefix() { if (!Window.Visible) { return true; } ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); return false; } } public static class Window { public static bool Visible; private static int closed = -1; private static MasterySail sail; private static Container chest; private static int page; private static string selection = ""; private static Vector2 scroll; private static Rect window; private static GUISkin skin; private static bool concept; private static readonly string[] ApexNames = new string[8] { "Bordeaux", "Königsblau", "Smaragdgrün", "Purpur", "Elfenbein", "Anthrazit", "Schwarz / Weiß / Rot", "Weiß / Schwarz / Rot" }; private static List<ItemData> items = new List<ItemData>(); public static bool Blocks => Visible || closed == Time.frameCount; private static void Open() { //IL_0007: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) Visible = true; scroll = Vector2.zero; window = new Rect(30f, 35f, 820f, 640f); ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); } public static void OpenBook() { sail = null; chest = null; page = 0; Open(); } public static void OpenSail(MasterySail s) { sail = s; chest = null; selection = s.View.GetZDO().GetString("MasteryTestSail", ""); concept = selection.EndsWith("_concept"); page = 2; Open(); } public static void OpenChest(Container c) { chest = c; sail = null; page = 3; items = (from i in c.GetInventory().GetAllItems() group i by i.m_shared.m_name into g select g.First()).ToList(); foreach (GameObject item2 in ObjectDB.instance.m_items) { ItemDrop item = item2.GetComponent<ItemDrop>(); if ((Object)(object)item != (Object)null && Reserves.Minimum(c, item.m_itemData.m_shared.m_name) > 0 && !items.Any((ItemData i) => i.m_shared.m_name == item.m_itemData.m_shared.m_name)) { items.Add(item.m_itemData); } } Open(); } public static void Close() { Visible = false; sail = null; chest = null; closed = Time.frameCount; } public static void Tick() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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) if (Visible) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || Input.GetKeyDown((KeyCode)27) || ((Object)(object)sail != (Object)null && Vector3.Distance(((Component)sail).transform.position, ((Component)localPlayer).transform.position) > 25f) || ((Object)(object)chest != (Object)null && Vector3.Distance(((Component)chest).transform.position, ((Component)localPlayer).transform.position) > 5f)) { Close(); return; } ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); } } public static void Draw() { //IL_0143: Unknown result type (might be due to invalid IL or missing references) //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_00b1: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) if (!Visible || (Object)(object)Player.m_localPlayer == (Object)null) { return; } GUISkin val = GUI.skin; Matrix4x4 matrix = GUI.matrix; try { if ((Object)(object)skin == (Object)null) { Type type = typeof(MasteryPlugin).Assembly.GetType("ValheimMastery.Runtime.BoardTheme"); skin = (GUISkin)AccessTools.Property(type, "Skin").GetValue(null, null); } GUI.skin = skin; float num = Mathf.Min(1f, Mathf.Min((float)Screen.width / 880f, (float)Screen.height / 710f)); GUI.matrix = Matrix4x4.Scale(Vector3.one * num); string text = (((Object)(object)chest != (Object)null) ? Voyages.T("MASTERY · KISTENRESERVE", "MASTERY · CHEST RESERVE") : (((Object)(object)sail != (Object)null) ? Voyages.T("MASTERY · SEGEL", "MASTERY · SAILS") : Voyages.T("MASTERY · ABENTEUERBUCH", "MASTERY · ADVENTURE BOOK"))); window = GUI.Window(492765, window, new WindowFunction(Contents), text); } finally { GUI.skin = val; GUI.matrix = matrix; } } private static void Contents(int id) { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) GUILayout.Space(35f); if (!Voyages.Local) { GUILayout.Label(Voyages.T("Diese erste Testfassung kann nur in einer lokalen Einzelspielerwelt bearbeitet werden.", "This first prototype can only be edited in a local single-player world."), (GUILayoutOption[])(object)new GUILayoutOption[0]); } if ((Object)(object)chest == (Object)null && (Object)(object)sail == (Object)null) { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button(Voyages.T("Abenteuerbuch", "Adventure book"), (GUILayoutOption[])(object)new GUILayoutOption[0])) { page = 0; scroll = Vector2.zero; } if (GUILayout.Button(Voyages.T("Schatzspuren", "Treasure trails"), (GUILayoutOption[])(object)new GUILayoutOption[0])) { page = 1; scroll = Vector2.zero; } GUILayout.EndHorizontal(); } scroll = GUILayout.BeginScrollView(scroll, (GUILayoutOption[])(object)new GUILayoutOption[0]); if ((Object)(object)chest != (Object)null) { Chest(); } else if ((Object)(object)sail != (Object)null) { Sails(); } else if (page == 1) { Trails(); } else { Book(); } GUILayout.EndScrollView(); if (GUILayout.Button(Voyages.T("Schließen", "Close"), (GUILayoutOption[])(object)new GUILayoutOption[0])) { Close(); } GUI.DragWindow(new Rect(0f, 0f, 820f, 28f)); } private static void Book() { //IL_0034: 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_005f: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; GUILayout.Label(Voyages.T("Meisterschaften · vorhandene Skillstände bleiben erhalten. Neue Bossnachweise zählen ab jetzt, wenn du den letzten Treffer ausführst.", "Masteries · existing skill progress is preserved. New boss records count from now on when you land the final blow."), (GUILayoutOption[])(object)new GUILayoutOption[0]); MasterySkill[] skills = Voyages.Skills; foreach (MasterySkill s in skills) { int num = Voyages.Level(localPlayer, s); GUILayout.Label(((num == 100) ? "◆ " : "· ") + Voyages.Name(s) + " " + num + " / 100", (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Space(8f); GUILayout.Label(Voyages.T("Bossnachweise", "Boss records"), (GUILayoutOption[])(object)new GUILayoutOption[0]); foreach (string item in Adventure.Bosses(localPlayer)) { GameObject prefab = ZNetScene.instance.GetPrefab(item); Character val = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<Character>()); GUILayout.Label(((Object)(object)val == (Object)null) ? item : Localization.instance.Localize(val.m_name), (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Label(Voyages.T("Besondere Funde · neu aufgesammelte Edelsteine, seltene Erze und Ritualgegenstände", "Notable finds · newly picked-up gems, rare ores and ritual items"), (GUILayoutOption[])(object)new GUILayoutOption[0]); foreach (string item2 in Adventure.Finds(localPlayer)) { GameObject prefab = ObjectDB.instance.GetItemPrefab(item2); ItemDrop val2 = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<ItemDrop>()); GUILayout.Label(((Object)(object)val2 == (Object)null) ? item2 : Localization.instance.Localize(val2.m_itemData.m_shared.m_name), (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Label(Voyages.T("Entdeckte Titel", "Discovered titles"), (GUILayoutOption[])(object)new GUILayoutOption[0]); for (int j = 0; j < 3; j++) { if (Adventure.State(localPlayer, j) == 4) { GUILayout.Label("◆ " + Adventure.Title(j), (GUILayoutOption[])(object)new GUILayoutOption[0]); } } GUILayout.Label(Voyages.T("Segel: Shift + E am Steuer. Kistenreserve: Shift + E an einer Kiste. Diese Ergänzungen vergeben keine XP oder Werteboni.", "Sails: Shift + E at the helm. Chest reserves: Shift + E at a chest. These additions grant no XP or stat bonuses."), (GUILayoutOption[])(object)new GUILayoutOption[0]); } private static void Trails() { Player localPlayer = Player.m_localPlayer; GUILayout.Label(Voyages.T("Drei kurze Erkundungsspuren. Pro Figur einmal; der Titel erscheint im Abenteuerbuch. Bei einem Weltwechsel beginnt eine offene Spur neu.", "Three short exploration trails. Once per character; titles appear in the adventure book. An unfinished trail restarts when changing worlds."), (GUILayoutOption[])(object)new GUILayoutOption[0]); for (int i = 0; i < 3; i++) { GUILayout.Label(Adventure.Title(i) + " · " + Voyages.Name(Adventure.TrailSkills[i]), (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(Adventure.Instruction(localPlayer, i), (GUILayoutOption[])(object)new GUILayoutOption[0]); if (Adventure.State(localPlayer, i) == 0) { GUI.enabled = Voyages.Local; if (GUILayout.Button(Voyages.T("Spur aufnehmen", "Follow trail"), (GUILayoutOption[])(object)new GUILayoutOption[0])) { Adventure.Begin(localPlayer, i); } GUI.enabled = true; } GUILayout.Space(15f); } } private static void Sails() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_00a1: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(400f) }); if (GUILayout.Button("Vanilla", (GUILayoutOption[])(object)new GUILayoutOption[0])) { selection = ""; } MasterySkill[] skills = Voyages.Skills; foreach (MasterySkill val in skills) { string text = SkillRegistry.Key(val); if (GUILayout.Button(((Voyages.Level(localPlayer, val) == 100) ? "◆ " : "· ") + Voyages.Name(val) + ((Voyages.Level(localPlayer, val) == 100) ? "" : (" · " + Voyages.Level(localPlayer, val) + "/100")), (GUILayoutOption[])(object)new GUILayoutOption[0])) { selection = text + (concept ? "_concept" : ""); } } for (int j = 0; j < 8; j++) { if (GUILayout.Button("APEX · " + ApexNames[j], (GUILayoutOption[])(object)new GUILayoutOption[0])) { selection = "apex" + j; } } GUILayout.EndVertical(); GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(Voyages.T("Vorschau", "Preview"), (GUILayoutOption[])(object)new GUILayoutOption[0]); if (selection != "") { Texture2D val2 = MasterySail.Texture(selection); if ((Object)(object)val2 != (Object)null) { GUILayout.Label((Texture)(object)val2, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(280f), GUILayout.Height(280f) }); } } else { GUILayout.Label(Voyages.T("Das unveränderte Segel dieses Schiffes.", "This ship's original sail."), (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Label(Voyages.T("Level 100 schaltet dein Skillsegel frei. Apex benötigt alle " + Voyages.Skills.Length + " Meisterschaften. Kostenlos; ohne Wertebonus.", "Level 100 unlocks a skill sail. Apex requires all " + Voyages.Skills.Length + " masteries. Free; no stat bonus."), (GUILayoutOption[])(object)new GUILayoutOption[0]); Voyages.Animate.Value = GUILayout.Toggle(Voyages.Animate.Value, Voyages.T("Apex-Symbole animieren", "Animate Apex symbols"), (GUILayoutOption[])(object)new GUILayoutOption[0]); GUI.enabled = Voyages.Local && MasterySail.Unlocked(localPlayer, selection); if (GUILayout.Button(Voyages.T("Auf dieses Schiff anwenden", "Apply to this ship"), (GUILayoutOption[])(object)new GUILayoutOption[0])) { sail.Choose(localPlayer, selection); } GUI.enabled = true; GUILayout.Label(Voyages.T("Auswahl bleibt am Schiff gespeichert. Die Windbewegung des Originalsegels bleibt erhalten.", "Selection is saved on the ship. Original sail movement in the wind is preserved."), (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.EndVertical(); GUILayout.EndHorizontal(); } private static void Chest() { GUILayout.Label(Voyages.T("Mindestbestand pro Material. AzuCraftyBoxes darf nur den Überschuss verbrauchen; manuelles Entnehmen bleibt möglich. Leere Einstellungen bleiben gespeichert.", "Minimum stock per material. AzuCraftyBoxes can only consume the surplus; manual withdrawal is unchanged. Settings persist when a chest is emptied."), (GUILayoutOption[])(object)new GUILayoutOption[0]); if (items.Count == 0) { GUILayout.Label(Voyages.T("Lege zuerst Material in diese Kiste.", "Put material in this chest first."), (GUILayoutOption[])(object)new GUILayoutOption[0]); } foreach (ItemData item in items) { string name = item.m_shared.m_name; int num = Reserves.Minimum(chest, name); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(Localization.instance.Localize(name) + " · " + chest.GetInventory().CountItems(name, -1, true) + " / " + Voyages.T("Reserve ", "reserve ") + num, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(420f) }); GUI.enabled = Reserves.Accessible(chest, Player.m_localPlayer); if (GUILayout.Button("−10", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(66f) })) { Reserves.Set(chest, Player.m_localPlayer, name, Math.Max(0, num - 10)); } if (GUILayout.Button("+10", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(66f) })) { Reserves.Set(chest, Player.m_localPlayer, name, Math.Min(100000, num + 10)); } if (GUILayout.Button("0", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(45f) })) { Reserves.Set(chest, Player.m_localPlayer, name, 0); } GUI.enabled = true; GUILayout.EndHorizontal(); } } } public static class Reserves { public const string Prefix = "MasteryTestReserve."; private static FieldInfo containerField; internal static readonly MethodInfo checkAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); public static bool Available; internal static void Install(Harmony harmony) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown Type type = AccessTools.TypeByName("AzuCraftyBoxes.IContainers.VanillaContainer"); if (!(type == null)) { containerField = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((FieldInfo f) => f.FieldType == typeof(Container)); if (!(containerField == null)) { harmony.Patch((MethodBase)AccessTools.Method(type, "ProcessContainerInventory", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Reserves), "Process", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(type, "ItemCount", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Reserves), "Count", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(type, "RemoveItem", new Type[2] { typeof(string), typeof(int) }, (Type[])null), new HarmonyMethod(typeof(Reserves), "Remove", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Available = true; } } } public static int Minimum(Container chest, string item) { ZNetView val = (((Object)(object)chest == (Object)null) ? null : ((Component)chest).GetComponent<ZNetView>()); return (!((Object)(object)val == (Object)null) && val.IsValid()) ? Mathf.Clamp(val.GetZDO().GetInt("MasteryTestReserve." + item, 0), 0, 100000) : 0; } public static int Spendable(Container chest, string item) { return (!((Object)(object)chest == (Object)null)) ? Math.Max(0, chest.GetInventory().CountItems(item, -1, true) - Minimum(chest, item)) : 0; } public static bool Accessible(Container chest, Player p) { //IL_0036: 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_008e: Unknown result type (might be due to invalid IL or missing references) return Voyages.Local && (Object)(object)chest != (Object)null && (Object)(object)p != (Object)null && !((Character)p).IsDead() && !chest.IsInUse() && Vector3.Distance(((Component)chest).transform.position, ((Component)p).transform.position) < 5f && checkAccess != null && (bool)checkAccess.Invoke(chest, new object[1] { p.GetPlayerID() }) && Voyages.Access(p, ((Component)chest).transform.position); } public static bool Set(Container chest, Player p, string item, int value) { if (!Accessible(chest, p) || string.IsNullOrEmpty(item) || value < 0 || value > 100000) { return false; } ZNetView component = ((Component)chest).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } component.InvokeRPC("MasteryChestReserve", new object[2] { item, value }); return true; } private static Container Chest(object wrapper) { object? value = containerField.GetValue(wrapper); return (Container)((value is Container) ? value : null); } private static void Process(object __instance, string __0, int __1, ref int __2) { if (Voyages.Local) { __2 = Math.Min(__2, __1 + Spendable(Chest(__instance), __0)); } } private static void Count(object __instance, string __0, ref int __result) { if (Voyages.Local) { __result = Math.Max(0, __result - Minimum(Chest(__instance), __0)); } } private static void Remove(object __instance, string __0, ref int __1) { if (Voyages.Local) { __1 = Math.Min(__1, Spendable(Chest(__instance), __0)); } } } public sealed class ReserveEndpoint : MonoBehaviour { private Container chest; private ZNetView view; private void Awake() { chest = ((Component)this).GetComponent<Container>(); view = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)view != (Object)null && view.IsValid()) { view.Register<string, int>("MasteryChestReserve", (Action<long, string, int>)SetReserve); } } private void SetReserve(long sender, string item, int value) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)view == (Object)null) && view.IsValid() && view.IsOwner() && item != null && item.Length <= 160 && value >= 0 && value <= 100000 && Voyages.Local && !((Object)(object)chest == (Object)null) && !chest.IsInUse()) { long num = Voyages.RequestCharacter(sender, ((Component)chest).transform.position, 5f); if (num != 0 && !(Reserves.checkAccess == null) && (bool)Reserves.checkAccess.Invoke(chest, new object[1] { num }) && !((Object)(object)ObjectDB.instance == (Object)null) && ObjectDB.instance.m_items.Any((GameObject o) => (Object)(object)o != (Object)null && (Object)(object)o.GetComponent<ItemDrop>() != (Object)null && o.GetComponent<ItemDrop>().m_itemData.m_shared.m_name == item)) { view.GetZDO().Set("MasteryTestReserve." + item, value); } } } } [HarmonyPatch(typeof(Container), "Awake")] internal static class ReserveStart { private static void Postfix(Container __instance) { if ((Object)(object)((Component)__instance).GetComponent<ReserveEndpoint>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<ReserveEndpoint>(); } } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class ReserveHover { private static void Postfix(ref string __result) { if (Reserves.Available) { __result = __result + "\n[<color=yellow>Shift + E</color>] " + Voyages.T("Kistenreserve", "Chest reserve"); } } } [HarmonyPatch(typeof(Container), "Interact")] internal static class ReserveUse { private static bool Prefix(Container __instance, Humanoid __0, bool __1, bool __2, ref bool __result) { if (!Reserves.Available || __1 || (Object)(object)__0 != (Object)(object)Player.m_localPlayer || (!__2 && !Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303))) { return true; } if (!Reserves.Accessible(__instance, Player.m_localPlayer)) { return true; } Window.OpenChest(__instance); __result = true; return false; } } public static class Adventure { private const string Key = "org.valheim.mastery.voyages.test."; public static readonly MasterySkill[] TrailSkills = (MasterySkill[])(object)new MasterySkill[3] { (MasterySkill)11, (MasterySkill)12, (MasterySkill)9 }; public static readonly string[] TitlesDe = new string[3] { "Waldkundiger", "Spurenleser", "Küstenwanderer" }; public static readonly string[] TitlesEn = new string[3] { "Woodland scout", "Trail reader", "Coastal wanderer" }; private static readonly HashSet<string> Notable = new HashSet<string> { "Amber", "AmberPearl", "Ruby", "SilverOre", "BlackMetal", "FlametalOreNew", "YmirRemains", "DragonEgg", "GoblinTotem" }; public static int State(Player p, int id) { string value; int result; return (p.m_customData.TryGetValue("org.valheim.mastery.voyages.test.trail." + id, out value) && int.TryParse(value, out result)) ? result : 0; } public static string Title(int id) { return Voyages.De ? TitlesDe[id] : TitlesEn[id]; } public static bool Begin(Player p, int id) { if (!Voyages.Local || (Object)(object)p == (Object)null || id < 0 || id >= 3 || State(p, id) != 0) { return false; } Set(p, "trail." + id, "1"); SaveStart(p, id); return true; } private static void Set(Player p, string key, string value) { p.m_customData["org.valheim.mastery.voyages.test." + key] = value; } private static void SaveStart(Player p, int id) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) Set(p, "xp." + id, GeneralSkillStore.ReadTotalXp((IDictionary<string, string>)p.m_customData, TrailSkills[id]).ToString("R", CultureInfo.InvariantCulture)); Set(p, "world." + id, ZNet.instance.GetWorldUID().ToString(CultureInfo.InvariantCulture)); string key = "x." + id; float x = ((Component)p).transform.position.x; Set(p, key, x.ToString("R", CultureInfo.InvariantCulture)); string key2 = "z." + id; x = ((Component)p).transform.position.z; Set(p, key2, x.ToString("R", CultureInfo.InvariantCulture)); } private static double Read(Player p, string key) { string value; double result; return (p.m_customData.TryGetValue("org.valheim.mastery.voyages.test." + key, out value) && double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out result)) ? result : 0.0; } public static string Instruction(Player p, int id) { return State(p, id) switch { 0 => Voyages.T("Spur beginnen", "Start this trail"), 4 => Voyages.T("Abgeschlossen · Titel freigeschaltet", "Completed · title unlocked"), 1 => id switch { 1 => Voyages.T("Weide ein Wildtier aus und erhalte Jagd-XP.", "Skin a wild animal and earn Hunter XP."), 0 => Voyages.T("Sammle eine wilde Zutat und erhalte Sammel-XP.", "Gather a wild ingredient and earn Foraging XP."), _ => Voyages.T("Fange einen Fisch und erhalte Angel-XP.", "Catch a fish and earn Fishing XP."), }, 2 => id switch { 1 => Voyages.T("Folge der Spur in ein Grasland mindestens 250 m vom Startpunkt entfernt.", "Follow the trail to Meadows at least 250 m from the starting point."), 0 => Voyages.T("Erkunde den Dunklen Wald, mindestens 250 m vom Startpunkt entfernt.", "Explore the Black Forest at least 250 m from the starting point."), _ => Voyages.T("Erreiche ein anderes Ufer: mindestens 250 m entfernt und höchstens 5 m über dem Wasser.", "Reach another shore: at least 250 m away and no more than 5 m above water."), }, _ => Voyages.T("Führe dort dieselbe Tätigkeit erneut aus. Dein Fund ist ein kosmetischer Titel.", "Repeat the activity there. Your discovery unlocks a cosmetic title."), }; } public static void Tick(Player p) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (((Character)p).IsDead() || ((Character)p).IsTeleporting()) { return; } MasterySkill[] skills = Voyages.Skills; foreach (MasterySkill val in skills) { if (Voyages.Level(p, val) >= 100 && !p.m_customData.ContainsKey("org.valheim.mastery.voyages.test.mastery." + val)) { Set(p, "mastery." + val, DateTime.UtcNow.ToString("o")); } } for (int j = 0; j < 3; j++) { int num = State(p, j); if (num < 1 || num > 3) { continue; } p.m_customData.TryGetValue("org.valheim.mastery.voyages.test.world." + j, out var value); if (value != ZNet.instance.GetWorldUID().ToString(CultureInfo.InvariantCulture)) { SaveStart(p, j); Set(p, "trail." + j, "1"); continue; } double num2 = GeneralSkillStore.ReadTotalXp((IDictionary<string, string>)p.m_customData, TrailSkills[j]); if (num == 1 && num2 > Read(p, "xp." + j)) { Set(p, "trail." + j, "2"); Set(p, "xp." + j, num2.ToString("R", CultureInfo.InvariantCulture)); } if (num == 2 && Destination(p, j)) { Set(p, "trail." + j, "3"); Set(p, "xp." + j, num2.ToString("R", CultureInfo.InvariantCulture)); } if (num == 3 && Destination(p, j) && num2 > Read(p, "xp." + j)) { Set(p, "trail." + j, "4"); Set(p, "title." + j, "1"); ((Character)p).Message((MessageType)2, Voyages.T("Schatzspur abgeschlossen: ", "Treasure trail completed: ") + Title(j), 0, (Sprite)null, false); } } } public static bool Destination(Player p, int id) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_0075: 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_007f: 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_008f: Invalid comparison between Unknown and I4 //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Invalid comparison between Unknown and I4 Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor((float)Read(p, "x." + id), ((Component)p).transform.position.y, (float)Read(p, "z." + id)); if (Utils.DistanceXZ(val, ((Component)p).transform.position) < 250f) { return false; } Biome val2 = Heightmap.FindBiome(((Component)p).transform.position); switch (id) { case 0: return (int)val2 == 8; case 1: return (int)val2 == 1; default: { float num = (((Object)(object)ZoneSystem.instance == (Object)null) ? 30f : ZoneSystem.instance.m_waterLevel); return ((Component)p).transform.position.y >= num - 1f && ((Component)p).transform.position.y <= num + 5f && (int)val2 != 256; } } } public static void RecordBoss(Character boss) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (Voyages.Local && !((Object)(object)localPlayer == (Object)null) && boss.IsBoss() && !((Character)localPlayer).IsDead() && !(Vector3.Distance(((Component)localPlayer).transform.position, ((Component)boss).transform.position) > 70f)) { object? value = AccessTools.Field(typeof(Character), "m_lastHit").GetValue(boss); HitData val = (HitData)((value is HitData) ? value : null); if (val != null && !((Object)(object)val.GetAttacker() != (Object)(object)localPlayer)) { Set(localPlayer, "boss." + Utils.GetPrefabName(((Component)boss).gameObject), DateTime.UtcNow.ToString("o")); } } } public static IEnumerable<string> Bosses(Player p) { foreach (KeyValuePair<string, string> kv in p.m_customData) { KeyValuePair<string, string> keyValuePair = kv; if (keyValuePair.Key.StartsWith("org.valheim.mastery.voyages.test.boss.")) { keyValuePair = kv; yield return keyValuePair.Key.Substring("org.valheim.mastery.voyages.test.boss.".Length); } } } public static void Found(string prefab) { Player localPlayer = Player.m_localPlayer; if (Voyages.Local && (Object)(object)localPlayer != (Object)null && prefab != null && Notable.Contains(prefab)) { Set(localPlayer, "find." + prefab, DateTime.UtcNow.ToString("o")); } } public static IEnumerable<string> Finds(Player p) { foreach (KeyValuePair<string, string> kv in p.m_customData) { KeyValuePair<string, string> keyValuePair = kv; if (keyValuePair.Key.StartsWith("org.valheim.mastery.voyages.test.find.")) { keyValuePair = kv; yield return keyValuePair.Key.Substring("org.valheim.mastery.voyages.test.find.".Length); } } } } [HarmonyPatch(typeof(Character), "OnDeath")] internal static class BossRecord { private static void Prefix(Character __instance) { Adventure.RecordBoss(__instance); } } [HarmonyPatch(typeof(Humanoid), "Pickup", new Type[] { typeof(GameObject), typeof(bool), typeof(bool) })] internal static class FindRecord { private static void Prefix(Humanoid __instance, GameObject __0, out string __state) { __state = (((Object)(object)__instance == (Object)(object)Player.m_localPlayer && (Object)(object)__0 != (Object)null) ? Utils.GetPrefabName(__0) : null); } private static void Postfix(bool __result, string __state) { if (__result) { Adventure.Found(__state); } } } public static class TestIcons { private static MethodInfo get; internal static void Load() { get = AccessTools.Method(typeof(MasteryPlugin).Assembly.GetType("ValheimMastery.Runtime.MasterySkillIcons"), "Get", new Type[1] { typeof(MasterySkill) }, (Type[])null); if (get == null) { throw new MissingMethodException("Core shared skill icon API"); } } public static Sprite Get(MasterySkill skill) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown if (get == null) { Load(); } return (Sprite)get.Invoke(null, new object[1] { skill }); } } [HarmonyPatch] internal static class SizeTestPrayerHudIcon { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(MasteryPlugin).Assembly.GetType("ValheimMastery.Runtime.PrayerPointHud"), "PlaceIcon", (Type[])null, (Type[])null); } private static void Prefix(ref Vector2 __1, ref float __2) { float num = __2 / 0.85f; float num2 = num * 1.0847458f; float num3 = __1.y + __2 * 0.55f; __1.y = num3 - num * 0.18f - num2 * 0.5f; __2 = num2; } } public static class ApexAnimation { public const int FramesPerSecond = 24; public const int FrameCount = 192; private static readonly Texture2D[] frames = (Texture2D[])(object)new Texture2D[192]; private static bool warming; public static int Frame => (int)(Time.time * 24f) % 192; public static Texture2D Texture(int frame) { frame %= 192; if (!warming) { warming = true; ((MonoBehaviour)Voyages.Instance).StartCoroutine(Warm()); } if ((Object)(object)frames[frame] == (Object)null) { frames[frame] = MasterySail.Texture("apex-fire" + frame); } return frames[frame]; } private static IEnumerator Warm() { for (int i = 0; i < 192; i++) { if ((Object)(object)frames[i] == (Object)null) { frames[i] = MasterySail.Texture("apex-fire" + i); } if (i % 2 == 1) { yield return null; } } } } [HarmonyPatch] internal static class TestBowOrientation { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(MasteryPlugin).Assembly.GetType("ValheimMastery.Runtime.SlayerAssets"), "Register", (Type[])null, (Type[])null); } private static void Postfix(ObjectDB __0) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__0 == (Object)null) { return; } GameObject itemPrefab = __0.GetItemPrefab("SlayerRuneBow"); if ((Object)(object)itemPrefab == (Object)null) { return; } Transform val = itemPrefab.transform.Find("attach"); if (!((Object)(object)val == (Object)null)) { Transform val2 = val.Find("Mastery_SlayerRuneBow"); if (!((Object)(object)val2 == (Object)null)) { val2.localRotation = Quaternion.Euler(90f, 0f, 0f); } } } } [HarmonyPatch] internal static class TestHelmetEyes { private static Mesh eyeMesh; private static MethodBase TargetMethod() { return AccessTools.Method(typeof(MasteryPlugin).Assembly.GetType("ValheimMastery.Runtime.SlayerAssets"), "Register", (Type[])null, (Type[])null); } private static void Postfix(ObjectDB __0) { //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: 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) if ((Object)(object)__0 == (Object)null) { return; } foreach (GameObject item in __0.m_items) { if ((Object)(object)item == (Object)null || !((Object)item).name.StartsWith("SlayerHelmet_", StringComparison.Ordinal)) { continue; } Transform val = item.transform.Find("attach/default"); Transform val2 = (((Object)(object)val == (Object)null) ? null : val.Find("Mastery_" + ((Object)item).name)); if ((Object)(object)val2 == (Object)null || (Object)(object)val2.Find("MasteryTestEyes") != (Object)null) { continue; } Renderer component = ((Component)val2).GetComponent<Renderer>(); if ((Object)(object)component == (Object)null) { continue; } if ((Object)(object)eyeMesh == (Object)null) { eyeMesh = CreateMesh(); } GameObject val3 = new GameObject("MasteryTestEyes"); val3.transform.SetParent(val2, false); val3.layer = ((Component)val2).gameObject.layer; val3.AddComponent<MeshFilter>().sharedMesh = eyeMesh; Material val4 = new Material(component.sharedMaterial); ((Object)val4).name = "MasteryTestEyes_" + ((Object)item).name; Color val5 = Colour(((Object)item).name); if (val4.HasProperty("_Color")) { val4.SetColor("_Color", new Color(val5.r * 0.35f, val5.g * 0.35f, val5.b * 0.35f, 1f)); } if (val4.HasProperty("_MainTex")) { val4.SetTexture("_MainTex", (Texture)(object)Texture2D.whiteTexture); } string[] array = new string[2] { "_EmissionMap", "_EmissiveTex" }; foreach (string text in array) { if (val4.HasProperty(text)) { val4.SetTexture(text, (Texture)(object)Texture2D.whiteTexture); } } if (val4.HasProperty("_EmissionColor")) { val4.SetColor("_EmissionColor", val5 * 2.2f); } val4.EnableKeyword("_EMISSION"); if (val4.HasProperty("_Metallic")) { val4.SetFloat("_Metallic", 0f); } if (val4.HasProperty("_Glossiness")) { val4.SetFloat("_Glossiness", 0f); } MeshRenderer val6 = val3.AddComponent<MeshRenderer>(); ((Renderer)val6).sharedMaterial = val4; ((Renderer)val6).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val6).receiveShadows = false; val3.AddComponent<HelmetEyeGlow>().Colour = val5; } } public static Color Colour(string name) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_00eb: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) if (name.EndsWith("_Blood")) { return new Color(1f, 0.035f, 0.015f); } if (name.EndsWith("_Bone")) { return new Color(1f, 0.83f, 0.53f); } if (name.EndsWith("_Dusk")) { return new Color(0.2f, 0.52f, 1f); } if (name.EndsWith("_Hood")) { return new Color(0.6f, 0.2f, 1f); } if (name.EndsWith("_Dread")) { return new Color(1f, 0.12f, 0.015f); } return new Color(1f, 0.43f, 0.065f); } private static Mesh CreateMesh() { //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_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_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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Expected O, but got Unknown //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[8]; int[] array2 = new int[24]; for (int i = 0; i < 2; i++) { float num = ((i != 0) ? 1 : (-1)); int num2 = i * 4; int num3 = i * 12; ref Vector3 reference = ref array[num2]; reference = Fit(num * 0.031f, 0.027f); ref Vector3 reference2 = ref array[num2 + 1]; reference2 = Fit(num * 0.068f, 0.031f); ref Vector3 reference3 = ref array[num2 + 2]; reference3 = Fit(num * 0.068f, 0.043f); ref Vector3 reference4 = ref array[num2 + 3]; reference4 = Fit(num * 0.031f, 0.039f); int[] array3 = new int[12] { 0, 1, 2, 0, 2, 3, 2, 1, 0, 3, 2, 0 }; for (int j = 0; j < array3.Length; j++) { array2[num3 + j] = num2 + array3[j]; } } Vector3[] array4 = (Vector3[])(object)new Vector3[8]; Vector2[] array5 = (Vector2[])(object)new Vector2[8]; for (int j = 0; j < 8; j++) { ref Vector3 reference5 = ref array4[j]; reference5 = Vector3.forward; ref Vector2 reference6 = ref array5[j]; reference6 = new Vector2((float)((j % 4 == 1 || j % 4 == 2) ? 1 : 0), (float)((j % 4 >= 2) ? 1 : 0)); } Mesh val = new Mesh(); ((Object)val).name = "Mastery fitted eye openings"; val.vertices = array; val.normals = array4; val.uv = array5; val.triangles = array2; Mesh val2 = val; val2.RecalculateBounds(); return val2; } private static Vector3 Fit(float x, float y) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) return new Vector3(x * 0.9f, y * 0.9f - 0.005f, 0.1134f); } } public sealed class HelmetEyeGlow : MonoBehaviour { public Color Colour; private Renderer target; private MaterialPropertyBlock properties; private float next; private void Awake() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown target = ((Component)this).GetComponent<Renderer>(); properties = new MaterialPropertyBlock(); } private void LateUpdate() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)target == (Object)null) && target.isVisible && !(Time.time < next)) { next = Time.time + 0.05f; float num = 2.05f + 0.16f * Mathf.Sin(Time.time * 4.7f) + 0.08f * Mathf.Sin(Time.time * 9.3f); target.GetPropertyBlock(properties); properties.SetColor("_EmissionColor", Colour * num); target.SetPropertyBlock(properties); } } } public static class ForagingPickup { private static Player cachedPlayer; private static float nextRead; private static float factor = 1f; public static float Multiplier(int level) { return 1f + 2f * (float)(Math.Max(1, Math.Min(100, level)) - 1) / 99f; } public static float Range(Player player) { float autoPickupRange = player.m_autoPickupRange; if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !Voyages.Local) { return autoPickupRange; } if ((Object)(object)player != (Object)(object)cachedPlayer || Time.unscaledTime >= nextRead) { cachedPlayer = player; nextRead = Time.unscaledTime + 1f; factor = Multiplier(Voyages.Level(player, (MasterySkill)11)); } return autoPickupRange * factor; } } [HarmonyPatch(typeof(Player), "AutoPickup")] internal static class ForagingPickupRange { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { FieldInfo objB = AccessTools.Field(typeof(Player), "m_autoPickupRange"); MethodInfo operand = AccessTools.Method(typeof(ForagingPickup), "Range", (Type[])null, (Type[])null); List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; foreach (CodeInstruction item in list) { if (item.opcode == OpCodes.Ldfld && object.Equals(item.operand, objB)) { item.opcode = OpCodes.Call; item.operand = operand; num++; } } if (num != 2) { throw new InvalidOperationException("Unexpected native AutoPickup radius reads: " + num); } return list; } } [HarmonyPatch] internal static class ForagingPickupTooltip { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(MasteryPlugin).Assembly.GetType("ValheimMastery.Runtime.InventoryCombatPanel"), "TooltipText", (Type[])null, (Type[])null); } private static void Postfix(Player __0, MasterySkill __1, ref string __result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Invalid comparison between Unknown and I4 if ((int)__1 == 11 && !((Object)(object)__0 == (Object)null) && Voyages.Local) { float num = ForagingPickup.Multiplier(Voyages.Level(__0, (MasterySkill)11)); string text = __result; __result = text + "\n" + Voyages.T("Aufheberadius: ", "Auto-pickup radius: ") + (num * 100f).ToString("0") + "% (" + (__0.m_autoPickupRange * num).ToString("0.##") + " m). " + Voyages.T("Wächst bis 300% auf Level 100.", "Grows to 300% at level 100."); } } } public sealed class HomePoint : MonoBehaviour, Interactable, Hoverable { public const string Id = "MasteryTestHomePoint"; public const string GuidKey = "MasteryHomeGuid"; private const float SavedPositionTolerance = 0.1f; private static GameObject root; private static GameObject prefab; private static readonly HashSet<HomePoint> Loaded = new HashSet<HomePoint>(); private static readonly CultureInfo Inv = CultureInfo.InvariantCulture; internal static readonly Type Home = typeof(MasteryPlugin).Assembly.GetType("ValheimMastery.Runtime.ConstructionHomeTeleport"); public static string Key => "org.valheim.mastery.test.home." + (((Object)(object)ZNet.instance == (Object)null) ? 0 : ZNet.instance.GetWorldUID()).ToString(Inv); public static bool Selected => Voyages.Local && (Object)(object)Player.m_localPlayer != (Object)null && Player.m_localPlayer.m_customData.ContainsKey(Key); public Vector3 Arrival => ((Component)this).transform.position + ((Component)this).transform.forward * 1.5f + Vector3.up * 0.3f; public static bool Read(out ZDOID id, out Vector3 point) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (!ReadSelection(out id, out point, out var guid)) { return false; } HomePoint homePoint = Resolve(guid, point); if ((Object)(object)homePoint != (Object)null) { id = ((Component)homePoint).GetComponent<ZNetView>().GetZDO().m_uid; } return true; } private static bool ReadSelection(out ZDOID id, out Vector3 point, out string guid) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) id = ZDOID.None; point = Vector3.zero; guid = null; Player localPlayer = Player.m_localPlayer; if (!Selected || !localPlayer.m_customData.TryGetValue(Key, out var value)) { return false; } string[] array = value.Split(';'); int num = 0; if (array.Length == 8 && array[0] == "v2") { if (!Guid.TryParseExact(array[7], "N", out var result) || result == Guid.Empty) { return false; } guid = array[7]; num = 1; } else if (array.Length != 6) { return false; } if (!long.TryParse(array[num], NumberStyles.Integer, Inv, out var result2) || result2 != localPlayer.GetPlayerID() || !long.TryParse(array[num + 1], NumberStyles.Integer, Inv, out var result3) || !uint.TryParse(array[num + 2], NumberStyles.Integer, Inv, out var result4) || !float.TryParse(array[num + 3], NumberStyles.Float, Inv, out var result5) || !float.TryParse(array[num + 4], NumberStyles.Float, Inv, out var result6) || !float.TryParse(array[num + 5], NumberStyles.Float, Inv, out var result7)) { return false; } point = new Vector3(result5, result6, result7); id = new ZDOID(result3, result4); return !((ZDOID)(ref id)).IsNone() && Finite(point); } private void OnEnable() { Loaded.Add(this); } private void OnDisable() { Loaded.Remove(this); } private void OnDestroy() { Loaded.Remove(this); } private static HomePoint Resolve(string guid, Vector3 saved) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) HomePoint homePoint = null; int num = 0; foreach (HomePoint item in Loaded) { if (!((Object)(object)item == (Object)null)) { ZNetView component = ((Component)item).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && component.GetZDO().GetPrefab() == StringExtensionMethods.GetStableHashCode("MasteryTestHomePoint") && !(Vector3.Distance(item.Arrival, saved) > 0.1f) && (guid == null || !(component.GetZDO().GetString("MasteryHomeGuid", "") != guid))) { homePoint = item; num++; } } } return (num == 1) ? homePoint : null; } private static string EnsureGuid(ZNetView view) { ZDO zDO = view.GetZDO(); string text = zDO.GetString("MasteryHomeGuid", ""); if (Guid.TryParseExact(text, "N", out var result) && result != Guid.Empty) { return text; } if (!view.IsOwner()) { view.ClaimOwnership(); } if (!view.IsOwner()) { return null; } text = Guid.NewGuid().ToString("N"); zDO.Set("MasteryHomeGuid", text); return text; } private static void SaveSelection(Player p, ZDOID id, Vector3 pos, string guid) { p.m_customData[Key] = string.Join(";", "v2", p.GetPlayerID().ToString(Inv), ((ZDOID)(ref id)).UserID.ToString(Inv), ((ZDOID)(ref id)).ID.ToString(Inv), pos.x.ToString("R", Inv), pos.y.ToString("R", Inv), pos.z.ToString("R", Inv), guid); } private static bool Finite(Vector3 p) { return !float.IsNaN(((Vector3)(ref p)).sqrMagnitude) && !float.IsInfinity(((Vector3)(ref p)).sqrMagnitude); } public static bool TryDestination(Player player, out Vector3 point) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) point = Vector3.zero; if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !ReadSelection(out var _, out point, out var guid)) { return false; } HomePoint homePoint = Resolve(guid, point); if ((Object)(object)homePoint != (Object)null) { if (!PrivateArea.CheckAccess(((Component)homePoint).transform.position, 0f, false, false)) { return false; } if (guid == null) { guid = EnsureGuid(((Component)homePoint).GetComponent<ZNetView>()); if (guid == null) { return false; } SaveSelection(player, ((Component)homePoint).GetComponent<ZNetView>().GetZDO().m_uid, point, guid); } return true; } return (Object)(object)ZNetScene.instance != (Object)null && !ZNetScene.instance.IsAreaReady(point); } public static bool HasDestination(PlayerProfile profile) { Vector3 point; return TryDestination(Player.m_localPlayer, out point) || profile.HaveCustomSpawnPoint(); } public static Vector3 Destination(PlayerProfile profile) { //IL_0017: 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_0019: 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) Vector3 point; return TryDestination(Player.m_localPlayer, out point) ? point : profile.GetCustomSpawnPoint(); } public bool Interact(Humanoid human, bool hold, bool alt) { //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_0078: Unknown result type (might be due to invalid IL or missing references) Player val = (Player)(object)((human is Player) ? human : null); ZNetView component = ((Component)this).GetComponent<ZNetView>(); if (hold || !Voyages.Local || (Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || ((Character)val).IsDead() || ((Character)val).IsTeleporting() || (Object)(object)component == (Object)null || !component.IsValid() || Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position) > 5f || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { return false; } if (alt) { val.m_customData.Remove(Key); ((Character)val).Message((MessageType)2, Voyages.T("Heimkehrziel gelöscht. Wieder gilt dein gesetztes Bett.", "Home destination cleared. Your selected bed is used again."), 0, (Sprite)null, false); return true; } if (!SafePosition(Arrival, out var _)) { ((Character)val).Message((MessageType)2, Voyages.T("Vor dem Heimkehrpfahl fehlt ein freier, sicherer Standplatz.", "The home marker needs a clear, safe landing spot in front."), 0, (Sprite)null, false); return false; } string text = EnsureGuid(component); if (text == null) { return false; } SaveSelection(val, component.GetZDO().m_uid, Arrival, text); ((Character)val).Message((MessageType)2, Voyages.T("Heimkehrpunkt gesetzt. Dein Bett bleibt unverändert.", "Home destination set. Your bed remains unchanged."), 0, (Sprite)null, false); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetHoverName() { return Voyages.T("Heimkehrpfahl", "Homecoming marker"); } public float GetHoverOffset() { return 0f; } public string GetHoverText() { //IL_002a: 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) ZNetView component = ((Component)this).GetComponent<ZNetView>(); ZDOID id; Vector3 point; bool flag = Read(out id, out point) && (Object)(object)component != (Object)null && component.IsValid() && component.GetZDO().m_uid == id; return GetHoverName() + (flag ? Voyages.T(" · dein Heimkehrziel", " · your home destination") : "") + "\n[<color=yellow>E</color>] " + Voyages.T("Heimkehrziel setzen", "Set home destination") + "\n[<color=yellow>Shift + E</color>] " + Voyages.T("Zurück zur Bettnutzung", "Use bed again"); } public static bool SafePosition(Vector3 near, out Vector3 point) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: 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) //IL_0022: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) point = near; float num = default(float); if (!Finite(near) || (Object)(object)ZoneSystem.instance == (Object)null || !ZoneSystem.instance.FindFloor(near, ref num) || Math.Abs(num - near.y) > 2f) { return false; } point.y = num + 0.1f; if (Floating.GetLiquidLevel(point, 1f, (LiquidType)10) > point.y) { return false; } if (!PrivateArea.CheckAccess(point, 0f, false, false)) { return false; } int mask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" }); return !Physics.CheckCapsule(point + Vector3.up * 0.35f, point + Vector3.up * 1.65f, 0.3f, mask, (QueryTriggerInteraction)1); } public static bool ValidateDestination(Player player, Vector3 requested) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Vector3 safe; return ResolveDestination(player, requested, out safe); } public static bool ResolveDestination(Player player, Vector3 requested, out Vector3 safe) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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) safe = requested; if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return false; } if (!ReadSelection(out var _, out var point, out var guid) || (Object)(object)ZNetScene.instance == (Object)null) { return false; } if (Vector3.Distance(point, requested) > 0.01f) { return false; } HomePoint homePoint = Resolve(guid, point); if ((Object)(object)homePoint == (Object)null || !PrivateArea.CheckAccess(((Component)homePoint).transform.position, 0f, false, false)) { return false; } if (guid == null) { guid = EnsureGuid(((Component)homePoint).GetComponent<ZNetView>()); if (guid == null) { return false; } SaveSelection(player, ((Component)homePoint).GetComponent<ZNetView>().GetZDO().m_uid, point, guid); } return SafePosition(homePoint.Arrival, out safe); } public static void Register(ObjectDB db, ZNetScene scene) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Expected O, but got Unknown //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)db == (Object)null || (Object)(object)db.GetItemPrefab("Hammer") == (Object)null) { return; } PieceTable buildPieces = db.GetItemPrefab("Hammer").GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces; GameObject val = ((IEnumerable<GameObject>)buildPieces.m_pieces).FirstOrDefault((Func<GameObject, bool>)((GameObject p) => (Object)(object)p != (Object)null && (Object)(object)p.GetComponent<Sign>() != (Object)null)); if ((Object)(object)val == (Object)null) { return; } if ((Object)(object)prefab == (Object)null) { root = new GameObject("MasteryTestHomeTemplates"); root.SetActive(false); Object.DontDestroyOnLoad((Object)(object)root); prefab = Object.Instantiate<GameObject>(val, root.transform, false); ((Object)prefab).name = "MasteryTestHomePoint"; prefab.SetActive(true); Sign[] componentsInChildren = prefab.GetComponentsInChildren<Sign>(true); foreach (Sign val2 in componentsInChildren) { TextMeshProUGUI textWidget = val2.m_textWidget; if ((Object)(object)textWidget != (Object)null) { ((TMP_Text)textWidget).text = ""; ((Behaviour)textWidget).enabled = false; GameObject val3 = new GameObject("HomeEmblem", new Type[2] { typeof(RectTransform), typeof(Image) }); val3.layer = ((Component)textWidget).gameObject.layer; RectTransform val4 = (RectTransform)val3.transform; ((Transform)val4).SetParent(((TMP_Text)textWidget).transform, false); val4.anchorMin = new Vector2(0.1f, 0.1f); val4.anchorMax = new Vector2(0.9f, 0.9f); Vector2 offsetMin = (val4.offsetMax = Vector2.zero); val4.offsetMin = offsetMin; Image component = val3.GetComponent<Image>(); component.sprite = TestIcons.Get((MasterySkill)17); component.preserveAspect = true; ((Graphic)component).raycastTarget = false; } Object.DestroyImmediate((Object)(object)val2); } Piece component2 = prefab.GetComponent<Piece>(); component2.m_name = "$mastery_test_home_marker"; component2.m_description = "$mastery_test_home_marker_desc"; component2.m_icon = TestIcons.Get((MasterySkill)17); component2.m_resources = (Requirement[])(object)new Requirement[3] { Cost(db, "Wood", 10), Cost(db, "Stone", 5), Cost(db, "SurtlingCore", 1) }; prefab.AddComponent<HomePoint>(); } prefab.GetComponent<Piece>().m_enabled = (Object)(object)scene == (Object)null || Voyages.Local; if (!buildPieces.m_pieces.Contains(prefab)) { buildPieces.m_pieces.Add(prefab); } if ((Object)(object)scene != (Object)null) { Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(scene); if (!dictionary.ContainsKey(StringExtensionMethods.GetStableHashCode("MasteryTestHomePoint"))) { dictionary[StringExtensionMethods.GetStableHashCode("MasteryTestHomePoint")] = prefab; scene.m_prefabs.Add(prefab); } } } private static Requirement Cost(ObjectDB db, string item, int amount) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown Requirement val = new Requirement(); val.m_resItem = db.GetItemPrefab(item).GetComponent<ItemDrop>(); val.m_amount = amount; val.m_recover = true; return val; } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class HomeDb { [HarmonyPriority(0)] private static void Postfix(ObjectDB __instance) { HomePoint.Register(__instance, ZNetScene.instance); } } [HarmonyPatch(typeof(MasteryText), "T", new Type[] { typeof(string) })] internal static class HomeDescription { private static void Postfix(ref string __result) { if (__result != null && Voyages.Local) { __result = __result.Replace("Heimkehr zum gesetzten eigenen Bett", "Heimkehr zum gesetzten Heimkehrpfahl (sonst zum eigenen Bett)").Replace("Heimkehr zum gesetzten Bett", "Heimkehr zum gesetzten Heimkehrpfahl (sonst zum Bett)").Replace("return home to your own selected bed", "return home to your selected home marker (otherwise your bed)") .Replace("return home to your selected bed", "return home to your selected home marker (otherwise your bed)"); } } } [HarmonyPatch(typeof(Localization), "Localize", new Type[] { typeof(string) })] internal static class HomeLabels { private static void Postfix(string __0, ref string __result) { if (__0 == "$mastery_test_home_marker") { __result = Voyages.T("Heimkehrpfahl", "Homecoming marker"); } if (__0 == "$mastery_test_home_marker_desc") { __result = Voyages.T("E: persönliches Ziel für Baukunst-Heimkehr setzen. Bett und Wiedererscheinung bleiben unverändert. Shift+E: Ziel löschen.", "E: set your Construction return-home destination. Bed and respawn remain unchanged. Shift+E: clear destination."); } } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class HomeCopy { [HarmonyPriority(0)] private static void Postfix(ObjectDB __instance) { HomePoint.Register(__instance, ZNetScene.instance); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class HomeScene { [HarmonyPriority(0)] private static void Postfix(ZNetScene __instance) { HomePoint.Register(ObjectDB.instance, __instance); } } [HarmonyPatch] internal static class HomeWording { private static IEnumerable<MethodBase> TargetMethods() { try { string[] array = new string[3] { "Begin", "ReturnToOrigin", "Draw" }; foreach (string name in array) { yield return AccessTools.Method(HomePoint.Home, name, (Type[])null, (Type[])null); } } finally { } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { foreach (CodeInstruction c in instructions) { if (c.opcode == OpCodes.Ldstr) { string text = (string)c.operand; text = text.Replace("Nach Hause zum gesetzten Bett", "Zum Heimkehrziel reisen").Replace("Return home to your selected bed", "Travel to your home destination").Replace("Nur dein eigenes gesetztes Bett in dieser Welt.", "Gesetzter Heimkehrpfahl, sonst dein eigenes Bett in dieser Welt.") .Replace("Only your own selected bed in this world.", "Your selected home marker, otherwise your own bed in this world.") .Replace("Dein gesetztes Bett", "Dein Heimkehrziel") .Replace("dein eigenes Bett", "einen Heimkehrpfahl oder dein eigenes Bett") .Replace("your selected bed", "your home destination") .Replace("Bett oder Ziel", "Heimkehrpunkt oder Ziel") .Replace("your bed or destination", "your home marker or destination"); c.operand = text; } yield return c; } } }
plugins/ValheimMastery/ValheimMastery.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using MagicaCloth2; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Audio; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Utilities; using UnityEngine.Networking; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; using ValheimMastery.Combat; using ValheimMastery.Itemization; using ValheimMastery.PrayerPrototype; using ValheimMastery.Progression; using ValheimMastery.Recovery; using ValheimMastery.Runtime; using ValheimMastery.Specials; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace ValheimMastery.Progression { internal static class ValheimVersionPolicy { internal const string Current = "1.0.20"; internal const string Previous = "1.0.17"; internal const string Legacy = "1.0.16"; internal const string Oldest = "1.0.15"; internal static bool Supports(string version) { if (version == null) { return false; } if (version.StartsWith("l-", StringComparison.Ordinal)) { version = version.Substring(2); } switch (version) { default: return version == "1.0.15"; case "1.0.20": case "1.0.17": case "1.0.16": return true; } } internal static int ExactExpectedPlayerSaveReturns(string version) { if (version == null) { return 0; } if (version.StartsWith("l-", StringComparison.Ordinal)) { version = version.Substring(2); } switch (version) { case "1.0.20": return 1; default: return 0; case "1.0.17": case "1.0.16": case "1.0.15": return 2; } } } } namespace ValheimMastery.Runtime { internal static class PrayerDisplayNames { internal static readonly string[] Names = new string[30] { "Steinmut I", "Steinmut II", "Steinmut III", "Kampfesmut I", "Kampfesmut II", "Kampfesmut III", "Klarer Wille I", "Klarer Wille II", "Klarer Wille III", "Sicherer Flug I", "Sicherer Flug II", "Sicherer Flug III", "Runeneinklang I", "Runeneinklang II", "Runeneinklang III", "Gemessener Atem", "Eid der Genesung", "Seher-Eid", "Jäger-Eid", "Eisen-Eid", "Letzte Glut", "Dauernder Schwur", "Kriegerbund", "Jägerbund", "Seherbund", "Schlacht-Eid", "Fernschuss-Eid", "Runenwächter-Eid", "Wanderer-Eid", "Einklang-Eid" }; internal static string Name(int index) { if (index < 0 || index >= Names.Length) { throw new ArgumentOutOfRangeException("index"); } return Names[index]; } } } namespace ValheimMastery.PrayerPrototype { public static class PrayerP03Save { public const string Key = "org.valheim.mastery.prayer.p03.resource"; public static string Encode(long units, long remainder) { if (units < 0 || remainder < 0 || remainder >= 100000000 || (units == 0 && remainder != 0)) { throw new ArgumentException("Invalid P03 resource."); } return "1|" + units.ToString(CultureInfo.InvariantCulture) + "|" + remainder.ToString(CultureInfo.InvariantCulture); } public static bool TryDecode(string raw, int maximum, out long units, out long remainder) { units = (remainder = 0L); if (raw == null || raw.Length > 80) { return false; } string[] array = raw.Split('|'); if (array.Length != 3 || array[0] != "1" || !long.TryParse(array[1], NumberStyles.None, CultureInfo.InvariantCulture, out units) || !long.TryParse(array[2], NumberStyles.None, CultureInfo.InvariantCulture, out remainder) || units < 0 || units > (long)maximum * 27720L || remainder < 0 || remainder >= 100000000 || (units == 0 && remainder != 0)) { return false; } return true; } } public sealed class PrayerP03Entry { public readonly string Id; public readonly int Level; public readonly int SecondsPerPoint; public readonly int DrainMultiplier; public readonly string Family; public PrayerP03Entry(string id, int level, int seconds, string family) { if (string.IsNullOrEmpty(id) || level < 1 || level > 100 || seconds <= 0) { throw new ArgumentException("Invalid P03 prayer definition."); } Id = id; Level = level; SecondsPerPoint = seconds; Family = family; int drainMultiplier; switch (family) { default: drainMultiplier = 3; break; case "utility": case "vow": drainMultiplier = ((!(id == "mending.oath")) ? 1 : 3); break; case "survival": case "package": drainMultiplier = 5; break; } DrainMultiplier = drainMultiplier; } } public static class PrayerP03Catalogue { public static readonly PrayerP03Entry[] Entries = new PrayerP03Entry[30] { new PrayerP03Entry("resolve.1", 1, 60, "resolve"), new PrayerP03Entry("resolve.2", 10, 45, "resolve"), new PrayerP03Entry("resolve.3", 28, 30, "resolve"), new PrayerP03Entry("fervour.1", 4, 60, "fervour"), new PrayerP03Entry("fervour.2", 13, 45, "fervour"), new PrayerP03Entry("fervour.3", 31, 30, "fervour"), new PrayerP03Entry("intent.1", 7, 60, "intent"), new PrayerP03Entry("intent.2", 16, 45, "intent"), new PrayerP03Entry("intent.3", 34, 30, "intent"), new PrayerP03Entry("trueflight.1", 8, 55, "trueflight"), new PrayerP03Entry("trueflight.2", 26, 40, "trueflight"), new PrayerP03Entry("trueflight.3", 44, 28, "trueflight"), new PrayerP03Entry("attunement.1", 9, 55, "attunement"), new PrayerP03Entry("attunement.2", 27, 40, "attunement"), new PrayerP03Entry("attunement.3", 45, 28, "attunement"), new PrayerP03Entry("breath.measured", 19, 35, "utility"), new PrayerP03Entry("mending.oath", 22, 35, "utility"), new PrayerP03Entry("oath.seer", 37, 30, "survival"), new PrayerP03Entry("oath.hunter", 40, 30, "survival"), new PrayerP03Entry("oath.iron", 43, 30, "survival"), new PrayerP03Entry("ember.last", 49, 20, "survival"), new PrayerP03Entry("vow.enduring", 55, 30, "vow"), new PrayerP03Entry("covenant.warrior", 60, 15, "package"), new PrayerP03Entry("covenant.hunter", 62, 18, "package"), new PrayerP03Entry("covenant.seer", 63, 18, "package"), new PrayerP03Entry("battle.oath", 70, 12, "package"), new PrayerP03Entry("farshot.oath", 74, 12, "package"), new PrayerP03Entry("runewarden.oath", 77, 12, "package"), new PrayerP03Entry("wayfarer.oath", 85, 24, "utility"), new PrayerP03Entry("accord.oath", 90, 10, "package") }; public static int[] IndicesByLevel() { int[] array = new int[Entries.Length]; for (int i = 0; i < array.Length; i++) { array[i] = i; } Array.Sort(array, delegate(int a, int b) { int level = Entries[a].Level; int num = level.CompareTo(Entries[b].Level); return (num == 0) ? a.CompareTo(b) : num; }); return array; } public static int IndexOf(string id) { for (int i = 0; i < Entries.Length; i++) { if (string.Equals(Entries[i].Id, id, StringComparison.Ordinal)) { return i; } } return -1; } public static ulong Conflicts(int index) { if (index < 0 || index >= Entries.Length) { throw new ArgumentOutOfRangeException("index"); } int num = Slot(index); ulong num2 = 0uL; for (int i = 0; i < Entries.Length; i++) { if (i != index) { int num3 = Slot(i); if ((num == 5 && num3 != 4 && num3 != 8) || (num3 == 5 && num != 4 && num != 8) || (num == num3 && num != 7)) { num2 |= (ulong)(1L << i); } } } return num2; } public static int Slot(int index) { if (index < 0 || index >= Entries.Length) { throw new ArgumentOutOfRangeException("index"); } if (index < 3) { return 0; } if (index < 6) { return 1; } if (index < 9 || (index >= 12 && index < 15)) { return 2; } if (index >= 17 && index <= 20) { return 4; } if ((index < 9 || index >= 12) && (index < 22 || index > 27)) { switch (index) { case 29: break; case 16: return 8; case 21: return 7; default: return 6; } } return 5; } } public struct PrayerP03Bonuses { public readonly int Defence; public readonly int MeleeAccuracy; public readonly int MeleePower; public readonly int RangedAccuracy; public readonly int RangedPower; public readonly int MagicAccuracy; public readonly int MagicPower; public PrayerP03Bonuses(int defence, int meleeAccuracy, int meleePower, int rangedAccuracy, int rangedPower, int magicAccuracy, int magicPower) { Defence = defence; MeleeAccuracy = meleeAccuracy; MeleePower = meleePower; RangedAccuracy = rangedAccuracy; RangedPower = rangedPower; MagicAccuracy = magicAccuracy; MagicPower = magicPower; } } public sealed class PrayerP03State { public const long UnitsPerPoint = 27720L; private const long TicksPerSecond = 10000000L; private long lastTicks; public ulong ActiveMask { get; private set; } public long Units { get; private set; } public long DrainRemainder { get; private set; } public int Level { get; private set; } public bool CapeEfficiency { get; private set; } public PrayerP03State(int level, long units, long remainder, long ticks) { if (level < 1 || level > 100 || units < 0 || units > (long)level * 27720L || remainder < 0 || remainder >= 100000000 || ticks < 0 || (units == 0 && remainder != 0)) { throw new ArgumentOutOfRangeException("Invalid P03 state."); } Level = level; Units = units; DrainRemainder = remainder; lastTicks = ticks; } public void Advance(long ticks) { if (ticks < lastTicks) { throw new ArgumentOutOfRangeException("ticks"); } long num = ticks - lastTicks; lastTicks = ticks; if (ActiveMask == 0 || num == 0) { return; } long num2 = 0L; for (int i = 0; i < PrayerP03Catalogue.Entries.Length; i++) { if ((ActiveMask & (ulong)(1L << i)) != 0) { num2 += 27720L / (long)PrayerP03Catalogue.Entries[i].SecondsPerPoint * PrayerP03Catalogue.Entries[i].DrainMultiplier; } } long num3 = num2 * (CapeEfficiency ? 8 : 10); long num4 = 100000000L; long num5 = num / 10000000; if (num5 > Units * 10 / num3) { Exhaust(); return; } long num6 = num5 * num3 % 10 * 10000000 + num % 10000000 * num3 + DrainRemainder; long num7 = num5 * num3 / 10 + num6 / num4; if (num7 >= Units) { Exhaust(); return; } Units -= num7; DrainRemainder = num6 % num4; } private void Exhaust() { Units = 0L; DrainRemainder = 0L; ActiveMask = 0uL; } public void SetCapeEfficiency(bool enabled, long ticks) { Advance(ticks); CapeEfficiency = enabled; } public static bool ValidQuickMask(ulong mask, int level) { if (mask == 0 || mask >> PrayerP03Catalogue.Entries.Length != 0) { return false; } int num = 0; for (int i = 0; i < PrayerP03Catalogue.Entries.Length; i++) { if ((mask & (ulong)(1L << i)) != 0 && (++num > 3 || PrayerP03Catalogue.Entries[i].Level > level || (mask & PrayerP03Catalogue.Conflicts(i)) != 0)) { return false; } } return true; } public bool ToggleQuick(ulong mask, long ticks) { if (!ValidQuickMask(mask, Level)) { return false; } Advance(ticks); if (ActiveMask == mask) { ActiveMask = 0uL; return true; } if (Units == 0) { return false; } ActiveMask = mask; return true; } public bool Toggle(int index, long ticks) { Advance(ticks); if (index < 0 || index >= PrayerP03Catalogue.Entries.Length || Level < PrayerP03Catalogue.Entries[index].Level || Units == 0) { return false; } ulong num = (ulong)(1L << index); if ((ActiveMask & num) != 0) { ActiveMask &= ~num; } else { ActiveMask = (ActiveMask & ~PrayerP03Catalogue.Conflicts(index)) | num; } return true; } public void Deactivate(long ticks) { Advance(ticks); ActiveMask = 0uL; } public void Restore(int points, long ticks) { if (points < 0) { throw new ArgumentOutOfRangeException("points"); } Advance(ticks); Units = Math.Min((long)Level * 27720L, Units + (long)points * 27720L); } public void OnDeath(long ticks) { Deactivate(ticks); Units = (long)Level * 27720L; DrainRemainder = 0L; } public bool ConsumeLastEmber(long ticks) { Advance(ticks); if (!Active(20) || Units < 27720) { return false; } Units = 0L; DrainRemainder = 0L; ActiveMask = 0uL; return true; } public static float LastEmberReserve(float before, float requested, float maximum) { if (float.IsNaN(before) || float.IsInfinity(before) || float.IsNaN(requested) || float.IsInfinity(requested) || float.IsNaN(maximum) || float.IsInfinity(maximum) || requested <= 0f || before <= requested || maximum <= 0f) { return 0f; } return Math.Min((before - requested) * 0.5f, maximum * 0.2f); } public bool Active(int index) { if (index >= 0 && index < 30) { return (ActiveMask & (ulong)(1L << index)) != 0; } return false; } public PrayerP03Bonuses Bonuses() { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; int[] array = new int[3] { 5, 10, 15 }; int[] array2 = new int[3] { 5, 10, 15 }; int[] array3 = new int[3] { 5, 10, 15 }; int[] array4 = new int[3] { 4, 8, 12 }; int[] array5 = new int[3] { 5, 10, 15 }; for (int i = 0; i < 30; i++) { if (!Active(i)) { continue; } if (i < 3) { num += array[i]; continue; } if (i < 6) { num3 += array2[i - 3]; continue; } if (i < 9) { num2 += array3[i - 6]; continue; } if (i < 12) { num4 += array4[i - 9]; num5 += array4[i - 9]; continue; } if (i < 15) { num6 += array5[i - 12]; continue; } switch (i) { case 22: num2 += 16; num3 += 18; num += 18; break; case 23: num4 += 16; num5 += 16; num += 8; break; case 24: num6 += 18; num7 += 3; num += 8; break; case 25: num2 += 20; num3 += 22; num += 23; break; case 26: num4 += 20; num5 += 22; num += 23; break; case 27: num6 += 23; num7 += 5; num += 23; break; case 29: num2 += 14; num4 += 14; num6 += 14; num3 += 12; num5 += 12; num7 += 12; num += 15; break; } } return new PrayerP03Bonuses(num, num2, num3, num4, num5, num6, num7); } public void SetLevel(int level, long ticks) { Advance(ticks); if (level < 1 || level > 100) { throw new ArgumentOutOfRangeException("level"); } Level = level; Units = Math.Min(Units, (long)level * 27720L); for (int i = 0; i < 30; i++) { if (Active(i) && PrayerP03Catalogue.Entries[i].Level > level) { ActiveMask &= (ulong)(~(1L << i)); } } if (Units == 0) { ActiveMask = 0uL; DrainRemainder = 0L; } } } } namespace ValheimMastery.Progression { public sealed class LeaderboardResponseBuffer { public const int Limit = 1048576; private readonly MemoryStream bytes = new MemoryStream(); public bool Rejected { get; private set; } public int Length => (int)bytes.Length; public void DeclareLength(ulong length) { if (length > 1048576) { Rejected = true; } } public bool Append(byte[] data, int count) { if (Rejected) { return false; } if (count < 0 || (data == null && count != 0) || (data != null && count > data.Length) || count > 1048576 - bytes.Length) { Rejected = true; return false; } if (count > 0) { bytes.Write(data, 0, count); } return true; } public string Text() { if (Rejected) { throw new InvalidDataException("Leaderboard response exceeds byte budget."); } return new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetString(bytes.GetBuffer(), 0, (int)bytes.Length); } } public static class LeaderboardLocalPolicy { public const int SkillCount = 22; public const int LegacySkillCount = 21; public const string OnlineEndpoint = "https://valheim-mastery-leaderboard.valheim-mastery-leaderboard-local.workers.dev"; public static long UnixNow => (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds; public static bool IsOnline(string endpoint) { if (endpoint != null && Regex.IsMatch(endpoint, "\\Ahttps://valheim-mastery-leaderboard\\.valheim-mastery-leaderboard-local\\.workers\\.dev(?::443)?/?\\z", RegexOptions.IgnoreCase) && Uri.TryCreate(endpoint, UriKind.Absolute, out Uri result) && result.Scheme == "https" && result.Port == 443 && result.Host == "valheim-mastery-leaderboard.valheim-mastery-leaderboard-local.workers.dev") { return Clean(result); } return false; } private static bool Clean(Uri uri) { if (uri.AbsolutePath == "/" && uri.Query.Length == 0 && uri.Fragment.Length == 0) { return uri.UserInfo.Length == 0; } return false; } public static bool AcceptsEndpoint(string endpoint) { if (!IsOnline(endpoint)) { if (endpoint != null && Regex.IsMatch(endpoint, "\\Ahttp://(?:127\\.0\\.0\\.1|\\[::1\\])(?::[0-9]{1,5})?/?\\z", RegexOptions.IgnoreCase) && Uri.TryCreate(endpoint, UriKind.Absolute, out Uri result) && result.Scheme == "http" && (result.Host == "127.0.0.1" || result.Host == "[::1]" || result.Host == "::1" || result.Host == "[0000:0000:0000:0000:0000:0000:0000:0001]")) { return Clean(result); } return false; } return true; } public static bool Hex(string value, int length) { if (value == null || value.Length != length) { return false; } foreach (char c in value) { if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) { return false; } } return true; } public static string NewToken() { byte[] array = new byte[32]; using (RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create()) { randomNumberGenerator.GetBytes(array); } return ToHex(array); } private static string ToHex(byte[] bytes) { return BitConverter.ToString(bytes).Replace("-", "").ToLowerInvariant(); } public static string Hash(string value) { using SHA256 sHA = SHA256.Create(); return ToHex(sHA.ComputeHash(Encoding.UTF8.GetBytes(value))); } public static bool ValidChallenge(string key, string nonce, long expires, int difficulty, string signature, string expectedKey, long now) { if (key == expectedKey && Hex(key, 64) && Hex(nonce, 32) && Hex(signature, 64) && difficulty >= 1 && difficulty <= 20 && expires > now) { return expires <= now + 3600; } return false; } public static bool LeadingZeroBits(byte[] hash, int bits) { if (hash == null || bits < 1 || bits > hash.Length * 8) { return false; } for (int i = 0; i < bits / 8; i++) { if (hash[i] != 0) { return false; } } if (bits % 8 != 0) { return hash[bits / 8] >> 8 - bits % 8 == 0; } return true; } public static string Solve(string signature, int difficulty, long expires, Func<bool> cancelled, int milliseconds) { if (!Hex(signature, 64) || difficulty < 1 || difficulty > 20 || milliseconds < 1 || milliseconds > 30000) { return null; } Stopwatch stopwatch = Stopwatch.StartNew(); byte[] array = new byte[81]; Encoding.ASCII.GetBytes(signature + ":", 0, 65, array, 0); using (SHA256 sHA = SHA256.Create()) { for (int i = 0; i < 16777216; i++) { if ((i & 0xFF) == 0 && (cancelled() || stopwatch.ElapsedMilliseconds >= milliseconds || UnixNow >= expires)) { return null; } int num = 1; int num2; for (num2 = i; num2 >= 10; num2 /= 10) { num++; } num2 = i; for (int num3 = 65 + num - 1; num3 >= 65; num3--) { array[num3] = (byte)(48 + num2 % 10); num2 /= 10; } if (LeadingZeroBits(sHA.ComputeHash(array, 0, 65 + num), difficulty)) { return i.ToString(CultureInfo.InvariantCulture); } } } return null; } public static int BackoffSeconds(int failures, string retryAfter, long now) { int num = (int)Math.Min(1800.0, 30.0 * Math.Pow(2.0, Math.Min(6, Math.Max(0, failures - 1)))); DateTime result2; if (long.TryParse(retryAfter, NumberStyles.None, CultureInfo.InvariantCulture, out var result)) { num = (int)Math.Max(num, Math.Min(86400L, result)); } else if (DateTime.TryParse(retryAfter, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out result2)) { num = (int)Math.Max(num, Math.Min(86400.0, Math.Max(0.0, (result2.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds - (double)now))); } return num; } } internal static class FloorTerrainPolicy { internal const float MaxHeightChange = 0.75f; internal static bool Supported(string name) { switch (name) { default: return name == "grausten_floor_4x4"; case "wood_floor": case "wood_floor_1x1": case "stone_floor_2x2": case "blackmarble_floor": case "grausten_floor_2x2": return true; } } internal static bool Contains(float x, float z, float minX, float maxX, float minZ, float maxZ) { if (x >= minX - 0.001f && x <= maxX + 0.001f && z >= minZ - 0.001f) { return z <= maxZ + 0.001f; } return false; } internal static bool NearGround(float target, float ground) { if (!float.IsNaN(target) && !float.IsInfinity(target) && !float.IsNaN(ground) && !float.IsInfinity(ground)) { return Math.Abs(target - ground) <= 0.75f; } return false; } } public static class ConstructionBuildHistory { public const int Version = 2; private const string Prefix = "org.valheim.mastery.skill.construction.site.v2."; public static string SiteKey(long world, string prefab, float x, float y, float z) { return "org.valheim.mastery.skill.construction.site.v2." + world.ToString(CultureInfo.InvariantCulture) + ":" + Cell(x) + ":" + Cell(y) + ":" + Cell(z) + ":" + prefab; } private static string Cell(float coordinate) { return Math.Round((double)coordinate * 100.0, MidpointRounding.AwayFromZero).ToString(CultureInfo.InvariantCulture); } public static bool Record(IDictionary<string, string> data, string site, bool explicitlyRebuilt) { bool result = explicitlyRebuilt || data.ContainsKey(site); data[site] = "1"; data.Remove("org.valheim.mastery.skill.construction.rebuildDebt"); return result; } public static bool CanCountProjectPart(bool rebuilt, int version, bool counted, double placed, double start) { if (!counted && start > 0.0 && placed >= start) { if (rebuilt) { return version < 2; } return true; } return false; } } internal static class SharedBuildingPolicy { internal const float BaseRadius = 20f; internal const float MaximumRadius = 245f; internal static float LegacyRadius(int width, int depth) { if (width <= 0 || depth <= 0) { return 20f; } return (float)Math.Ceiling(Math.Sqrt((double)width * (double)width + (double)depth * (double)depth) / 2.0); } internal static float UnlockedRadius(int level, bool cape) { return 20f + RemainingSkillFormula.BuildRange(Math.Max(1, Math.Min(100, level))) + (float)(cape ? 100 : 0); } internal static bool Contains(float x, float z, float cx, float cz, float radius) { double num = (double)x - (double)cx; double num2 = (double)z - (double)cz; if (radius > 0f && !float.IsNaN(radius) && !float.IsInfinity(radius)) { return num * num + num2 * num2 <= (double)radius * (double)radius; } return false; } } internal static class AreaFuelPolicy { internal static int Missing(float fuel, float maximum) { if (float.IsNaN(fuel) || float.IsInfinity(fuel) || float.IsNaN(maximum) || float.IsInfinity(maximum) || maximum <= 0f || maximum > 10000f) { return 0; } return Math.Max(0, (int)Math.Floor(maximum) - (int)Math.Ceiling(Math.Max(0f, fuel))); } internal static float Settled(float fuel, float maximum, float secondsPerFuel, long last, long now, bool burning) { if (float.IsNaN(fuel) || float.IsInfinity(fuel)) { return 0f; } double num = ((last <= 0 || now <= last) ? 0.0 : ((double)(now - last) / 10000000.0)); return (float)Math.Max(0.0, (double)Math.Min(maximum, fuel) - ((burning && secondsPerFuel > 0f) ? (num / (double)secondsPerFuel) : 0.0)); } } public sealed class EquipmentDisplayCandidate { public readonly string Prefab; public readonly string Title; public readonly string Description; public readonly int Level; public readonly int Quality; public EquipmentDisplayCandidate(string prefab, string title, string description, int level, int quality) { Prefab = prefab; Title = title; Description = description; Level = level; Quality = quality; } } public sealed class EquipmentDisplayGroup { public readonly string Title; public readonly string Description; public readonly int Level; public readonly int FirstIndex; public readonly List<string> Prefabs = new List<string>(); public readonly List<int> Qualities = new List<int>(); internal EquipmentDisplayGroup(EquipmentDisplayCandidate item, int index) { Title = item.Title; Description = item.Description; Level = item.Level; FirstIndex = index; } internal void Add(EquipmentDisplayCandidate item) { if (!Prefabs.Contains(item.Prefab)) { Prefabs.Add(item.Prefab); if (item.Quality > 0 && !Qualities.Contains(item.Quality)) { Qualities.Add(item.Quality); } } } } public static class EquipmentDisplayGrouper { public static List<EquipmentDisplayGroup> Group(IList<EquipmentDisplayCandidate> items) { List<EquipmentDisplayGroup> list = new List<EquipmentDisplayGroup>(); Dictionary<string, EquipmentDisplayGroup> dictionary = new Dictionary<string, EquipmentDisplayGroup>(StringComparer.Ordinal); if (items == null) { return list; } for (int i = 0; i < items.Count; i++) { EquipmentDisplayCandidate equipmentDisplayCandidate = items[i]; if (equipmentDisplayCandidate != null && !string.IsNullOrEmpty(equipmentDisplayCandidate.Prefab)) { int level = equipmentDisplayCandidate.Level; string key = level.ToString(CultureInfo.InvariantCulture) + ":" + Field(equipmentDisplayCandidate.Title) + Field(equipmentDisplayCandidate.Description); if (!dictionary.TryGetValue(key, out var value)) { value = new EquipmentDisplayGroup(equipmentDisplayCandidate, i); dictionary.Add(key, value); list.Add(value); } value.Add(equipmentDisplayCandidate); } } return list; } private static string Field(string value) { value = value ?? ""; return value.Length.ToString(CultureInfo.InvariantCulture) + ":" + value; } } public static class MasteryText { public static Func<bool> UseGerman = () => true; private static readonly Dictionary<string, string> Catalog = CreateCatalog(); private static readonly Dictionary<char, List<string>> Index = CreateIndex(); private static readonly Dictionary<string, string> Cache = new Dictionary<string, string>(StringComparer.Ordinal); public static int Count => Catalog.Count; public static bool Has(string text) { if (text != null) { return Catalog.ContainsKey(text); } return false; } public static string Number(double value, string format) { return value.ToString(format, UseGerman() ? CultureInfo.GetCultureInfo("de-DE") : CultureInfo.InvariantCulture); } private static Dictionary<char, List<string>> CreateIndex() { Dictionary<char, List<string>> dictionary = new Dictionary<char, List<string>>(); foreach (string key in Catalog.Keys) { if (key.Length != 0) { if (!dictionary.TryGetValue(key[0], out var value)) { value = new List<string>(); dictionary[key[0]] = value; } value.Add(key); } } foreach (List<string> value2 in dictionary.Values) { value2.Sort((string a, string b) => b.Length.CompareTo(a.Length)); } return dictionary; } public static string T(string text) { if (string.IsNullOrEmpty(text)) { return text; } if (MasteryPublicNames.TryExact(text, out var result)) { if (!UseGerman()) { return result; } return MasteryCapeNames.German(result); } if (!UseGerman()) { return English(text); } return MasterySenseNames.Render(MasteryCapeNames.German(MasteryPublicNames.Render(text)), german: true); } public static string[] T(string[] values) { if (values == null) { return null; } string[] array = null; for (int i = 0; i < values.Length; i++) { string text = T(values[i]); if (!string.Equals(text, values[i], StringComparison.Ordinal)) { if (array == null) { array = (string[])values.Clone(); } array[i] = text; } } return array ?? values; } private static bool Word(char c) { if (!char.IsLetterOrDigit(c) && c != '_') { return c == '$'; } return true; } public static string English(string text) { if (string.IsNullOrEmpty(text)) { return text; } if (MasteryPublicNames.TryExact(text, out var result)) { return result; } if (MasterySenseNames.TryExact(text, german: false, out result)) { return result; } if (Catalog.TryGetValue(text, out result)) { return MasterySenseNames.Render(MasteryPublicNames.Render(result), german: false); } if (Cache.TryGetValue(text, out result)) { return result; } StringBuilder stringBuilder = new StringBuilder(text.Length); int num = 0; while (num < text.Length) { if (text[num] == '<' || text[num] == '`' || text[num] == '$') { int i = num + 1; if (text[num] == '<') { int num2 = text.IndexOf('>', i); i = ((num2 < 0) ? text.Length : (num2 + 1)); } else if (text[num] == '`') { int num3 = text.IndexOf('`', i); i = ((num3 < 0) ? text.Length : (num3 + 1)); } else { for (; i < text.Length && Word(text[i]); i++) { } } stringBuilder.Append(text, num, i - num); num = i; continue; } string text2 = null; if (Index.TryGetValue(text[num], out var value)) { foreach (string item in value) { int num4 = num + item.Length; if (num4 <= text.Length && (!Word(item[0]) || num <= 0 || !Word(text[num - 1])) && (!Word(item[item.Length - 1]) || num4 >= text.Length || !Word(text[num4])) && string.CompareOrdinal(text, num, item, 0, item.Length) == 0) { text2 = item; break; } } } if (text2 != null) { stringBuilder.Append(Catalog[text2]); num += text2.Length; } else { stringBuilder.Append(text[num++]); } } result = MasterySenseNames.Render(MasteryPublicNames.Render(stringBuilder.ToString()), german: false); if (Cache.Count >= 2048) { Cache.Clear(); } Cache[text] = result; return result; } private static Dictionary<string, string> CreateCatalog() { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); dictionary.Add("\nBoegen, Staebe, nichtmetallische Ausruestung und saemtliche Pfeile/Bolzen gehoeren zu Handwerk.", "\nBows, staves, non-metal equipment and all arrows/bolts belong to Crafting."); dictionary.Add("\nCape ab 100: weitere 10% kuerzere Herstellung. Kein Effekt auf Essen oder Traenke.", "\nCape at 100: another 10% shorter production time. No effect on food or potions."); dictionary.Add("\nDarin +", "\nIncludes +"); dictionary.Add("\nErzrausch mit Cape/Spitzhacke: ", "\nOre rush with cape/pickaxe: "); dictionary.Add("\nErzschmelzen: fertige Barren geben dem Einfueller Schmiede-XP, auch nach erneutem Einloggen.", "\nSmelting: finished bars award Smithing XP to the player who loaded the ore, even after logging in again."); dictionary.Add("\nHoehere Level verbessern Faellschaden und Ertrag. Cape: getragen +10% Ertrag.", "\nHigher levels improve chopping damage and yield. Cape: +10% yield while worn."); dictionary.Add("\nHolzfaellerrausch mit Cape/Axt: ", "\nLumber rush with cape/axe: "); dictionary.Add("\nKern-/Edelholz 10, Uralte Rinde 20, Yggdrasilholz 50, Eschenholz 60. Passende Axt weiterhin erforderlich.", "\nCore/fine wood 10, ancient bark 20, Yggdrasil wood 50, ashwood 60. Appropriate axe still required."); dictionary.Add("\nLaufender Altauftrag: XP seit dem Update erfasst.", "\nExisting contract: XP tracked since the update."); dictionary.Add("\nNahrung wird danach addiert.", "\nFood is added afterwards."); dictionary.Add("\nNatuerlich gewachsene Baeume und ihre Staemme; keine Bauwerke, Holzstapel oder Baumstuempfe.", "\nNaturally grown trees and their logs; no buildings, wood stacks or stumps."); dictionary.Add("\nRechtsklick: öffnen. Überlauf fällt auf den Boden.", "\nRight-click: open. Overflow drops to the ground."); dictionary.Add("\nRezeptwissen, Materialien, Werkbankstufe und Weltfortschritt bleiben erforderlich.", "\nRecipe knowledge, materials, station level and world progression are still required."); dictionary.Add("\nSchleichen: Agility bestimmt Tarnwirkung und Ausdauerverbrauch nach Vanilla.", "\nSneaking: Agility determines stealth and stamina cost using vanilla scaling."); dictionary.Add("\nSchwimmkosten skalieren nach Vanilla. Nahrung gibt zusaetzliche Ausdauer.", "\nSwimming costs scale as in vanilla. Food adds extra stamina."); dictionary.Add("\nSerienbelohnung: +", "\nStreak reward: +"); dictionary.Add("\nUpgrades: +2 benoetigte Level je Qualitaetsstufe (maximal 99).", "\nUpgrades: +2 required levels per quality tier (maximum 99)."); dictionary.Add("\nWachstum: ", "\nGrowth: "); dictionary.Add("\nWerkzeuganforderungen bleiben bestehen. Hoeheres Level verbessert den Ertrag aelterer Tiers.", "\nTool requirements still apply. Higher levels improve yield from earlier tiers."); dictionary.Add("\nWildschwein, Hirsch, Wolf, Lox und Hase: Kadaver mit E ausweiden. Regulärer Loot bleibt erhalten; nach 5 Minuten fällt er ohne Hunter-XP heraus. Keine Zucht-/Zähm-XP.\nCoop: ein XP-Topf nach Schadensanteil. F2 wählt Fährtensinn, Q aktiviert. Jagdtagebuch am Baumeisterbrett.\nCape: Alt+F1 ohne Hammer oder Angel, 4min Jagdmeister, danach 6min Cooldown.", "\nBoar, deer, wolf, lox and hare: press E to harvest carcasses. Normal loot is retained; after 5 minutes it drops without Hunter XP. No breeding/taming XP.\nCo-op: one XP pool shared by damage contribution. F2 selects Tracking sense, Q activates it. Hunting journal at the construction board.\nCape: Alt+F1 without hammer or rod, Huntmaster for 4min, then 6min cooldown."); dictionary.Add("\nXP erst bei erfolgreicher Ernte, nach Art und Menge inklusive Bonusloot.\nPflanzengates gelten beim Anbau; Ernten, Weitergeben und Verarbeiten bleiben frei.\nRasterpflanzen: 2 ab 10, 4 ab 50, 6 ab 100; linke Alt-Taste fuer einzeln. Weinreben einzeln.\nSammelernte: 20% ab 60, +4 Prozentpunkte/Level, 100% ab 80; keine Kettenreaktion.\nZaehmen, Reiten und Schlachten gehoeren zu Tiermeister. Saatgutbonus nur fuer nach dem Update ausgewachsene Pflanzen mit Saatgut-Rezept.\nCape ab 100: +10 Prozentpunkte Ertragschance.", "\nXP is awarded on successful harvest, by species and quantity including bonus loot.\nPlanting gates apply only to planting; harvesting, sharing and processing remain free.\nGrid planting: 2 at 10, 4 at 50,6 at 100; Left Alt plants individually. Vines are planted individually.\nArea harvest: 20% at 60, +4 percentage points per level, 100% at 80; no chain reactions.\nTaming, riding and slaughter belong to Beastmaster. Seed bonus only for plants grown after the update with a seed recipe.\nCape at 100:+10 percentage points bonus yield chance."); dictionary.Add("\nXP erst bei erfolgreicher Ernte, nach Art und Menge inklusive Bonusloot.\nPflanzengates gelten beim Anbau; Ernten, Weitergeben und Verarbeiten bleiben frei.\nRasterpflanzen: 2 ab 10, 4 ab 50, 6 ab 100; linke Alt-Taste fuer einzeln. Weinreben einzeln.\nSammelernte: 20% ab 60, +4 Prozentpunkte/Level, 100% ab 80; keine Kettenreaktion.\nZaehmen: +20% Geschwindigkeit je 20 Level; bester Farmer im 15m-Umkreis.\nEinmalige Zaehm-XP nach Beitrag; Schlacht-XP nur fuer ausgewachsene Nachzucht/aufgezogene Huehner. Kein Jungtier-/Wildtier-XP. Saatgutbonus nur fuer nach dem Update ausgewachsene Pflanzen mit Saatgut-Rezept.\nCape ab 100: +10 Prozentpunkte Ertragschance.", "\nXP is awarded on successful harvest, by species and quantity including bonus loot.\nPlanting gates apply only to planting; harvesting, sharing and processing remain free.\nGrid planting: 2 at 10, 4 at 50, 6 at 100; Left Alt plants individually. Vines are planted individually.\nArea harvest: 20% at 60, +4 percentage points/level, 100% at 80; no chain reactions.\nTaming: +20% speed per 20 levels; best farmer within 15m.\nOne-time taming XP by contribution; slaughter XP only for mature bred animals/raised chickens. No juvenile/wild animal XP. Seed bonus only for plants grown after the update with a seed recipe.\nCape at 100: +10 percentage points bonus yield chance."); dictionary.Add("\nXP fuer echte Schiffsstrecke, gleich fuer Ruder und Mitfahrer. Schiffboni vom Steuermann, Kartenradius persoenlich.\nCape am Ruder: Umschalt links + F1, 4min Rueckenwind, danach 6min Cooldown.", "\nXP for actual ship travel, equal for helmsman and passengers. Ship bonuses come from the helmsman; map radius is personal.\nCape at the helm: Left Shift + F1, 4min tailwind, then 6min cooldown."); dictionary.Add("\nXP fuer erfolgreich hergestellte Produkte und Aufwertungen; Reparieren gibt keine XP.", "\nXP for successfully crafted products and upgrades; repairs grant no XP."); dictionary.Add("\nXP fuer fertige Flaschen inklusive Bonus. Metbasen geben keine XP. Trankwerte bleiben fest.\nMaterialersparnis 5/10/15/20/25% ab 20/40/60/80/100. Cape beim Befuellen: weitere 10% kuerzer, eine garantierte Bonusflasche.", "\nXP for finished bottles including bonuses. Mead bases grant no XP. Potion stats stay fixed.\nMaterial saving 5/10/15/20/25% at 20/40/60/80/100. Cape when filling: another 10% shorter, one guaranteed bonus bottle."); dictionary.Add("\nXP fuer fertige Portionen; am Feuer erst bei Abnahme. Verbranntes: ein Drittel. Lebensmittelwerte bleiben fest.\nMaterialersparnis: 5/10/15/20/25% ab Level 20/40/60/80/100. Bonusportionen geben volle XP.\nKoch-Cape: beim Einsetzen vor Verbrennen schuetzen.", "\nXP for finished servings; at a fire, only on collection. Burnt food: one third. Food stats remain fixed.\nMaterial saving: 5/10/15/20/25% at levels 20/40/60/80/100. Bonus servings grant full XP.\nCooking cape: wear when placing food to prevent burning."); dictionary.Add("\nXP fuer gueltige Auftragskills. Coop: volle XP in 70m; Marken beim Abschluss. Jagdinstinkt ab 60, Cape-Berserk ab 100.", "\nXP for valid contract kills. Co-op: full XP within 70m; tokens on completion. Hunting instinct from 60, cape berserk from 100."); dictionary.Add("\nXP fuer tatsaechlich erzeugtes Holz, inklusive Bonusloot. Keine Treffer-XP.", "\nXP for actual wood drops, including bonus loot. No XP per hit."); dictionary.Add("\nXP für gelandete Angel- und Harpunenfänge nach Art und Qualität. Bonusfisch gibt zusätzliche XP. Keine XP durch Aufheben oder Wiederfangen weggeworfener Fische.\nKeine Fischart-Levelgates; passender Köder ist beim Angeln nötig. Harpunenfang ab Angeln-Level 20, auch ohne Cape oder Wasserwanderer: vom Ufer, vom Boot oder im flachen Wasser. Fischgründe: gemeinsamer Bestand, Erholung nach einem Spieltag.\nF2 wählt Fischersinn, Q aktiviert. Fangbuch am Baumeisterbrett. Wasserwanderer mit C: 4 Minuten auf Wasser laufen, danach 6 Minuten Abklingzeit. Beim Apex die Fähigkeit als C-Auswahl speichern.", "\nXP for landed rod and harpoon catches, by species and quality. Bonus fish grant additional XP. No XP for picking up or recatching discarded fish.\nNo species level gates; matching bait is required for rod fishing. Harpoon fishing unlocks at Fishing level 20, without a cape or Waterwalker: from shore, a boat or shallow water. Fishing grounds: shared stocks, recovery after one in-game day.\nF2 selects Fishing sense, Q activates it. Fishing journal at the construction board. Waterwalker with C: walk on water for 4 minutes, followed by a 6-minute cooldown. With Apex, save the ability as your C selection."); dictionary.Add("\nXP für neue Bauteile, Projekte und Bauaufträge. Wiederaufbau: 25% Bau-XP. Abreißen und Reparieren allein geben keine XP.\nMaterialersparnis 5/10/15/20/25% ab 20/40/60/80/100. Kostenlose Bauteile geben keine Rohstoffe zurück. Bekannte Baurezepte bleiben beim Import nutzbar.\nBaumeisterbrett: Baugebiet festlegen, Projekt wählen. Cape mit Hammer: Alt+F1 öffnet die Auswahl für Gebietsreparatur mit 4min Bauen ohne Ausdauer oder Heimkehr zum gesetzten eigenen Bett. Bau-Buff: danach 6min CD; Heimkehr: 6min CD; normale Transportregeln gelten.", "\nXP for new building pieces, projects and work orders. Rebuilding: 25% building XP. Demolishing or repairing alone grants no XP.\nMaterial saving 5/10/15/20/25% at 20/40/60/80/100. Free pieces do not return resources. Known building recipes remain usable after import.\nConstruction board: define an area and choose a project. Cape with hammer: Alt+F1 opens the choice of area repair with no building stamina cost for 4min, or return home to your own selected bed. Build buff: then 6min cooldown; return home: 6min cooldown; normal transport rules apply."); dictionary.Add("\nXP nur fuer echte wilde Beeren, Pilze und Kraeuter inklusive Bonusfunden. Keine Pflueck-Gates.\nAngebaute Pflanzen geben Landwirtschaft-XP. Wegwerfen und Aufheben gibt keine Sammel-XP.\nReicher Fund: zwei weitere Exemplare derselben Ressource.\nSammlersinn [", "\nXP only for wild berries, mushrooms and herbs, including bonus finds. No gathering gates.\nCultivated plants grant Farming XP. Dropping and picking up items grants no Foraging XP.\nRich find: two extra units of the same resource.\nForaging sense ["); dictionary.Add("\nXP nur fuer tatsaechliche Erz-/Steindrops, einschliesslich Bonusloot.", "\nXP only for actual ore/stone drops, including bonus loot."); dictionary.Add("\nXP: Sprinten, Schwimmen, bewegte Spruenge, Ausweichen und Schleichen nahe unalarmierten Gegnern.", "\nXP: running, swimming, moving jumps, dodging and sneaking near unaware enemies."); dictionary.Add("\n[Umschalt + Benutzen] Serienkochen: bis ", "\n[Shift + Use] Batch cooking: up to "); dictionary.Add(" (+0,5 je Magielevel; Nahrung zusätzlich)", " (+0.5 per Magic level; food adds more)"); dictionary.Add(" (aktuell ", " (current "); dictionary.Add(" (angebaut)", " (cultivated)"); dictionary.Add(" (ohne Sterne/Multiplikator). Abschluss: +20% Auftrags-XP und ", " (before stars/multiplier). Completion: +20% contract XP and "); dictionary.Add(" 100 (aktuell ", " 100 (current "); dictionary.Add(" Abschluss-XP (20 %) · Serie: ", " completion XP (20%) · Streak: "); dictionary.Add(" Abschlussmarken. Weltfortschritt erforderlich.", " completion tokens. World progression required."); dictionary.Add(" An der Werkbank: vorhandenen Max Cape über Stil umfärben (getragenen bevorzugt). Acht Farben, identische Boni.", " At a workbench: recolour an existing Max Cape using Style (equipped cape preferred). Eight colours, identical bonuses."); dictionary.Add(" Auftrags-XP insgesamt · +", " total contract XP · +"); dictionary.Add(" Basis-Marken.\nCoop: beide volle gleiche XP; beim letzten Kill beide innerhalb 70m fuer gleiche Abschlussmarken. Beitritt vor dem ersten Kill.", " base tokens.\nCo-op: both receive full equal XP; both must be within 70m on the last kill for equal completion tokens. Join before the first kill."); dictionary.Add(" Basis-XP", " base XP"); dictionary.Add(" Basis-XP bei Qualität 1. Qualitätsfaktoren: 1 / 1,5 / 2 / 3 / 4. Passender Köder, kein Levelgate.", " base XP at quality 1. Quality multipliers: 1 / 1.5 / 2 / 3 / 4. Requires matching bait; no level gate."); dictionary.Add(" Basis-XP pro Meter fuer jedes Besatzungsmitglied.", " base XP per metre for every crew member."); dictionary.Add(" Basis-XP pro tatsaechlich geernteter Einheit. Kultivierter Anbau gehoert zu Landwirtschaft.", " base XP per unit actually harvested. Cultivated crops belong to Farming."); dictionary.Add(" Basis-XP; Rohzutaten geben noch keine XP.", " base XP; raw ingredients do not grant XP yet."); dictionary.Add(" Felder absenken · ", " cells to lower · "); dictionary.Add(" Felder. Ausdauer regeneriert zwischen den Arbeitsschritten.", " cells. Stamina regenerates between steps."); dictionary.Add(" Gebets-XP", " Prayer XP"); dictionary.Add(" Harz.", " resin."); dictionary.Add(" Hirschfelle + ", " deer hides + "); dictionary.Add(" Kampfminuten. Coop nutzt den hoechsten aktiven Bonus fuer beide; keine Addition.", " combat minutes. Co-op uses the highest active bonus for both players; bonuses do not stack."); dictionary.Add(" Kein Jagd-Levelgate. Gezähmte/gezüchtete Tiere zählen zu Farming.", " No Hunter level gate. Tamed/bred animals count towards Farming."); dictionary.Add(" Kisten vorgemerkt: Inventarplatz freimachen.", " crates pending: free inventory space."); dictionary.Add(" Marken (enthalten)", " tokens (included)"); dictionary.Add(" Material-Meilenstein ", " Material milestone "); dictionary.Add(" Meter. Bereiche anderer Baubretter dürfen sich nicht überlappen.", " metres. Areas of different construction boards must not overlap."); dictionary.Add(" Minuten.", " minutes."); dictionary.Add(" Minuten. Kultivierter Boden und ausreichend Platz erforderlich.", " minutes. Requires cultivated soil and sufficient space."); dictionary.Add(" Nachbarabschnitte derselben Ader, je 15% Schaden (2m).", " adjacent sections of the same deposit, 15% damage each (2m)."); dictionary.Add(" Noch ", " Remaining: "); dictionary.Add(" Qualität", " quality"); dictionary.Add(" Sekunden verbleibend.", " seconds remaining."); dictionary.Add(" Slayer-Testmarken hinzugefuegt. Guthaben: ", " Slayer test tokens added. Balance: "); dictionary.Add(" Spieltagen, wenn der Bereich frei ist.", " in-game days, if the area is clear."); dictionary.Add(" Stein. Hacke und Spitzhacke im Inventar; Ausdauer und Hackenhaltbarkeit werden pro Feld verbraucht. Keine Terrain-XP oder Drops.", " stone. Keep a hoe and pickaxe in your inventory; stamina and hoe durability are consumed per cell. No terrain XP or drops."); dictionary.Add(" Teile", " pieces"); dictionary.Add(" Tierstufe", " creature tier"); dictionary.Add(" XP bis zum naechsten Level", " XP to next level"); dictionary.Add(" XP nur für tatsächliche Ernte.", " XP only for actual harvests."); dictionary.Add(" XP zum nächsten Level", " XP to next level"); dictionary.Add(" abgeschlossene Aufträge · Serie: ", " completed contracts · Streak: "); dictionary.Add(" alte Testkit-Capes entfernt; reguläre Capes werden auf Level 100 gecraftet.", " old test kit capes removed; regular capes are crafted at level 100."); dictionary.Add(" anheben · ", " to raise · "); dictionary.Add(" auf den Boden", " to the ground"); dictionary.Add(" benötigt", " requires"); dictionary.Add(" entstehen 2 ", " produces two "); dictionary.Add(" erforderlich (aktuell ", " required (current "); dictionary.Add(" erforderlich.", " required."); dictionary.Add(" freie Plaetze", " empty slots"); dictionary.Add(" fuer diesen Testcharakter auf Level ", " for this test character set to level "); dictionary.Add(" ins Inventar", " into inventory"); dictionary.Add(" m · Weltfortschritt: ", " m · World progression: "); dictionary.Add(" noch nicht bereit, ", " not ready, "); dictionary.Add(" nötig.", " required."); dictionary.Add(" pflanzen", " planting"); dictionary.Add(" und ", " and "); dictionary.Add(" und Mastery Cape", " and Mastery Cape"); dictionary.Add(" und Verteidigung ", " and Defence "); dictionary.Add(" weitere Freischaltungen – siehe Skilldetails.", " more unlocks – see skill details."); dictionary.Add(" zum Herstellen/Aufwerten erforderlich.", " required to craft/upgrade."); dictionary.Add(" zum Pflanzen erforderlich (aktuell ", " required to plant (current "); dictionary.Add(" zum Schmelzen erforderlich.", " required to smelt."); dictionary.Add(" zum Steuern", " to steer"); dictionary.Add(" zum Steuern erforderlich. Mitfahren bleibt frei.", " required to steer. Passengers have no level requirement."); dictionary.Add(" zum Zubereiten erforderlich.", " required to prepare."); dictionary.Add(" zum Zubereiten. Essen und Weitergeben bleiben frei.", " to prepare. Eating and sharing have no level requirement."); dictionary.Add(" zum Zubereiten. Trinken und Weitergeben bleiben frei.", " to prepare. Drinking and sharing have no level requirement."); dictionary.Add(" | wird abgefuellt", " | bottling"); dictionary.Add(" · Abschluss-XP: ", " · Completion XP: "); dictionary.Add(" · Alt+E: eigenen Plan abbrechen", " · Alt+E: cancel own blueprint"); dictionary.Add(" · Bild↑/Bild↓: drehen · E: setzen · Esc: abbrechen\n", " · Page Up/Page Down: rotate · E: place · Esc: cancel\n"); dictionary.Add(" · Kapazitaet ", " · Capacity "); dictionary.Add(" · Rekord ", " · Record "); dictionary.Add(" · Rezept dauerhaft freischalten", " · Permanently unlock recipe"); dictionary.Add(" · Schulterplatz · Bonus nur getragen.", " · Shoulder slot · Bonus only while worn."); dictionary.Add(" · Stufe ", " · Level "); dictionary.Add(" · abgeschlossen", " · completed"); dictionary.Add(" — noch ", " — remaining: "); dictionary.Add("% (doppelte XP).", "% (double XP)."); dictionary.Add("% (ohne Ueberladung)", "% (not overloaded)"); dictionary.Add("% Chance auf keinen Materialverbrauch", "% chance to consume no materials"); dictionary.Add("% Chance auf keinen Rezeptmaterialverbrauch", "% chance to consume no recipe materials"); dictionary.Add("% Genauigkeit. Slayer ", "% accuracy. Slayer "); dictionary.Add("% Schaden, +", "% damage, +"); dictionary.Add("% Sofortschmelzen", "% instant smelting"); dictionary.Add("% der Basiskosten", "% of base cost"); dictionary.Add("% doppelter Ertrag und XP bei ", "% double yield and XP for "); dictionary.Add("% von Vanilla-Basiszeit.", "% of vanilla base time."); dictionary.Add("%; doppelter ", "%; double "); dictionary.Add("%; voller Brennstoffbedarf.", "%; full fuel cost."); dictionary.Add("+0,25 natürliche Regeneration je Tick", "+0.25 natural regeneration per tick"); dictionary.Add("+10 Traglast", "+10 carry weight"); dictionary.Add("+10% Verwertung. Alt+F1 ohne Hammer/Angel: 4min doppelte Verwertungsgeschwindigkeit und +25% Ausbeute. Danach 6min Cooldown.", "+10% carcass yield. Alt+F1 without hammer/rod: double harvesting speed and +25% yield for 4min. Then 6min cooldown."); dictionary.Add("+10% Verwertung; 20% schneller ausweiden", "+10% carcass yield; 20% faster harvesting"); dictionary.Add("+10% Zugkraft; 15% Köderrückgewinnung", "+10% pull; 15% bait recovery"); dictionary.Add("+10% maximale Reitausdauer; +5% normale Schlachtmaterialien im Mittel. Keine zusätzliche XP durch Bonusmaterial.", "+10% maximum riding stamina; +5% ordinary slaughter materials on average. Bonus materials do not grant extra XP."); dictionary.Add("+100m Baugebietsradius am Brett, halber Hammerverschleiß. Alt+F1 mit Hammer öffnet die Auswahl: Baugebiet reparieren und 4min keine Bauausdauer oder Heimkehr zum gesetzten eigenen Bett. Bau-Buff: danach 6min Cooldown; Heimkehr: 6min Cooldown; normale Transportregeln gelten.", "+100m building-area radius at the board, half hammer wear. Alt+F1 with a hammer opens the choice: repair the building area and build without stamina for 4min, or return home to your own selected bed. Build buff: then 6min cooldown; return home: 6min cooldown; normal transport rules apply."); dictionary.Add("+100m Baugebietsradius am Brett, halber Hammerverschleiß. Alt+F1 mit Hammer: einmalige Reparatur des gesamten am Baubrett definierten Gebiets, 4min keine Bauausdauer. 6min Cooldown.", "+100m building-area radius at the board, half hammer wear. Alt+F1 with hammer: repair the entire area defined at the construction board once; no building stamina cost for 4min. 6min cooldown."); dictionary.Add("+125m Baugebietsradius am Brett; Meister-Bauaufträge", "+125m building-area radius at the board; master work orders"); dictionary.Add("+15% Verwertung; Fährtensinn 80m / 20s / 30s", "+15% carcass yield; Tracking sense 80m / 20s / 30s"); dictionary.Add("+20% Reitausdauer, +10% normale Schlachtmaterialien.", "+20% riding stamina, +10% regular slaughter materials."); dictionary.Add("+20% Verwertung; 40% schneller ausweiden; Trophäen x1,3", "+20% carcass yield; 40% faster harvesting; trophies x1.3"); dictionary.Add("+20% Zugkraft; 20% Köderrückgewinnung; Sinn 45m / 20s", "+20% pull; 20% bait recovery; sense 45m / 20s"); dictionary.Add("+20% maximale Reitausdauer; +10% normale Schlachtmaterialien im Mittel. Keine zusätzliche XP durch Bonusmaterial.", "+20% maximum riding stamina; +10% ordinary slaughter materials on average. Bonus materials do not grant extra XP."); dictionary.Add("+25% Verwertung; Cape: +10% Ausbeute, 4min Jagdmeister (Alt+F1), danach 6min CD", "+25% carcass yield; cape: +10% yield, 4min Huntmaster (Alt+F1), then 6min CD"); dictionary.Add("+25% Zugkraft; Fischersinn 60m / 25s", "+25% pull; Fishing sense 60m / 25s"); dictionary.Add("+30% Abbauschaden, 25% weniger Spitzhacken-Ausdauer. Nur mit Bergbau-Cape.", "+30% mining damage, 25% less pickaxe stamina cost. Requires Mining cape."); dictionary.Add("+30% Fällschaden, 25% weniger Axt-Ausdauer. Nur mit Holzfäller-Cape. Kein zusätzlicher Kampfschaden.", "+30% chopping damage, 25% less axe stamina cost. Requires Woodcutting cape. No extra combat damage."); dictionary.Add("+30% Reitausdauer, +15% normale Schlachtmaterialien.", "+30% riding stamina, +15% regular slaughter materials."); dictionary.Add("+30% maximale Reitausdauer; +15% normale Schlachtmaterialien im Mittel. Keine zusätzliche XP durch Bonusmaterial.", "+30% maximum riding stamina; +15% ordinary slaughter materials on average. Bonus materials do not grant extra XP."); dictionary.Add("+40% Reitausdauer, +20% normale Schlachtmaterialien.", "+40% riding stamina, +20% regular slaughter materials."); dictionary.Add("+40% maximale Reitausdauer; +20% normale Schlachtmaterialien im Mittel. Keine zusätzliche XP durch Bonusmaterial.", "+40% maximum riding stamina; +20% ordinary slaughter materials on average. Bonus materials do not grant extra XP."); dictionary.Add("+5% Verwertung; Trophäenchance x1,1", "+5% carcass yield; trophy chance x1.1"); dictionary.Add("+50% Reitausdauer, +25% normale Schlachtmaterialien; Tiermeister-Cape und Rudelbund.", "+50% riding stamina, +25% regular slaughter materials; Beastmaster cape and Packbond."); dictionary.Add("+50% Reitausdauer, +25% normale Schlachtmaterialien; Tiermeister-Cape: zusätzlich +20% Reitausdauer und doppelte Drachen-Bodenregeneration; Rudelbund.", "+50% riding stamina, +25% regular slaughter materials; Beastmaster cape: an additional +20% riding stamina and double dragon ground regeneration; Packbond."); dictionary.Add("+50% maximale Reitausdauer; +25% normale Schlachtmaterialien im Mittel. Keine zusätzliche XP durch Bonusmaterial.", "+50% maximum riding stamina; +25% ordinary slaughter materials on average. Bonus materials do not grant extra XP."); dictionary.Add(", Gegenstelle ", ", remote "); dictionary.Add(", nach Bauleistung geteilt.", ", shared by building contribution."); dictionary.Add("-10% Einholkosten. Wasserwanderer mit C: 4 Minuten auf Wasser laufen. Danach 6 Minuten Abklingzeit. Harpunenfang ist ab Angeln-Level 20 ohne Cape möglich.", "-10% reeling cost. Waterwalker with C: walk on water for 4 minutes. Then a 6-minute cooldown. Harpoon fishing is available from Fishing level 20 without a cape."); dictionary.Add("-Saatgut", " seeds"); dictionary.Add("-Sporen", " spores"); dictionary.Add(". 1 Saatgut → 3 ", ". 1 seed → 3 "); dictionary.Add(". Am Baumeisterbrett auswählen; native Baurezepte und Materialien bleiben nötig.", ". Select at the construction board; native building recipes and materials are still required."); dictionary.Add(". Aus 1 ", ". One "); dictionary.Add(". F4: Zauberwechsel, F5: Zauberbuch.", ". F4: cycle spells; F5: open the spellbook."); dictionary.Add(". Mit Hammer auf einen Entwurf zeigen und E drücken.", ". Aim at a ghost piece with your hammer and press E."); dictionary.Add(". Noch nichts geändert. Mit mastery_importconfirm einmalig übernehmen.", ". No changes made yet. Use mastery_importconfirm to import once."); dictionary.Add(". Rezept und Materialien weiterhin erforderlich.", ". Recipe knowledge and materials are still required."); dictionary.Add(". XP erst bei der Ernte.", ". XP is awarded on harvest only."); dictionary.Add(". XP erst fuer den fertigen Barren; Ofen, Brennstoff und Erz weiterhin erforderlich.", ". XP is awarded for finished bars only; furnace, fuel and ore are still required."); dictionary.Add(". Zierformen haben dieselben Werte.", ". Cosmetic forms have identical stats."); dictionary.Add("1 Himbeere einsetzen", "Insert 1 raspberry"); dictionary.Add("10% Chance auf eine weitere Ressource pro gesammelter Einheit.", "10% chance of an extra resource per gathered unit."); dictionary.Add("10% Doppelfang mit doppelten XP; 25% Köderrückgewinnung", "10% double catch with double XP; 25% bait recovery"); dictionary.Add("10% Köderrückgewinnung bei Fang", "10% bait recovery on catch"); dictionary.Add("10% Köderrückgewinnung bei Fang; Harpunenfang freigeschaltet", "10% bait recovery on catch; harpoon fishing unlocked"); dictionary.Add("10% Materialersparnis, 20% Bonusflaschen und 20% kuerzere Gaerzeit.", "10% material saving, 20% bonus bottles and 20% shorter fermentation."); dictionary.Add("10% Saatgut-Rueckgewinnung; weiterer Ertragsbonus.", "10% seed recovery; additional yield bonus."); dictionary.Add("10% Saatgut-Rueckgewinnung; weiterer Ertragsbonus; 40% schnelleres Zaehmen.", "10% seed recovery; additional yield bonus; 40% faster taming."); dictionary.Add("10% bessere Manoevrierbarkeit und Beschleunigung.", "10% better manoeuvrability and acceleration."); dictionary.Add("10% mehr Abbauschaden", "10% more mining damage"); dictionary.Add("10% mehr Faellschaden", "10% more chopping damage"); dictionary.Add("10% schneller rudern.", "10% faster rowing."); dictionary.Add("10% schneller unter Segeln.", "10% faster under sail."); dictionary.Add("10% weniger Gebetspunkte-Verbrauch beim Tragen.", "Prayer point drain is reduced by 10% while worn."); dictionary.Add("15% Doppelfang; Cape: -10% Einholkosten. Wasserwanderer mit C: 4 Minuten Wasserlaufen, danach 6 Minuten Abklingzeit.", "15% double catch; cape: -10% reeling cost. Waterwalker with C: walk on water for 4 minutes, followed by a 6-minute cooldown."); dictionary.Add("15% Materialersparnis, 30% Bonusflaschen und 30% kuerzere Gaerzeit.", "15% material saving, 30% bonus bottles and 30% shorter fermentation."); dictionary.Add("15% groesserer persoenlicher Kartenradius an Bord.", "15% greater personal map exploration radius on board."); dictionary.Add("15% mehr Regeneration beim Gehen/Stehen ausserhalb des Kampfes", "15% more regeneration while walking/standing outside combat"); dictionary.Add("2% Chance auf einen reichen Fund (+2 derselben Ressource).", "2% chance of a rich find (+2 of the same resource)."); dictionary.Add("20% Ertragschance; Sammlersinn auf Q, 15m / 5s, 30s Abklingzeit.", "20% bonus yield chance; Foraging sense on Q, 15m / 5s, 30s cooldown."); dictionary.Add("20% Materialersparnis; 10 Reparaturen in 6m", "20% material saving; 10 repairs within 6m"); dictionary.Add("20% Sammelernte-Chance, +4 Prozentpunkte je Level bis 100% bei 80; 2,5m/bis 8 weitere Pflanzen; 15% Saatgut.", "20% area harvest chance, +4 percentage points per level up to 100% at 80; 2.5m/up to 8 additional plants; 15% seed recovery."); dictionary.Add("20% Sammelernte-Chance, +4 Prozentpunkte je Level bis 100% bei 80; 2,5m/bis 8 weitere Pflanzen; 15% Saatgut; 60% schnelleres Zaehmen.", "20% area harvest chance, +4 percentage points per level up to 100% at 80; 2.5m/up to 8 extra plants; 15% seed chance; 60% faster taming."); dictionary.Add("20% kuerzere Verarbeitung und 20% Bonusportionen.", "20% shorter processing time and 20% bonus servings."); dictionary.Add("20% schneller schwimmen und 20% weniger Fallschaden", "20% faster swimming and 20% less fall damage"); dictionary.Add("20% weniger Gebetspunkte-Verbrauch beim Tragen.", "20% less prayer point drain while worn."); dictionary.Add("24% kuerzere Herstellungszeit", "24% shorter production time"); dictionary.Add("25% Materialersparnis, 50% Bonusflaschen, 50% kuerzere Gaerzeit. Cape: weitere 10% kuerzer und eine garantierte Zusatzflasche pro Charge.", "25% material saving, 50% bonus bottles, 50% shorter fermentation. Cape: another 10% shorter and one guaranteed extra bottle per batch."); dictionary.Add("25% Materialersparnis; Cape-Auswahl mit Alt+F1: ganzes Baugebiet reparieren und 4min Bauen ohne Ausdauer oder Heimkehr zum gesetzten Bett; Bau-Buff danach 6min CD; Heimkehr 6min CD", "25% material saving; Alt+F1 cape selection: repair the building area and build without stamina for 4min, or return home to your selected bed; build buff: then 6min cooldown; return home: 6min cooldown"); dictionary.Add("25% Materialersparnis; Cape: ganzes Baugebiet reparieren, 4min Bauen ohne Ausdauer, Alt+F1, danach 6min CD", "25% material saving; cape: repair entire building area, no building stamina cost for 4min, Alt+F1, then 6min CD"); dictionary.Add("25% weniger Ausdauer bei Gegenwehr", "25% less stamina cost when fish struggle"); dictionary.Add("3 Ertrag nach etwa ", "3 yield after approximately "); dictionary.Add("30% Ertragschance, 4% reicher Fund; Sammlersinn 25m / 7s.", "30% bonus yield chance, 4% rich find; Foraging sense 25m / 7s."); dictionary.Add("30% kuerzere Verarbeitung und 30% Bonusportionen.", "30% shorter processing time and 30% bonus servings."); dictionary.Add("36% kuerzere Herstellungszeit", "36% shorter production time"); dictionary.Add("4 m Bauschutz: bestehendes Gebäude / Pflanze im Änderungsbereich.", "4m building protection: existing building / plant within the modification area."); dictionary.Add("40% Ertragschance; Sammlersinn 35m / 10s.", "40% bonus yield chance; Foraging sense 35m / 10s."); dictionary.Add("5% weniger Spitzhacken-Ausdauer", "5% lower pickaxe stamina cost"); dictionary.Add("50% Ertragschance; Sammlersinn 50m / 12s. Cape halbiert dessen Abklingzeit auf 15s.", "50% bonus yield chance; Foraging sense 50m / 12s. Cape halves its cooldown to 15s."); dictionary.Add("50% kuerzere Verarbeitung und 50% Bonusportionen. Mit Koch-Cape eingesetztes Essen verbrennt nicht.", "50% shorter processing time and 50% bonus servings. Food placed while wearing the Cooking cape does not burn."); dictionary.Add("6% Chance auf einen reichen Fund.", "6% chance of a rich find."); dictionary.Add("60% kuerzere Herstellungszeit; Cape: weitere 10% kuerzer", "60% shorter production time; cape: another 10% shorter"); dictionary.Add("7% Chance auf kompletten Aderbruch; Bergbau-Cape: +10% Ertrag und Erzrausch", "7% chance of full vein collapse; Mining cape: +10% yield and Ore rush"); dictionary.Add("7% Chance auf kompletten Aderbruch; Bergbau-Cape: +10% Ertrag; Erzrausch: 4min, danach 6min Cooldown", "7% chance of full vein collapse; Mining cape: +10% yield; Ore rush: 4min, then 6min cooldown"); dictionary.Add(": +0,25 natürliche Regeneration je Tick", ": +0.25 natural regeneration per tick"); dictionary.Add(": +10 Traglast", ": +10 carry weight"); dictionary.Add(": Abklingzeit aktiv.", ": on cooldown."); dictionary.Add(": Meisterschaft aktiv – 4 Minuten", ": mastery active – 4 minutes"); dictionary.Add(": Rezeptmaterialien gespart!", ": recipe materials saved!"); dictionary.Add(": Runen fehlen.", ": runes missing."); dictionary.Add(": Zoom und Munitionsersparnis", ": zoom and ammo saving"); dictionary.Add(": Zoom und Munitionsrückgewinnung", ": zoom and ammo recovery"); dictionary.Add(": nichts gefunden. Keine Abklingzeit.", ": nothing found. No cooldown."); dictionary.Add(": wechseln", ": switch"); dictionary.Add("; 4min +30% Abbauschaden, -25% Ausdauer, danach 6min Cooldown.", "; +30% mining damage, -25% stamina cost for 4min, then 6min cooldown."); dictionary.Add("; 4min +30% Faellschaden, -25% Axt-Ausdauer, danach 6min Cooldown.", "; +30% chopping damage, -25% axe stamina cost for 4min, then 6min cooldown."); dictionary.Add("; Cape reduziert Herstellungszeit zusaetzlich um 10%", "; cape reduces production time by a further 10%"); dictionary.Add("; etwa ", "; approximately "); dictionary.Add("Ab Magie ", "From Magic "); dictionary.Add("Abbau", "Mining"); dictionary.Add("Abbauanforderung. Zusätzlich ist die passende Spitzhacke erforderlich.", "Mining requirement. The appropriate pickaxe is also required."); dictionary.Add("Abklingzeit aktiv.", "on cooldown."); dictionary.Add("Abscheulichkeiten", "Abominations"); dictionary.Add("Agility-Meisterschaftsumhang", "Agility skillcape"); dictionary.Add("Aktion nicht moeglich.", "Action unavailable."); dictionary.Add("Aktiv: ", "Active: "); dictionary.Add("Aktiver Style-Bonus", "Active style bonus"); dictionary.Add("Aktiviert nur die ausgewaehlte Ortung. F2 wechselt den Modus.", "Activates only the selected sense. F2 switches modes."); dictionary.Add("Aktuell: ", "Current: "); dictionary.Add("Aktuelle Werte", "Current stats"); dictionary.Add("Alchemie", "Alchemy"); dictionary.Add("Alchemie-Charge", "Alchemy batch"); dictionary.Add("Alchemie-Meisterschaftsumhang", "Alchemy skillcape"); dictionary.Add("Alle", "All"); dictionary.Add("Alle Freischaltungen", "All unlocks"); dictionary.Add("Am Auftragsboard interagieren.", "Interact with the contract board."); dictionary.Add("An der Runenschmiede zu Runen prägen.", "Craft runes at the Rune Forge."); dictionary.Add("Ancient Staff: nächsten freigeschalteten Barrage-Zauber auswählen.", "Ancient Staff: select the next unlocked Barrage spell."); dictionary.Add("Anforderung nur zum Steuern. Mitfahren bleibt frei; Baumaterialien und Weltfortschritt bleiben erforderlich. ", "Requirement applies only to steering. Passengers have no level gate; building materials and world progression are still required. "); dictionary.Add("Anforderung zum Herstellen/Brauen; Trinken bleibt frei. XP erst fuer fertige Flaschen. Bonusflaschen geben volle XP, Trankwerte bleiben fest.", "Requirement for crafting/brewing; drinking has no level gate. XP is awarded for finished bottles only. Bonus bottles grant full XP; potion stats stay fixed."); dictionary.Add("Anforderung zum Zubereiten. Essen und Weitergabe sind frei. Fertige Portion: ", "Preparation requirement. Eating and sharing have no level gate. Finished serving: "); dictionary.Add("Angel-Meisterschaftsumhang", "Fishing skillcape"); dictionary.Add("Angeln", "Fishing"); dictionary.Add("Angriff", "Attack"); dictionary.Add("Angriffs-Meisterschaftsumhang", "Attack skillcape"); dictionary.Add("Anthrazit", "Anthracite"); dictionary.Add("Anzahl muss zwischen 1 und 1000000 liegen.", "Amount must be between 1 and 1000000."); dictionary.Add("AoE: 1 Nachbarabschnitt, 15% Schaden", "AoE: 1 adjacent section, 15% damage"); dictionary.Add("AoE: 2 Nachbarabschnitte, je 15% Schaden", "AoE: 2 adjacent sections, 15% damage each"); dictionary.Add("Arkanwerkstatt", "Arcane workshop"); dictionary.Add("Aschenherz", "Ash Heart"); dictionary.Add("Aschenkomet", "Ash Comet"); dictionary.Add("Aschenkrähe", "Ash crow"); dictionary.Add("Aschenlande und 48% kuerzere Herstellungszeit", "Ashlands and 48% shorter production time"); dictionary.Add("Aschenlande-Rezepte; 40% kuerzer, 40% Bonusportionen; Serienkochen bis 6 freie Plaetze.", "Ashlands recipes; 40% shorter, 40% bonus servings; batch cooking up to 6 empty slots."); dictionary.Add("Aschland-Ausbauhof", "Ashlands expansion yard"); dictionary.Add("Aschlande", "Ashlands"); dictionary.Add("Ashlands-Magie", "Ashlands magic"); dictionary.Add("Asksvine zähmen und reiten.", "Tame and ride asksvin."); dictionary.Add("Auf einen Standort zeigen.", "Aim at a location."); dictionary.Add("Auftraege, Coop, Slayer-Shop und Prestige.", "Contracts, co-op, Slayer shop and prestige."); dictionary.Add("Auftrag abbrechen (XP bleiben, Serie endet)", "Cancel contract (keep XP, end streak)"); dictionary.Add("Auftragsfokus · +10% Slayer-XP / 15 aktive Kampfminuten · 40 Marken", "Contract focus · +10% Slayer XP / 15 active combat minutes · 40 tokens"); dictionary.Add("Auftragsgegner", "Contract targets"); dictionary.Add("Auftragssinn", "Contract sense"); dictionary.Add("Auftragsziele in 80m sichtbar; -15% Angriffsausdauer bei anvisiertem Auftragsziel.", "Contract targets visible within 80m; -15% attack stamina cost when aiming at a contract target."); dictionary.Add("Auftragsziele: +50% Max Hit und garantierte Genauigkeit.", "Contract targets: +50% max hit and guaranteed accuracy."); dictionary.Add("Aufträge", "Contracts"); dictionary.Add("Aufträge und Belohnungen", "Contracts and rewards"); dictionary.Add("Ausdauer", "Stamina"); dictionary.Add("Ausdauer oder Hammerhaltbarkeit fehlt.", "Not enough stamina or hammer durability."); dictionary.Add("Ausführungen", "variants"); dictionary.Add("Ausgeschmückt", "Ornate"); dictionary.Add("Ausrüstung", "Equipment"); dictionary.Add("Ausrüstung und Freischaltungen", "Equipment and unlocks"); dictionary.Add("Ausrüstungsanforderung · ", "Equipment requirement · "); dictionary.Add("Ausweichen", "Dodging"); dictionary.Add("Ausweiden", "Harvest carcass"); dictionary.Add("Ausweiden hier durch Gebietsschutz gesperrt.", "Area protection prevents harvesting here."); dictionary.Add("Ausweiden unterbrochen: ", "Carcass harvesting interrupted: "); dictionary.Add("Auszeichnung deiner Slayer-Meisterschaft.", "A tribute to your Slayer mastery."); dictionary.Add("BAUMEISTER · BAUKUNST", "BUILDER · CONSTRUCTION"); dictionary.Add("BERSERK! 4 Minuten gegen Auftragsziele.", "BERSERK! 4 minutes against contract targets."); dictionary.Add("Backhaus", "Bakery"); dictionary.Add("Baeren", "Bears"); dictionary.Add("Bannstab", "Bane staff"); dictionary.Add("Barren", "bars"); dictionary.Add("Barrenertrag", "bar yield"); dictionary.Add("Basaltwacht", "Basalt Guard"); dictionary.Add("Basis-Eitr", "Base Eitr"); dictionary.Add("Basis-XP bei Qualität 1. Qualitätsfaktoren: 1 / 1,5 / 2 / 3 / 4. Passender Köder, kein Levelgate.", "Base XP at quality 1. Quality multipliers: 1 / 1.5 / 2 / 3 / 4. Requires matching bait; no level gate."); dictionary.Add("Bauauftrag abgeschlossen.", "Construction contract completed."); dictionary.Add("Bauauftrag beginnen / fortsetzen", "Start / resume work order"); dictionary.Add("Bauauftrag benötigt 10 ", "Work order requires 10 "); dictionary.Add("Bauauftrag unterbrochen. Reservierte Materialien bleiben für den nächsten Versuch erhalten.", "Work order interrupted. Reserved materials are retained for the next attempt."); dictionary.Add("Bauaufträge", "Work orders"); dictionary.Add("Baubrett", "Construction board"); dictionary.Add("Bauen erfordert Construction ", "Building requires Construction "); dictionary.Add("Bauernhof mit vier Beeten", "Farm with four garden beds"); dictionary.Add("Baugebiet", "Building area"); dictionary.Add("Baugebiet festlegen", "Set building area"); dictionary.Add("Baugebiet und Aufträge", "Building area and orders"); dictionary.Add("Baugebiet, Projekte und Bauaufträge. E: öffnen.", "Building area, projects and work orders. E: open."); dictionary.Add("Baukunst", "Construction"); dictionary.Add("Baukunst-Meisterschaftsumhang", "Construction skillcape"); dictionary.Add("Baum, Erz, Fels oder Grab im Änderungsbereich.", "Tree, ore, rock or grave within the modification area."); dictionary.Add("Baumeisterbrett", "Construction board"); dictionary.Add("Bauplan nicht gesetzt: Das Baumeisterbrett ist für den Host nicht verfügbar. Brett erneut öffnen und versuchen.", "Blueprint not placed: construction board unavailable to the host. Reopen the board and try again."); dictionary.Add("Bauplan nicht gesetzt: Der Host hat das Gelände am Standort noch nicht geladen. Der Host muss zum Standort kommen; danach erneut versuchen.", "Blueprint not placed: the host has not loaded the terrain at this location. Ask the host to approach, then try again."); dictionary.Add("Bauplan nicht gesetzt: Der Host hat deinen Bereich noch nicht geladen. Der Host muss in deine Nähe kommen; danach erneut versuchen.", "Blueprint not placed: the host has not loaded your area. Ask the host to approach, then try again."); dictionary.Add("Bauplan: ", "Blueprint: "); dictionary.Add("Baupläne", "Blueprints"); dictionary.Add("Baupläne · echte Bauteile, gemeinsam mit Hammer + E errichten. Beete bleiben frei zum Kultivieren und Pflanzen.", "Blueprints · build real pieces together using hammer + E. Garden beds stay clear for cultivation and planting."); dictionary.Add("Bauprojekte", "Projects"); dictionary.Add("Bauteil-Rezept noch nicht freigeschaltet.", "Building piece recipe not unlocked yet."); dictionary.Add("Bauteile für Aufträge bearbeiten: 10 Holz (ab 1), Stein (20), Edelholz (50), schwarzer Marmor (90). Produkte werden im Auftrag verbraucht; keine erneute Handwerks-/Schmiede-XP. Materialersparnis gilt auch hier.", "Process parts for work orders: 10 wood (level 1), stone (20), fine wood (50), black marble (90). Products are consumed by the order; no additional Crafting/Smithing XP. Material saving also applies here."); dictionary.Add("Bauteile nach Schaden oder fehlenden Ersatzbaumaterialien sortieren. Native Reparaturen bleiben kostenlos.", "Sort pieces by damage or missing replacement materials. Native repairs remain free."); dictionary.Add("Bearbeitung: ", "Processing: "); dictionary.Add("Bebaute Flächen bleiben geschützt. Bestätigte Bodenänderungen bleiben beim Entfernen des Entwurfs bestehen.", "Built-up areas remain protected. Confirmed terrain changes remain when removing the blueprint."); dictionary.Add("Beeren- und Kräutergarten", "Berry and herb garden"); dictionary.Add("Befestigung", "Fortification"); dictionary.Add("Belegt: Gebäude, Pflanze, Grab, Baum oder Felsen im Grundriss.", "Occupied: building, plant, grave, tree or rock within the footprint."); dictionary.Add("Belohnungen", "Rewards"); dictionary.Add("Benutzen", "Use"); dictionary.Add("Benötigt Mastery ", "Requires Mastery "); dictionary.Add("Bereit", "Ready"); dictionary.Add("Bergbau", "Mining"); dictionary.Add("Bergbau-Meisterschaft: Aderbruch!", "Mining mastery: vein collapse!"); dictionary.Add("Bergbau-Meisterschaftsumhang", "Mining skillcape"); dictionary.Add("Berserk (Strg + F1): 4 Minuten +50% Max Hit und garantierte Genauigkeit gegen aktive Auftragsziele. Roar-Emote; danach 6 Minuten Cooldown. Nur getragen.", "Berserk (Ctrl + F1): +50% max hit and guaranteed accuracy against active contract targets for 4 minutes. Roar emote; then 6 minute cooldown. Only while worn."); dictionary.Add("Berserk aktivieren, sobald dein Charakter frei handeln kann.", "Activate Berserk when your character can act freely."); dictionary.Add("Bestiarium", "Bestiary"); dictionary.Add("Bestückt", "Baited"); dictionary.Add("Betäubt einen großen Bergdrachen ohne ihn zu verletzen. Sechs Körpertreffer oder vier Kopftreffer; den gelandeten Drachen anschließend füttern.", "Tranquilizes a large mountain drake without injuring it. Six body hits or four head hits; then feed the landed drake."); dictionary.Add("Betäubungspfeil", "Tranquilizer arrow"); dictionary.Add("Bewegungsschub", "Movement burst"); dictionary.Add("Blaubeere", "Blueberry"); dictionary.Add("Blaubeere pflanzen", "Plant blueberry"); dictionary.Add("Blaubeeren; Rasterpflanzen mit 2 Pflanzen pro Aktion.", "blueberries; grid planting with 2 plants per action."); dictionary.Add("Blauer Pilz", "Blue mushroom"); dictionary.Add("Blauer Pilz pflanzen", "Plant blue mushroom"); dictionary.Add("Block entfernen: ", "Unblock: "); dictionary.Add("Block-Ausdauerkosten", "Block stamina cost"); dictionary.Add("Blockieren (100)", "Block target (100)"); dictionary.Add("Blutegel freigelassen.", "Leech released."); dictionary.Add("Blutegel gefangen.", "Leech captured."); dictionary.Add("Blutegel halten (zusätzlich Angeln 85); +10% Reitausdauer, +5% normale Schlachtmaterialien.", "Keep leeches (also requires Fishing 85); +10% riding stamina, +5% regular slaughter materials."); dictionary.Add("Blutkrone", "Blood crown"); dictionary.Add("Blutrune", "Blood Rune"); dictionary.Add("Blutspuren und Verletzungszustand; Trophäen x1,2", "Blood trails and injury status; trophies x1.2"); dictionary.Add("Boden", "Floor"); dictionary.Add("Boden/Wand/Dach aus schwarzem Marmor oder höher.", "Floors/walls/roofs made of black marble or higher-tier materials."); dictionary.Add("Bossangebote umgestellt; gilt beim naechsten Angebotswechsel.", "Boss offers toggled; takes effect on the next offer refresh."); dictionary.Add("Bossangebote: ", "Boss offers: "); dictionary.Add("Bossangebote: an", "Boss offers: on"); dictionary.Add("Bossangebote: aus", "Boss offers: off"); dictionary.Add("Bossauftraege; Prestige (3 Punkte)", "Boss contracts; prestige (3 points)"); dictionary.Add("Brechbeere", "Bukeperry"); dictionary.Add("Brechbeere pflanzen", "Plant bukeperry"); dictionary.Add("Breite 10–160m", "Width 10–160m"); dictionary.Add("Bären zähmen.", "Tame bears."); dictionary.Add("Bärensattel", "Bear saddle"); dictionary.Add("Cape mit Hammer: Alt+F1 öffnet die Auswahl für Gebietsreparatur mit 4min Bauen ohne Ausdauer oder Heimkehr zum gesetzten eigenen Bett. Bau-Buff: danach 6min CD; Heimkehr: 6min CD; normale Transportregeln gelten.", "Cape with hammer: Alt+F1 opens the choice of area repair with no building stamina cost for 4min, or return home to your own selected bed. Build buff: then 6min cooldown; return home: 6min cooldown; normal transport rules apply."); dictionary.Add("Cape-Kraft wählen (Alt + F1 mit Hammer)", "Choose cape power (Alt + F1 with hammer)"); dictionary.Add("Cape: noch ", "Cape: remaining "); dictionary.Add("Chance auf keinen Munitionsverbrauch ", "chance to consume no ammo "); dictionary.Add("Chargenplanung: gewünschte Charge und fehlende Zutaten am eigenen Fermenter vormerken.", "Batch planning: select a desired batch and inspect missing ingredients at your own fermenter."); dictionary.Add("Combat-Ausrüstungssperren sind derzeit deaktiviert. Angezeigt werden die hinterlegten Anforderungen.", "Combat equipment gates are currently disabled. Configured requirements are shown."); dictionary.Add("Constructioncape aktivieren (Alt + F1 mit Hammer)", "Activate Construction cape (Alt + F1 with hammer)"); dictionary.Add("Coop beitreten: ", "Join co-op: "); dictionary.Add("Coop · volle XP innerhalb 70m vom Ziel", "Co-op · full XP within 70m of the target"); dictionary.Add("Coop-Auftrag fuer zwei Spieler", "Co-op contract for two players"); dictionary.Add("Coop: Partner kann vor dem ersten Kill beitreten", "Co-op: partner can join before the first kill"); dictionary.Add("Dach", "Roof"); dictionary.Add("Dauernder Schwur", "Enduring Vow"); dictionary.Add("Deep-North-Magie", "Deep North magic"); dictionary.Add("Defence Mastery rettet dich vor dem tödlichen Treffer!", "Defence Mastery saves you from a lethal hit!"); dictionary.Add("Deine aktuellen Werte", "Your current stats"); dictionary.Add("Dekor", "Decoration"); dictionary.Add("Der Aelteste", "The Elder"); dictionary.Add("Der Charakter besitzt bereits Mastery-Fortschritt; Import würde ihn überschreiben.", "This character already has Mastery progress; importing would overwrite it."); dictionary.Add("Der Charakter verwendet ein nicht unterstütztes Save-Schema.", "This character uses an unsupported save schema."); dictionary.Add("Der Köcherplatz ist bereits belegt.", "The quiver slot is already occupied."); dictionary.Add("Der Mastery-Köcher konnte nicht in seinen Platz verschoben werden.", "The Mastery quiver could not be moved into its slot."); dictionary.Add("Der Uralte", "The Elder"); dictionary.Add("Deutlicher Bisshinweis", "Clear bite notification"); dictionary.Add("Die Koenigin", "The Queen"); dictionary.Add("Die Königin", "The Queen"); dictionary.Add("Diese Kiste enthält keine gültige Lieferung.", "This crate contains no valid delivery."); dictionary.Add("Dieser Drache lässt sich nicht zähmen.", "This dragon cannot be tamed."); dictionary.Add("Distel", "Thistle"); dictionary.Add("Distel pflanzen", "Plant thistle"); dictionary.Add("Dorf-Baupläne sind vorübergehend deaktiviert.", "Village blueprints are temporarily disabled."); dictionary.Add("Dorf-Holztor", "Village wooden gate"); dictionary.Add("Dorfplatz", "Village square"); dictionary.Add("Dorfweg", "Village path"); dictionary.Add("Dornenflug", "Thorn Flight"); dictionary.Add("Dornwacht", "Thorn Watch"); dictionary.Add("Drachen", "Drakes"); dictionary.Add("Drachensattel", "Drake saddle"); dictionary.Add("Drakkar steuern.", "steer a drakkar."); dictionary.Add("Dritter Blockplatz", "Third block slot"); dictionary.Add("Dunkles Erz aus den Ebenen. Im Hochofen zu Schwarzmetall schmelzen. Bergbau 40 und Eisenspitzhacke zum Abbauen.", "Dark ore from the Plains. Smelt in a blast furnace to produce black metal. Requires Mining 40 and an iron pickaxe to mine."); dictionary.Add("Dämmerkreis", "Dusk Circle"); dictionary.Add("Dämmermal", "Dusk Mark"); dictionary.Add("Dämmerrune", "Dusk Rune"); dictionary.Add("Dämmerschirm", "Dusk Shield"); dictionary.Add("Ebenen", "Plains"); dictionary.Add("Ebenen-Rezepte; Serienkochen bis 4 freie Plaetze.", "Plains recipes; batch cooking up to 4 empty slots."); dictionary.Add("Ebenenauftraege", "Plains contracts"); dictionary.Add("Edelholz und Teer; 10% Materialersparnis", "Fine wood and tar; 10% material saving"); dictionary.Add("Effekt folgt", "Effect pending"); dictionary.Add("Effektiv", "Effective"); dictionary.Add("Effektive Accuracy", "Effective Accuracy"); dictionary.Add("Effektive Attack", "Effective Attack"); dictionary.Add("Effektive Defence", "Effective Defence"); dictionary.Add("Effektive Magic", "Effective Magic"); dictionary.Add("Effektive Strength", "Effective Strength"); dictionary.Add("Eid der Genesung", "Oath of Recovery"); dictionary.Add("Eigenschutz", "Self protection"); dictionary.Add("Ein Kisteninhalt ist derzeit nicht verfügbar. Kiste bleibt erhalten.", "A crate item is currently unavailable. The crate has been retained."); dictionary.Add("Ein leichter Köcher für erfahrene Fernkämpfer. Freigeschaltet mit Mastery Fernkampf 25.", "A light quiver for experienced archers. Unlocked at Mastery Ranged 25."); dictionary.Add("Eine geweiht gewuerzte Basis fuer den Fermenter.", "A consecrated mead base for the fermenter."); dictionary.Add("Eine konkrete Zielressource für den Sammlersinn auswählen.", "Select an exact resource for gatherer's sense."); dictionary.Add("Einklang-Eid", "Oath of Harmony"); dictionary.Add("Einschlag, höchstens 4 Ziele", "Impact, up to 4 targets"); dictionary.Add("Eisen und +5% Ertrag", "Iron and +5% yield"); dictionary.Add("Eisen und mindestens 15% Bonusertrag", "Iron and at least 15% bonus yield"); dictionary.Add("Eisen-Eid", "Iron Oath"); dictionary.Add("Eisen/Sumpf und 12% kuerzere Herstellungszeit", "Iron/Swamp and 12% shorter production time"); dictionary.Add("Eisenverstärkung; +50m Baugebietsradius am Brett", "Iron reinforcement; +50m building-area radius at the board"); dictionary.Add("Eissplitterlanze", "Ice Shard Lance"); dictionary.Add("Eitr-/Blutkosten", "Eitr/blood costs"); dictionary.Add("Elfenbein", "Ivory"); dictionary.Add("Endgame", "Endgame"); dictionary.Add("Endgame-Baustoffe; 15% Materialersparnis; 5 Reparaturen in 4m", "Endgame materials; 15% material saving; 5 repairs within 4m"); dictionary.Add("Erfordert Slayer ", "Requires Slayer "); dictionary.Add("Erholung beginnt ausserhalb des Kampfes 0,5s frueher", "recovery starts 0.5s earlier outside combat"); dictionary.Add("Erholung beim Gehen/Stehen ausserhalb Kampf", "Recovery while walking/standing outside combat"); dictionary.Add("Erholungspause ausserhalb Kampf", "Recovery delay outside combat"); dictionary.Add("Erster Blockplatz", "First block slot"); dictionary.Add("Ertrag", "Yield"); dictionary.Add("Erwarteter Roh-Treffer", "Expected raw hit"); dictionary.Add("Erzkiste", "Ore crate"); dictionary.Add("Erzrausch", "Ore rush"); dictionary.Add("Erzrausch bereit in ", "Ore rush ready in "); dictionary.Add("Erzrausch! 4 Minuten, +30% Abbauschaden, -25% Ausdauer.", "Ore rush! 4 minutes, +30% mining damage, -25% stamina cost."); dictionary.Add("Erzrausch: Bergbau 100, getragenes Bergbau-Cape und Spitzhacke erforderlich.", "Ore rush requires Mining 100, an equipped Mining cape and a pickaxe."); dictionary.Add("Eschenholz und mindestens 35% Bonusertrag", "Ashwood and at least 35% bonus yield"); dictionary.Add("Eschenholz und weitere +5% Holzertrag", "Ashwood and another +5% wood yield"); dictionary.Add("Faellanforderung. Zusaetzlich bleibt die passende Axt erforderlich.", "Woodcutting requirement. The appropriate axe is also required."); dictionary.Add("Faellen", "Chopping"); dictionary.Add("Fallschaden", "Fall damage"); dictionary.Add("Fangbuch", "Fishing journal"); dictionary.Add("Favorit entfernen: ", "Remove preferred target: "); dictionary.Add("Fellkiste", "Hide crate"); dictionary.Add("Fernkampf", "Ranged"); dictionary.Add("Fernkampf-Meisterschaftsumhang", "Ranged skillcape"); dictionary.Add("Fernkampfstil", "Ranged style"); dictionary.Add("Fernschuss-Eid", "Farshot Oath"); dictionary.Add("Fertigkeiten öffnen → Skill anklicken für alle Details", "Open skills → click a skill for full details"); dictionary.Add("Festungshof", "Fortress courtyard"); dictionary.Add("Feuerbereich", "Fire area"); dictionary.Add("Feuerprojektil", "Fire projectile"); dictionary.Add("Fisch", "Fish"); dictionary.Add("Fisch beißt! Jetzt anschlagen.", "Fish biting! Set the hook now."); dictionary.Add("Fischersinn", "Fishing sense"); dictionary.Add("Fischersinn zeigt Art/Qualität; 15% weniger Ausdauer bei Gegenwehr", "Fishing sense shows species/quality; 15% less stamina cost when fish struggle"); dictionary.Add("Fischersinn: 30m / 15s / 30s CD", "Fishing sense: 30m / 15s / 30s CD"); dictionary.Add("Flaechenabbau freigeschaltet", "Area mining unlocked"); dictionary.Add("Flammetall, +5% Ertrag und weitere 5% weniger Ausdauer", "Flametal, +5% yield and another 5% lower stamina cost"); dictionary.Add("Flammetall, mindestens 35% Bonusertrag und weitere 5% weniger Ausdauer", "Flametal, at least 35% bonus yield and another 5% lower stamina cost"); dictionary.Add("Floss", "Raft"); dictionary.Add("Fläche, höchstens 5 Ziele", "Area, up to 5 targets"); dictionary.Add("Fokus verbleibend: ", "Focus remaining: "); dictionary.Add("Frei sammelbar in der Wildnis; ", "Freely gatherable in the wild; "); dictionary.Add("Freie Architektur: zählt neue, noch stehende Bauteile passender Kategorien im Gebiet ab Projektstart. Wiederaufbau gibt 25% Bau-XP, keinen erneuten Projektbonus.", "Freeform building: counts new, still-standing pieces of the required categories in this area from project start. Rebuilding grants 25% building XP, without another project bonus."); dictionary.Add("Freigeschaltet", "Unlocked"); dictionary.Add("Freischaltungen", "Unlocks"); dictionary.Add("Frostlinie, höchstens 3 Ziele", "Frost line, up to 3 targets"); dictionary.Add("Frostprojektil", "Frost projectile"); dictionary.Add("Frostwiderstand, mittlere Heilung und Schwimmtrank; 5% Materialersparnis, 10% Bonusflaschen, 10% kuerzere Gaerzeit.", "frost resistance, medium healing and swimming mead; 5% material saving, 10% bonus bottles, 10% shorter fermentation."); dictionary.Add("Fuenfter Blockplatz", "Fifth block slot"); dictionary.Add("Fuling-Berserker", "Fuling berserkers"); dictionary.Add("Fulinge", "Fulings"); dictionary.Add("Funkenwurf", "Spark Cast"); dictionary.Add("Funktional", "Functional"); dictionary.Add("Fächer, höchstens 3 Ziele", "Fan, up to 3 targets"); dictionary.Add("Fächer, höchstens 4 Ziele", "Fan, up to 4 targets"); dictionary.Add("Fährtensinn", "Tracking sense"); dictionary.Add("Fährtensinn 100m / 25s / 22,5s; drei Fallen", "Tracking sense 100m / 25s / 22.5s; three traps"); dictionary.Add("Fährtensinn 60m / 16s / 37,5s; Art und Sterne", "Tracking sense 60m / 16s / 37.5s; species and stars"); dictionary.Add("Fährtensinn: 40m / 12s / 45s CD", "Tracking sense: 40m / 12s / 45s CD"); dictionary.Add("Fällen", "Chopping"); dictionary.Add("GEBET", "PRAYER"); dictionary.Add("Gaerzeit", "Fermentation time"); dictionary.Add("Gartenparzelle", "Garden plot"); dictionary.Add("Gartenweg", "Garden path"); dictionary.Add("Gebet", "Prayer"); dictionary.Add("Gebete", "Prayers"); dictionary.Add("Gebete werden geladen", "Loading prayers"); dictionary.Add("Gebetsaltar", "Prayer altar"); dictionary.Add("Gebetspunkte auffüllen", "Restore Prayer points"); dictionary.Add("Gebetspunkte aufgefüllt.", "Prayer points restored."); dictionary.Add("Gebietsreparatur angefordert: das gesamte festgelegte Baugebiet wird geprüft.", "Area repair requested: checking the entire defined building area."); dictionary.Add("Gebirge", "Mountains"); dictionary.Add("Gebirgs-Rezepte (unter anderem Zwiebelsuppe und Wolfsspiesse).", "Mountain recipes (including onion soup and wolf skewers)."); dictionary.Add("Gefangener Blutegel", "Captured leech"); dictionary.Add("Gegen Auftragsziele: +", "Against contract targets: +"); dictionary.Add("Gegnerortung", "Target sense"); dictionary.Add("Gegnerortung: Auftragsziele markiert.", "Target sense: contract targets marked."); dictionary.Add("Gelber Pilz", "Yellow mushroom"); dictionary.Add("Gelber Pilz pflanzen", "Plant yellow mushroom"); dictionary.Add("Gelände nicht vollständig geladen.", "Terrain not fully loaded."); dictionary.Add("Gelände noch nicht geladen.", "Terrain not loaded yet."); dictionary.Add("Gelände oder Übergangsrand außerhalb des Baugebiets.", "Terrain or transition edge outside the building area."); dictionary.Add("Gelände prüfen / vorbereiten: ", "Check / prepare terrain: "); dictionary.Add("Gelände vorbereiten", "Prepare terrain"); dictionary.Add("Gelände vorbereitet.", "Terrain prepared."); dictionary.Add("Gelände wurde inzwischen verändert. Erneut prüfen.", "Terrain has changed. Check again."); dictionary.Add("Gelände: ", "Terrain: "); dictionary.Add("Geländeanpassung überschreitet 2 m.", "Terrain adjustment exceeds 2m."); dictionary.Add("Geländearbeit anhalten", "Pause terrain work"); dictionary.Add("Geländeauftrag ist zu groß. Einzelne Gebäudepläne verwenden.", "Terrain job is too large. Use individual building blueprints."); dictionary.Add("Gemeinsame Anforderung für alle Ausführungen.", "All variants share this requirement."); dictionary.Add("Gemeinschaft", "Community"); dictionary.Add("Gemessener Atem", "Measured Breath"); dictionary.Add("Gerste, Flachs, Moltebeeren und Rasterpflanzen mit 4 Pflanzen.", "barley, flax, cloudberries and grid planting with 4 plants."); dictionary.Add("Gerstenwein, Leichtfuss, Ratatosk und Todeskito-Abwehr.", "barley wine, lightfoot, Ratatosk and deathsquito repellent."); dictionary.Add("Geräteschuppen", "Tool shed"); dictionary.Add("Geschützter Standort.", "Protected location."); dictionary.Add("Geschütztes Gelände.", "Protected terrain."); dictionary.Add("Gesperrt", "Locked"); dictionary.Add("Gezieltes Feuerprojektil", "Aimed fire projectile"); dictionary.Add("Gezähmte/gezüchtete Tiere zählen zu Tiermeister.", "Tamed/bred animals count towards Beastmaster."); dictionary.Add("Giftpilz", "Toadstool"); dictionary.Add("Giftpilz pflanzen", "Plant toadstool"); dictionary.Add("Giftwiderstandsmet.", "poison resistance mead."); dictionary.Add("Glutbogen", "Ember Arc"); dictionary.Add("Glutnadel", "Ember Needle"); dictionary.Add("Glutrune", "Ember Rune"); dictionary.Add("Glutsäule", "Ember Pillar"); dictionary.Add("Gold", "Gold"); dictionary.Add("Grasland", "Meadows"); dictionary.Add("Graulinge", "Greylings"); dictionary.Add("Grauzwerge", "Greydwarves"); dictionary.Add("Große Bergdrachen betäuben, füttern und mit Sattel fliegen.", "Tranquilize and feed large mountain drakes, then fly using a saddle."); dictionary.Add("Große Halle mit Thronsaal", "Great hall with throne room"); dictionary.Add("Große Schmiede", "Large forge"); dictionary.Add("Großer Hafen", "Large harbour"); dictionary.Add("Großer Schmelzhof", "Large smelting yard"); dictionary.Add("Grund-Eitr", "Base Eitr"); dictionary.Add("Grundausdauer", "Base stamina"); dictionary.Add("Grün = Level erreicht", "Green = level reached"); dictionary.Add("Guenstige Winde", "Favourable winds"); dictionary.Add("Guenstige Winde bereit in ", "Favourable winds ready in "); dictionary.Add("Guenstige Winde! 4 Minuten Rueckenwind.", "Favourable winds! 4 minutes of tailwind."); dictionary.Add("Guenstige Winde: Segel-Cape am Ruder; 4 Minuten Rueckenwind, danach 6 Minuten Cooldown.", "Favourable winds: Sailing cape at the helm; 4 minutes of tailwind, then 6 minute cooldown."); dictionary.Add("Guenstige Winde: am Ruder mit Umschalt links + F1 (konfigurierbar) 4 Minuten Rueckenwind. Danach 6 Minuten Cooldown. Nicht mit Moder stapelbar. Nur getragen.", "Favourable winds: at the helm, press Left Shift + F1 (configurable) for a 4 minute tailwind. Then 6 minute cooldown. Does not stack with Moder. Only while worn."); dictionary.Add("Guenstige Winde: getragenes Segel-Meisterschaftscape und Platz am Ruder erforderlich.", "Favourable winds requires an equipped Sailing cape and a place at the helm."); dictionary.Add("Hacke und einsatzbereite Spitzhacke benötigt.", "Requires a hoe and a usable pickaxe."); dictionary.Add("Hafen", "Harbour"); dictionary.Add("Hafen / Brücke: Gelände bleibt unverändert. Pfähle auf tragfähigen Grund bauen.", "Harbour / bridge: terrain stays unchanged. Build posts on solid ground."); dictionary.Add("Hafenböden müssen über Wasser stehen.", "Harbour floors must be above water."); dictionary.Add("Hafenlager", "Harbour warehouse"); dictionary.Add("Hafer, Poteitr, Gruenkohl, Preiselbeeren, Straussenfarn und weitere Pilze pflanzen.", "plant oats, poteitr, kale, lingonberries, fiddleheads and more mushrooms."); dictionary.Add("Hainfunke", "Grove Spark"); dictionary.Add("Halle", "Hall"); dictionary.Add("Hallen-/Hafenprojekte; +100m Baugebietsradius am Brett", "Hall/harbour projects; +100m building-area radius at the board"); dictionary.Add("Handwerk", "Crafting"); dictionary.Add("Handwerks-Meisterschaftsumhang", "Crafting skillcape"); dictionary.Add("Herrenhaus", "Manor"); dictionary.Add("Herstellen/Aufwerten", "Craft/upgrade"); dictionary.Add("Herstellen: Qualitaet 1. Aufwerten: +2 Level je Qualitaetsstufe, maximal 99. Materialien, Rezept und Station bleiben erforderlich.", "Crafting: quality 1. Upgrading: +2 levels per quality tier, capped at 99. Materials, recipe knowledge and station are still required."); dictionary.Add("Herstellzeit", "Production time"); dictionary.Add("Himbeere", "Raspberry"); dictionary.Add("Himbeere pflanzen", "Plant raspberry"); dictionary.Add("Hirsche flüchten nicht mehr vor dir.", "Deer no longer flee from you."); dictionary.Add("Hirsche flüchten nicht mehr vor dir.", "Deer no longer flee from you."); dictionary.Add("Hirsche zähmen.", "Tame deer."); dictionary.Add("Hochofenhof", "Blast furnace yard"); dictionary.Add("Hohe Alchemie: Gegenstand gegen Münzen auflösen; bezahlt mit Eitr und Runen.", "High Alchemy: convert an item into coins, paying Eitr and runes."); dictionary.Add("Holzfaell-Meisterschaftsumhang", "Woodcutting skillcape"); dictionary.Add("Holzfaellen", "Woodcutting"); dictionary.Add("Holzfaellerrausch", "Lumber rush"); dictionary.Add("Holzfällen", "Woodcutting"); dictionary.Add("Holzfällerrausch", "Lumber rush"); dictionary.Add("Holzfällerrausch bereit in ", "Lumber rush ready in "); dictionary.Add("Holzfällerrausch! 4 Minuten, +30% Fällschaden, -25% Axt-Ausdauer.", "Lumber rush! 4 minutes, +30% chopping damage, -25% axe stamina cost."); dictionary.Add("Holzfällerrausch: Holzfällen 100, getragenes Holzfäller-Cape und Axt erforderlich.", "Lumber rush requires Woodcutting 100, an equipped Woodcutting cape and an axe."); dictionary.Add("Holzkiste", "Wood crate"); dictionary.Add("Holzlager", "Wood store"); dictionary.Add("Holzstab mit gefasstem Glutfokus. Zaubert schon ohne Eitrnahrung; Runen werden beim Wirken verbraucht.", "Wooden staff with a bound ember focus. Casts without Eitr food; casting consumes runes."); dictionary.Add("Holzwachtturm", "Wooden watchtower"); dictionary.Add("Höchstens 32 offene Baupläne je Gebiet.", "Maximum of 32 unfinished blueprints per area."); dictionary.Add("Höhenunterschied über 2 m. Standort wechseln oder vorher vorbereiten.", "Height difference exceeds 2m. Choose another location or prepare the terrain first."); dictionary.Add("Hühnerhof", "Chicken yard"); dictionary.Add("Im Fermenter entstehen daraus sechs Prayer-Traenke.", "Ferment this base to make six Prayer potions."); dictionary.Add("Im Inventar: Q ortet aktive Auftragsziele. F2 wechselt die Ortung; auch am Board waehlbar.", "In inventory: Q locates active contract targets. F2 switches senses; also selectable at the board."); dictionary.Add("Im am Baubrett definierten Baugebiet aktivieren.", "Activate inside the area defined at the construction board."); dictionary.Add("In jedem Biom anbaubar. Ernte, Weitergabe und Verarbeitung sind frei; Boden, Platz und Saatgut bleiben erforderlich.", "Plantable in every biome. Harvesting, sharing and processing have no level gate; soil, space and seeds are still required."); dictionary.Add("Inhalt", "Contents"); dictionary.Add("Inventar voll – der Blutegel bleibt frei.", "Inventory full – the leech remains free."); dictionary.Add("Inventar voll – der Blutegel bleibt frei.", "Inventory full – the leech remains free."); dictionary.Add("Jaegerkompass", "Hunter's compass"); dictionary.Add("Jagd", "Hunter"); dictionary.Add("Jagd-Meisterschaftsumhang", "Hunter skillcape"); dictionary.Add("Jagdinstinkt", "Hunting instinct"); dictionary.Add("Jagdinstinkt ab 60: Alt + Q. Cape-Berserk: Strg + F1. Tasten konfigurierbar.", "Hunting instinct from 60: Alt + Q. Cape berserk: Ctrl + F1. Keys are configurable."); dictionary.Add("Jagdinstinkt ab Slayer 60.", "Hunting instinct requires Slayer 60."); dictionary.Add("Jagdinstinkt! 60 Sekunden.", "Hunting instinct! 60 seconds."); dictionary.Add("Jagdinstinkt: 60s Ortung/80m und -15% Auftrags-Ausdauer; Aschlande", "Hunting instinct: 60s tracking/80m and -15% stamina cost against contract targets; Ashlands"); dictionary.Add("Jagdtagebuch", "Hunting journal"); dictionary.Add("Jotun-Bläschen", "Jotun puffs"); dictionary.Add("Jotun-Bläschen pflanzen", "Plant Jotun puffs"); dictionary.Add("Jotunpuffs und Magierkappen pflanzen.", "plant jotun puffs and magecaps."); dictionary.Add("Jäger-Eid", "Hunter's Oath"); dictionary.Add("Jägerbund", "Hunter's Pact"); dictionary.Add("Jägerkompass im Inventar oder Slayer 60 erforderlich.", "Requires a hunter's compass in your inventory or Slayer 60."); dictionary.Add("Kadaver", "Carcass"); dictionary.Add("Kampf-Ausdauerkosten", "Combat stamina costs"); dictionary.Add("