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 RagnaroksWrath v0.29.1
plugins/RagnaroksWrath.dll
Decompiled 17 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using RavenIron.RagnaroksWrath.Client; using RavenIron.RagnaroksWrath.Config; using RavenIron.RagnaroksWrath.Core; using RavenIron.RagnaroksWrath.Feedback; using RavenIron.RagnaroksWrath.Net; using RavenIron.RagnaroksWrath.Systems; using RavenIron.RagnaroksWrath.Systems.World; using RavenIron.RagnaroksWrath.Visuals; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("Raven Iron")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.29.1.0")] [assembly: AssemblyInformationalVersion("0.29.1+fafe091cadc7d9fb43403dfda22c261076e244fb")] [assembly: AssemblyProduct("Ragnarok's Wrath")] [assembly: AssemblyTitle("RagnaroksWrath")] [assembly: AssemblyVersion("0.29.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace RavenIron.RagnaroksWrath { [BepInPlugin("com.raveniron.ragnarokswrath", "Ragnarok's Wrath", "0.29.1")] [BepInProcess("valheim.exe")] [BepInProcess("valheim_server.exe")] public class RagnaroksWrath : BaseUnityPlugin { public const string PluginId = "com.raveniron.ragnarokswrath"; public const string PluginName = "Ragnarok's Wrath"; public const string PluginVersion = "0.29.1"; private Harmony _harmony; public static RagnaroksWrath Instance { get; private set; } public static ManualLogSource Log { get; private set; } public static bool IsSimulationAuthority() { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return false; } return instance.IsServer(); } public static bool IsDedicated() { ZNet instance = ZNet.instance; if ((Object)(object)instance != (Object)null) { return instance.IsDedicated(); } return false; } private void Awake() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 Instance = this; Log = ((BaseUnityPlugin)this).Logger; ConfigFile advanced = new ConfigFile(Path.Combine(Paths.ConfigPath, "com.raveniron.ragnarokswrath.advanced.cfg"), false, ((BaseUnityPlugin)this).Info.Metadata); ModConfig.Bind(((BaseUnityPlugin)this).Config, advanced); _harmony = new Harmony("com.raveniron.ragnarokswrath"); _harmony.PatchAll(); ((Component)this).gameObject.AddComponent<WorldTick>(); RegisterSystems(); if ((int)SystemInfo.graphicsDeviceType != 4) { ((Component)this).gameObject.AddComponent<PlagueFog>(); ((Component)this).gameObject.AddComponent<FrostBreath>(); ((Component)this).gameObject.AddComponent<ScorchAsh>(); ((Component)this).gameObject.AddComponent<RelicRunes>(); ((Component)this).gameObject.AddComponent<HealthEffects>(); ((Component)this).gameObject.AddComponent<ConsequenceEffects>(); } Log.LogInfo((object)"Ragnarok's Wrath v0.29.1 loaded."); } internal static void RegisterSystems() { WorldTick.Register(new SeasonSystem()); WorldTick.Register(new WeatherSystem()); WorldTick.Register(new WindSystem()); WorldTick.Register(new BiomeStateSystem()); WorldTick.Register(new FireSystem()); WorldTick.Register(new PlagueSystem()); WorldTick.Register(new EcologySystem()); WorldTick.Register(new FarmingSystem()); WorldTick.Register(new WorldStateSystem()); WorldTick.Register(new HealthSystem()); WorldTick.Register(new ConsequenceSystem()); WorldTick.Register(new RivalrySystem()); WorldTick.Register(new RelicSystem()); WorldTick.Register(new TitleSystem()); WorldTick.Register(new ZoneSyncSystem()); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; Instance = null; } } } namespace RavenIron.RagnaroksWrath.Visuals { public class FrostBreath : MonoBehaviour { private const float CheckInterval = 0.5f; private ParticleSystem _system; private bool _buildFailed; private float _nextCheck; private float _nextBreath; private void Update() { //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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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) //IL_00ee: 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_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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) if (Time.time < _nextCheck) { return; } _nextCheck = Time.time + 0.5f; try { ZoneSync.EnsureRegistered(); SeasonSync.EnsureRegistered(); if (!ModConfig.FrostBreathEnabled.Value) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || localPlayer.InShelter()) { return; } Vector3 position = ((Component)localPlayer).transform.position; float frost = ZoneSync.StateAt(ZoneKey.FromWorldPos(position)).Frost; if (!float.IsNaN(frost) && !(frost < ModConfig.FrostBreathFloor.Value) && !(Time.time < _nextBreath)) { if ((Object)(object)_system == (Object)null && !_buildFailed) { Build(); } if (!((Object)(object)_system == (Object)null)) { ((Component)_system).transform.position = position + Vector3.up * 1.55f + ((Component)localPlayer).transform.forward * 0.25f; ((Component)_system).transform.rotation = ((Component)localPlayer).transform.rotation; _system.Emit(3 + Mathf.RoundToInt(Mathf.Clamp01(frost) * 4f)); _nextBreath = Time.time + Random.Range(3.2f, 4.4f); } } } catch (Exception ex) { _buildFailed = true; RagnaroksWrath.Log.LogWarning((object)("FrostBreath: disabled after error: " + ex.Message)); } } private void Build() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0095: 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_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_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject("ragnarokswrath_frost_breath"); val.transform.SetParent(((Component)this).transform, false); _system = val.AddComponent<ParticleSystem>(); MainModule main = _system.main; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.8f, 1.4f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.25f, 0.55f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.12f, 0.3f); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.92f, 0.96f, 1f, 0.3f)); ((MainModule)(ref main)).maxParticles = 64; ShapeModule shape = _system.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4; ((ShapeModule)(ref shape)).angle = 14f; ((ShapeModule)(ref shape)).radius = 0.04f; EmissionModule emission = _system.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f); ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>(); ((Renderer)component).material = ParticleKit.BuildMaterial("FrostBreath"); component.sortMode = (ParticleSystemSortMode)1; RagnaroksWrath.Log.LogInfo((object)"FrostBreath: emitter built."); } catch (Exception ex) { _buildFailed = true; if ((Object)(object)_system != (Object)null) { Object.Destroy((Object)(object)((Component)_system).gameObject); _system = null; } RagnaroksWrath.Log.LogWarning((object)("FrostBreath: build failed, breath disabled: " + ex.Message)); } } } internal static class ParticleKit { private static readonly string[] CandidateShaders = new string[6] { "Particles/Standard Unlit", "Legacy Shaders/Particles/Alpha Blended", "Sprites/Default", "UI/Default", "Particles/Standard Surface", "Legacy Shaders/Particles/Additive" }; public static Material BuildMaterial(string owner) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) Shader val = FindShader(owner); Texture2D val2 = new Texture2D(64, 64, (TextureFormat)4, false); float num = 31.5f; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num2 = ((float)j - num) / num; float num3 = ((float)i - num) / num; float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3); float num5 = Mathf.Clamp01(1f - num4); val2.SetPixel(j, i, new Color(1f, 1f, 1f, num5 * num5)); } } val2.Apply(); return new Material(val) { mainTexture = (Texture)(object)val2 }; } private static Shader FindShader(string owner) { string[] candidateShaders = CandidateShaders; foreach (string text in candidateShaders) { Shader val = Shader.Find(text); if ((Object)(object)val != (Object)null) { RagnaroksWrath.Log.LogInfo((object)(owner + ": using shader '" + text + "'.")); return val; } } throw new InvalidOperationException("no particle shader available"); } public static Material BuildRuneMaterial(string owner) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) Shader val = FindShader(owner); Texture2D val2 = new Texture2D(128, 128, (TextureFormat)4, false); Color val3 = default(Color); ((Color)(ref val3))..ctor(1f, 1f, 1f, 0f); for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { val2.SetPixel(j, i, val3); } } DrawStroke(val2, 0, 0, 64, 0.38f, 0.1f, 0.38f, 0.9f); DrawStroke(val2, 0, 0, 64, 0.38f, 0.86f, 0.72f, 0.98f); DrawStroke(val2, 0, 0, 64, 0.38f, 0.62f, 0.72f, 0.74f); DrawStroke(val2, 1, 0, 64, 0.5f, 0.1f, 0.5f, 0.9f); DrawStroke(val2, 1, 0, 64, 0.5f, 0.62f, 0.24f, 0.92f); DrawStroke(val2, 1, 0, 64, 0.5f, 0.62f, 0.76f, 0.92f); DrawStroke(val2, 0, 1, 64, 0.18f, 0.14f, 0.82f, 0.86f); DrawStroke(val2, 0, 1, 64, 0.82f, 0.14f, 0.18f, 0.86f); DrawStroke(val2, 1, 1, 64, 0.36f, 0.08f, 0.36f, 0.92f); DrawStroke(val2, 1, 1, 64, 0.36f, 0.7f, 0.72f, 0.5f); DrawStroke(val2, 1, 1, 64, 0.72f, 0.5f, 0.36f, 0.3f); val2.Apply(); return new Material(val) { mainTexture = (Texture)(object)val2 }; } private static void DrawStroke(Texture2D tex, int tileX, int tileY, int tile, float x0, float y0, float x1, float y1) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0058: 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_005a: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(x0, y0); Vector2 val2 = new Vector2(x1, y1) - val; float num = Mathf.Max(((Vector2)(ref val2)).sqrMagnitude, 1E-06f); for (int i = 0; i < tile; i++) { for (int j = 0; j < tile; j++) { Vector2 val3 = new Vector2(((float)j + 0.5f) / (float)tile, ((float)i + 0.5f) / (float)tile); float num2 = Mathf.Clamp01(Vector2.Dot(val3 - val, val2) / num); float num3 = Vector2.Distance(val3, val + val2 * num2); if (!(num3 >= 0.055f)) { float num4 = Mathf.Clamp01((0.055f - num3) / 0.01925f); int num5 = tileX * tile + j; int num6 = tileY * tile + i; Color pixel = tex.GetPixel(num5, num6); if (num4 > pixel.a) { tex.SetPixel(num5, num6, new Color(1f, 1f, 1f, num4)); } } } } } } public class PlagueFog : MonoBehaviour { private const float UpdateInterval = 1f; private ParticleSystem _system; private bool _buildFailed; private float _nextUpdate; private void Update() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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) if (Time.time < _nextUpdate) { return; } _nextUpdate = Time.time + 1f; try { ZoneSync.EnsureRegistered(); SeasonSync.EnsureRegistered(); if (!ModConfig.PlagueFogEnabled.Value) { SetEmission(0f); return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { SetEmission(0f); return; } if (localPlayer.InShelter()) { SetEmission(0f); return; } Vector3 position = ((Component)localPlayer).transform.position; float num = FogMath.EmissionFor(ZoneSync.StateAt(ZoneKey.FromWorldPos(position)).Plague, ModConfig.PlagueFogDensity.Value); if (num > 0f && (Object)(object)_system == (Object)null && !_buildFailed) { Build(); } if (!((Object)(object)_system == (Object)null)) { ((Component)_system).transform.position = position + Vector3.up * 0.5f; SetEmission(num); } } catch (Exception ex) { _buildFailed = true; RagnaroksWrath.Log.LogWarning((object)("PlagueFog: disabled after error: " + ex.Message)); } } private void SetEmission(float rate) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_system == (Object)null)) { EmissionModule emission = _system.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(rate); } } private void Build() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0095: 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_00b6: 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_00d5: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject("ragnarokswrath_plague_fog"); val.transform.SetParent(((Component)this).transform, false); _system = val.AddComponent<ParticleSystem>(); MainModule main = _system.main; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(6f, 10f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.05f, 0.2f); ((MainModule)(ref main)).startSize = new MinMaxCurve(2.5f, 4.5f); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.42f, 0.5f, 0.38f, 0.16f)); ((MainModule)(ref main)).maxParticles = 600; ShapeModule shape = _system.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)5; ((ShapeModule)(ref shape)).scale = new Vector3(42f, 2.5f, 42f); EmissionModule emission = _system.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f); ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>(); ((Renderer)component).material = ParticleKit.BuildMaterial("PlagueFog"); component.sortMode = (ParticleSystemSortMode)1; RagnaroksWrath.Log.LogInfo((object)"PlagueFog: emitter built."); } catch (Exception ex) { _buildFailed = true; if ((Object)(object)_system != (Object)null) { Object.Destroy((Object)(object)((Component)_system).gameObject); _system = null; } RagnaroksWrath.Log.LogWarning((object)("PlagueFog: build failed, fog disabled: " + ex.Message)); } } } public class RelicRunes : MonoBehaviour { private const float UpdateInterval = 1f; private const float EmissionRate = 3f; private static readonly Color Blessed = new Color(0.79f, 0.71f, 0.35f, 0.85f); private static readonly Color Cursed = new Color(0.71f, 0.31f, 0.31f, 0.85f); private readonly Dictionary<ZoneKey, ParticleSystem> _columns = new Dictionary<ZoneKey, ParticleSystem>(4); private readonly List<ZoneKey> _dead = new List<ZoneKey>(4); private Material _material; private bool _buildFailed; private float _nextUpdate; private void Update() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (Time.time < _nextUpdate) { return; } _nextUpdate = Time.time + 1f; try { RelicSync.EnsureRegistered(); Player localPlayer = Player.m_localPlayer; bool flag = ModConfig.RelicRunesEnabled.Value && (Object)(object)localPlayer != (Object)null && !_buildFailed; _dead.Clear(); ZoneKey zoneKey = (flag ? ZoneKey.FromWorldPos(((Component)localPlayer).transform.position) : default(ZoneKey)); foreach (KeyValuePair<ZoneKey, ParticleSystem> column in _columns) { if (!flag || Math.Abs(column.Key.X - zoneKey.X) > 1 || Math.Abs(column.Key.Y - zoneKey.Y) > 1 || !RelicSync.RelicAt(column.Key).Standing) { _dead.Add(column.Key); } } for (int i = 0; i < _dead.Count; i++) { ParticleSystem val = _columns[_dead[i]]; _columns.Remove(_dead[i]); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } if (!flag) { return; } for (int j = -1; j <= 1; j++) { for (int k = -1; k <= 1; k++) { ZoneKey zoneKey2 = new ZoneKey(zoneKey.X + j, zoneKey.Y + k); if (_columns.ContainsKey(zoneKey2)) { continue; } RelicLedger.Relic relic = RelicSync.RelicAt(zoneKey2); if (relic.Standing) { ParticleSystem val2 = BuildColumn(zoneKey2, relic.Cursed); if ((Object)(object)val2 != (Object)null) { _columns[zoneKey2] = val2; } } } } } catch (Exception ex) { _buildFailed = true; RagnaroksWrath.Log.LogWarning((object)("RelicRunes: disabled after error: " + ex.Message)); } } private ParticleSystem BuildColumn(ZoneKey zone, bool cursed) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_018a: 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_0198: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_material == (Object)null) { _material = ParticleKit.BuildRuneMaterial("RelicRunes"); } Vector3 val = zone.ToWorldPos(); Vector3 val2 = default(Vector3); Biome val3 = default(Biome); BiomeArea val4 = default(BiomeArea); Heightmap val5 = default(Heightmap); ZoneSystem.instance.GetGroundData(ref val, ref val2, ref val3, ref val4, ref val5); GameObject val6 = new GameObject($"ragnarokswrath_relic_runes_{zone.X}_{zone.Y}"); val6.transform.SetParent(((Component)this).transform, false); val6.transform.position = val + Vector3.up * 0.4f; ParticleSystem obj = val6.AddComponent<ParticleSystem>(); MainModule main = obj.main; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(4f, 6f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.25f, 0.45f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.28f, 0.42f); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(cursed ? Cursed : Blessed); ((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0f); ((MainModule)(ref main)).maxParticles = 64; ShapeModule shape = obj.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)10; ((ShapeModule)(ref shape)).radius = 1.2f; TextureSheetAnimationModule textureSheetAnimation = obj.textureSheetAnimation; ((TextureSheetAnimationModule)(ref textureSheetAnimation)).enabled = true; ((TextureSheetAnimationModule)(ref textureSheetAnimation)).numTilesX = 2; ((TextureSheetAnimationModule)(ref textureSheetAnimation)).numTilesY = 2; ((TextureSheetAnimationModule)(ref textureSheetAnimation)).animation = (ParticleSystemAnimationType)0; ((TextureSheetAnimationModule)(ref textureSheetAnimation)).frameOverTime = new MinMaxCurve(0f); ((TextureSheetAnimationModule)(ref textureSheetAnimation)).startFrame = new MinMaxCurve(0f, 1f); EmissionModule emission = obj.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(3f); ParticleSystemRenderer component = val6.GetComponent<ParticleSystemRenderer>(); ((Renderer)component).material = _material; component.sortMode = (ParticleSystemSortMode)1; RagnaroksWrath.Log.LogInfo((object)string.Format("RelicRunes: column raised at {0} ({1}).", zone, cursed ? "cursed" : "blessed")); return obj; } catch (Exception ex) { _buildFailed = true; RagnaroksWrath.Log.LogWarning((object)("RelicRunes: build failed, runes disabled: " + ex.Message)); return null; } } } public class ScorchAsh : MonoBehaviour { private const float UpdateInterval = 1f; private ParticleSystem _system; private bool _buildFailed; private float _nextUpdate; private void Update() { //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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) if (Time.time < _nextUpdate) { return; } _nextUpdate = Time.time + 1f; try { ZoneSync.EnsureRegistered(); if (!ModConfig.ScorchAshEnabled.Value) { SetEmission(0f); return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { SetEmission(0f); return; } if (localPlayer.InShelter()) { SetEmission(0f); return; } Vector3 position = ((Component)localPlayer).transform.position; float num = AshMath.EmissionFor(ZoneSync.StateAt(ZoneKey.FromWorldPos(position)).Scorch, ModConfig.ScorchAshDensity.Value); if (num > 0f && (Object)(object)_system == (Object)null && !_buildFailed) { Build(); } if (!((Object)(object)_system == (Object)null)) { ((Component)_system).transform.position = position + Vector3.up * 3.5f; SetEmission(num); } } catch (Exception ex) { _buildFailed = true; RagnaroksWrath.Log.LogWarning((object)("ScorchAsh: disabled after error: " + ex.Message)); } } private void SetEmission(float rate) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_system == (Object)null)) { EmissionModule emission = _system.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(rate); } } private void Build() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0095: 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_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_00cc: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject("ragnarokswrath_scorch_ash"); val.transform.SetParent(((Component)this).transform, false); _system = val.AddComponent<ParticleSystem>(); MainModule main = _system.main; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(5f, 9f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.02f, 0.1f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.12f, 0.3f); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.16f, 0.15f, 0.14f, 0.75f)); ((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0.015f); ((MainModule)(ref main)).maxParticles = 800; ShapeModule shape = _system.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)5; ((ShapeModule)(ref shape)).scale = new Vector3(28f, 1.5f, 28f); EmissionModule emission = _system.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f); ParticleSystemRenderer component = val.GetComponent<ParticleSystemRenderer>(); ((Renderer)component).material = ParticleKit.BuildMaterial("ScorchAsh"); component.sortMode = (ParticleSystemSortMode)1; RagnaroksWrath.Log.LogInfo((object)"ScorchAsh: emitter built."); } catch (Exception ex) { _buildFailed = true; if ((Object)(object)_system != (Object)null) { Object.Destroy((Object)(object)((Component)_system).gameObject); _system = null; } RagnaroksWrath.Log.LogWarning((object)("ScorchAsh: build failed, ash disabled: " + ex.Message)); } } } } namespace RavenIron.RagnaroksWrath.Systems { public class TitleSystem : IWorldSystem { public const string Stormrider = "Stormrider"; public const string Plaguewalker = "Plaguewalker"; public const string Winterborn = "Winterborn"; public const string Ashbringer = "Ashbringer"; public const string Warden = "Warden"; public const string Despoiler = "Despoiler"; private readonly Dictionary<long, float> _winterSeconds = new Dictionary<long, float>(8); private readonly HashSet<long> _knownOnline = new HashSet<long>(); private readonly HashSet<long> _seenThisTick = new HashSet<long>(); private readonly HashSet<long> _stormHeld = new HashSet<long>(); private readonly HashSet<long> _plagueHeld = new HashSet<long>(); private readonly HashSet<long> _winterbornHeld = new HashSet<long>(); private bool _sawWinter; private readonly HashSet<long> _ashbringerHeld = new HashSet<long>(); private readonly HashSet<long> _wardenHeld = new HashSet<long>(); private readonly HashSet<long> _despoilerHeld = new HashSet<long>(); private bool _storeLoaded; public string Name => "TitleSystem"; public bool Enabled => ModConfig.EnableTitle.Value; public float IntervalSeconds => ModConfig.TitleIntervalSeconds.Value; public void Initialise() { RagnaroksWrath.Log.LogInfo((object)("[" + Name + "] titles: Stormrider (in a storm's area), Plaguewalker " + string.Format("(plague >= {0:F2} underfoot), {1} ", ModConfig.PlagueSpreadThreshold.Value, "Winterborn") + $"({ModConfig.WinterbornSeconds.Value:F0}s online in Winter). Latest earned wins.")); } public void Tick(float deltaSeconds) { //IL_00e8: 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_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) TitleSync.EnsureRegistered(); if (!Persistence.IsLoaded) { return; } if (!_storeLoaded) { TitleStore.Load(); _storeLoaded = TitleStore.IsLoaded; } if (!_storeLoaded) { return; } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return; } List<ZDO> allCharacterZDOS; try { allCharacterZDOS = instance.GetAllCharacterZDOS(); } catch { return; } if (allCharacterZDOS == null) { return; } bool flag = SeasonSystem.Current == Season.Winter; if (!flag) { _winterSeconds.Clear(); if (_sawWinter) { TitleStore.ClearWinterborn(); } _sawWinter = false; } else { _sawWinter = true; } float value = ModConfig.PlagueSpreadThreshold.Value; _seenThisTick.Clear(); for (int i = 0; i < allCharacterZDOS.Count; i++) { ZDO val = allCharacterZDOS[i]; if (val == null || !val.IsValid()) { continue; } long num = val.GetLong(ZDOVars.s_playerID, 0L); if (num == 0L) { continue; } _seenThisTick.Add(num); Vector3 position = val.GetPosition(); if (_knownOnline.Add(num)) { foreach (KeyValuePair<long, string> item in TitleStore.All()) { TitleSync.Broadcast(item.Key, item.Value); } } string text = null; if (TitleEdge.Rises(_stormHeld, num, WeatherSystem.IsStormAt(position))) { text = "Stormrider"; } if (TitleEdge.Rises(_plagueHeld, num, Persistence.Get(ZoneKey.FromWorldPos(position)).Plague >= value)) { text = "Plaguewalker"; } float num2 = TitleEdge.WinterSeconds(_winterSeconds, num, flag, deltaSeconds); if (TitleEdge.Rises(_winterbornHeld, num, flag && num2 >= ModConfig.WinterbornSeconds.Value) && !TitleStore.WinterbornThisWinter(num)) { TitleStore.MarkWinterborn(num); text = "Winterborn"; } if (ModConfig.EnableRivalry.Value && RivalryLedger.IsLoaded) { if (TitleEdge.Rises(_ashbringerHeld, num, RivalryLedger.MaxGrudgeFor(num, ModConfig.GrudgeScale.Value) >= ModConfig.AshbringerGrudge.Value)) { text = "Ashbringer"; } if (TitleEdge.Rises(_wardenHeld, num, RivalrySystem.CareZonesHeld(num) >= ModConfig.WardenZonesHeld.Value)) { text = "Warden"; } if (TitleEdge.Rises(_despoilerHeld, num, RivalrySystem.HarmZonesHeld(num) >= ModConfig.DespoilerZonesHeld.Value)) { text = "Despoiler"; } } if (text != null) { Award(num, val, text); } } _knownOnline.RemoveWhere((long id) => !_seenThisTick.Contains(id)); } private void Award(long playerId, ZDO zdo, string title) { if (!(TitleStore.Get(playerId) == title)) { TitleStore.Set(playerId, title); TitleSync.Broadcast(playerId, title); string text = zdo.GetString(ZDOVars.s_playerName, ""); RagnaroksWrath.Log.LogInfo((object)$"[{Name}] {text} ({playerId}) earned {title}."); if (ModConfig.AnnounceTitles.Value && !string.IsNullOrEmpty(text) && text != "Stranger" && text != "...") { MessageFeed.ToEveryone(text + " is now " + title + "."); } } } } public class ZoneSyncSystem : IWorldSystem { public string Name => "ZoneSyncSystem"; public bool Enabled => ModConfig.EnableZoneSync.Value; public float IntervalSeconds => ModConfig.ZoneSyncIntervalSeconds.Value; public void Initialise() { RagnaroksWrath.Log.LogInfo((object)($"[{Name}] pushing a {ModConfig.ZoneSyncRadiusZones.Value * 2 + 1}x" + $"{ModConfig.ZoneSyncRadiusZones.Value * 2 + 1} zone ring to each player every " + $"{IntervalSeconds:F0}s (absolute snapshots, defaults included).")); } public void Tick(float deltaSeconds) { //IL_007c: 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) ZoneSync.EnsureRegistered(); VersionSync.EnsureRegistered(); if (!Persistence.IsLoaded) { return; } VersionSync.MaybeBroadcast(deltaSeconds); ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return; } List<ZNetPeer> peers; try { peers = instance.GetPeers(); } catch { return; } if (peers == null) { return; } int radius = Math.Max(1, ModConfig.ZoneSyncRadiusZones.Value); ZDOMan instance2 = ZDOMan.instance; for (int i = 0; i < peers.Count; i++) { ZNetPeer val = peers[i]; if (val != null && val.IsReady()) { long playerId = 0L; ZDO val2 = ((instance2 != null) ? instance2.GetZDO(val.m_characterID) : null); if (val2 != null) { playerId = val2.GetLong(ZDOVars.s_playerID, 0L); } ZoneSync.SendRing(val.m_uid, playerId, ZoneKey.FromWorldPos(val.m_refPos), radius); } } } } } namespace RavenIron.RagnaroksWrath.Systems.World { public class BiomeStateSystem : IWorldSystem { private readonly List<ZoneKey> _contacted = new List<ZoneKey>(64); private readonly Dictionary<ZoneKey, float> _grudgeByZone = new Dictionary<ZoneKey, float>(64); private readonly HashSet<ZoneKey> _mercyZones = new HashSet<ZoneKey>(); private int _cursor; public string Name => "BiomeStateSystem"; public bool Enabled => ModConfig.EnableBiomeState.Value; public float IntervalSeconds => ModConfig.BiomeStateIntervalSeconds.Value; public void Initialise() { RagnaroksWrath.Log.LogInfo((object)($"[{Name}] recovery {ModConfig.BiomeRecoveryPerHour.Value:F3}/h, " + $"frost pressure {ModConfig.BiomeFrostPressurePerHour.Value:F3}/h, " + $"contact radius {ModConfig.BiomeContactRadiusZones.Value} zone(s), " + $"max {ModConfig.BiomeMaxZonesPerTick.Value} zone(s)/tick.")); } public void Tick(float deltaSeconds) { if (!Persistence.IsLoaded) { return; } _contacted.Clear(); _grudgeByZone.Clear(); _mercyZones.Clear(); CollectContactedZones(_contacted, _grudgeByZone, _mercyZones); if (_contacted.Count == 0) { _cursor = 0; return; } if (_cursor >= _contacted.Count) { _cursor = 0; } float value = ModConfig.BiomeRecoveryPerHour.Value; float value2 = ModConfig.BiomeFrostPressurePerHour.Value; float coldMultiplier = SeasonSystem.ColdMultiplier(); float fireRiskMultiplier = SeasonSystem.FireRiskMultiplier(); float pressurePerHour = ModConfig.PlagueGrowthPerHour.Value * SeasonSystem.PlagueGrowthMultiplier(); float value3 = ModConfig.PlagueCorruptionBoost.Value; int num = Math.Min(ModConfig.BiomeMaxZonesPerTick.Value, _contacted.Count); int num2 = 0; for (int i = 0; i < num; i++) { ZoneKey zoneKey = _contacted[_cursor]; _cursor = (_cursor + 1) % _contacted.Count; double num3 = ZoneClock.CreditOnContact(zoneKey); if (!(num3 <= 0.0)) { float value4; float grudge = (_grudgeByZone.TryGetValue(zoneKey, out value4) ? value4 : 0f); float num4 = RivalryMath.GrudgedRecovery(value, grudge); if (_mercyZones.Contains(zoneKey)) { num4 *= 1f + ModConfig.MercyRecoveryBonus.Value; } num4 *= RelicSystem.RecoveryMultiplierAt(zoneKey); ZoneState state = BiomeDrift.Apply(Persistence.Get(zoneKey), num3, num4, RivalryMath.GrudgedPressure(value2, grudge), coldMultiplier, fireRiskMultiplier, RivalryMath.GrudgedPressure(pressurePerHour, grudge), value3); Persistence.Set(zoneKey, state); num2++; } } if (num2 > 0 && ModConfig.VerboseLogging.Value) { RagnaroksWrath.Log.LogInfo((object)($"[{Name}] drifted {num2} of {_contacted.Count} contacted zone(s); " + $"{Persistence.TrackedZoneCount} zone(s) tracked.")); } } private static void CollectContactedZones(List<ZoneKey> into, Dictionary<ZoneKey, float> grudges, HashSet<ZoneKey> mercies) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return; } int value = ModConfig.BiomeContactRadiusZones.Value; bool flag = ModConfig.EnableRivalry.Value && RivalryLedger.IsLoaded; float value2 = ModConfig.GrudgeScale.Value; List<ZDO> allCharacterZDOS; try { allCharacterZDOS = instance.GetAllCharacterZDOS(); } catch (Exception ex) { RagnaroksWrath.Log.LogWarning((object)("[BiomeStateSystem] could not read character ZDOs: " + ex.Message)); return; } if (allCharacterZDOS == null) { return; } for (int i = 0; i < allCharacterZDOS.Count; i++) { ZDO val = allCharacterZDOS[i]; if (val == null || !val.IsValid()) { continue; } long num = (flag ? val.GetLong(ZDOVars.s_playerID, 0L) : 0); ZoneKey zoneKey = ZoneKey.FromWorldPos(val.GetPosition()); for (int j = -value; j <= value; j++) { for (int k = -value; k <= value; k++) { ZoneKey zoneKey2 = new ZoneKey(zoneKey.X + j, zoneKey.Y + k); if (!into.Contains(zoneKey2)) { into.Add(zoneKey2); } if (num != 0L) { RivalryLedger.Row row = RivalryLedger.Get(zoneKey2, num); float num2 = RivalryMath.GrudgeFor(row.Harm, row.Care, value2); if (num2 > 0f && (!grudges.TryGetValue(zoneKey2, out var value3) || num2 > value3)) { grudges[zoneKey2] = num2; } if (RivalrySystem.IsDominantCarer(zoneKey2, num)) { mercies.Add(zoneKey2); } } } } } } } public class ConsequenceSystem : IWorldSystem { private readonly HashSet<ZoneKey> _announced = new HashSet<ZoneKey>(); public string Name => "ConsequenceSystem"; public bool Enabled => ModConfig.EnableConsequence.Value; public float IntervalSeconds => ModConfig.ConsequenceIntervalSeconds.Value; public void Initialise() { RagnaroksWrath.Log.LogInfo((object)("[" + Name + "] the drift store grows hands: barren pickables (plague >= " + $"{ModConfig.BarrenPlagueThreshold.Value:F2} / scorch >= {ModConfig.BarrenScorchThreshold.Value:F2}), " + $"starred spawns (corruption >= {ModConfig.EmpowerCorruptionThreshold.Value:F2}, " + $"x{ModConfig.EmpowerLevelUpMultiplierAtFull.Value:F1} odds at full), sickened wildlife " + $"(plague >= {ModConfig.SickenPlagueThreshold.Value:F2}), withering crops (blight >= " + $"{ModConfig.CropWitherBlightThreshold.Value:F2}). Player structures are NEVER touched.")); } public void Tick(float deltaSeconds) { //IL_005a: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) if (!Persistence.IsLoaded || !ModConfig.AnnounceConsequences.Value) { return; } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return; } List<ZDO> allCharacterZDOS; try { allCharacterZDOS = instance.GetAllCharacterZDOS(); } catch { return; } if (allCharacterZDOS == null) { return; } for (int i = 0; i < allCharacterZDOS.Count; i++) { ZDO val = allCharacterZDOS[i]; if (val == null || !val.IsValid()) { continue; } Vector3 position = val.GetPosition(); ZoneKey zoneKey = ZoneKey.FromWorldPos(position); if (_announced.Contains(zoneKey)) { continue; } ConsequenceFlags consequenceFlags = ConsequenceMath.FlagsFor(Persistence.Get(zoneKey), ModConfig.BarrenPlagueThreshold.Value, ModConfig.BarrenScorchThreshold.Value, ModConfig.SickenPlagueThreshold.Value, ModConfig.EmpowerCorruptionThreshold.Value, ModConfig.CropWitherBlightThreshold.Value); if (consequenceFlags != ConsequenceFlags.None) { _announced.Add(zoneKey); MessageFeed.ToPlayersNear(position, 64f, LineFor(consequenceFlags)); if (ModConfig.VerboseLogging.Value) { RagnaroksWrath.Log.LogInfo((object)$"[{Name}] zone {zoneKey} announced: {consequenceFlags}."); } } } } internal static string LineFor(ConsequenceFlags flags) { if ((flags & ConsequenceFlags.Empowered) != ConsequenceFlags.None) { return "Something festers in this ground."; } if ((flags & ConsequenceFlags.Barren) != ConsequenceFlags.None) { return "The land here has gone barren."; } if ((flags & ConsequenceFlags.Sickening) != ConsequenceFlags.None) { return "The wild things here are sickening."; } return "Nothing planted here will live."; } } public class EcologySystem : IWorldSystem { private readonly List<KeyValuePair<ZoneKey, ZoneState>> _snapshot = new List<KeyValuePair<ZoneKey, ZoneState>>(64); public string Name => "EcologySystem"; public bool Enabled => ModConfig.EnableEcology.Value; public float IntervalSeconds => ModConfig.EcologyIntervalSeconds.Value; public void Initialise() { RagnaroksWrath.Log.LogInfo((object)($"[{Name}] blight corrupts at {ModConfig.EcologyCorruptionPerHour.Value:F3}/h " + $"where plague>={ModConfig.EcologyPlagueThreshold.Value:F2} or " + $"scorch>={ModConfig.EcologyScorchThreshold.Value:F2}.")); } public void Tick(float deltaSeconds) { if (!Persistence.IsLoaded) { return; } float value = ModConfig.EcologyCorruptionPerHour.Value; float value2 = ModConfig.EcologyPlagueThreshold.Value; float value3 = ModConfig.EcologyScorchThreshold.Value; _snapshot.Clear(); foreach (KeyValuePair<ZoneKey, ZoneState> item in Persistence.All()) { if (item.Value.Plague >= value2 || item.Value.Scorch >= value3) { _snapshot.Add(item); } } for (int i = 0; i < _snapshot.Count; i++) { ZoneState state = EcologyPressure.Apply(_snapshot[i].Value, deltaSeconds, value, value2, value3); Persistence.Set(_snapshot[i].Key, state); } } } public class FarmingSystem : IWorldSystem { private string[] _cropPrefabs = Array.Empty<string>(); private int _prefabCursor; private readonly List<ZDO> _found = new List<ZDO>(128); private int _sweepIndex; private readonly Dictionary<ZoneKey, int> _cropCounts = new Dictionary<ZoneKey, int>(32); private float _rotationSeconds; public string Name => "FarmingSystem"; public bool Enabled => ModConfig.EnableFarming.Value; public float IntervalSeconds => ModConfig.FarmingIntervalSeconds.Value; public void Initialise() { _cropPrefabs = (ModConfig.FarmingCropPrefabs.Value ?? "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < _cropPrefabs.Length; i++) { _cropPrefabs[i] = _cropPrefabs[i].Trim(); } RagnaroksWrath.Log.LogInfo((object)($"[{Name}] sweeping {_cropPrefabs.Length} crop prefab(s) every {IntervalSeconds:F0}s; " + $"depletion {ModConfig.FarmingDepletionPerCropHour.Value:F4}/crop-hour. " + "Depletion is WRITTEN here; the growth consumer bites client-side " + $"(x{ModConfig.FarmingGrowthSlowdownAtFull.Value:0.##} grow time at full depletion).")); } public void Tick(float deltaSeconds) { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) if (!Persistence.IsLoaded || _cropPrefabs.Length == 0) { return; } ZDOMan instance = ZDOMan.instance; if (instance == null) { return; } _rotationSeconds += deltaSeconds; string text = _cropPrefabs[_prefabCursor]; try { bool flag = false; while (!flag) { flag = instance.GetAllZDOsWithPrefabIterative(text, _found, ref _sweepIndex); } } catch (Exception ex) { RagnaroksWrath.Log.LogWarning((object)("[" + Name + "] sweep failed on '" + text + "': " + ex.Message)); _found.Clear(); _sweepIndex = 0; return; } for (int i = 0; i < _found.Count; i++) { ZDO val = _found[i]; if (val != null && val.IsValid()) { ZoneKey key = ZoneKey.FromWorldPos(val.GetPosition()); _cropCounts.TryGetValue(key, out var value); _cropCounts[key] = value + 1; } } if (ModConfig.VerboseLogging.Value && _found.Count > 0) { RagnaroksWrath.Log.LogInfo((object)$"[{Name}] '{text}': {_found.Count} standing."); } _found.Clear(); _sweepIndex = 0; _prefabCursor++; if (_prefabCursor < _cropPrefabs.Length) { return; } _prefabCursor = 0; float num = _rotationSeconds / 3600f; _rotationSeconds = 0f; float value2 = ModConfig.FarmingDepletionPerCropHour.Value; if (value2 > 0f && num > 0f) { foreach (KeyValuePair<ZoneKey, int> cropCount in _cropCounts) { ZoneState state = Persistence.Get(cropCount.Key); state.Fertility += value2 * (float)cropCount.Value * num; Persistence.Set(cropCount.Key, state); } } if (ModConfig.VerboseLogging.Value && _cropCounts.Count > 0) { RagnaroksWrath.Log.LogInfo((object)$"[{Name}] rotation complete: crops in {_cropCounts.Count} zone(s)."); } _cropCounts.Clear(); } } public class FireSystem : IWorldSystem { public const string FireFrontGuid = "com.raveniron.firefront"; private static readonly Version MinimumFireFrontVersion = new Version(0, 17, 2); private static readonly Version IgniterFireFrontVersion = new Version(0, 17, 3); private static readonly Version PerFireIgniterFireFrontVersion = new Version(1, 0, 2); private static readonly Version GameOneZeroFireFrontVersion = new Version(0, 20, 0); private static readonly Version RainFireFrontVersion = new Version(0, 21, 0); private bool _fireFrontPresent; private PropertyInfo _instanceProperty; private MethodInfo _collectMethod; private PropertyInfo _igniterProperty; private bool _igniterAbsenceLogged; private readonly List<Vector3> _firePositions = new List<Vector3>(64); private readonly List<ZoneKey> _burningZones = new List<ZoneKey>(16); private MethodInfo _collectWithIgnitersMethod; private bool _collectWithIgnitersResolved; private Version _fireFrontVersion; private bool _perFire; private readonly List<long> _fireIgniters = new List<long>(64); private readonly object[] _collectWithIgnitersArgs = new object[2]; private readonly List<KeyValuePair<ZoneKey, long>> _blame = new List<KeyValuePair<ZoneKey, long>>(16); private bool _blameMismatchLogged; private readonly ArsonFootprint _arson = new ArsonFootprint(); private readonly List<ZoneKey> _arsonZones = new List<ZoneKey>(16); private readonly object[] _collectArgs = new object[1]; private MethodInfo _igniteMethod; private bool _igniteGroundAbsenceLogged; private readonly Random _rng = new Random(); private readonly List<ZDO> _stormPlayers = new List<ZDO>(8); private readonly List<ZDO> _sectorScratch = new List<ZDO>(256); private MethodInfo _rainMethod; private bool _rainAbsenceLogged; private readonly object[] _rainArgs = new object[1]; public string Name => "FireSystem"; public bool Enabled => ModConfig.EnableFire.Value; public float IntervalSeconds => ModConfig.FireScorchIntervalSeconds.Value; public void Initialise() { _fireFrontPresent = Chainloader.PluginInfos.ContainsKey("com.raveniron.firefront"); if (!_fireFrontPresent) { RagnaroksWrath.Log.LogWarning((object)("[" + Name + "] FireFront not present — dormant. It ships as a dependency of this mod; a manual install likely skipped it. Scorch will not accrue from fire; install FireFront (com.raveniron.firefront) 0.17.2+ to light the world's memory.")); return; } Version version = (_fireFrontVersion = Chainloader.PluginInfos["com.raveniron.firefront"].Metadata.Version); RagnaroksWrath.Log.LogInfo((object)($"[{Name}] FireFront {version} detected — bridging. Burning zones gain " + $"{ModConfig.FireScorchPerMinute.Value:F3} scorch/min.")); if (version < MinimumFireFrontVersion) { RagnaroksWrath.Log.LogWarning((object)($"[{Name}] FireFront {version} predates {MinimumFireFrontVersion} — its read API " + "is missing, so scorch CANNOT accrue. Update FireFront; until then every bridge tick will name the unresolved surface.")); } else if (version < IgniterFireFrontVersion) { RagnaroksWrath.Log.LogInfo((object)($"[{Name}] FireFront {version} predates {IgniterFireFrontVersion} — arson " + "attribution stays dormant; scorch is unaffected.")); } else if (version < PerFireIgniterFireFrontVersion) { RagnaroksWrath.Log.LogInfo((object)($"[{Name}] FireFront {version} predates {PerFireIgniterFireFrontVersion} — it names " + "one igniter for the whole map, so arson is blamed on that player only where their fire has spread. Update FireFront to blame each fire on whoever lit it.")); } if (version < GameOneZeroFireFrontVersion) { RagnaroksWrath.Log.LogWarning((object)($"[{Name}] FireFront {version} predates {GameOneZeroFireFrontVersion}, which is the " + "first build ported to Valheim 1.0.7. On 1.0.7 it cannot resolve its own save path, so fires do not survive a restart and anything downstream of them here will look wrong for the wrong reason. Update FireFront.")); } if (ModConfig.StormLightningEnabled.Value) { bool value = ModConfig.StormsForceWeather.Value; RagnaroksWrath.Log.LogInfo((object)("[" + Name + "] storm lightning armed — ~1 bolt per " + $"{ModConfig.LightningMeanMinutes.Value:0.#} storm-minutes, landing " + $"{ModConfig.LightningRingMinMeters.Value:0}-{ModConfig.LightningRingMaxMeters.Value:0}m " + $"from a present player, {ModConfig.LightningStandoffMeters.Value:0}m homestead standoff; " + (value ? "rain judged by each storm's rolled look, since the sky is forced." : "rain judged where each bolt would land, by FireFront's reading of the world's weather."))); if (!value && version < RainFireFrontVersion) { RagnaroksWrath.Log.LogWarning((object)($"[{Name}] FireFront {version} predates {RainFireFrontVersion}, which added the " + "rain read lightning needs when no storm sky is forced. Without it no bolt can be checked for rain, so none will fall. Update FireFront.")); } } } public void Tick(float deltaSeconds) { if (!_fireFrontPresent || !Persistence.IsLoaded || !TryCollectFirePositions()) { return; } TryLightning(); if (_firePositions.Count == 0) { _arson.Clear(); return; } _burningZones.Clear(); FireScorch.CollectBurningZones(_firePositions, _burningZones); float num = FireScorch.ScorchDelta(ModConfig.FireScorchPerMinute.Value, deltaSeconds); if (num <= 0f) { return; } float value = ModConfig.ArsonHarmPerScorchPoint.Value; bool flag = value > 0f && ModConfig.EnableRivalry.Value && RivalryLedger.IsLoaded; long num2 = 0L; bool flag2 = false; if (_perFire) { _arson.Clear(); if (!FireBlame.Collect(_firePositions, _fireIgniters, _blame) && !_blameMismatchLogged) { _blameMismatchLogged = true; RagnaroksWrath.Log.LogWarning((object)($"[{Name}] FireFront returned {_firePositions.Count} fire(s) but " + $"{_fireIgniters.Count} igniter(s) - no arson booked while they disagree.")); } if (flag) { for (int i = 0; i < _blame.Count; i++) { RivalryLedger.AddHarm(_blame[i].Key, _blame[i].Value, num * value); } } } else { num2 = TryReadIgniter(); _arson.Observe(num2, _burningZones, _arsonZones); flag2 = num2 != 0L && _arsonZones.Count > 0 && flag; } for (int j = 0; j < _burningZones.Count; j++) { ZoneKey zoneKey = _burningZones[j]; ZoneState state = Persistence.Get(zoneKey); state.Scorch += num; Persistence.Set(zoneKey, state); if (flag2 && _arsonZones.Contains(zoneKey)) { RivalryLedger.AddHarm(zoneKey, num2, num * value); } } if (ModConfig.VerboseLogging.Value) { RagnaroksWrath.Log.LogInfo((object)$"[{Name}] {_firePositions.Count} fire(s) scorching {_burningZones.Count} zone(s)."); } } private void TryLightning() { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0147: 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_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.StormLightningEnabled.Value || !WeatherSystem.StormActive) { return; } float num = LightningStrike.ChancePerTick(IntervalSeconds, ModConfig.LightningMeanMinutes.Value); if (_rng.NextDouble() > (double)num || (!_perFire && TryReadIgniter() != 0L)) { return; } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return; } List<ZDO> allCharacterZDOS; try { allCharacterZDOS = instance.GetAllCharacterZDOS(); } catch { return; } if (allCharacterZDOS == null) { return; } _stormPlayers.Clear(); for (int i = 0; i < allCharacterZDOS.Count; i++) { ZDO val = allCharacterZDOS[i]; if (val != null && val.IsValid() && val.GetLong(ZDOVars.s_playerID, 0L) != 0L && WeatherSystem.IsStormAt(val.GetPosition())) { _stormPlayers.Add(val); } } if (_stormPlayers.Count == 0) { return; } Vector3 val2 = LightningStrike.StrikePoint(_stormPlayers[_rng.Next(_stormPlayers.Count)].GetPosition(), _rng.NextDouble(), _rng.NextDouble(), ModConfig.LightningRingMinMeters.Value, ModConfig.LightningRingMaxMeters.Value); bool value = ModConfig.StormsForceWeather.Value; bool? rainingWhereItLands = (value ? ((bool?)null) : TryReadRainAt(val2)); if (!LightningStrike.SkyAllows(value, WeatherSystem.StormIsDry, rainingWhereItLands)) { if (ModConfig.VerboseLogging.Value) { RagnaroksWrath.Log.LogInfo((object)($"[{Name}] bolt withheld at ({val2.x:F0}, {val2.z:F0}) — " + (value ? "the storm's forced sky is wet." : ((rainingWhereItLands == true) ? "FireFront reads rain there." : "FireFront cannot say whether it rains there.")))); } } else if (IsNearPlayerBuilt(val2, ModConfig.LightningStandoffMeters.Value)) { if (ModConfig.VerboseLogging.Value) { RagnaroksWrath.Log.LogInfo((object)$"[{Name}] bolt grounded by the homestead in {ZoneKey.FromWorldPos(val2)} — lost."); } } else if (TryIgniteGround(val2, ModConfig.LightningIgniteRadiusMeters.Value)) { MessageFeed.ToPlayersNear(val2, 64f, "Lightning splits the sky!", MessageFeed.Placement.Centre); RagnaroksWrath.Log.LogInfo((object)($"[{Name}] lightning strike at ({val2.x:F0}, {val2.z:F0}) in " + $"{ZoneKey.FromWorldPos(val2)} — the fire, if any, is FireFront's now.")); } } private bool IsNearPlayerBuilt(Vector3 strike, float standoff) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Homestead.IsNearPlayerBuilt(strike, standoff, _sectorScratch, resultWhenUncheckable: true); } private bool TryIgniteGround(Vector3 origin, float radius) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) try { if (_igniteMethod == null) { Type type = _collectMethod?.DeclaringType; if (type == null) { return false; } _igniteMethod = type.GetMethod("IgniteGroundNear", BindingFlags.Instance | BindingFlags.Public); if (_igniteMethod == null) { if (!_igniteGroundAbsenceLogged) { _igniteGroundAbsenceLogged = true; RagnaroksWrath.Log.LogInfo((object)("[" + Name + "] FireFront has no IgniteGroundNear surface — storm lightning dormant; scorch unaffected.")); } return false; } } object obj = _instanceProperty?.GetValue(null); if (obj == null) { return false; } _igniteMethod.Invoke(obj, new object[2] { origin, radius }); return true; } catch (Exception ex) { RagnaroksWrath.Log.LogWarning((object)("[" + Name + "] lightning ignite failed: " + ex.Message)); return false; } } private bool? TryReadRainAt(Vector3 position) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) try { if (_rainMethod == null) { MethodInfo methodInfo = (_collectMethod?.DeclaringType?.Assembly.GetType("FireFront.Utils.ValheimBridge"))?.GetMethod("IsRainingAt", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Vector3) }, null); if (methodInfo == null || methodInfo.ReturnType != typeof(bool)) { if (!_rainAbsenceLogged) { _rainAbsenceLogged = true; RagnaroksWrath.Log.LogWarning((object)("[" + Name + "] FireFront has no ValheimBridge.IsRainingAt surface (0.21.0+) — with no storm sky forced, no bolt can be checked for rain, so none will fall. Scorch is unaffected. Update FireFront.")); } return null; } _rainMethod = methodInfo; } _rainArgs[0] = position; return (bool)_rainMethod.Invoke(null, _rainArgs); } catch (Exception ex) { RagnaroksWrath.Log.LogWarning((object)("[" + Name + "] could not read FireFront's weather, so the bolt is withheld: " + (ex.InnerException ?? ex).Message)); return null; } } private long TryReadIgniter() { try { if (_igniterProperty == null) { Type type = _collectMethod?.DeclaringType; if (type == null) { return 0L; } _igniterProperty = type.GetProperty("CurrentFireIgniterPlayerId", BindingFlags.Instance | BindingFlags.Public); if (_igniterProperty == null) { if (!_igniterAbsenceLogged) { _igniterAbsenceLogged = true; RagnaroksWrath.Log.LogInfo((object)("[" + Name + "] FireFront predates the igniter surface (0.17.3) — arson attribution dormant; scorch still accrues.")); } return 0L; } } object obj = _instanceProperty?.GetValue(null); if (obj == null) { return 0L; } return (long)_igniterProperty.GetValue(obj); } catch (Exception) { return 0L; } } private bool TryCollectFirePositions() { try { if (_collectMethod == null) { Type type = ((object)Chainloader.PluginInfos["com.raveniron.firefront"].Instance).GetType().Assembly.GetType("FireFront.Fire.FireManager"); if (type == null) { RagnaroksWrath.Log.LogWarning((object)("[" + Name + "] FireFront.Fire.FireManager not found — FireFront's API moved.")); return false; } _instanceProperty = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); _collectMethod = type.GetMethod("CollectActiveFirePositions", BindingFlags.Instance | BindingFlags.Public); if (_instanceProperty == null || _collectMethod == null) { _collectMethod = null; RagnaroksWrath.Log.LogWarning((object)("[" + Name + "] FireManager.Instance or CollectActiveFirePositions not found — FireFront is present but older than 0.17.2. Scorch will not accrue.")); return false; } } if (!_collectWithIgnitersResolved) { _collectWithIgnitersResolved = true; _collectWithIgnitersMethod = _collectMethod.DeclaringType.GetMethod("CollectActiveFiresWithIgniters", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(List<Vector3>), typeof(List<long>) }, null); if (_collectWithIgnitersMethod != null) { RagnaroksWrath.Log.LogInfo((object)("[" + Name + "] FireFront names each fire's igniter - arson is blamed per fire.")); } else if (_fireFrontVersion != null && _fireFrontVersion >= PerFireIgniterFireFrontVersion) { RagnaroksWrath.Log.LogWarning((object)($"[{Name}] FireFront {_fireFrontVersion} has no CollectActiveFiresWithIgniters" + "(List<Vector3>, List<long>) - FireFront's API moved. Arson falls back to its single igniter, blamed only where that fire has spread.")); } } object value = _instanceProperty.GetValue(null); if (value == null) { return false; } _firePositions.Clear(); _fireIgniters.Clear(); if (_collectWithIgnitersMethod != null) { _collectWithIgnitersArgs[0] = _firePositions; _collectWithIgnitersArgs[1] = _fireIgniters; _collectWithIgnitersMethod.Invoke(value, _collectWithIgnitersArgs); _perFire = true; } else { _collectArgs[0] = _firePositions; _collectMethod.Invoke(value, _collectArgs); _perFire = false; } return true; } catch (Exception ex) { RagnaroksWrath.Log.LogWarning((object)("[" + Name + "] could not read FireFront fires: " + ex.Message)); return false; } } } public class HealthSystem : IWorldSystem { private const float SaveCadenceSeconds = 60f; private const float KeepaliveSeconds = 30f; private bool _storeLoaded; private float _sinceSave; private readonly Dictionary<long, long> _peerByPlayer = new Dictionary<long, long>(8); private readonly Dictionary<long, float> _lastSent = new Dictionary<long, float>(8); private readonly Dictionary<long, float> _lastSentAt = new Dictionary<long, float>(8); private readonly HashSet<long> _seenThisTick = new HashSet<long>(); private readonly List<long> _departed = new List<long>(4); public string Name => "HealthSystem"; public bool Enabled => ModConfig.EnableHealth.Value; public float IntervalSeconds => ModConfig.HealthIntervalSeconds.Value; public void Initialise() { RagnaroksWrath.Log.LogInfo((object)($"[{Name}] exposure: clean->max in {ModConfig.ExposureMinutesToMax.Value:F0}min at full plague " + $"(floor {0.15f:F2}), max->clean in {ModConfig.ExposureRecoveryMinutes.Value:F0}min; " + $"poison-resist x{ModConfig.ExposurePoisonResistMultiplier.Value:F2} accrual, " + $"rested x{ModConfig.ExposureRestedRecoveryMultiplier.Value:F1} recovery. " + "Weakens, never kills — regen multipliers only, applied client-side.")); } public void Tick(float deltaSeconds) { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) HealthSync.EnsureRegistered(); if (!Persistence.IsLoaded) { return; } if (!_storeLoaded) { HealthStore.Load(); _storeLoaded = HealthStore.IsLoaded; } if (!_storeLoaded) { return; } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return; } List<ZDO> allCharacterZDOS; try { allCharacterZDOS = instance.GetAllCharacterZDOS(); } catch { return; } if (allCharacterZDOS == null) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; MapPeersToPlayers(instance); _seenThisTick.Clear(); float value = ModConfig.ExposureMinutesToMax.Value; float value2 = ModConfig.ExposureRecoveryMinutes.Value; float value3 = ModConfig.ExposurePoisonResistMultiplier.Value; float value4 = ModConfig.ExposureRestedRecoveryMultiplier.Value; int num = 0; for (int i = 0; i < allCharacterZDOS.Count; i++) { ZDO val = allCharacterZDOS[i]; if (val == null || !val.IsValid()) { continue; } long num2 = val.GetLong(ZDOVars.s_playerID, 0L); if (num2 != 0L) { _seenThisTick.Add(num2); ZoneKey zone = ZoneKey.FromWorldPos(val.GetPosition()); float plague = Persistence.Get(zone).Plague; int num3 = RemedyBitsFor(num2, realtimeSinceStartup); float num4 = HealthStore.Get(num2); float num5 = (RivalrySystem.IsDominantCarer(zone, num2) ? (1f + ModConfig.MercySicknessBonus.Value) : 1f); num5 *= RelicSystem.ExposureDecayMultAt(zone); float minutesToMax = value * RelicSystem.ExposureMinutesMultAt(zone); float num6 = ((plague >= 0.15f) ? ExposureMath.Accrue(num4, plague, minutesToMax, (num3 & 1) != 0, value3, deltaSeconds) : ExposureMath.Decay(num4, value2, (num3 & 2) != 0, value4, deltaSeconds, num5)); if (num6 != num4) { HealthStore.Set(num2, num6); } if (num6 > 0f) { num++; } MaybeSync(num2, num6, realtimeSinceStartup); } } PruneDeparted(); _sinceSave += deltaSeconds; if (_sinceSave >= 60f) { _sinceSave = 0f; HealthStore.SaveIfDirty(); } if (ModConfig.VerboseLogging.Value && num > 0) { RagnaroksWrath.Log.LogInfo((object)$"[{Name}] {num} exposed player(s) of {_seenThisTick.Count} online."); } } private void MaybeSync(long playerId, float exposure, float now) { if (_peerByPlayer.TryGetValue(playerId, out var value)) { _lastSent.TryGetValue(playerId, out var value2); _lastSentAt.TryGetValue(playerId, out var value3); if (ExposureMath.QuantizedDiffer(value2, exposure) || (exposure > 0f && now - value3 >= 30f)) { HealthSync.SendExposure(value, playerId, exposure); _lastSent[playerId] = exposure; _lastSentAt[playerId] = now; } } } private void MapPeersToPlayers(ZNet znet) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) _peerByPlayer.Clear(); List<ZNetPeer> peers; try { peers = znet.GetPeers(); } catch { return; } if (peers == null) { return; } ZDOMan instance = ZDOMan.instance; if (instance == null) { return; } for (int i = 0; i < peers.Count; i++) { ZNetPeer val = peers[i]; if (val == null || !val.IsReady()) { continue; } ZDO zDO = instance.GetZDO(val.m_characterID); if (zDO != null) { long num = zDO.GetLong(ZDOVars.s_playerID, 0L); if (num != 0L) { _peerByPlayer[num] = val.m_uid; } } } } private int RemedyBitsFor(long playerId, float now) { if (_peerByPlayer.TryGetValue(playerId, out var value)) { return HealthSync.RemedyBitsFor(value, now); } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && localPlayer.GetPlayerID() == playerId) { return HealthSync.ComputeLocalRemedyBits(localPlayer); } return 0; } private void PruneDeparted() { _departed.Clear(); foreach (KeyValuePair<long, float> item in _lastSent) { if (!_seenThisTick.Contains(item.Key)) { _departed.Add(item.Key); } } for (int i = 0; i < _departed.Count; i++) { _lastSent.Remove(_departed[i]); _lastSentAt.Remove(_departed[i]); } } } public class PlagueSystem : IWorldSystem { private readonly Random _rng = new Random(); private readonly List<KeyValuePair<ZoneKey, float>> _plagued = new List<KeyValuePair<ZoneKey, float>>(32); private readonly HashSet<ZoneKey> _infected = new HashSet<ZoneKey>(); private readonly List<ZoneKey> _targets = new List<ZoneKey>(16); public string Name => "PlagueSystem"; public bool Enabled => ModConfig.EnablePlague.Value; public float IntervalSeconds => ModConfig.PlagueSpreadIntervalSeconds.Value; public void Initialise() { RagnaroksWrath.Log.LogInfo((object)($"[{Name}] spread every {IntervalSeconds:F0}s at {ModConfig.PlagueSpreadChance.Value:P0} " + $"per frontier zone (threshold {ModConfig.PlagueSpreadThreshold.Value:F2}, " + $"seed {ModConfig.PlagueSeedAmount.Value:F2}). Growth and cure live in BiomeDrift. " + (ModConfig.PlagueGenesisEnabled.Value ? ($"Genesis: outbreaks take root organically, ~{ModConfig.PlagueGenesisMeanHours.Value:0.#}h " + "mean on clean ground, faster on blighted, storm-carried.") : "Genesis OFF: outbreaks start only by admin hand."))); } public void Tick(float deltaSeconds) { //IL_011d: Unknown result type (might be due to invalid IL or missing references) if (!Persistence.IsLoaded) { return; } _plagued.Clear(); _infected.Clear(); foreach (KeyValuePair<ZoneKey, ZoneState> item in Persistence.All()) { if (!(item.Value.Plague <= 0f)) { _plagued.Add(new KeyValuePair<ZoneKey, float>(item.Key, item.Value.Plague)); _infected.Add(item.Key); } } TryGenesis(); if (_plagued.Count == 0) { return; } _targets.Clear(); PlagueSpread.CollectSpreadTargets(_plagued, ModConfig.PlagueSpreadThreshold.Value, _infected, _targets); if (_targets.Count == 0) { return; } float value = ModConfig.PlagueSpreadChance.Value; float value2 = ModConfig.PlagueSeedAmount.Value; int value3 = ModConfig.PlagueMaxSpreadsPerTick.Value; int num = 0; for (int i = 0; i < _targets.Count; i++) { if (num >= value3) { break; } ZoneKey zone = _targets[i]; float num2 = value * WeatherSystem.PlagueSpreadMultiplierAt(zone.ToWorldPos()); if (!(_rng.NextDouble() > (double)num2)) { ZoneState state = Persistence.Get(zone); state.Plague = value2; Persistence.Set(zone, state); num++; } } if (num > 0 && ModConfig.VerboseLogging.Value) { RagnaroksWrath.Log.LogInfo((object)($"[{Name}] seeded {num} zone(s) from {_plagued.Count} infected " + $"({_targets.Count} frontier candidate(s)).")); } } private void TryGenesis() { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.PlagueGenesisEnabled.Value) { return; } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return; } List<ZDO> allCharacterZDOS; try { allCharacterZDOS = instance.GetAllCharacterZDOS(); } catch { return; } if (allCharacterZDOS == null || allCharacterZDOS.Count == 0) { return; } ZDO val = allCharacterZDOS[_rng.Next(allCharacterZDOS.Count)]; if (val == null || !val.IsValid() || val.GetLong(ZDOVars.s_playerID, 0L) == 0L) { return; } int num = Math.Max(0, ModConfig.BiomeContactRadiusZones.Value); ZoneKey zoneKey = ZoneKey.FromWorldPos(val.GetPosition()); ZoneKey zoneKey2 = new ZoneKey(zoneKey.X + _rng.Next(-num, num + 1), zoneKey.Y + _rng.Next(-num, num + 1)); ZoneState state = Persistence.Get(zoneKey2); if (!(state.Plague > 0f)) { float num2 = PlagueGenesis.Weight(state.Corruption, state.Scorch); float num3 = WeatherSystem.PlagueSpreadMultiplierAt(zoneKey2.ToWorldPos()); float num4 = PlagueGenesis.ChancePerTick(IntervalSeconds, ModConfig.PlagueGenesisMeanHours.Value) * num2 * num3; if (!(_rng.NextDouble() > (double)num4)) { state.Plague = ModConfig.PlagueSeedAmount.Value; Persistence.Set(zoneKey2, state); ZoneClock.MarkContact(zoneKey2); RagnaroksWrath.Log.LogInfo((object)($"[{Name}] sickness takes root in {zoneKey2} " + $"(ground weight {num2:0.##}, storm x{num3:0.##}).")); } } } } public sealed class RelicSystem : IWorldSystem { private const float SaveCadenceSeconds = 60f; private const float RebroadcastSeconds = 60f; private bool _ledgerLoaded; private float _sinceSave; private float _sinceBroadcast; private WorldCondition _lastCondition = WorldCondition.Stable; private bool _conditionSeen; private readonly HashSet<ZoneKey> _storyTold = new HashSet<ZoneKey>(); private readonly Dictionary<ZoneKey, long> _presentPeer = new Dictionary<ZoneKey, long>(64); private readonly HashSet<ZoneKey> _occupied = new HashSet<ZoneKey>(); private static readonly List<KeyValuePair<ZoneKey, bool>> _warResults = new List<KeyValuePair<ZoneKey, bool>>(4); private readonly List<ZoneKey> _scratch = new List<ZoneKey>(16); private readonly List<KeyValuePair<ZoneKey, RelicLedger.Peaks>> _peaksSnapshot = new List<KeyValuePair<ZoneKey, RelicLedger.Peaks>>(16); public string Name => "RelicSystem"; public bool Enabled => ModConfig.EnableRelic.Value; public float IntervalSeconds => ModConfig.RelicIntervalSeconds.Value; internal static void ResetWorldState() { _warResults.Clear(); } public static void NotifyWarResolved(ZoneKey zone, bool wildWon) { if (ModConfig.EnableRelic.Value) { _warResults.Add(new KeyValuePair<ZoneKey, bool>(zone, wildWon)); } } public static float RecoveryMultiplierAt(ZoneKey zone) { if (!ModConfig.EnableRelic.Value || !RelicLedger.IsLoaded) { return 1f; } RelicLedger.Relic relic = RelicLedger.RelicAt(zone); return RelicMath.RecoveryMultiplier(relic.Type, relic.Cursed, ModConfig.RelicBlessedRecoveryMult.Value, ModConfig.RelicCursedRecoveryMult.Value); } public static float ExposureDecayMultAt(ZoneKey zone) { if (!ModConfig.EnableRelic.Value || !RelicLedger.IsLoaded) { return 1f; } RelicLedger.Relic relic = RelicLedger.RelicAt(zone); return RelicMath.ExposureDecayMultiplier(relic.Type, relic.Cursed, ModConfig.RelicBlessedExposureDrainMult.Value); } public static float ExposureMinutesMultAt(ZoneKey zone) { if (!ModConfig.EnableRelic.Value || !RelicLedger.IsLoaded) { return 1f; } RelicLedger.Relic relic = RelicLedger.RelicAt(zone); return RelicMath.ExposureMinutesMultiplier(relic.Type, relic.Cursed, ModConfig.RelicCursedExposureAccrualMult.Value); } public void Initialise() { RagnaroksWrath.Log.LogInfo((object)("[" + Name + "] consecrated places: fire healed / plague cured -> blessed, war resolved -> by the victor, Stricken recovered -> the era stone. Auras: " + $"recovery x{ModConfig.RelicBlessedRecoveryMult.Value:0.##} blessed / " + $"x{ModConfig.RelicCursedRecoveryMult.Value:0.##} cursed; exposure drain " + $"x{ModConfig.RelicBlessedExposureDrainMult.Value:0.##} blessed, accrual " + $"x{ModConfig.RelicCursedExposureAccrualMult.Value:0.##} cursed.")); } public void Tick(float deltaSeconds) { if (!Persistence.IsLoaded) { _warResults.Clear(); return; } if (!_ledgerLoaded) { RelicLedger.Load(); _ledgerLoaded = RelicLedger.IsLoaded; } if (!_ledgerLoaded) { _warResults.Clear(); return; } RelicSync.EnsureRegistered(); CollectPresence(); UpdatePeaks(); ConsecrateCompletions(); DrainWarResults(); WatchEra(); RetryPending(); RetryPlacement(); TellStories(); _sinceBroadcast += deltaSeconds; if (_sinceBroadcast >= 60f) { _sinceBroadcast = 0f; RelicSync.BroadcastAll(); } _sinceSave += deltaSeconds; if (_sinceSave >= 60f) { _sinceSave = 0f; RelicLedger.SaveIfDirty(); } } public static void OnRelicBroken(ZoneKey zone, long vandalPlayerId) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (RelicLedger.IsLoaded && RelicLedger.RelicAt(zone).Standing) { RelicLedger.RemoveRelic(zone); RelicSync.BroadcastRemoval(zone); if (vandalPlayerId != 0L && ModConfig.EnableRivalry.Value && RivalryLedger.IsLoaded) { RivalryLedger.AddHarm(zone, vandalPlayerId, ModConfig.RelicVandalHarm.Value); } MessageFeed.ToPlayersNear(zone.ToWorldPos(), 64f, "The stone lies broken. The land forgets.", MessageFeed.Placement.Centre); RagnaroksWrath.Log.LogInfo((object)($"[RelicSystem] relic in {zone} desecrated" + ((vandalPlayerId != 0L) ? $" by {vandalPlayerId} (harm booked)." : " (no attacker identified)."))); } } private void CollectPresence() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) _presentPeer.Clear(); _occupied.Clear(); ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return; } List<ZDO> allCharacterZDOS; try { allCharacterZDOS = instance.GetAllCharacterZDOS(); } catch { return; } if (allCharacterZDOS == null) { return; } int num = Math.Max(0, ModConfig.BiomeContactRadiusZones.Value); for (int i = 0; i < allCharacterZDOS.Count; i++) { ZDO val = allCharacterZDOS[i]; if (val == null || !val.IsValid() || val.GetLong(ZDOVars.s_playerID, 0L) == 0L) { continue; } ZoneKey item = ZoneKey.FromWorldPos(val.GetPosition()); _occupied.Add(item); long owner = val.GetOwner(); for (int j = -num; j <= num; j++) { for (int k = -num; k <= num; k++) { ZoneKey key = new ZoneKey(item.X + j, item.Y + k); if (owner != 0L && !_presentPeer.ContainsKey(key)) { _presentPeer[key] = owner; } } } } } private void UpdatePeaks() { float value = ModConfig.FireRelicPeakThreshold.Value; float value2 = ModConfig.PlagueRelicPeakThreshold.Value; foreach (KeyValuePair<ZoneKey, ZoneState> item in Persistence.All()) { if (!RelicLedger.RelicAt(item.Key).Standing) { RelicLedger.Peaks peaks = RelicLedger.PeaksFor(item.Key); float num = RelicMath.TrackPeak(item.Value.Scorch, value, peaks.Scorch); float num2 = RelicMath.TrackPeak(item.Value.Plague, value2, peaks.Plague); if (num != peaks.Scorch || num2 != peaks.Plague) { RelicLedger.SetPeaks(item.Key, new RelicLedger.Peaks { Scorch = num, Plague = num2 }); } } } } private void ConsecrateCompletions() { _peaksSnapshot.Clear(); foreach (KeyValuePair<ZoneKey, RelicLedger.Peaks> item in RelicLedger.AllPeaks()) { _peaksSnapshot.Add(item); } for (int i = 0; i < _peaksSnapshot.Count; i++) { ZoneKey key = _peaksSnapshot[i].Key; RelicLedger.Peaks value = _peaksSnapshot[i].Value; ZoneState zoneState = Persistence.Get(key); if (RelicMath.ShouldConsecrate(value.Scorch, zoneState.Scorch)) { TryConsecrate(key, 0, cursed: false); } else if (RelicMath.ShouldConsecrate(value.Plague, zoneState.Plague)) { TryConsecrate(key, 1, cursed: false); } } } private void DrainWarResults() { for (int i = 0; i < _warResults.Count; i++) { TryConsecrate(_warResults[i].Key, 2, !_warResults[i].Value); } _warResults.Clear(); } private void WatchEra() { WorldCondition condition = WorldStateSystem.Condition; if (!_conditionSeen) { _conditionSeen = true; _lastCondition = condition; } else { if (condition == _lastCondition) { return; } if (condition == WorldCondition.Stricken && !RelicLedger.EraArmed) { int num = 0; foreach (KeyValuePair<ZoneKey, ZoneState> item in Persistence.All()) { float num2 = RivalryMath.ZoneDamage(item.Value); if (num2 > 0f) { RelicLedger.SetEraSnapshot(item.Key, num2); num++; } } RagnaroksWrath.Log.LogInfo((object)$"[{Name}] the land is stricken — era armed over {num} zone(s)."); } else if (RelicLedger.EraArmed && (condition == WorldCondition.Stable || condition == WorldCondition.Flourishing)) { ZoneKey zoneKey = default(ZoneKey); float num3 = 0f; foreach (KeyValuePair<ZoneKey, float> item2 in RelicLedger.EraSnapshot()) { if (!RelicLedger.RelicAt(item2.Key).Standing) { float num4 = item2.Value - RivalryMath.ZoneDamage(Persistence.Get(item2.Key)); if (num4 > num3) { num3 = num4; zoneKey = item2.Key; } } } RelicLedger.ClearEra(); if (num3 > 0f) { RagnaroksWrath.Log.LogInfo((object)$"[{Name}] the era turns — {zoneKey} healed {num3:0.###}, the most of any ground."); TryConsecrate(zoneKey, 3, cursed: false); } } _lastCondition = condition; } } private void RetryPending() { if (RelicLedger.PendingCount == 0) { return; } _scratch.Clear(); foreach (KeyValuePair<ZoneKey, RelicLedger.Relic> item in RelicLedger.AllPending()) { if (_presentPeer.ContainsKey(item.Key)) { _scratch.Add(item.Key); } } for (int i = 0; i < _scratch.Count; i++) { RelicLedger.Relic relic = default(RelicLedger.Relic); foreach (KeyValuePair<ZoneKey, RelicLedger.Relic> item2 in RelicLedger.AllPending()) { if (item2.Key == _scratch[i]) { relic = item2.Value; break; } } RelicLedger.RemovePending(_scratch[i]); Commit(_scratch[i], relic); } } private void RetryPlacement() { foreach (KeyValuePair<ZoneKey, RelicLedger.Relic> item in RelicLedger.AllRelics()) { if (!item.Value.Placed && _presentPeer.TryGetValue(item.Key, out var value)) { RelicSync.RequestPlacement(value, item.Key, item.Value); } } } private void TellStories() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair<ZoneKey, RelicLedger.Relic> item in RelicLedger.AllRelics()) { if (!_storyTold.Contains(item.Key) && _occupied.Contains(item.Key)) { _storyTold.Add(item.Key); MessageFeed.ToPlayersNear(item.Key.ToWorldPos(), 64f, RelicMath.Story(item.Value.Type, item.Value.Cursed)); } } } private void TryConsecrate(ZoneKey zone, int type, bool cursed) { if (!RelicLedger.RelicAt(zone).Standing) { RelicLedger.Relic relic = new RelicLedger.Relic { Type = type, Cursed = cursed, Day = SeasonSystem.CurrentDayOrZero() }; if (!_presentPeer.ContainsKey(zone)) { RelicLedger.AddPending(zone, relic); RagnaroksWrath.Log.LogInfo((object)$"[{Name}] consecration of {zone} queued — nobody present to raise the stone."); } else { Commit(zone, relic); } } } private void Commit(ZoneKey zone, RelicLedger.Relic relic) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (relic.Standing) { RelicLedger.SetRelic(zone, relic); RelicSync.BroadcastRelic(zone, relic); if (_presentPeer.TryGetValue(zone, out var value)) { RelicSync.RequestPlacement(value, zone, relic); } _storyTold.Remove(zone); MessageFeed.ToPlayersNear(zone.ToWorldPos(), 64f, relic.Cursed ? "The gods curse this ground. Its stone remembers." : "The gods bless this ground. Its stone remembers.", MessageFeed.Placement.Centre); RagnaroksWrath.Log.LogInfo((object)($"[{Name}] consecrated {zone}: type {relic.Type}, " + string.Format("{0}, day {1}.", relic.Cursed ? "cursed" : "blessed", relic.Day))); } } } public class RivalrySystem : IWorldSystem { private const float SaveCadenceSeconds = 60f; private bool _ledgerLoaded; private float _sinceSave; private string[] _cropPrefabs = Array.Empty<string>(); private int _prefabCursor; private readonly List<ZDO> _found = new List<ZDO>(128); private int _sweepIndex; private long _rotationMaxPlantTime; private readonly Dictionary<ZoneKey, float> _lastDamage = new Dictionary<ZoneKey, float>(64); private readonly Dictionary<ZoneKey, List<long>> _present = new Dictionary<ZoneKey, List<long>>(32); private readonly List<ZoneKey> _stale = new List<ZoneKey>(16); private static readonly Dictionary<ZoneKey, RivalryContest.Holder> _careHolders = new Dictionary<ZoneKey, RivalryContest.Holder>(32); private static readonly Dictionary<ZoneKey, RivalryContest.Holder> _harmHolders = new Dictionary<ZoneKey, RivalryContest.Holder>(32); private readonly Dictionary<ZoneKey, Dictionary<long, float>> _careValues = new Dictionary<ZoneKey, Dictionary<long, float>>(32); private readonly Dictionary<ZoneKey, Dictionary<long, float>> _harmValues = new Dictionary<ZoneKey, Dictionary<long, float>>(32); private readonly List<RivalryContest.Flip> _flips = new List<RivalryContest.Flip>(4); private readonly Dictionary<long, string> _names = new Dictionary<long, string>(8); private static readonly Dictionary<ZoneKey, float> _warIntensity = new Dictionary<ZoneKey, float>(8); private readonly Dictionary<ZoneKey, float> _warScratch = new Dictionary<ZoneKey, float>(8); private readonly List<ZoneKey> _warEnded = new List<ZoneKey>(4); public string Name => "RivalrySystem"; public bool Enabled => ModConfig.EnableRivalry.Value; public float IntervalSeconds => ModConfig.RivalryIntervalSeconds.Value; public static int ContestedZoneCount => _warIntensity.Count; public static bool IsDominantCarer(ZoneKey zone, long playerId) { if (playerId != 0L && _careHolders.TryGetValue(zone, out var value)) { return value.Player == playerId; } return false; } public static int CareZonesHeld(long playerId) { return RivalryContest.ZonesHeld(_careHolders, playerId); } public static int HarmZonesHeld(long playerId) { return RivalryContest.ZonesHeld(_harmHolders, playerId); } public static float WarIntensityAt(ZoneKey zone) { if (!_warIntensity.TryGetValue(zone, out var value)) { return 0f; } return value; } internal static void ResetWorldState() { _careHolders.Clear(); _harmHolders.Clear(); _warIntensity.Clear(); } public void Initialise() { _cropPrefabs = (ModConfig.FarmingCropPrefabs.Value ?? "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < _cropPrefabs.Length; i++) { _cropPrefabs[i] = _cropPrefabs[i].Trim(); } RagnaroksWrath.Log.LogInfo((object)("[" + Name + "] the influence ledger, all phases. Writers armed: tending " + $"({ModConfig.TendingCarePerPlant.Value:F3} care/plant, watermarked), healing presence " + $"({ModConfig.CarePerHealedPoint.Value:F2} care/healed point, split by ring), and arson " + $"({ModConfig.ArsonHarmPerScorchPoint.Value:F2} harm/scorch point) — see FireSystem's " + "own line for whether the installed FireFront exposes the igniter it needs. " + $"Both columns fade, half-life {ModConfig.RivalryHalfLifeHours.Value:F0}h.")); } public void Tick(float deltaSeconds) { if (!Persistence.IsLoaded) { return; } if (!_ledgerLoaded) { RivalryLedger.Load(); _ledgerLoaded = RivalryLedger.IsLoaded; } if (_ledgerLoaded) { RivalryLedger.DecayAll(RivalryMath.DecayFactor(ModConfig.RivalryHalfLifeHours.Value, deltaSeconds)); ObserveHealing(); SweepTending(); UpdateContest(); UpdateWar(); _sinceSave += deltaSeconds; if (_sinceSave >= 60f) { _sinceSave = 0f; RivalryLedger.SaveIfDirty(); } } } private void ObserveHealing() { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return; } List<ZDO> allCharacterZDOS; try { allCharacterZDOS = instance.GetAllCharacterZDOS(); } catch { return; } if (allCharacterZDOS == null) { return; } foreach (List<long> value5 in _present.Values) { value5.Clear(); } int num = Math.Max(0, ModConfig.BiomeContactRadiusZones.Value); for (int i = 0; i < allCharacterZDOS.Count; i++) { ZDO val = allCharacterZDOS[i]; if (val == null || !val.IsValid()) { continue; } long num2 = val.GetLong(ZDOVars.s_playerID, 0L); if (num2 == 0L) { continue; } string text = val.GetString(ZDOVars.s_playerName, ""); if (!string.IsNullOrEmpty(text) && text != "Stranger" && text != "...") { _names[num2] = text; } ZoneKey zoneKey = ZoneKey.FromWorldPos(val.GetPosition()); for (int j = -num; j <= num; j++) { for (int k = -num; k <= num; k++) { ZoneKey key = new ZoneKey(zoneKey.X + j, zoneKey.Y + k); if (!_present.TryGetValue(key, out var value)) { value = (_present[key] = new List<long>(4)); } value.Add(num2); } } } float value2 = ModConfig.CarePerHealedPoint.Value; foreach (KeyValuePair<ZoneKey, List<long>> item in _present) { if (item.Value.Count == 0) { continue; } float num3 = RivalryMath.ZoneDamage(Persistence.Get(item.Key)); if (_lastDamage.TryGetValue(item.Key, out var value3)) { float num4 = RivalryMath.SplitAmong(RivalryMath.CareFromHealing(value3, num3, value2), item.Value.Count); if (num4 > 0f) { for (int l = 0; l < item.Value.Count; l++) { RivalryLedger.AddCare(item.Key, item.Value[l], num4); } } } _lastDamage[item.Key] = num3; } _stale.Clear(); foreach (KeyValuePair<ZoneKey, float> item2 in _lastDamage) { if (!_present.TryGetValue(item2.Key, out var value4) || value4.Count == 0) { _stale.Add(item2.Key); } } for (int m = 0; m < _stale.Count; m++) { _lastDamage.Remove(_stale[m]); } } private void SweepTending() { //IL_011f: Unknown result type (might be due to invalid IL or missing references) if (_cropPrefabs.Length == 0 || ModConfig.TendingCarePerPlant.Value <= 0f) { return; } ZDOMan instance = ZDOMan.instance; if (instance == null) { return; } string text = _cropPrefabs[_prefabCursor]; try { bool flag = false; while (!flag) { flag = instance.GetAllZDOsWithPrefabIterative(text, _found, ref _sweepIndex); } } catch (Exception ex) { RagnaroksWrath.Log.LogWarning((object)("[" + Name + "] tending sweep failed on '" + text + "': " + ex.Message)); _found.Clear(); _sweepIndex = 0; return; } long plantWatermark = RivalryLedger.PlantWatermark; int num = 0; for (int i = 0; i < _found.Count; i++) { ZDO val = _found[i]; if (val == null || !val.IsValid()) { continue; } long num2 = val.GetLong(ZDOVars.s_plantTime, 0L); if (num2 > _rotationMaxPlantTime) { _rotationMaxPlantTime = num2; } if (RivalryMath.IsNewPlant(num2, plantWatermark)) { long num3 = val.GetLong(ZDOVars.s_creator, 0L); if (num3 != 0L) { RivalryLedger.AddCare(ZoneKey.FromWorldPos(val.GetPosition()), num3, ModConfig.TendingCarePerPlant.Value); num++; } } } if (ModConfig.VerboseLogging.Value && num > 0) { RagnaroksWrath.Log.LogInfo((object)$"[{Name}] '{text}': {num} new plant(s) booked."); } _found.Clear(); _sweepIndex = 0; _prefabCursor++; if (_prefabCursor >= _cropPrefabs.Length) { _prefabCursor = 0; RivalryLedger.PlantWatermark = _rotationMaxPlantTime; _rotationMaxPlantTime = 0L; } } private void UpdateContest() { foreach (Dictionary<long, float> value4 in _careValues.Values) { value4.Clear(); } foreach (Dictionary<long, float> value5 in _harmValues.Values) { value5.Clear(); } foreach (KeyValuePair<RivalryLedger.Key, RivalryLedger.Row> item in RivalryLedger.All()) { if (item.Value.Care > 0f) { if (!_careValues.TryGetValue(item.Key.Zone, out var value)) { value = (_careValues[item.Key.Zone] = new Dictionary<long, float>(4)); } value[item.Key.Player] = item.Value.Care; } if (item.Value.Harm > 0f) { if (!_harmValues.TryGetValue(item.Key.Zone, out var value2)) { value2 = (_harmValues[item.Key.Zone] = new Dictionary<long, float>(4)); } value2[item.Key.Player] = item.Value.Harm; } } PruneEmpty(_careValues); PruneEmpty(_harmValues); float value3 = ModConfig.ContestHysteresis.Value; _flips.Clear(); RivalryContest.Update(_careValues, _careHolders, ModConfig.CareDominanceFloor.Value, value3, _flips); Announce(_flips, "{0} now tends this ground more than {1}."); _flips.Clear(); RivalryContest.Update(_harmValues, _harmHolders, ModConfig.HarmDominanceFloor.Value, value3, _flips); Announce(_flips, "This ground now fears {0} more than {1}."); } private static void PruneEmpty(Dictionary<ZoneKey, Dictionary<long, float>> values) { List<ZoneKey> list = null; foreach (KeyValuePair<ZoneKey, Dictionary<long, float>> value in values) { if (value.Value.Count == 0) { List<ZoneKey> obj = list ?? new List<ZoneKey>(4); list = obj; obj.Add(value.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { values.Remove(list[i]); } } } private void UpdateWar() { //IL_00b2: 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) float value = ModConfig.ContestBlightThreshold.Value; float value2 = ModConfig.ContestCareThreshold.Value; float value3 = ModConfig.StormContestMultiplier.Value; _warScratch.Clear(); foreach (KeyValuePair<ZoneKey, Dictionary<long, float>> careValue in _careValues) { float num = 0f; foreach (float value4 in careValue.Value.Values) { num += value4; } if (RivalryContest.IsContested(RivalryContest.BlightOf(Persistence.Get(careValue.Key)), num, value, value2)) { bool inStorm = WeatherSystem.IsStormAt(careValue.Key.ToWorldPos()); _warScratch[careValue.Key] = RivalryContest.Intensity(contested: true, inStorm, value3); } } _warEnded.Clear(); foreach (KeyValuePair<ZoneKey, float> item in _warIntensity) { if (!_warScratch.ContainsKey(item.Key)) { _warEnded.Add(item.Key); } } for (int i = 0; i < _warEnded.Count; i++) { ZoneKey zoneKey = _warEnded[i]; RivalryContest.WarWinner warWinner = RivalryContest.Winner(RivalryContest.BlightOf(Persistence.Get(zoneKey)), value); if (ModConfig.AnnounceContests.Value) { MessageFeed.ToPlayersNear(zoneKey.ToWorldPos(), 64f, (warWinner == RivalryContest.WarWinner.Wild) ? "The wild has taken this ground back." : "The blight has claimed this ground.", MessageFeed.Placement.Centre); } RagnaroksWrath.Log.LogInfo((object)$"[{Name}] war in {zoneKey} resolved: {warWinner}."); RelicSystem.NotifyWarResolved(zoneKey, warWinner == RivalryContest.WarWinner.Wild); }