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 StandingStonesOfValheim v1.1.0
StandingStonesOfValheim.dll
Decompiled a week 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.Generic; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Splatform; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was fully created with the assistance of Generative AI: the code was written by Claude (Anthropic) through Claude Code.")] [assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace StandingStonesOfValheim; [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class Commands { private static void Postfix() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_00bb: 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_00ac: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown new ConsoleCommand("ssov_info", "- StandingStonesOfValheim: how many of each standing stone this world has, and which ones you have found", (ConsoleEvent)delegate(ConsoleEventArgs args) { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_0165: 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) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { Stone stone = StoneData.Active(localPlayer); args.Context.AddString("Chosen: " + ((stone != null) ? stone.Id : "none") + ". Found: " + Join(StoneData.Found(localPlayer)) + ". Bound to the altar: " + Join(StoneData.Bound(localPlayer)) + "."); } if (OnServer(args.Context)) { Vector3 from = (((Object)(object)localPlayer != (Object)null) ? ((Component)localPlayer).transform.position : Vector3.zero); List<LocationInstance> list = Instances(null); if (list.Count == 0) { args.Context.AddString("This world has no standing stones yet. With PlaceInExistingWorlds on they are added a little after the world loads; ssov_placestones (devcommands) adds them now."); } else { Stone[] all = Stone.All; foreach (Stone stone2 in all) { List<LocationInstance> list2 = Instances(stone2); if (list2.Count != 0) { list2.Sort((LocationInstance a, LocationInstance b) => Distance(a, from).CompareTo(Distance(b, from))); args.Context.AddString(stone2.Id + ": " + list2.Count + " in the world, closest " + Distance(list2[0], from).ToString("0", CultureInfo.InvariantCulture) + " m away"); } } args.Context.AddString("Teleport to one: ssov_goto [stone] (needs devcommands)"); } } }, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); new ConsoleCommand("ssov_goto", "[stone] - StandingStonesOfValheim: teleport to the closest standing stone of that god, or without a name to the closest one you haven't found", (ConsoleEvent)delegate(ConsoleEventArgs args) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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_0177: 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_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (OnServer(args.Context) && !((Object)(object)localPlayer == (Object)null)) { Stone stone = null; if (args.Length > 1) { Stone[] all = Stone.All; foreach (Stone stone2 in all) { if (string.Equals(stone2.Id, args[1], StringComparison.OrdinalIgnoreCase)) { stone = stone2; } } if (stone == null) { args.Context.AddString("Unknown stone " + args[1] + "."); return; } } Vector3 position = ((Component)localPlayer).transform.position; List<string> list = StoneData.Found(localPlayer); bool flag = false; LocationInstance instance = default(LocationInstance); foreach (LocationInstance item in Instances(stone)) { Stone stone3 = Stone.ByLocation(item.m_location.m_prefabName); if (stone != null || !list.Contains(stone3.Id)) { if (!flag || Distance(item, position) < Distance(instance, position)) { instance = item; } flag = true; } } if (!flag) { args.Context.AddString((stone == null) ? "You have found every stone this world has." : ("This world has no " + stone.Id + " stone.")); } else { Vector3 position2 = instance.m_position; ((Character)localPlayer).TeleportTo(new Vector3(position2.x + 6f, position2.y + 1f, position2.z + 6f), ((Component)localPlayer).transform.rotation, true); args.Context.AddString("Teleporting " + Distance(instance, position).ToString("0", CultureInfo.InvariantCulture) + " m to " + instance.m_location.m_prefabName + "."); } } }, true, false, false, false, false, false, (ConsoleOptionsFetcher)delegate { List<string> list = new List<string>(); foreach (Stone item2 in Stone.Placed()) { list.Add(item2.Id); } return list; }, false, false, false); new ConsoleCommand("ssov_placestones", "- StandingStonesOfValheim: add the stones this world is missing now (as on a world's first start with the mod, also in explored land); host or single player", (ConsoleEvent)delegate(ConsoleEventArgs args) { if (OnServer(args.Context)) { args.Context.AddString("Looking for missing stones; the result follows here and in the log."); ExistingWorlds.RunNow(args.Context); } }, true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); new ConsoleCommand("ssov_reset", "- StandingStonesOfValheim: this character forgets every standing stone (for testing)", (ConsoleEvent)delegate(ConsoleEventArgs args) { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { StoneData.Reset(Player.m_localPlayer); StoneEffects.Apply(Player.m_localPlayer); args.Context.AddString("Forgot every standing stone."); } }, true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); new ConsoleCommand("ssov_findall", "- StandingStonesOfValheim: this character has found every standing stone (for testing)", (ConsoleEvent)delegate(ConsoleEventArgs args) { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { Stone[] all = Stone.All; foreach (Stone stone in all) { StoneData.AddFound(Player.m_localPlayer, stone.Id); } args.Context.AddString("Found every standing stone."); } }, true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static string Join(List<string> ids) { if (ids.Count != 0) { return string.Join(", ", ids.ToArray()); } return "none"; } private static bool OnServer(Terminal context) { if ((Object)(object)ZoneSystem.instance != (Object)null && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { return true; } context.AddString("Where the stones are is only known on the server (single player or the host)."); return false; } internal static List<LocationInstance> Instances(Stone only) { //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_0046: Unknown result type (might be due to invalid IL or missing references) List<LocationInstance> list = new List<LocationInstance>(); foreach (LocationInstance location in ZoneSystem.instance.GetLocationList()) { if (location.m_location != null) { Stone stone = Stone.ByLocation(location.m_location.m_prefabName); if (stone != null && (only == null || only == stone)) { list.Add(location); } } } return list; } internal static float Distance(LocationInstance instance, Vector3 from) { //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_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) Vector3 position = instance.m_position; Vector2 val = new Vector2(position.x - from.x, position.z - from.z); return ((Vector2)(ref val)).magnitude; } } [HarmonyPatch(typeof(TextsDialog), "ShowText", new Type[] { typeof(TextInfo) })] internal static class CompendiumDebug { private static void Postfix(TextsDialog __instance) { //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) TMP_Text textArea = __instance.m_textArea; if ((Object)(object)textArea == (Object)null) { return; } textArea.overflowMode = (TextOverflowModes)0; textArea.ForceMeshUpdate(false, false); if (!Plugin.DebugLog.Value || (Object)(object)Player.m_localPlayer == (Object)null || StoneData.Active(Player.m_localPlayer) == null) { return; } string text = textArea.text ?? ""; int num = ((textArea.textInfo != null) ? textArea.textInfo.characterCount : (-1)); string text2 = ""; TMP_FontAsset font = textArea.font; List<char> list = default(List<char>); if ((Object)(object)font != (Object)null && !font.HasCharacters(text, ref list) && list != null) { foreach (char item in list) { string text3 = text2; int num2 = item; text2 = text3 + num2.ToString("X4") + " "; } } string text4 = ""; if (textArea.textInfo != null && num > 0) { for (int i = Math.Max(0, num - 12); i < num; i++) { text4 += textArea.textInfo.characterInfo[i].character; } } ManualLogSource log = Plugin.Log; object[] array = new object[21] { "Compendium text: length ", text.Length, ", laid out ", num, ", font ", ((Object)(object)font != (Object)null) ? ((Object)font).name : "?", ", overflow ", textArea.overflowMode, ", max chars ", textArea.maxVisibleCharacters, ", max lines ", textArea.maxVisibleLines, ", wrapping ", textArea.textWrappingMode, ", rect ", null, null, null, null, null, null }; Rect rect = textArea.rectTransform.rect; array[15] = ((Rect)(ref rect)).size; array[16] = ", missing glyphs: "; array[17] = ((text2.Length > 0) ? text2 : "none"); array[18] = ", ends with \""; array[19] = text4.Replace("\n", "\\n"); array[20] = "\""; log.LogInfo((object)string.Concat(array)); Plugin.Log.LogInfo((object)("Compendium text is: " + text.Replace("\n", "\\n"))); } } internal static class ExistingWorlds { private enum Thing { Other, Building, Natural, BigRock } private class Index { internal readonly Dictionary<Vector2s, List<ZDO>> Buildings = new Dictionary<Vector2s, List<ZDO>>(); internal readonly Dictionary<Vector2s, List<ZDO>> Nature = new Dictionary<Vector2s, List<ZDO>>(); } private enum Why { Building, Height, Land, NearStone, NearPlace, LandEdge, Slope, Lava, BigRock, Count } private class Found { internal bool Ok; internal Vector3 Spot; } internal const string DoneKey = "standingstones_existing_v1"; private const float BuildingDistance = 50f; private const float RingClear = 5f; private const float NaturalScoreRadius = 12f; private const float MaxSlope = 2.5f; private static readonly MethodInfo registerLocation = AccessTools.Method(typeof(ZoneSystem), "RegisterLocation", (Type[])null, (Type[])null); private static readonly MethodInfo spawnLocation = AccessTools.Method(typeof(ZoneSystem), "SpawnLocation", (Type[])null, (Type[])null); private static readonly FieldInfo generatedZones = AccessTools.Field(typeof(ZoneSystem), "m_generatedZones"); private static readonly FieldInfo objectsByID = AccessTools.Field(typeof(ZDOMan), "m_objectsByID"); private static bool started; private static float readySince = -1f; private static readonly Dictionary<int, Thing> kinds = new Dictionary<int, Thing>(); private static readonly int[] why = new int[9]; internal static void Tick() { if ((Object)(object)ZNet.instance == (Object)null) { started = false; readySince = -1f; } else { if (started || !Plugin.PlaceInExistingWorlds.Value) { return; } ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || ZDOMan.instance == null || WorldGenerator.instance == null || !instance.LocationsGenerated) { readySince = -1f; return; } if (readySince < 0f) { readySince = Time.time; } if (!(Time.time - readySince < 10f)) { started = true; if (instance.GetGlobalKey("standingstones_existing_v1")) { Plugin.Debug("Stones in existing worlds: this world already had its pass."); } else { ((MonoBehaviour)Plugin.Instance).StartCoroutine(Run(null)); } } } } internal static void RunNow(Terminal context) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(Run(context)); } private static Thing KindOf(int prefabHash) { if (kinds.TryGetValue(prefabHash, out var value)) { return value; } value = Thing.Other; GameObject prefab = ZNetScene.instance.GetPrefab(prefabHash); if ((Object)(object)prefab != (Object)null) { if ((Object)(object)prefab.GetComponent<Piece>() != (Object)null) { value = Thing.Building; } else if ((Object)(object)prefab.GetComponent<Character>() != (Object)null || (Object)(object)prefab.GetComponent<ItemDrop>() != (Object)null || (Object)(object)prefab.GetComponent<Container>() != (Object)null || (Object)(object)prefab.GetComponent<TombStone>() != (Object)null || (Object)(object)prefab.GetComponent<Ship>() != (Object)null || (Object)(object)prefab.GetComponent<RuneStone>() != (Object)null || (Object)(object)prefab.GetComponent<Vegvisir>() != (Object)null || (Object)(object)prefab.GetComponent<LocationProxy>() != (Object)null) { value = Thing.Other; } else if ((Object)(object)prefab.GetComponent<MineRock5>() != (Object)null || (Object)(object)prefab.GetComponent<MineRock>() != (Object)null) { value = Thing.BigRock; } else if ((Object)(object)prefab.GetComponent<TreeBase>() != (Object)null || (Object)(object)prefab.GetComponent<TreeLog>() != (Object)null || (Object)(object)prefab.GetComponent<Destructible>() != (Object)null || (Object)(object)prefab.GetComponent<Pickable>() != (Object)null) { value = Thing.Natural; } } kinds[prefabHash] = value; return value; } private static Index BuildIndex() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_0093: Unknown result type (might be due to invalid IL or missing references) Index index = new Index(); IDictionary dictionary = ((objectsByID != null) ? (objectsByID.GetValue(ZDOMan.instance) as IDictionary) : null); if (dictionary == null) { return index; } foreach (object value2 in dictionary.Values) { ZDO val = (ZDO)((value2 is ZDO) ? value2 : null); if (val == null) { continue; } Thing thing = KindOf(val.GetPrefab()); if (thing != Thing.Other) { Dictionary<Vector2s, List<ZDO>> dictionary2 = ((thing == Thing.Building) ? index.Buildings : index.Nature); Vector2s zone = ZoneSystem.GetZone(val.GetPosition()); if (!dictionary2.TryGetValue(zone, out var value)) { value = (dictionary2[zone] = new List<ZDO>()); } value.Add(val); } } return index; } private static IEnumerable<ZDO> Near(Dictionary<Vector2s, List<ZDO>> map, Vector3 p, float radius) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) Vector2s zone = ZoneSystem.GetZone(p); int reach = Mathf.CeilToInt(radius / 64f); for (int dx = -reach; dx <= reach; dx++) { for (int dy = -reach; dy <= reach; dy++) { if (!map.TryGetValue(new Vector2s(zone.x + dx, zone.y + dy), out var list)) { continue; } foreach (ZDO zdo in list) { Vector3 q = zdo.GetPosition(); Vector2 val = new Vector2(q.x - p.x, q.z - p.z); if (((Vector2)(ref val)).sqrMagnitude <= radius * radius) { yield return zdo; } } } } } private static IEnumerator Run(Terminal context) { ZoneSystem zones = ZoneSystem.instance; HashSet<Vector2s> generated = ((generatedZones != null) ? (generatedZones.GetValue(zones) as HashSet<Vector2s>) : null); if (generated == null || registerLocation == null || spawnLocation == null) { Plugin.Log.LogWarning((object)"Stones in existing worlds: this version of the game isn't the one the mod knows; nothing placed."); yield break; } Plugin.Log.LogInfo((object)"Stones in existing worlds: looking for missing stones..."); Index index = BuildIndex(); yield return null; List<Vector3> stones = new List<Vector3>(); Dictionary<string, int> counts = new Dictionary<string, int>(); foreach (LocationInstance location2 in zones.GetLocationList()) { if (location2.m_location != null) { Stone stone = Stone.ByLocation(location2.m_location.m_prefabName); if (stone != null) { stones.Add(location2.m_position); counts.TryGetValue(stone.Id, out var value); counts[stone.Id] = value + 1; } } } Dictionary<Vector2s, Biome> unexplored = new Dictionary<Vector2s, Biome>(); int checkedZones = 0; Vector2s val = default(Vector2s); for (int x = -158; x <= 158; x++) { for (int i = -158; i <= 158; i++) { ((Vector2s)(ref val))..ctor(x, i); Vector3 zonePos = ZoneSystem.GetZonePos(val); if (!(((Vector3)(ref zonePos)).magnitude > 9800f) && !generated.Contains(val) && !zones.m_locationInstances.ContainsKey(val)) { unexplored[val] = WorldGenerator.instance.GetBiome(zonePos); checkedZones++; } } if (x % 16 == 0) { yield return null; } } Plugin.Debug("Stones in existing worlds: " + checkedZones + " unexplored zones, " + generated.Count + " explored"); Random random = new Random(WorldGenerator.instance.GetSeed() ^ 0x55A1); Dictionary<string, int> placed = new Dictionary<string, int>(); Dictionary<string, int> placedExplored = new Dictionary<string, int>(); for (int round = 1; round <= 2; round++) { try { Stone[] all = Stone.All; foreach (Stone stone2 in all) { ZoneLocation location = null; foreach (ZoneLocation location3 in zones.m_locations) { if (location3 != null && location3.m_prefabName == stone2.LocationName) { location = location3; break; } } if (location == null) { continue; } counts.TryGetValue(stone2.Id, out var have); placed.TryGetValue(stone2.Id, out var done); int missing = Plugin.CopiesPerStone.Value - have - done; if (missing <= 0) { continue; } if (round == 1) { missing = 1; } for (int copy = 0; copy < missing; copy++) { ResetWhy(); Vector3 spot; bool explored; if (round == 1) { if (!FindExplored(stone2, generated, index, stones, random, out spot)) { Plugin.Debug("Stones in existing worlds: no spot in explored land for " + stone2.Id + " (turned down: " + WhyText() + ")"); break; } explored = true; } else { Found found = new Found(); yield return ((MonoBehaviour)Plugin.Instance).StartCoroutine(FindUnexplored(stone2, unexplored, stones, random, found)); spot = found.Spot; if (found.Ok) { explored = false; } else { if (!FindExplored(stone2, generated, index, stones, random, out spot)) { Plugin.Debug("Stones in existing worlds: no spot anywhere for another " + stone2.Id + " (turned down: " + WhyText() + ")"); break; } explored = true; } } if (explored) { Build(location, stone2, spot, index, random); } else { registerLocation.Invoke(zones, new object[3] { location, spot, false }); unexplored.Remove(ZoneSystem.GetZone(spot)); } stones.Add(spot); Add(placed, stone2.Id); if (explored) { Add(placedExplored, stone2.Id); } yield return null; } yield return null; } } finally { } } int inExplored = 0; int inUnexplored = 0; List<string> report = new List<string>(); Stone[] all2 = Stone.All; foreach (Stone stone3 in all2) { if (placed.TryGetValue(stone3.Id, out var value2)) { placedExplored.TryGetValue(stone3.Id, out var value3); inExplored += value3; inUnexplored += value2 - value3; report.Add(stone3.Id + " " + value2 + ((value3 > 0) ? (" (" + value3 + " in explored land)") : "")); } } List<string> short_ = new List<string>(); Stone[] all3 = Stone.All; foreach (Stone stone4 in all3) { counts.TryGetValue(stone4.Id, out var value4); placed.TryGetValue(stone4.Id, out var value5); if (value4 + value5 < Plugin.CopiesPerStone.Value) { short_.Add(stone4.Id + " " + (value4 + value5)); } } if (short_.Count > 0) { Plugin.Log.LogInfo((object)("Stones in existing worlds: no good spot left for every copy of: " + string.Join(", ", short_.ToArray()) + " (stones now in the world)")); } zones.SetGlobalKey("standingstones_existing_v1"); string summary = ((report.Count == 0) ? "every god already had its stones; nothing added." : ("added " + (inExplored + inUnexplored) + " stones, " + inExplored + " in explored land and " + inUnexplored + " where nobody has been yet: " + string.Join(", ", report.ToArray()) + ".")); Plugin.Log.LogInfo((object)("Stones in existing worlds: " + summary)); if ((Object)(object)context != (Object)null) { context.AddString("Stones in existing worlds: " + summary); } } private static void Add(Dictionary<string, int> map, string id) { map.TryGetValue(id, out var value); map[id] = value + 1; } private static void Build(ZoneLocation location, Stone stone, Vector3 spot, Index index, Random random) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (ZDO item in new List<ZDO>(Near(index.Nature, spot, 5f))) { if (!item.IsOwner()) { item.SetOwner(ZDOMan.GetSessionID()); } ZDOMan.instance.DestroyZDO(item); num++; } ZoneSystem instance = ZoneSystem.instance; registerLocation.Invoke(instance, new object[3] { location, spot, true }); Quaternion val = Quaternion.Euler(0f, (float)random.Next(16) * 22.5f, 0f); spawnLocation.Invoke(instance, new object[7] { location, random.Next(), spot, val, (object)(SpawnMode)0, new List<GameObject>(), false }); Plugin.Debug("Stones in existing worlds: built " + stone.Id + " at " + ((Vector3)(ref spot)).ToString("F0") + " in explored land (" + num + " trees/rocks cleared)"); } private static void ResetWhy() { Array.Clear(why, 0, why.Length); } private static string WhyText() { List<string> list = new List<string>(); for (int i = 0; i < why.Length; i++) { if (why[i] > 0) { list.Add(((Why)i).ToString() + " " + why[i]); } } if (list.Count != 0) { return string.Join(", ", list.ToArray()); } return "no spots looked at"; } private static bool No(Why reason) { why[(int)reason]++; return false; } private static bool Suits(Stone stone, Vector3 p, List<Vector3> stones, out float height) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_006f: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_021e: 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_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: 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) WorldGenerator instance = WorldGenerator.instance; height = instance.GetHeight(p.x, p.z); float num = height - 30f; float num2 = (stone.Coast ? 0.6f : (((int)stone.Biome == 2) ? 0.1f : 1f)); float num3 = (stone.Coast ? 4f : 1000f); if (num < num2 || num > num3) { return No(Why.Height); } if ((instance.GetBiome(p) & stone.Biome) == 0) { return No(Why.Land); } float value = Plugin.StoneSpacing.Value; foreach (Vector3 stone2 in stones) { Vector2 val = new Vector2(stone2.x - p.x, stone2.z - p.z); if (((Vector2)(ref val)).sqrMagnitude < value * value) { return No(Why.NearStone); } } Vector2s zone = ZoneSystem.GetZone(p); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (ZoneSystem.instance.m_locationInstances.TryGetValue(new Vector2s(zone.x + i, zone.y + j), out var value2) && value2.m_location != null) { if (i == 0 && j == 0) { return No(Why.NearPlace); } float num4 = Mathf.Max(value2.m_location.m_exteriorRadius, value2.m_location.m_interiorRadius) + 20f; Vector2 val2 = new Vector2(value2.m_position.x - p.x, value2.m_position.z - p.z); if (((Vector2)(ref val2)).sqrMagnitude < num4 * num4) { return No(Why.NearPlace); } } } } if (!stone.Coast) { for (int k = 0; k < 4; k++) { float num5 = (float)k * (float)Math.PI / 2f; if ((instance.GetBiome(p + new Vector3(Mathf.Sin(num5), 0f, Mathf.Cos(num5)) * 24f) & stone.Biome) == 0) { return No(Why.LandEdge); } } } float num6 = height; float num7 = height; for (int l = 1; l <= 2; l++) { for (int m = 0; m < 8; m++) { float num8 = ((float)m * 45f + (float)l * 22.5f) * ((float)Math.PI / 180f); float height2 = instance.GetHeight(p.x + Mathf.Sin(num8) * (float)l * 6f, p.z + Mathf.Cos(num8) * (float)l * 6f); num6 = Mathf.Min(num6, height2); num7 = Mathf.Max(num7, height2); if (num7 - num6 > 2.5f) { return No(Why.Slope); } } } if (LavaCheck.NearLava(p)) { return No(Why.Lava); } return true; } private static float BigRockRadius(Stone stone) { //IL_0001: 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) if ((stone.Biome & 0x64) == 0) { return 14f; } return 26f; } private static bool FindExplored(Stone stone, HashSet<Vector2s> generated, Index index, List<Vector3> stones, Random random, out Vector3 spot) { //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_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_0053: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_0110: 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_0120: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: 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_01cb: 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) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) spot = Vector3.zero; float num = float.MaxValue; float radius = BigRockRadius(stone); List<Vector2s> list = new List<Vector2s>(); foreach (Vector2s item in generated) { if (stone.Coast || (WorldGenerator.instance.GetBiome(ZoneSystem.GetZonePos(item)) & stone.Biome) != 0) { list.Add(item); } } for (int num2 = list.Count - 1; num2 > 0; num2--) { int index2 = random.Next(num2 + 1); Vector2s value = list[num2]; list[num2] = list[index2]; list[index2] = value; } int num3 = 0; for (int i = 0; i < list.Count && i < 600; i++) { if (num3 >= 30) { break; } Vector3 zonePos = ZoneSystem.GetZonePos(list[i]); for (int j = 0; j < 3; j++) { Vector3 val = zonePos + new Vector3((float)random.NextDouble() * 48f - 24f, 0f, (float)random.NextDouble() * 48f - 24f); bool flag = false; using (IEnumerator<ZDO> enumerator2 = Near(index.Buildings, val, 50f).GetEnumerator()) { if (enumerator2.MoveNext()) { _ = enumerator2.Current; flag = true; } } if (flag) { No(Why.Building); } else { if (!Suits(stone, val, stones, out var height)) { continue; } val.y = height; float num4 = 0f; foreach (ZDO item2 in Near(index.Nature, val, radius)) { if (KindOf(item2.GetPrefab()) == Thing.BigRock) { flag = true; No(Why.BigRock); break; } Vector3 position = item2.GetPosition(); Vector2 val2 = new Vector2(position.x - val.x, position.z - val.z); if (((Vector2)(ref val2)).sqrMagnitude <= 144f) { num4 += 1f; } } if (!flag) { num3++; if (!(num4 >= num)) { num = num4; spot = val; } } } } } return num < float.MaxValue; } private static IEnumerator FindUnexplored(Stone stone, Dictionary<Vector2s, Biome> unexplored, List<Vector3> stones, Random random, Found result) { result.Ok = false; Biome lands = (Biome)(stone.Coast ? (stone.Biome | 0x100) : stone.Biome); List<Vector2s> candidates = new List<Vector2s>(); foreach (KeyValuePair<Vector2s, Biome> item in unexplored) { if ((item.Value & lands) != 0 && !ZoneSystem.instance.m_locationInstances.ContainsKey(item.Key)) { candidates.Add(item.Key); } } for (int num = candidates.Count - 1; num > 0; num--) { int index = random.Next(num + 1); Vector2s value = candidates[num]; candidates[num] = candidates[index]; candidates[index] = value; } for (int z = 0; z < candidates.Count; z++) { Vector3 center = ZoneSystem.GetZonePos(candidates[z]); for (int i = 0; i < 5; i++) { Vector3 val = center + new Vector3((float)random.NextDouble() * 48f - 24f, 0f, (float)random.NextDouble() * 48f - 24f); if (Suits(stone, val, stones, out var height)) { val.y = height; result.Spot = val; result.Ok = true; yield break; } } if (z % 150 == 149) { yield return null; } } } } internal static class HelMark { [HarmonyPatch(typeof(Player), "OnDeath")] private static class DeathPatch { private static void Prefix(Player __instance) { dyingWithHel = (Object)(object)__instance == (Object)(object)Player.m_localPlayer && StoneEffects.LocalHas("Hel"); graveMade = false; } private static void Postfix(Player __instance) { if (dyingWithHel && graveMade && (Object)(object)EnvMan.instance != (Object)null) { StoneData.SetMarkUntil(__instance, Now() + (double)EnvMan.instance.m_dayLengthSec); Plugin.Debug("Hel's mark until " + StoneData.MarkUntil(__instance).ToString("F0")); } dyingWithHel = false; } } [HarmonyPatch(typeof(TombStone), "Setup")] private static class GravePatch { private static void Postfix(long ownerUID) { if (dyingWithHel && (Object)(object)Player.m_localPlayer != (Object)null && ownerUID == Player.m_localPlayer.GetPlayerID()) { graveMade = true; } } } internal const string EffectName = "SSoV_SE_HelMark"; private static bool dyingWithHel; private static bool graveMade; private static int Hash => StringExtensionMethods.GetStableHashCode("SSoV_SE_HelMark"); private static double Now() { if (!((Object)(object)ZNet.instance != (Object)null)) { return 0.0; } return ZNet.instance.GetTimeSeconds(); } internal static bool IsMarked(Player player) { return StoneData.MarkUntil(player) > Now(); } internal static double SecondsLeft(Player player) { return StoneData.MarkUntil(player) - Now(); } internal static void Refresh(Player player, bool tell) { SEMan sEMan = ((Character)player).GetSEMan(); bool flag = IsMarked(player); if (!flag && StoneData.MarkUntil(player) > 0.0) { StoneData.SetMarkUntil(player, 0.0); } if (flag && !sEMan.HaveStatusEffect(Hash)) { sEMan.AddStatusEffect(Hash, false, 0, 0f, (short)0); if (tell) { ((Character)player).Message((MessageType)2, "$ssov_hel_marked", 0, (Sprite)null, false); } } else if (!flag && sEMan.HaveStatusEffect(Hash)) { sEMan.RemoveStatusEffect(Hash, true); } } internal static void Lift(Player player) { if (!(StoneData.MarkUntil(player) <= 0.0)) { StoneData.SetMarkUntil(player, 0.0); Refresh(player, tell: false); ((Character)player).Message((MessageType)2, "$ssov_hel_lifted", 0, (Sprite)null, false); Plugin.Debug("Hel's mark lifted"); } } } internal class SE_HelMark : StatusEffect { public override bool IsDone() { Character character = base.m_character; Player val = (Player)(object)((character is Player) ? character : null); if (!((StatusEffect)this).IsDone()) { if ((Object)(object)val != (Object)null) { return !HelMark.IsMarked(val); } return false; } return true; } public override string GetIconText() { Character character = base.m_character; Player val = (Player)(object)((character is Player) ? character : null); if ((Object)(object)val == (Object)null) { return ""; } double num = HelMark.SecondsLeft(val); if (num <= 0.0) { return ""; } int num2 = Mathf.CeilToInt((float)num); int num3 = num2 / 3600; int num4 = num2 / 60 % 60; if (num3 <= 0) { return num4 + ":" + (num2 % 60).ToString("00"); } return num3 + ":" + num4.ToString("00") + ":" + (num2 % 60).ToString("00"); } public override string GetTooltipString() { return Texts.Get("ssov_hel_mark_tooltip", Mathf.RoundToInt(Stone.Find("Hel").V(2)).ToString()); } } internal static class Hints { private const string RequestRpc = "SSoV_HintRequest"; private const string AnswerRpc = "SSoV_HintAnswer"; private const float NearDistance = 700f; private const float FarDistance = 2000f; private static readonly string[] Directions = new string[8] { "n", "ne", "e", "se", "s", "sw", "w", "nw" }; private static readonly MethodInfo serverPeerId = AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null); private static float lastAsked = -100f; internal static void RegisterRpcs() { ZRoutedRpc.instance.Register<ZPackage>("SSoV_HintRequest", (Action<long, ZPackage>)OnRequest); ZRoutedRpc.instance.Register<ZPackage>("SSoV_HintAnswer", (Action<long, ZPackage>)OnAnswer); } internal static void Ask(Stone touched, Vector3 at) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && ZRoutedRpc.instance != null && !(Time.time - lastAsked < 3f)) { lastAsked = Time.time; ZPackage val = new ZPackage(); val.Write(touched.Id); val.Write(at); val.Write(string.Join(",", StoneData.Found(localPlayer).ToArray())); ZRoutedRpc.instance.InvokeRoutedRPC((long)serverPeerId.Invoke(ZRoutedRpc.instance, null), "SSoV_HintRequest", new object[1] { val }); } } private static void OnRequest(long sender, ZPackage request) { //IL_0034: 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_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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)ZoneSystem.instance == (Object)null) { return; } Stone stone = Stone.Find(request.ReadString()); Vector3 val = request.ReadVector3(); List<string> list = new List<string>(request.ReadString().Split(',')); bool flag = false; bool flag2 = false; float num = float.MaxValue; float num2 = float.MaxValue; Vector3 val2 = Vector3.zero; Vector3 val3 = Vector3.zero; foreach (LocationInstance item in Commands.Instances(null)) { Stone stone2 = Stone.ByLocation(item.m_location.m_prefabName); if (stone2 != null && !list.Contains(stone2.Id)) { float num3 = Commands.Distance(item, val); if (num3 < num) { num = num3; val2 = item.m_position; flag = true; } if (stone != null && stone2.Land == stone.Land && num3 < num2) { num2 = num3; val3 = item.m_position; flag2 = true; } } } if (flag2) { val2 = val3; num = num2; } ZPackage val4 = new ZPackage(); if (!flag) { val4.Write(-1); val4.Write(0); } else { float num4 = Mathf.Atan2(val2.x - val.x, val2.z - val.z) * 57.29578f; val4.Write((Mathf.RoundToInt(num4 / 45f) % 8 + 8) % 8); val4.Write((!(num < 700f)) ? ((num < 2000f) ? 1 : 2) : 0); } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SSoV_HintAnswer", new object[1] { val4 }); Plugin.Debug("Hint for " + sender + ": " + (flag ? ("stone " + num.ToString("F0") + " m away") : "none left")); } private static void OnAnswer(long sender, ZPackage answer) { int num = answer.ReadInt(); int num2 = answer.ReadInt(); string text = ((num < 0) ? Texts.Get("ssov_hint_none") : Texts.Get("ssov_hint", Texts.Get("ssov_dir_" + Directions[num]), Texts.Get("ssov_far_" + num2))); ((MonoBehaviour)Plugin.Instance).StartCoroutine(ShowWhenRead(text)); } private static IEnumerator ShowWhenRead(string text) { float until = Time.time + 120f; while ((Object)(object)TextViewer.instance != (Object)null && TextViewer.instance.IsVisible() && Time.time < until) { yield return null; } yield return (object)new WaitForSeconds(0.4f); if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } } [BepInPlugin("StandingStonesOfValheim", "StandingStonesOfValheim", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "StandingStonesOfValheim"; public const string ModName = "StandingStonesOfValheim"; public const string Version = "1.1.0"; internal static ConfigEntry<int> CopiesPerStone; internal static ConfigEntry<float> StoneSpacing; internal static ConfigEntry<bool> PlaceInExistingWorlds; internal static ConfigEntry<KeyboardShortcut> DailyKey; internal static ConfigEntry<bool> DebugLog; internal static ManualLogSource Log; internal static Plugin Instance; private void Awake() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00ce: 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) Log = ((BaseUnityPlugin)this).Logger; Instance = this; CopiesPerStone = ((BaseUnityPlugin)this).Config.Bind<int>("1 - World generation", "CopiesPerStone", 3, new ConfigDescription("How many of each god's stone a world has. The game tries this many when a world is made; in an older world the missing ones are added once (see PlaceInExistingWorlds). A copy that finds no good spot is left out.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), new object[1] { Admin() })); StoneSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("1 - World generation", "StoneSpacing", 400f, new ConfigDescription("The least distance in metres between any two standing stones.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 3000f), new object[1] { Admin() })); PlaceInExistingWorlds = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - World generation", "PlaceInExistingWorlds", true, "In a world made before this mod (or missing some stones), the server adds the missing stones once, after the world loads: one of each god's in land already explored (on open, fairly flat ground away from players' buildings and the game's own places), the rest in land nobody has been to yet. Then the world is marked, so it doesn't happen again. ssov_placestones (devcommands) runs it again by hand."); DailyKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("2 - Keys", "DailyPowerKey", new KeyboardShortcut((KeyCode)104, (KeyCode[])(object)new KeyCode[0]), "The key that calls your stone's daily power (Freyja's blessing). Ignored while Alt is held, so Alt+H stays free for other mods."); DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - Debug", "DebugLog", false, "Writes how the stones were built and where they are to the BepInEx log. Useful when reporting a problem."); Stone.BindConfig(((BaseUnityPlugin)this).Config); Texts.LoadOwn(); ((Component)this).gameObject.AddComponent<StoneUpdater>(); PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabs; ZoneManager.OnVanillaLocationsAvailable += OnVanillaLocations; new Harmony("StandingStonesOfValheim").PatchAll(typeof(Plugin).Assembly); } internal static ConfigurationManagerAttributes Admin() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ConfigurationManagerAttributes val = new ConfigurationManagerAttributes(); val.IsAdminOnly = true; return val; } private void OnVanillaPrefabs() { PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabs; StoneEffects.Register(); RuneAltar.Register(); } private void OnVanillaLocations() { ZoneManager.OnVanillaLocationsAvailable -= OnVanillaLocations; StoneBuilder.RegisterLocations(); } internal static void Debug(string message) { if (DebugLog.Value) { Log.LogInfo((object)message); } } } internal static class Powers { [HarmonyPatch(typeof(SEMan), "Internal_AddStatusEffect")] private static class AddEffectPatch { private static void Postfix(SEMan __instance, int nameHash, StatusEffect __result) { if (!((Object)(object)__result == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)/*isinst with value type is only supported in some contexts*/ != (Object)(object)Player.m_localPlayer)) { if (nameHash == corpseRunHash) { HelMark.Lift(Player.m_localPlayer); } else if ((nameHash == coldHash || nameHash == freezingHash) && StoneEffects.LocalHas("Skadi")) { Soften(__result); } } } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] private static class FoodValuePatch { private static void Postfix(Player __instance, ref float hp, ref float stamina) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { if (StoneEffects.LocalHas("Loki")) { hp *= 1f - Stone.Find("Loki").P(2); } if (HelMark.IsMarked(__instance)) { float num = 1f - Stone.Find("Hel").P(2); hp *= num; stamina *= num; } } } } [HarmonyPatch(typeof(Character), "ApplyDamage")] private static class DamagePatch { private static bool Prefix(Character __instance, HitData hit, out bool __state) { __state = !__instance.IsDead() && __instance.GetHealth() > 0f; Player val = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || hit == null) { return true; } if (((Character)val).GetSEMan().HaveStatusEffect(BaldrWardHash)) { return false; } return !BaldrSaves(val, hit); } private static void Postfix(Character __instance, HitData hit, bool __state) { if (__state && hit != null && !(__instance is Player) && !(__instance.GetHealth() > 0f)) { Character attacker = hit.GetAttacker(); KilledBy((Player)(object)((attacker is Player) ? attacker : null)); } } } [HarmonyPatch(typeof(Game), "Start")] private static class RpcPatch { private static void Postfix() { ZRoutedRpc.instance.Register("SSoV_Kill", (Action<long>)delegate { HealIfBlessed(); }); Hints.RegisterRpcs(); } } [HarmonyPatch(typeof(Humanoid), "BlockAttack")] private static class BlockPatch { private static void Prefix(Humanoid __instance) { weakBlock = StoneEffects.Has((Character)(object)__instance, "Vidarr"); } private static void Postfix() { weakBlock = false; } } [HarmonyPatch(typeof(ItemData), "GetBlockPower", new Type[] { typeof(float) })] private static class BlockPowerPatch { private static void Postfix(ref float __result) { if (weakBlock) { __result *= 1f - Stone.Find("Vidarr").P(1); } } } [HarmonyPatch(typeof(Ship), "GetSailForce")] private static class SailPatch { private static void Postfix(Ship __instance, ref Vector3 __result) { //IL_000a: 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) if (Steering(__instance)) { __result *= 1f + Stone.Find("Njord").P(0); } } } [HarmonyPatch(typeof(Ship), "CustomFixedUpdate")] private static class RowPatch { private static void Prefix(Ship __instance, out float __state) { __state = __instance.m_backwardForce; if (Steering(__instance)) { __instance.m_backwardForce = __state * (1f + Stone.Find("Njord").P(0)); } } private static void Postfix(Ship __instance, float __state) { __instance.m_backwardForce = __state; } } internal const string Freyja = "Freyja"; internal const string Baldr = "Baldr"; internal const string BaldrWardName = "SSoV_SE_BaldrWard"; internal const string BlessingName = "SSoV_SE_FreyjaBlessing"; internal const string KillRpc = "SSoV_Kill"; private static readonly int coldHash = StringExtensionMethods.GetStableHashCode("Cold"); private static readonly int freezingHash = StringExtensionMethods.GetStableHashCode("Freezing"); private static readonly int corpseRunHash = StringExtensionMethods.GetStableHashCode("CorpseRun"); private static readonly FieldInfo seCharacter = AccessTools.Field(typeof(SEMan), "m_character"); private static readonly HashSet<StatusEffect> softened = new HashSet<StatusEffect>(); private static bool weakBlock; internal static int BaldrWardHash => StringExtensionMethods.GetStableHashCode("SSoV_SE_BaldrWard"); internal static int BlessingHash => StringExtensionMethods.GetStableHashCode("SSoV_SE_FreyjaBlessing"); internal static bool IsMelee(SkillType skill) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected I4, but got Unknown switch (skill - 1) { case 0: case 1: case 2: case 3: case 4: case 6: case 10: return true; default: return false; } } internal static int Today() { if (!((Object)(object)EnvMan.instance != (Object)null)) { return 0; } return EnvMan.instance.GetDay(); } internal static bool UsedToday(Player player, string id) { return StoneData.LastDaily(player, id) >= Today(); } internal static void RegisterEffects() { //IL_004f: 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) //IL_0074: Expected O, but got Unknown //IL_00ab: 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_00d1: Expected O, but got Unknown //IL_0108: 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_012e: Expected O, but got Unknown Stone stone = Stone.Find("Baldr"); Stone stone2 = Stone.Find("Freyja"); Stone stone3 = Stone.Find("Hel"); SE_Timed sE_Timed = ScriptableObject.CreateInstance<SE_Timed>(); ((Object)sE_Timed).name = "SSoV_SE_BaldrWard"; ((StatusEffect)sE_Timed).m_name = "$ssov_baldr_ward"; sE_Timed.TooltipKey = "ssov_baldr_ward_tooltip"; ((StatusEffect)sE_Timed).m_icon = Runes.Icon(stone.Rune, Color.white, "BaldrWard"); ItemManager.Instance.AddStatusEffect(new CustomStatusEffect((StatusEffect)(object)sE_Timed, false)); SE_Blessing sE_Blessing = ScriptableObject.CreateInstance<SE_Blessing>(); ((Object)sE_Blessing).name = "SSoV_SE_FreyjaBlessing"; ((StatusEffect)sE_Blessing).m_name = "$ssov_freyja_blessing"; ((StatusEffect)sE_Blessing).m_icon = Runes.Icon(stone2.Rune, new Color(1f, 0.55f, 0.7f), "FreyjaBlessing"); ItemManager.Instance.AddStatusEffect(new CustomStatusEffect((StatusEffect)(object)sE_Blessing, false)); SE_HelMark sE_HelMark = ScriptableObject.CreateInstance<SE_HelMark>(); ((Object)sE_HelMark).name = "SSoV_SE_HelMark"; ((StatusEffect)sE_HelMark).m_name = "$ssov_hel_mark"; ((StatusEffect)sE_HelMark).m_icon = Runes.Icon(stone3.Rune, new Color(0.6f, 0.45f, 0.9f), "HelMark"); ItemManager.Instance.AddStatusEffect(new CustomStatusEffect((StatusEffect)(object)sE_HelMark, false)); } internal static void OnStoneChanged(Player player) { SEMan sEMan = ((Character)player).GetSEMan(); softened.Clear(); if (sEMan.HaveStatusEffect(coldHash)) { sEMan.RemoveStatusEffect(coldHash, true); } if (sEMan.HaveStatusEffect(freezingHash)) { sEMan.RemoveStatusEffect(freezingHash, true); } } private static void Soften(StatusEffect effect) { SE_Stats val = (SE_Stats)(object)((effect is SE_Stats) ? effect : null); if (!((Object)(object)val == (Object)null) && softened.Add(effect)) { float num = Stone.Find("Skadi").P(0); Plugin.Debug("Skadi softens " + ((Object)effect).name + ": health regen " + val.m_healthRegenMultiplier + ", stamina regen " + val.m_staminaRegenMultiplier + ", eitr regen " + val.m_eitrRegenMultiplier + ", health per tick " + val.m_healthPerTick + ", speed " + val.m_speedModifier); val.m_healthRegenMultiplier = Mathf.Lerp(val.m_healthRegenMultiplier, 1f, num); val.m_staminaRegenMultiplier = Mathf.Lerp(val.m_staminaRegenMultiplier, 1f, num); val.m_eitrRegenMultiplier = Mathf.Lerp(val.m_eitrRegenMultiplier, 1f, num); val.m_healthPerTick *= 1f - num; val.m_speedModifier *= 1f - num; val.m_staminaDrainPerSec *= 1f - num; } } private static bool BaldrSaves(Player player, HitData hit) { if (!StoneEffects.LocalHas("Baldr") || ((Character)player).InGodMode()) { return false; } float num = hit.GetTotalDamage() * Game.m_localDamgeTakenRate; if (((Character)player).GetHealth() - num > 0f || UsedToday(player, "Baldr")) { return false; } Stone stone = Stone.Find("Baldr"); StoneData.SetLastDaily(player, "Baldr", Today()); ((Character)player).SetHealth(Mathf.Max(1f, ((Character)player).GetMaxHealth() * stone.P(0))); StatusEffect val = ((Character)player).GetSEMan().AddStatusEffect(BaldrWardHash, true, 0, 0f, (short)0); if ((Object)(object)val != (Object)null) { val.m_ttl = stone.V(1); } ((Character)player).Message((MessageType)2, "$ssov_baldr_saved", 0, (Sprite)null, false); StoneEvents.PlayChooseEffect(player); Plugin.Debug("Baldr turned aside a blow of " + num.ToString("F0")); return true; } internal static void CallDaily(Player player) { Stone stone = StoneData.Active(player); if (stone == null || stone.Id != "Freyja" || !StoneEffects.LocalHas("Freyja")) { ((Character)player).Message((MessageType)2, "$ssov_no_power", 0, (Sprite)null, false); return; } if (UsedToday(player, "Freyja")) { ((Character)player).Message((MessageType)2, "$ssov_freyja_used", 0, (Sprite)null, false); return; } StoneData.SetLastDaily(player, "Freyja", Today()); StatusEffect val = ((Character)player).GetSEMan().AddStatusEffect(BlessingHash, true, 0, 0f, (short)0); if ((Object)(object)val != (Object)null) { val.m_ttl = stone.V(2); } ((Character)player).Message((MessageType)2, "$ssov_freyja_called", 0, (Sprite)null, false); StoneEvents.PlayChooseEffect(player); } private static void KilledBy(Player killer) { if (!((Object)(object)killer == (Object)null)) { if ((Object)(object)killer == (Object)(object)Player.m_localPlayer) { HealIfBlessed(); } else if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(((Character)killer).GetOwner(), "SSoV_Kill", new object[0]); } } } private static void HealIfBlessed() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && ((Character)localPlayer).GetSEMan().HaveStatusEffect(BlessingHash)) { ((Character)localPlayer).Heal(((Character)localPlayer).GetMaxHealth() * Stone.Find("Freyja").P(1), true); } } private static bool Steering(Ship ship) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && ship.IsOwner() && StoneEffects.LocalHas("Njord")) { return (Object)(object)localPlayer.GetControlledShip() == (Object)(object)ship; } return false; } } internal class SE_Timed : StatusEffect { internal string TooltipKey; public override string GetTooltipString() { if (TooltipKey == null) { return ((StatusEffect)this).GetTooltipString(); } return Texts.Get(TooltipKey); } } internal class SE_Blessing : SE_Timed { public override string GetTooltipString() { Stone stone = Stone.Find("Freyja"); return Texts.Get("ssov_freyja_blessing_tooltip", Mathf.RoundToInt(stone.V(0)).ToString(), Mathf.RoundToInt(stone.V(1)).ToString()); } public override void ModifyAttack(SkillType skill, ref HitData hitData) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ((StatusEffect)this).ModifyAttack(skill, ref hitData); if (hitData != null) { ((DamageTypes)(ref hitData.m_damage)).Modify(1f + Stone.Find("Freyja").P(0)); } } } internal static class RuneAltar { [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] private static class UnlockPatch { private static void Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if (__result && (int)mode == 1 && (Object)(object)piece != (Object)null && piece.m_name == "$ssov_altar" && StoneData.Found(__instance).Count == 0) { __result = false; } } } internal const string PrefabName = "SSoV_RuneAltar"; internal const string Token = "$ssov_altar"; private const float Height = 1.7f; private static readonly string[] Bases = new string[3] { "Vegvisir_Eikthyr", "Vegvisir_GDKing", "RuneStone_Meadows" }; internal static void Register() { //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013c: 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_0163: Expected O, but got Unknown //IL_0166: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Expected O, but got Unknown //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_026c: 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_0286: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Expected O, but got Unknown //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Expected O, but got Unknown //IL_03ac: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Expected O, but got Unknown //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Expected O, but got Unknown GameObject val = null; string text = ""; string[] bases = Bases; foreach (string text2 in bases) { if ((Object)(object)PrefabManager.Instance.GetPrefab(text2) != (Object)null) { val = PrefabManager.Instance.CreateClonedPrefab("SSoV_RuneAltar", text2); text = text2; break; } } if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"No vegvisir or runestone to make the rune altar from; the altar is left out."); return; } for (int j = 0; j < 4; j++) { bool flag = false; MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren) { if (!(val2 is ZNetView)) { Object.DestroyImmediate((Object)(object)val2); flag = true; } } if (!flag) { break; } } Rigidbody[] componentsInChildren2 = val.GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody val3 in componentsInChildren2) { Object.DestroyImmediate((Object)(object)val3); } ZNetView val4 = val.GetComponent<ZNetView>(); if ((Object)(object)val4 == (Object)null) { val4 = val.AddComponent<ZNetView>(); } val4.m_persistent = true; Bounds val5 = Bounds(val, val.transform); if (((Bounds)(ref val5)).size.y > 0.01f) { val.transform.localScale = Vector3.one * (1.7f / ((Bounds)(ref val5)).size.y); } foreach (Transform item in val.transform) { Transform val6 = item; val6.localPosition -= new Vector3(((Bounds)(ref val5)).center.x, ((Bounds)(ref val5)).min.y, ((Bounds)(ref val5)).center.z); } val5 = Bounds(val, val.transform); GameObject val7 = new GameObject("SSoV_Hitbox"); val7.layer = LayerMask.NameToLayer("piece"); val7.transform.SetParent(val.transform, false); val7.transform.localPosition = ((Bounds)(ref val5)).center; val7.AddComponent<BoxCollider>().size = ((Bounds)(ref val5)).size; StoneBuilder.Tint(val, new Color(0.65f, 0.8f, 1f)); object[] array = new object[6] { "Rune altar from ", text, ": size ", null, null, null }; Vector3 val8 = ((Bounds)(ref val5)).size * (1.7f / Mathf.Max(((Bounds)(ref val5)).size.y, 0.01f)); array[3] = ((Vector3)(ref val8)).ToString("F2"); array[4] = ", renderers "; array[5] = val.GetComponentsInChildren<Renderer>(true).Length; Plugin.Debug(string.Concat(array)); Piece val9 = val.AddComponent<Piece>(); val9.m_name = "$ssov_altar"; val9.m_description = "$ssov_altar_desc"; val9.m_icon = Runes.Icon(Rune.Ansuz, new Color(0.75f, 0.85f, 1f), "Altar"); WearNTear val10 = val.AddComponent<WearNTear>(); val10.m_materialType = (MaterialType)1; val10.m_health = 1500f; val10.m_noRoofWear = true; val10.m_noSupportWear = true; CopyEffects(val9, val10); val.AddComponent<RuneAltarPiece>(); PieceConfig val11 = new PieceConfig(); val11.Name = "$ssov_altar"; val11.Description = "$ssov_altar_desc"; val11.PieceTable = "Hammer"; val11.Category = "Misc"; val11.Icon = val9.m_icon; val11.Requirements = (RequirementConfig[])(object)new RequirementConfig[2] { new RequirementConfig("Stone", 20, 0, true), new RequirementConfig("Wood", 10, 0, true) }; PieceManager.Instance.AddPiece(new CustomPiece(val, false, val11)); Plugin.Debug("Registered the rune altar"); } private static Bounds Bounds(GameObject go, Transform space) { //IL_0004: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0081: 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_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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_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) bool flag = false; Bounds result = default(Bounds); MeshFilter[] componentsInChildren = go.GetComponentsInChildren<MeshFilter>(false); foreach (MeshFilter val in componentsInChildren) { if ((Object)(object)val.sharedMesh == (Object)null) { continue; } Bounds bounds = val.sharedMesh.bounds; for (int j = 0; j < 8; j++) { Vector3 val2 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1)))); Vector3 val3 = space.InverseTransformPoint(((Component)val).transform.TransformPoint(val2)); if (!flag) { result = new Bounds(val3, Vector3.zero); flag = true; } else { ((Bounds)(ref result)).Encapsulate(val3); } } } return result; } private static void CopyEffects(Piece piece, WearNTear wear) { GameObject prefab = PrefabManager.Instance.GetPrefab("stone_wall_1x1"); if (!((Object)(object)prefab == (Object)null)) { Piece component = prefab.GetComponent<Piece>(); WearNTear component2 = prefab.GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { piece.m_placeEffect = component.m_placeEffect; } if ((Object)(object)component2 != (Object)null) { wear.m_destroyedEffect = component2.m_destroyedEffect; wear.m_hitEffect = component2.m_hitEffect; } } } } internal class RuneAltarPiece : MonoBehaviour, Hoverable, Interactable { public string GetHoverName() { return Localization.instance.Localize("$ssov_altar"); } public string GetHoverText() { return Localization.instance.Localize("$ssov_altar\n[<color=yellow><b>$KEY_Use</b></color>] $ssov_altar_open"); } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_002a: 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) if (hold) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } AltarPanel.Open(val, ((Component)this).transform.position); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public float GetHoverOffset() { return 0f; } } internal static class AltarPanel { private class Row { internal Stone Stone; internal Text Info; internal GameObject Button; internal Text ButtonLabel; } private const float RowHeight = 42f; private const float Width = 900f; private static GameObject panel; private static Vector3 altarAt; private static float openedAt; private static string status = ""; private static Color statusColor = Color.white; private static readonly List<Row> rows = new List<Row>(); private static Text statusText; internal static bool IsOpen => (Object)(object)panel != (Object)null; internal static void Open(Player player, Vector3 at) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) altarAt = at; openedAt = Time.time; status = ""; Build(player); } internal static void Close() { if (!((Object)(object)panel == (Object)null)) { Object.Destroy((Object)(object)panel); panel = null; GUIManager.BlockInput(false); } } internal static void Tick() { //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) if (!((Object)(object)panel == (Object)null)) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || Vector3.Distance(((Component)localPlayer).transform.position, altarAt) > 6f || Input.GetKeyDown((KeyCode)27) || (Time.time - openedAt > 0.3f && ZInput.GetButtonDown("Use"))) { Close(); } } } private static void Build(Player player) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: 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_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Expected O, but got Unknown //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Expected O, but got Unknown if ((Object)(object)panel != (Object)null) { return; } GUIManager instance = GUIManager.Instance; if (instance == null || (Object)(object)GUIManager.CustomGUIFront == (Object)null) { return; } List<Stone> list = new List<Stone>(); Stone[] all = Stone.All; foreach (Stone stone in all) { if (StoneData.HasFound(player, stone.Id)) { list.Add(stone); } } float num = 215f + (float)Mathf.Max(1, list.Count) * 42f; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 0.5f); panel = instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, val, val, Vector2.zero, 900f, num, false); rows.Clear(); Text(Localization.instance.Localize("$ssov_altar"), 0f, -38f, 840f, 30, instance.AveriaSerifBold, (TextAnchor)4, new Color(1f, 0.82f, 0.45f)); Text(Texts.Get("ssov_altar_help"), 0f, -82f, 820f, 16, instance.AveriaSerif, (TextAnchor)4, Color.white); if (list.Count == 0) { Text(Texts.Get("ssov_altar_empty"), 0f, -130f, 820f, 18, instance.AveriaSerif, (TextAnchor)4, Color.white); } for (int j = 0; j < list.Count; j++) { Row row = new Row(); row.Stone = list[j]; float y = -130f - (float)j * 42f; Icon(row.Stone, -405f, y); Text(Localization.instance.Localize(row.Stone.NameToken), -245f, y, 260f, 18, instance.AveriaSerifBold, (TextAnchor)3, Color.Lerp(row.Stone.Glow, Color.white, 0.55f)); row.Info = Text("", 120f, y, 400f, 15, instance.AveriaSerif, (TextAnchor)3, Color.white); Row target = row; row.Button = Button("", 360f, y, (UnityAction)delegate { Clicked(target); }); row.ButtonLabel = row.Button.GetComponentInChildren<Text>(); rows.Add(row); } statusText = Text("", 0f, 0f - num + 88f, 820f, 17, instance.AveriaSerifBold, (TextAnchor)4, Color.white); Button(Texts.Get("ssov_altar_close"), 0f, 0f - num + 40f, new UnityAction(Close)); Refresh(player); GUIManager.BlockInput(true); } private static void Clicked(Row row) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)panel == (Object)null)) { if (StoneData.HasBound(localPlayer, row.Stone.Id)) { StandingStone.Choose(localPlayer, row.Stone); Tell(Texts.Get("ssov_chosen", row.Stone.NameToken), Color.Lerp(row.Stone.Glow, Color.white, 0.55f)); } else { Bind(localPlayer, row.Stone); } Refresh(localPlayer); } } private static void Refresh(Player player) { //IL_0111: Unknown result type (might be due to invalid IL or missing references) Stone stone = StoneData.Active(player); foreach (Row row in rows) { bool flag = StoneData.HasBound(player, row.Stone.Id); row.Info.text = ((!flag) ? Texts.Get("ssov_altar_offering", OfferingText(row.Stone)) : ((row.Stone == stone) ? Texts.Get("ssov_altar_chosen") : "")); row.Button.SetActive(!flag || row.Stone != stone); if ((Object)(object)row.ButtonLabel != (Object)null) { row.ButtonLabel.text = Texts.Get(flag ? "ssov_altar_choose" : "ssov_altar_bind"); } } if ((Object)(object)statusText != (Object)null) { statusText.text = status; ((Graphic)statusText).color = statusColor; } } private static Text Text(string text, float x, float y, float width, int size, Font font, TextAnchor anchor, Color color) { //IL_0021: 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_0025: 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_0031: 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) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 1f); GameObject val2 = GUIManager.Instance.CreateText(text, panel.transform, val, val, new Vector2(x, y), font, size, color, true, Color.black, width, 42f, false); Text component = val2.GetComponent<Text>(); if ((Object)(object)component != (Object)null) { component.alignment = anchor; } return component; } private static void Icon(Stone stone, float x, float y) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("icon", new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(panel.transform, false); RectTransform component = val.GetComponent<RectTransform>(); Vector2 anchorMin = (component.anchorMax = new Vector2(0.5f, 1f)); component.anchorMin = anchorMin; component.anchoredPosition = new Vector2(x, y); component.sizeDelta = new Vector2(34f, 34f); val.GetComponent<Image>().sprite = Runes.Icon(stone); } private static GameObject Button(string text, float x, float y, UnityAction onClick) { //IL_0021: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 1f); GameObject val2 = GUIManager.Instance.CreateButton(text, panel.transform, val, val, new Vector2(x, y), 140f, 34f); Button component = val2.GetComponent<Button>(); ((UnityEvent)component.onClick).AddListener((UnityAction)delegate { if ((Object)(object)EventSystem.current != (Object)null) { EventSystem.current.SetSelectedGameObject((GameObject)null); } }); ((UnityEvent)component.onClick).AddListener(onClick); return val2; } internal static string OfferingText(Stone stone) { List<string> list = new List<string>(); Offering[] offerings = stone.Offerings; foreach (Offering offering in offerings) { ItemDrop val = ItemOf(offering); list.Add(Texts.Amount(offering.Amount, ((Object)(object)val != (Object)null) ? val.m_itemData.m_shared.m_name : offering.Item)); } return string.Join(", ", list.ToArray()); } private static ItemDrop ItemOf(Offering offering) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(offering.Item) : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.GetComponent<ItemDrop>(); } private static void Bind(Player player, Stone stone) { //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: 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) //IL_0081: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = ((Humanoid)player).GetInventory(); bool flag = player.NoCostCheat(); Offering[] offerings = stone.Offerings; foreach (Offering offering in offerings) { ItemDrop val = ItemOf(offering); if (!((Object)(object)val == (Object)null) && !flag && inventory.CountItems(val.m_itemData.m_shared.m_name, -1, false) < offering.Amount) { Tell(Texts.Get("ssov_altar_missing", OfferingText(stone)), new Color(1f, 0.55f, 0.45f)); return; } } if (!flag) { Offering[] offerings2 = stone.Offerings; foreach (Offering offering2 in offerings2) { ItemDrop val2 = ItemOf(offering2); if ((Object)(object)val2 != (Object)null) { inventory.RemoveItem(val2.m_itemData.m_shared.m_name, offering2.Amount, -1, false); } } } StoneData.AddBound(player, stone.Id); Tell(Texts.Get("ssov_altar_bound", stone.NameToken), Color.Lerp(stone.Glow, Color.white, 0.55f)); StoneEvents.PlayChooseEffect(player); } private static void Tell(string text, Color color) { //IL_0006: 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) status = text; statusColor = color; } } internal enum Rune { Tiwaz, Mannaz, Othala, Ingwaz, Eihwaz, Hagalaz, Berkano, Isa, Algiz, Thurisaz, Sowilo, Ansuz, Fehu, Kenaz, Uruz, Laguz } internal static class Runes { private static readonly Dictionary<string, Sprite> icons = new Dictionary<string, Sprite>(); private static Sprite dot; private static Vector2[][] Strokes(Rune rune) { return rune switch { Rune.Tiwaz => L(P(0.5f, 0.1f, 0.5f, 0.9f), P(0.25f, 0.65f, 0.5f, 0.9f, 0.75f, 0.65f)), Rune.Mannaz => L(P(0.3f, 0.1f, 0.3f, 0.9f), P(0.7f, 0.1f, 0.7f, 0.9f), P(0.3f, 0.9f, 0.7f, 0.55f), P(0.7f, 0.9f, 0.3f, 0.55f)), Rune.Othala => L(P(0.22f, 0.1f, 0.72f, 0.6f, 0.5f, 0.88f, 0.28f, 0.6f, 0.78f, 0.1f)), Rune.Ingwaz => L(P(0.5f, 0.15f, 0.78f, 0.5f, 0.5f, 0.85f, 0.22f, 0.5f, 0.5f, 0.15f)), Rune.Eihwaz => L(P(0.5f, 0.1f, 0.5f, 0.9f), P(0.5f, 0.9f, 0.72f, 0.72f), P(0.5f, 0.1f, 0.28f, 0.28f)), Rune.Hagalaz => L(P(0.3f, 0.1f, 0.3f, 0.9f), P(0.7f, 0.1f, 0.7f, 0.9f), P(0.3f, 0.62f, 0.7f, 0.38f)), Rune.Berkano => L(P(0.35f, 0.1f, 0.35f, 0.9f), P(0.35f, 0.9f, 0.68f, 0.7f, 0.35f, 0.5f, 0.68f, 0.3f, 0.35f, 0.1f)), Rune.Isa => L(P(0.5f, 0.1f, 0.5f, 0.9f)), Rune.Algiz => L(P(0.5f, 0.1f, 0.5f, 0.9f), P(0.25f, 0.85f, 0.5f, 0.5f, 0.75f, 0.85f)), Rune.Thurisaz => L(P(0.36f, 0.1f, 0.36f, 0.9f), P(0.36f, 0.72f, 0.66f, 0.5f, 0.36f, 0.28f)), Rune.Sowilo => L(P(0.66f, 0.9f, 0.34f, 0.6f, 0.66f, 0.4f, 0.34f, 0.1f)), Rune.Ansuz => L(P(0.36f, 0.1f, 0.36f, 0.9f), P(0.36f, 0.9f, 0.7f, 0.68f), P(0.36f, 0.68f, 0.7f, 0.46f)), Rune.Fehu => L(P(0.36f, 0.1f, 0.36f, 0.9f), P(0.36f, 0.6f, 0.72f, 0.86f), P(0.36f, 0.38f, 0.72f, 0.64f)), Rune.Kenaz => L(P(0.64f, 0.85f, 0.36f, 0.5f, 0.64f, 0.15f)), Rune.Uruz => L(P(0.3f, 0.1f, 0.3f, 0.9f, 0.7f, 0.66f, 0.7f, 0.1f)), _ => L(P(0.42f, 0.1f, 0.42f, 0.9f, 0.7f, 0.64f)), }; } private static Vector2[][] L(params Vector2[][] lines) { return lines; } private static Vector2[] P(params float[] xy) { //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) Vector2[] array = (Vector2[])(object)new Vector2[xy.Length / 2]; for (int i = 0; i < array.Length; i++) { ref Vector2 reference = ref array[i]; reference = new Vector2(xy[2 * i], xy[2 * i + 1]); } return array; } private static float Distance(Vector2[][] strokes, Vector2 p) { //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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_003e: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_0067: 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_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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) float num = 10f; foreach (Vector2[] array in strokes) { for (int j = 0; j + 1 < array.Length; j++) { Vector2 val = array[j]; Vector2 val2 = array[j + 1] - val; float num2 = Mathf.Clamp01(Vector2.Dot(p - val, val2) / Mathf.Max(((Vector2)(ref val2)).sqrMagnitude, 1E-06f)); float num3 = num; Vector2 val3 = val + val2 * num2 - p; num = Mathf.Min(num3, ((Vector2)(ref val3)).magnitude); } } return num; } internal static Sprite Icon(Stone stone) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return Icon(stone.Rune, stone.Glow, stone.Id); } internal static Sprite Icon(Rune rune, Color glow, string key) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: 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_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0163: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) if (icons.TryGetValue(key, out var value)) { return value; } Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); Vector2[][] strokes = Strokes(rune); Color[] array = (Color[])(object)new Color[4096]; Vector2 val2 = default(Vector2); Vector2 p = default(Vector2); Color val4 = default(Color); for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { ((Vector2)(ref val2))..ctor(((float)j + 0.5f) / 64f, ((float)i + 0.5f) / 64f); ((Vector2)(ref p))..ctor((val2.x - 0.5f) / 0.78f + 0.5f, (val2.y - 0.44f) / 0.76f + 0.5f); float num = Distance(strokes, p); float num2 = Mathf.Clamp01((0.075f - num) / 0.018f); float num3 = Mathf.Clamp01((0.115f - num) / 0.018f); float num4 = Mathf.Clamp01((0.24f - num) / 0.13f); Color val3 = Color.Lerp(glow, Color.white, 0.35f + 0.35f * Mathf.Clamp01(1f - num / 0.05f)); ((Color)(ref val4))..ctor(glow.r, glow.g, glow.b, num4 * num4 * 0.45f); val4 = Color.Lerp(val4, new Color(0.06f, 0.05f, 0.04f, 1f), num3); val4 = Color.Lerp(val4, val3, num2); val4.a = Mathf.Max(val4.a, Mathf.Max(num3, num2)); array[i * 64 + j] = val4; } } val.SetPixels(array); val.Apply(); value = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f)); ((Object)value).name = "SSoV_Icon_" + key; icons[key] = value; return value; } internal static Sprite Dot() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0106: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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) if ((Object)(object)dot != (Object)null) { return dot; } Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false); Color[] array = (Color[])(object)new Color[1024]; for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { Vector2 val2 = new Vector2((float)j + 0.5f - 16f, (float)i + 0.5f - 16f); float num = ((Vector2)(ref val2)).magnitude / 16f; Color val3 = ((num < 0.62f) ? new Color(0.95f, 0.15f, 0.1f) : new Color(0.1f, 0.02f, 0.02f)); val3.a = Mathf.Clamp01((0.95f - num) * 12f); array[i * 32 + j] = val3; } } val.SetPixels(array); val.Apply(); dot = Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f)); ((Object)dot).name = "SSoV_Heimdall"; return dot; } internal static Sprite Carving(Stone stone) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0121: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_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_00d4: 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) Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false); Vector2[][] strokes = Strokes(stone.Rune); Color glow = stone.Glow; Color[] array = (Color[])(object)new Color[16384]; for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { float num = Distance(strokes, new Vector2(((float)j + 0.5f) / 128f, ((float)i + 0.5f) / 128f)); float num2 = Mathf.Clamp01((0.045f - num) / 0.012f); float num3 = Mathf.Clamp01((0.12f - num) / 0.075f); Color val2 = Color.Lerp(glow, Color.white, num2 * 0.35f); val2.a = Mathf.Max(num2, num3 * num3 * 0.55f); array[i * 128 + j] = val2; } } val.SetPixels(array); val.Apply(); Sprite val3 = Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f), 128f); ((Object)val3).name = "SSoV_Rune_" + stone.Id; return val3; } } internal class StandingStone : MonoBehaviour, Hoverable, Interactable { public string m_stoneId; private Stone Stone => Stone.Find(m_stoneId); public string GetHoverName() { Stone stone = Stone; if (stone == null) { return ""; } return Localization.instance.Localize(stone.NameToken); } public string GetHoverText() { Stone stone = Stone; Player localPlayer = Player.m_localPlayer; if (stone == null || (Object)(object)localPlayer == (Object)null) { return ""; } string text = stone.NameToken + "\n[<color=yellow><b>$KEY_Use</b></color>] $ssov_read"; text = ((!StoneData.IsActive(localPlayer, stone.Id)) ? (text + "\n[<color=yellow><b>" + (ZInput.IsGamepadActive() ? "$KEY_AltKeys + $KEY_Use" : "$KEY_AltPlace + $KEY_Use") + "</b></color>] $ssov_choose") : (text + "\n<color=#9fd49f>$ssov_is_chosen</color>")); return Localization.instance.Localize(text); } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } Player val = (Player)(object)((user is Player) ? user : null); Stone stone = Stone; if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || stone == null) { return false; } bool flag = StoneData.AddFound(val, stone.Id); if (alt) { Choose(val, stone); } else { Read(stone); } if (flag) { StoneEvents.FoundFirstTime(val, stone, ((Component)this).transform.position); } if (flag || !alt) { Hints.Ask(stone, ((Component)this).transform.position); } return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public float GetHoverOffset() { return 0f; } private static void Read(Stone stone) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) string text = Texts.Get("ssov_kind_" + stone.Kind.ToString().ToLowerInvariant()); string text2 = ColorUtility.ToHtmlStringRGB(Color.Lerp(stone.Glow, Color.white, 0.25f)); string text3 = Texts.Get(stone.Key + "_lore") + "\n\n<color=#" + text2 + ">" + text + "</color>\n" + stone.EffectText(); TextViewer.instance.ShowText((Style)0, Localization.instance.Localize(stone.NameToken), text3, true); } internal static void Choose(Player player, Stone stone) { if (StoneData.IsActive(player, stone.Id)) { ((Character)player).Message((MessageType)2, Texts.Get("ssov_already_chosen", stone.NameToken), 0, (Sprite)null, false); return; } StoneData.SetActive(player, stone); StoneEffects.Apply(player); ((Character)player).Message((MessageType)2, Texts.Get("ssov_chosen", stone.NameToken), 0, Runes.Icon(stone), false); StoneEvents.PlayChooseEffect(player); } } internal static class StoneEvents { private static readonly string[] ChooseEffects = new string[2] { "fx_GP_Activation", "sfx_runestone_activate" }; private static readonly MethodInfo updateKnown = AccessTools.Method(typeof(Player), "UpdateKnownRecipesList", (Type[])null, (Type[])null); internal static void PlayChooseEffect(Player player) { //IL_003a: 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) string[] chooseEffects = ChooseEffects; foreach (string text in chooseEffects) { GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(text) : null); if (!((Object)(object)val == (Object)null)) { Object.Instantiate<GameObject>(val, ((Component)player).transform.position, Quaternion.identity); break; } } } internal static void FoundFirstTime(Player player, Stone stone, Vector3 at) { ((Character)player).Message((MessageType)1, Texts.Get("ssov_found", stone.NameToken), 0, Runes.Icon(stone), false); if (updateKnown != null) { updateKnown.Invoke(player, null); } Plugin.Debug(player.GetPlayerName() + " found " + stone.Id + " at " + ((Vector3)(ref at)).ToString("F0")); } } internal enum StoneKind { Path, Always, Cost, Daily } internal class StoneValue { internal readonly string Name; internal readonly float Default; internal readonly float Max; internal readonly string Description; internal ConfigEntry<float> Entry; internal StoneValue(string name, float value, float max, string description) { Name = name; Default = value; Max = max; Description = description; } } internal class Offering { internal readonly string Item; internal readonly int Amount; internal Offering(string item, int amount) { Item = item; Amount = amount; } } internal class Stone { private const Biome Shore = (Biome)25; internal readonly string Id; internal readonly StoneKind Kind; internal readonly Biome Biome; internal readonly bool Coast; internal readonly string Land; internal readonly Rune Rune; internal readonly SkillType[] Skills; internal readonly StoneValue[] Values; internal readonly Offering[] Offerings; internal static readonly Stone[] All = new Stone[16] { new Stone("Tyr", StoneKind.Path, (Biome)1, "ssov_land_meadows", Rune.Tiwaz, (SkillType