using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] namespace TheFloods; [BepInPlugin("marc.thefloods", "The Broken Cycle", "0.10.2")] public sealed class TheFloodsPlugin : BaseUnityPlugin { public const string PluginGuid = "marc.thefloods"; public const string PluginName = "The Broken Cycle"; public const string PluginVersion = "0.10.2"; internal static TheFloodsPlugin Instance; private FloodConfig _config; private FloodDirector _director; private FloodVisuals _visuals; private FloodWaterAdapter _waterAdapter; private FloodEnvironmentAdapter _environmentAdapter; private bool _rpcRegistered; private bool _loggedReady; internal void ReapplyWaterAfterNativeUpdate(WaterVolume volume) { if (_waterAdapter != null) { _waterAdapter.ReapplyAfterNativeUpdate(volume); } } private void LateUpdate() { try { if (_waterAdapter != null) { _waterAdapter.ReapplyForFrame(); _waterAdapter.SyncPhysicsIfNeeded(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("The Floods late water sync warning: " + ex.Message)); } } private void OnEnable() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnCameraPreCull)); } private void OnDisable() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnCameraPreCull)); } private void OnCameraPreCull(Camera camera) { try { if (_waterAdapter != null) { _waterAdapter.ReapplyVisualsForRender(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("The Floods camera water sync warning: " + ex.Message)); } } private void Awake() { //IL_0084: Unknown result type (might be due to invalid IL or missing references) Instance = this; _config = new FloodConfig(((BaseUnityPlugin)this).Config); _waterAdapter = new FloodWaterAdapter(((BaseUnityPlugin)this).Logger, _config); _environmentAdapter = new FloodEnvironmentAdapter(((BaseUnityPlugin)this).Logger, _config); _visuals = new FloodVisuals(_config); _director = new FloodDirector(((BaseUnityPlugin)this).Logger, _config, _waterAdapter, _environmentAdapter, _visuals); new Harmony("marc.thefloods").PatchAll(typeof(TheFloodsPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"The Broken Cycle 0.10.2: loaded. Waiting for world network."); } private void Update() { try { if (!_rpcRegistered && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register("TheFloods_State_01", (Action)ReceiveStateRpc); ZRoutedRpc.instance.Register("TheFloods_Message_01", (Action)ReceiveMessageRpc); ZRoutedRpc.instance.Register("TheFloods_Strike_01", (Action)ReceiveStrikeRpc); _rpcRegistered = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"The Floods: routed RPC handlers registered."); } _director.Tick(); if (!_loggedReady && _director.IsWorldReady) { _loggedReady = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"The Floods: world controller ready. Type 'floods help' in F5 for testing controls."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("The Floods Update error: " + ex)); } } private void OnGUI() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 try { if (Event.current != null && (int)Event.current.type == 7) { _visuals.Draw(_director.CurrentState, _director.CurrentStormStrength, _director.CurrentWildfireIntensity, _director.CurrentStormApproach, _config); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("The Floods sky overlay error: " + ex.Message)); } } private void OnDestroy() { try { _waterAdapter.Dispose(); if (_director != null) { _director.Dispose(); } _environmentAdapter.ReleaseForcedEnvironment(); _visuals.Dispose(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("The Floods cleanup warning: " + ex.Message)); } finally { Instance = null; } } private static void ReceiveStateRpc(long sender, string payload) { if (!((Object)(object)Instance == (Object)null)) { Instance._director.ReceiveState(payload); } } private static void ReceiveMessageRpc(long sender, string message) { if ((Object)(object)MessageHud.instance != (Object)null && !string.IsNullOrWhiteSpace(message)) { MessageHud.instance.ShowMessage((MessageType)2, message, 0, (Sprite)null, false); } } private static void ReceiveStrikeRpc(long sender, string payload) { if (!((Object)(object)Instance == (Object)null)) { Instance._director.ReceiveStrike(payload); } } internal bool TryHandleConsoleCommand(Terminal terminal) { string text = TerminalReflection.ReadInput(terminal); if (string.IsNullOrWhiteSpace(text)) { return false; } string[] array = text.Trim().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); bool flag = array.Length != 0 && array[0].Equals("floods", StringComparison.OrdinalIgnoreCase); bool flag2 = array.Length != 0 && array[0].Equals("strongwinds", StringComparison.OrdinalIgnoreCase); if (array.Length == 0 || (!flag && !flag2)) { return false; } TerminalReflection.ClearInput(terminal); if (!_director.IsAuthoritative) { TerminalReflection.Write(terminal, "The Floods: commands must be run by the world host/server."); return true; } string message = (flag2 ? _director.HandleStrongWindsCommand(array.Skip(1).ToArray()) : _director.HandleCommand(array.Skip(1).ToArray())); TerminalReflection.Write(terminal, message); return true; } } internal sealed class FloodEventProfile { internal readonly FloodEventType Type; internal readonly string DisplayName; internal readonly ConfigEntry Enabled; internal readonly ConfigEntry HeightMeters; internal readonly ConfigEntry MinimumHeightMeters; internal readonly ConfigEntry MaximumHeightMeters; internal readonly ConfigEntry OmenDays; internal readonly ConfigEntry RisingDays; internal readonly ConfigEntry PeakDays; internal readonly ConfigEntry RecedingDays; internal readonly ConfigEntry CooldownDays; internal readonly ConfigEntry DailyChance; internal FloodEventProfile(ConfigFile config, FloodEventType type, string section, string displayName, float defaultHeight, float defaultMinimumHeight, float defaultMaximumHeight, float defaultOmenDays, float defaultRisingDays, float defaultPeakDays, float defaultRecedingDays, int defaultCooldownDays, float defaultDailyChance) { Type = type; DisplayName = displayName; Enabled = config.Bind(section, "Enabled", true, "Allow this event to occur naturally."); HeightMeters = config.Bind(section, "HeightMeters", defaultHeight, "Legacy nominal height retained for older configs. Named events use MinimumHeightMeters and MaximumHeightMeters."); MinimumHeightMeters = config.Bind(section, "MinimumHeightMeters", defaultMinimumHeight, "Lowest possible sea-level surge when this event begins. The exact height is rolled once and saved with the event."); MaximumHeightMeters = config.Bind(section, "MaximumHeightMeters", defaultMaximumHeight, "Highest possible sea-level surge when this event begins. The exact height is rolled once and saved with the event."); OmenDays = config.Bind(section, "OmenDays", defaultOmenDays, "How long the distant warning phase lasts in Valheim days."); RisingDays = config.Bind(section, "RisingDays", defaultRisingDays, "How long the water takes to reach its height in Valheim days."); PeakDays = config.Bind(section, "PeakDays", defaultPeakDays, "How long the event remains at full strength in Valheim days."); RecedingDays = config.Bind(section, "RecedingDays", defaultRecedingDays, "How long the water takes to return in Valheim days."); CooldownDays = config.Bind(section, "CooldownDays", defaultCooldownDays, "Minimum completed in-game days before this event can occur naturally again."); DailyChance = config.Bind(section, "DailyChance", defaultDailyChance, "Natural chance for this event on each eligible in-game day. 0.01 = 1%."); } internal float GetMinimumHeight() { return Mathf.Min(MinimumHeightMeters.Value, MaximumHeightMeters.Value); } internal float GetMaximumHeight() { return Mathf.Max(MinimumHeightMeters.Value, MaximumHeightMeters.Value); } } internal sealed class FloodConfig { internal readonly ConfigEntry Enabled; internal readonly ConfigEntry MinimumWorldDay; internal readonly ConfigEntry GameDaySeconds; internal readonly ConfigEntry OmenDays; internal readonly ConfigEntry RisingDays; internal readonly ConfigEntry PeakDays; internal readonly ConfigEntry RecedingDays; internal readonly ConfigEntry MaximumSurgeMeters; internal readonly ConfigEntry DebugMaximumSurgeMeters; internal readonly FloodEventProfile StormTide; internal readonly FloodEventProfile FlashSurge; internal readonly FloodEventProfile GreatFlood; internal readonly FloodEventProfile Drought; internal readonly FloodEventProfile Wildfire; internal readonly ConfigEntry FirstOrdinaryEventMinimumHours; internal readonly ConfigEntry FirstOrdinaryEventMaximumHours; internal readonly ConfigEntry OrdinaryRecoveryMinimumHours; internal readonly ConfigEntry OrdinaryRecoveryMaximumHours; internal readonly ConfigEntry FlashSurgeRecoveryMinimumHours; internal readonly ConfigEntry FlashSurgeRecoveryMaximumHours; internal readonly ConfigEntry GreatFloodRecoveryMinimumHours; internal readonly ConfigEntry GreatFloodRecoveryMaximumHours; internal readonly ConfigEntry StormTideWeight; internal readonly ConfigEntry DroughtWeight; internal readonly ConfigEntry FlashSurgeWeight; internal readonly ConfigEntry GreatFloodFirstEligibleWorldHours; internal readonly ConfigEntry GreatFloodFirstTargetMinimumWorldHours; internal readonly ConfigEntry GreatFloodFirstTargetMaximumWorldHours; internal readonly ConfigEntry GreatFloodFirstForceByWorldHours; internal readonly ConfigEntry GreatFloodRepeatMinimumHours; internal readonly ConfigEntry GreatFloodRepeatMaximumHours; internal readonly ConfigEntry GreatFloodRepeatForceByHours; internal readonly ConfigEntry SevereDroughtChance; internal readonly ConfigEntry SevereDroughtMinimumMeters; internal readonly ConfigEntry SevereDroughtMaximumMeters; internal readonly ConfigEntry EnableFlashSurgeDrawdown; internal readonly ConfigEntry FlashSurgeDrawdownMinimumMeters; internal readonly ConfigEntry FlashSurgeDrawdownMaximumMeters; internal readonly ConfigEntry EnableLiveWaterLevel; internal readonly ConfigEntry EnableWaterSurfaceQueryPatch; internal readonly ConfigEntry EnableOceanRendererLift; internal readonly ConfigEntry OceanRendererMinimumSpan; internal readonly ConfigEntry WaterSurfaceScanSeconds; internal readonly ConfigEntry EnableNativeThunderstorm; internal readonly ConfigEntry NativeStormEnvironment; internal readonly ConfigEntry NativeStormStartStrength; internal readonly ConfigEntry SkyDarkening; internal readonly ConfigEntry EnableBlackHorizonStormBank; internal readonly ConfigEntry HorizonStormBankOpacity; internal readonly ConfigEntry HorizonStormBankHeight; internal readonly ConfigEntry EnableDistantLightningFlashes; internal readonly ConfigEntry WildfireSkyTintStrength; internal readonly ConfigEntry EnableApproachingStormFront; internal readonly ConfigEntry StormFrontDarkness; internal readonly ConfigEntry StormFrontHorizonHeight; internal readonly ConfigEntry EnableCustomStormAudio; internal readonly ConfigEntry MasterStormAudioVolume; internal readonly ConfigEntry IndoorStormAudioVolume; internal readonly ConfigEntry OutdoorWindAudioVolume; internal readonly ConfigEntry AudioFadeDuration; internal readonly ConfigEntry DebugAudioLogging; internal readonly ConfigEntry EnableLightningStrikes; internal readonly ConfigEntry EnableAmbientBolts; internal readonly ConfigEntry PlayerStrikeMinStrength; internal readonly ConfigEntry StrikeGapMinSeconds; internal readonly ConfigEntry StrikeGapMaxSeconds; internal readonly ConfigEntry DirectHitChance; internal readonly ConfigEntry StrikeGraceSeconds; internal readonly ConfigEntry MinLightningDamage; internal readonly ConfigEntry MaxLightningDamage; internal readonly ConfigEntry WetDamageMultiplier; internal readonly ConfigEntry LightningPushForce; internal readonly ConfigEntry RequireExposed; internal readonly ConfigEntry NonLethalLightning; internal readonly ConfigEntry BoltLightIntensity; internal readonly ConfigEntry BoltLightRange; internal readonly ConfigEntry BoltDurationSeconds; internal readonly ConfigEntry AmbientBoltsPerMinuteAtPeak; internal readonly ConfigEntry EnableThunderAudio; internal readonly ConfigEntry ThunderVolume; internal readonly ConfigEntry SpeedOfSoundMetersPerSecond; internal readonly ConfigEntry RainEnvironmentNames; internal readonly ConfigEntry DrynessRisePerHour; internal readonly ConfigEntry DrynessRiseDroughtMultiplier; internal readonly ConfigEntry DrynessRainResetSeconds; internal readonly ConfigEntry RainWetStormStrength; internal readonly ConfigEntry WildfireWeight; internal readonly ConfigEntry SpontaneousDrynessThreshold; internal readonly ConfigEntry SpontaneousPerWindowChance; internal readonly ConfigEntry SpontaneousWindowMinimumHours; internal readonly ConfigEntry SpontaneousWindowMaximumHours; internal readonly ConfigEntry LightningIgnitionChance; internal readonly ConfigEntry IgnitionMinRadius; internal readonly ConfigEntry IgnitionMaxRadius; internal readonly ConfigEntry MaxFireNodes; internal readonly ConfigEntry SpreadIntervalSeconds; internal readonly ConfigEntry SpreadChance; internal readonly ConfigEntry SpreadStepMeters; internal readonly ConfigEntry NodeLifeSeconds; internal readonly ConfigEntry NodeRadius; internal readonly ConfigEntry PlayerFireDamagePerTick; internal readonly ConfigEntry FireDamageIntervalSeconds; internal readonly ConfigEntry DamageStructures; internal readonly ConfigEntry DownwindBias; internal readonly ConfigEntry WildfireForcedEnvironment; internal readonly ConfigEntry EmberBedEnabled; internal readonly ConfigEntry EmberBedRadiusMultiplier; internal readonly ConfigEntry EmberBedOpacity; internal readonly ConfigEntry FlameStretchLength; internal readonly ConfigEntry MaxDetailedFireDistance; internal readonly ConfigEntry MeadowsFlammability; internal readonly ConfigEntry BlackForestFlammability; internal readonly ConfigEntry PlainsFlammability; internal readonly ConfigEntry SwampFlammability; internal readonly ConfigEntry MountainFlammability; internal readonly ConfigEntry MistlandsFlammability; internal readonly ConfigEntry AshlandsFlammability; internal readonly ConfigEntry DeepNorthFlammability; internal readonly ConfigEntry OtherBiomeFlammability; internal readonly ConfigEntry EnableStrongWinds; internal readonly ConfigEntry StrongWindsEventChance; internal readonly ConfigEntry StrongWindsCooldownHours; internal readonly ConfigEntry StrongWindsDurationMinutes; internal readonly ConfigEntry StrongWindsMinimumWorldDay; internal readonly ConfigEntry StrongWindsWindStrengthMultiplier; internal readonly ConfigEntry EnableTreefall; internal readonly ConfigEntry TreefallChance; internal readonly ConfigEntry TreefallDistanceFromPlayer; internal readonly ConfigEntry MaxTreefallsPerPlayer; internal readonly ConfigEntry MaxTreefallsGlobally; internal readonly ConfigEntry TreefallCooldownPerZoneSeconds; internal readonly ConfigEntry ProtectedBaseRadius; internal readonly ConfigEntry FallingTreeDamageToPlayers; internal readonly ConfigEntry FallingTreeDamageToCreatures; internal readonly ConfigEntry StrongWindStructureDamage; internal readonly ConfigEntry WindDebrisAmount; internal readonly ConfigEntry StrongWindsDebugMode; internal readonly ConfigEntry StrongWindsDebugIgnoreBaseProtection; internal readonly ConfigEntry DebugLogging; internal readonly ConfigEntry VerboseWaterTileBindingLogs; internal readonly ConfigEntry StartTestEventOnWorldLoad; internal readonly ConfigEntry TestStartPhase; internal FloodConfig(ConfigFile config) { Enabled = config.Bind("General", "Enabled", true, "Master switch for The Floods."); MinimumWorldDay = config.Bind("Event Rules", "MinimumWorldDay", 6, "No natural water event can occur before this Valheim day. V0.8 defaults to day 6 so an ordinary event can arrive during an active early world without appearing on day one."); GameDaySeconds = config.Bind("Timeline", "GameDaySecondsFallback", 1800f, "Fallback full Valheim day length used only if the game day API is unavailable."); OmenDays = config.Bind("Timeline", "OmenDays", 0.5f, "Custom/debug event omen duration in Valheim days."); RisingDays = config.Bind("Timeline", "RisingDays", 2f, "Custom/debug event rise duration in Valheim days."); PeakDays = config.Bind("Timeline", "PeakDays", 2f, "Custom/debug event peak duration in Valheim days."); RecedingDays = config.Bind("Timeline", "RecedingDays", 2f, "Custom/debug event receding duration in Valheim days."); MaximumSurgeMeters = config.Bind("Flood Height", "MaximumSurgeMeters", 3.5f, "Height used by legacy floods start and debug test events."); DebugMaximumSurgeMeters = config.Bind("Flood Height", "DebugMaximumSurgeMeters", 20f, "Safety cap for floods set ."); StormTide = new FloodEventProfile(config, FloodEventType.StormTide, "Storm Tide", "Storm Tide", 2.5f, 1.5f, 5f, 0.066667f, 0.166667f, 0.2f, 0.2f, 7, 0.075f); FlashSurge = new FloodEventProfile(config, FloodEventType.FlashSurge, "Flash Surge", "Flash Surge", 10f, 6f, 12f, 0.035f, 0.066667f, 0.1f, 0.233333f, 20, 0.028f); GreatFlood = new FloodEventProfile(config, FloodEventType.GreatFlood, "The Great Flood", "The Great Flood", 12f, 8f, 16f, 0.233333f, 0.6f, 0.4f, 0.6f, 55, 0.0075f); Drought = new FloodEventProfile(config, FloodEventType.Drought, "Drought", "Drought", 4f, 3f, 5f, 0.1f, 0.3f, 0.4f, 0.3f, 10, 0.12f); Wildfire = new FloodEventProfile(config, FloodEventType.Wildfire, "Wildfire", "Wildfire", 0f, 0f, 0f, 0.08f, 0.18f, 0.28f, 0.22f, 12, 0.02f); FirstOrdinaryEventMinimumHours = config.Bind("Water Cycle Scheduler", "FirstOrdinaryEventMinimumHours", 0.75f, "After MinimumWorldDay, the first ordinary event begins after a hidden random delay in this range. Hours are active server/world hours."); FirstOrdinaryEventMaximumHours = config.Bind("Water Cycle Scheduler", "FirstOrdinaryEventMaximumHours", 2f, "Largest hidden delay after MinimumWorldDay before the first ordinary event can begin."); OrdinaryRecoveryMinimumHours = config.Bind("Water Cycle Scheduler", "OrdinaryRecoveryMinimumHours", 1.5f, "Random quiet-world minimum after a Storm Tide or Drought ends before another ordinary event can begin."); OrdinaryRecoveryMaximumHours = config.Bind("Water Cycle Scheduler", "OrdinaryRecoveryMaximumHours", 3.5f, "Random quiet-world maximum after a Storm Tide or Drought ends before another ordinary event can begin."); FlashSurgeRecoveryMinimumHours = config.Bind("Water Cycle Scheduler", "FlashSurgeRecoveryMinimumHours", 2.5f, "Random quiet-world minimum after a Flash Surge ends before another ordinary event can begin."); FlashSurgeRecoveryMaximumHours = config.Bind("Water Cycle Scheduler", "FlashSurgeRecoveryMaximumHours", 5f, "Random quiet-world maximum after a Flash Surge ends before another ordinary event can begin."); GreatFloodRecoveryMinimumHours = config.Bind("Water Cycle Scheduler", "GreatFloodRecoveryMinimumHours", 6f, "Random quiet-world minimum after the Great Flood ends before any natural water event can begin."); GreatFloodRecoveryMaximumHours = config.Bind("Water Cycle Scheduler", "GreatFloodRecoveryMaximumHours", 10f, "Random quiet-world maximum after the Great Flood ends before any natural water event can begin."); StormTideWeight = config.Bind("Water Cycle Scheduler", "StormTideWeight", 45f, "Relative chance that the next ordinary water event is a Storm Tide."); DroughtWeight = config.Bind("Water Cycle Scheduler", "DroughtWeight", 40f, "Relative chance that the next ordinary water event is a Drought."); FlashSurgeWeight = config.Bind("Water Cycle Scheduler", "FlashSurgeWeight", 15f, "Relative chance that the next ordinary water event is a Flash Surge."); GreatFloodFirstEligibleWorldHours = config.Bind("Water Cycle Scheduler", "GreatFloodFirstEligibleWorldHours", 8f, "The Great Flood cannot naturally occur before this much total active world age."); GreatFloodFirstTargetMinimumWorldHours = config.Bind("Water Cycle Scheduler", "GreatFloodFirstTargetMinimumWorldHours", 15f, "Earliest target age for a world's first Great Flood. The exact target is hidden and randomized."); GreatFloodFirstTargetMaximumWorldHours = config.Bind("Water Cycle Scheduler", "GreatFloodFirstTargetMaximumWorldHours", 25f, "Latest target age for a world's first Great Flood. The exact target is hidden and randomized."); GreatFloodFirstForceByWorldHours = config.Bind("Water Cycle Scheduler", "GreatFloodFirstForceByWorldHours", 32f, "Safety limit: if a mature world still has not seen its first Great Flood, the scheduler waits for the next safe quiet window and begins one by this world age."); GreatFloodRepeatMinimumHours = config.Bind("Water Cycle Scheduler", "GreatFloodRepeatMinimumHours", 35f, "Minimum active-world hours before another Great Flood can be scheduled after one completes."); GreatFloodRepeatMaximumHours = config.Bind("Water Cycle Scheduler", "GreatFloodRepeatMaximumHours", 60f, "Maximum randomized active-world hours before another Great Flood is scheduled after one completes."); GreatFloodRepeatForceByHours = config.Bind("Water Cycle Scheduler", "GreatFloodRepeatForceByHours", 72f, "Safety limit after a Great Flood: the next one will be allowed at the first safe quiet window by this many active-world hours later."); SevereDroughtChance = config.Bind("Drought", "SevereDroughtChance", 0.2f, "Chance that a naturally scheduled Drought becomes a Severe Drought instead of the normal 3–5m retreat. 0.20 means 20%."); SevereDroughtMinimumMeters = config.Bind("Drought", "SevereDroughtMinimumMeters", 5f, "Smallest sea retreat for a Severe Drought."); SevereDroughtMaximumMeters = config.Bind("Drought", "SevereDroughtMaximumMeters", 7.5f, "Largest sea retreat for a Severe Drought."); RemoveLegacyDailyRollSettings(config); EnableFlashSurgeDrawdown = config.Bind("Flash Surge", "EnableDrawdown", true, "Before a Flash Surge, the sea can briefly pull back as a warning."); FlashSurgeDrawdownMinimumMeters = config.Bind("Flash Surge", "DrawdownMinimumMeters", 1f, "Smallest pre-surge sea retreat in metres. Used only when EnableDrawdown is true."); FlashSurgeDrawdownMaximumMeters = config.Bind("Flash Surge", "DrawdownMaximumMeters", 3f, "Largest pre-surge sea retreat in metres. Used only when EnableDrawdown is true."); EnableLiveWaterLevel = config.Bind("Flood Height", "EnableLiveWaterLevel", true, "Master switch for the live flood-water adapter. Use a copied test world first."); EnableWaterSurfaceQueryPatch = config.Bind("Flood Height", "EnableWaterSurfaceQueryPatch", true, "Uses Valheim WaterVolume terrain-water offsets for live flood physics without editing terrain."); EnableOceanRendererLift = config.Bind("Flood Height", "EnableOceanRendererLift", true, "Raises terrain-water mesh children so the shoreline visibly floods. Does not move terrain."); OceanRendererMinimumSpan = config.Bind("Flood Height", "OceanRendererMinimumSpan", 256f, "Legacy compatibility setting. Ocean tiles are identified through their linked Heightmap."); WaterSurfaceScanSeconds = config.Bind("Flood Height", "WaterSurfaceScanSeconds", 3f, "How often the mod scans for newly loaded terrain water tiles."); EnableNativeThunderstorm = config.Bind("Storm Visuals", "EnableNativeThunderstorm", true, "Use Valheim's native thunderstorm during active flood phases."); NativeStormEnvironment = config.Bind("Storm Visuals", "NativeStormEnvironment", "ThunderStorm", "Internal Valheim environment name to force during active flood phases."); NativeStormStartStrength = config.Bind("Storm Visuals", "NativeStormStartStrength", 0.45f, "Storm strength at which native thunder, rain and lightning begin. The omen remains mostly distant and black before this."); SkyDarkening = config.Bind("Storm Visuals", "SkyDarkening", 0.72f, "Strength of the storm-darkening overlay. 0 disables it."); EnableBlackHorizonStormBank = config.Bind("Storm Visuals", "EnableBlackHorizonStormBank", false, "Legacy screen-space storm-bank option. Disabled by default because it could form a hard black horizontal band on some displays."); HorizonStormBankOpacity = config.Bind("Storm Visuals", "HorizonStormBankOpacity", 0.88f, "Opacity of the distant black storm bank."); HorizonStormBankHeight = config.Bind("Storm Visuals", "HorizonStormBankHeight", 0.64f, "Vertical screen fraction occupied by the distant storm bank."); EnableDistantLightningFlashes = config.Bind("Storm Visuals", "EnableDistantLightningFlashes", true, "Adds subtle distant lightning flashes on top of Valheim's native thunderstorm."); WildfireSkyTintStrength = config.Bind("Storm Visuals", "WildfireSkyTintStrength", 0.52f, "Strength of the warm smoke tint during a wildfire event."); EnableApproachingStormFront = config.Bind("Storm Visuals", "EnableApproachingStormFront", false, "Legacy screen-space storm-front option. Disabled by default because it could look like a black overlay band instead of a distant sky."); StormFrontDarkness = config.Bind("Storm Visuals", "StormFrontDarkness", 0.95f, "Opacity of the approaching black storm front at full strength."); StormFrontHorizonHeight = config.Bind("Storm Visuals", "StormFrontHorizonHeight", 0.72f, "Screen height used by the distant storm-wall cloud band."); EnableCustomStormAudio = config.Bind("Storm Audio", "Enable Custom Storm Audio", true, "Loads the three supplied MP3 storm loops from TheBrokenCycle/Audio."); MasterStormAudioVolume = config.Bind("Storm Audio", "Master Storm Audio Volume", 0.85f, "Master volume multiplier for all custom storm audio."); IndoorStormAudioVolume = config.Bind("Storm Audio", "Indoor Storm Audio Volume", 0.72f, "Volume multiplier for stormoutside.mp3 when the player is inside a sealed shelter."); OutdoorWindAudioVolume = config.Bind("Storm Audio", "Outdoor Wind Audio Volume", 0.8f, "Volume multiplier for loudwind.mp3 and windthroughtrees.mp3 outdoors."); AudioFadeDuration = config.Bind("Storm Audio", "Audio Fade Duration", 4.5f, "Seconds used for custom storm audio fades and crossfades."); DebugAudioLogging = config.Bind("Storm Audio", "Debug Audio Logging", false, "Writes custom storm audio load/playback diagnostics when enabled."); EnableLightningStrikes = config.Bind("Lightning", "EnableLightningStrikes", true, "Allows storms to create real ground lightning strikes. Direct strikes can damage and kill exposed players."); EnableAmbientBolts = config.Bind("Lightning", "EnableAmbientBolts", true, "Shows non-damaging procedural bolts around players during active storm phases."); PlayerStrikeMinStrength = config.Bind("Lightning", "PlayerStrikeMinStrength", 0.55f, "Minimum storm strength before dangerous player-targeting lightning is allowed."); StrikeGapMinSeconds = config.Bind("Lightning", "StrikeGapMinSeconds", 25f, "Shortest real-time gap between dangerous lightning checks at peak storm strength."); StrikeGapMaxSeconds = config.Bind("Lightning", "StrikeGapMaxSeconds", 90f, "Longest real-time gap between dangerous lightning checks at the edge of a storm."); DirectHitChance = config.Bind("Lightning", "DirectHitChance", 0.12f, "Chance that a dangerous strike targets an exposed player instead of a nearby miss."); StrikeGraceSeconds = config.Bind("Lightning", "StrikeGraceSeconds", 8f, "Minimum real-time grace period between damaging strikes on the same player."); MinLightningDamage = config.Bind("Lightning", "MinLightningDamage", 40f, "Lightning damage near the dangerous-storm threshold."); MaxLightningDamage = config.Bind("Lightning", "MaxLightningDamage", 140f, "Lightning damage at peak storm strength. This can kill low-health players."); WetDamageMultiplier = config.Bind("Lightning", "WetDamageMultiplier", 1.5f, "Damage multiplier for wet players struck by lightning."); LightningPushForce = config.Bind("Lightning", "LightningPushForce", 8f, "Knockback force applied by a direct lightning strike."); RequireExposed = config.Bind("Lightning", "RequireExposed", true, "Sheltered players are immune to direct lightning strikes."); NonLethalLightning = config.Bind("Lightning", "NonLethalLightning", false, "If true, direct lightning leaves the player at 1 HP instead of killing them."); BoltLightIntensity = config.Bind("Lightning", "BoltLightIntensity", 6f, "World light intensity for procedural lightning bolts. V0.9.1 keeps this modest and uses the screen flash for most brightness."); BoltLightRange = config.Bind("Lightning", "BoltLightRange", 55f, "World light range for procedural lightning bolts. Kept short to avoid bloom streaking."); BoltDurationSeconds = config.Bind("Lightning", "BoltDurationSeconds", 0.48f, "How long a procedural bolt remains visible. The renderer enforces a visible hold so forks can be read by the eye."); AmbientBoltsPerMinuteAtPeak = config.Bind("Lightning", "AmbientBoltsPerMinuteAtPeak", 12f, "Approximate number of non-damaging ambient bolts per minute at peak storm strength."); EnableThunderAudio = config.Bind("Lightning", "EnableThunderAudio", true, "Play distance-delayed thunder cracks after each lightning strike."); ThunderVolume = config.Bind("Lightning", "ThunderVolume", 0.8f, "Volume multiplier for procedural thunder."); SpeedOfSoundMetersPerSecond = config.Bind("Lightning", "SpeedOfSoundMetersPerSecond", 340f, "Used to compute the delay between flash and thunder."); RainEnvironmentNames = config.Bind("Lightning", "RainEnvironmentNames", "Rain,LightRain,ThunderStorm,SwampRain,Mistlands_rain,Mistlands_thunder,Ashrain,Ashlands_ashrain", "Comma-separated environment names that count as wet rain for lightning ignition and wildfire suppression."); DrynessRisePerHour = config.Bind("Dryness", "DrynessRisePerHour", 0.055f, "How much the saved dryness index rises per active world hour without rain."); DrynessRiseDroughtMultiplier = config.Bind("Dryness", "DrynessRiseDroughtMultiplier", 3f, "Multiplier for dryness gain during drought phases."); DrynessRainResetSeconds = config.Bind("Dryness", "DrynessRainResetSeconds", 900f, "Real active seconds of rain/storm needed to pull dryness from 1 toward 0."); RainWetStormStrength = config.Bind("Dryness", "RainWetStormStrength", 0.62f, "Storm strength at which rain environments make the ground wet enough to block ignition."); WildfireWeight = config.Bind("Wildfire", "WildfireWeight", 1f, "Reserved tuning weight for wildfire scheduling. Wildfires use their own dryness-driven schedule instead of the water-event pool."); SpontaneousDrynessThreshold = config.Bind("Wildfire", "SpontaneousDrynessThreshold", 0.7f, "Dryness index required before spontaneous wildfire ignition can be scheduled."); SpontaneousPerWindowChance = config.Bind("Wildfire", "SpontaneousPerWindowChance", 0.05f, "Chance per wildfire schedule window to ignite when dryness and biome fuel allow it."); SpontaneousWindowMinimumHours = config.Bind("Wildfire", "SpontaneousWindowMinimumHours", 1f, "Shortest active-world delay between spontaneous wildfire ignition checks."); SpontaneousWindowMaximumHours = config.Bind("Wildfire", "SpontaneousWindowMaximumHours", 3f, "Longest active-world delay between spontaneous wildfire ignition checks."); LightningIgnitionChance = config.Bind("Wildfire", "LightningIgnitionChance", 0.25f, "Base chance that a dry lightning strike ignites a wildfire, before dryness and biome flammability are applied."); IgnitionMinRadius = config.Bind("Wildfire", "IgnitionMinRadius", 40f, "Closest distance from a player that natural wildfire ignition may choose."); IgnitionMaxRadius = config.Bind("Wildfire", "IgnitionMaxRadius", 120f, "Farthest distance from a player that natural wildfire ignition may choose."); MaxFireNodes = config.Bind("Wildfire", "MaxFireNodes", 96, "Hard cap on simultaneous local fire nodes for performance. The wildfire starts as a connected moving fire-front, then grows within this budget."); SpreadIntervalSeconds = config.Bind("Wildfire", "SpreadIntervalSeconds", 2.4f, "How often each fire node can attempt to spread. Lower values make the moving front build without waiting for isolated spots."); SpreadChance = config.Bind("Wildfire", "SpreadChance", 0.75f, "Chance that a fire node spreads on each interval during active fire phases."); SpreadStepMeters = config.Bind("Wildfire", "SpreadStepMeters", 3.6f, "Average distance between parent and child fire nodes in the connected wildfire front."); NodeLifeSeconds = config.Bind("Wildfire", "NodeLifeSeconds", 85f, "How long a fire node burns without rain, floodwater, or burnout suppression."); NodeRadius = config.Bind("Wildfire", "NodeRadius", 3.6f, "Base radius around each node that shows fire and can damage the player. The visual front joins neighbouring nodes into a continuous fire line."); PlayerFireDamagePerTick = config.Bind("Wildfire", "PlayerFireDamagePerTick", 8f, "Fire damage applied per tick when an unwet player stands in a fire node."); FireDamageIntervalSeconds = config.Bind("Wildfire", "FireDamageIntervalSeconds", 1.5f, "Real seconds between player fire-damage ticks."); DamageStructures = config.Bind("Wildfire", "DamageStructures", false, "Reserved safety valve for future structure/tree fire damage. The v0.9.0 implementation leaves structures untouched."); DownwindBias = config.Bind("Wildfire", "DownwindBias", 0.72f, "How strongly fire spread prefers the current wind direction."); WildfireForcedEnvironment = config.Bind("Wildfire", "WildfireForcedEnvironment", "", "Optional Valheim environment to force during wildfire. Empty leaves natural weather alone."); EmberBedEnabled = config.Bind("Wildfire Visuals", "EmberBedEnabled", true, "Adds a connected alpha-blended ember bed under wildfire nodes."); EmberBedRadiusMultiplier = config.Bind("Wildfire Visuals", "EmberBedRadiusMultiplier", 1.9f, "Ember-bed radius as a multiple of SpreadStepMeters."); EmberBedOpacity = config.Bind("Wildfire Visuals", "EmberBedOpacity", 0.55f, "Base alpha for the wildfire ground ember glow."); FlameStretchLength = config.Bind("Wildfire Visuals", "FlameStretchLength", 3f, "Vertical stretch length for flame particles."); MaxDetailedFireDistance = config.Bind("Wildfire Visuals", "MaxDetailedFireDistance", 60f, "Distance in metres for full flame and heat-haze particle density before LOD reduces emissions."); MeadowsFlammability = config.Bind("Wildfire Biomes", "MeadowsFlammability", 1f, "Ignition fuel multiplier for Meadows."); BlackForestFlammability = config.Bind("Wildfire Biomes", "BlackForestFlammability", 0.9f, "Ignition fuel multiplier for Black Forest."); PlainsFlammability = config.Bind("Wildfire Biomes", "PlainsFlammability", 1f, "Ignition fuel multiplier for Plains."); SwampFlammability = config.Bind("Wildfire Biomes", "SwampFlammability", 0.15f, "Ignition fuel multiplier for Swamp."); MountainFlammability = config.Bind("Wildfire Biomes", "MountainFlammability", 0.1f, "Ignition fuel multiplier for Mountain."); MistlandsFlammability = config.Bind("Wildfire Biomes", "MistlandsFlammability", 0.5f, "Ignition fuel multiplier for Mistlands."); AshlandsFlammability = config.Bind("Wildfire Biomes", "AshlandsFlammability", 0f, "Ignition fuel multiplier for Ashlands."); DeepNorthFlammability = config.Bind("Wildfire Biomes", "DeepNorthFlammability", 0f, "Ignition fuel multiplier for Deep North."); OtherBiomeFlammability = config.Bind("Wildfire Biomes", "OtherBiomeFlammability", 0.3f, "Ignition fuel multiplier for unknown or modded biomes."); EnableStrongWinds = config.Bind("Strong Winds", "Enable Strong Winds", true, "Allows the standalone Strong Winds disaster and Broken Cycle wind escalation."); StrongWindsEventChance = config.Bind("Strong Winds", "Event chance", 0.08f, "Chance that a strong-winds schedule window starts the event."); StrongWindsCooldownHours = config.Bind("Strong Winds", "Cooldown", 5f, "Minimum active world hours before another natural Strong Winds check."); StrongWindsDurationMinutes = config.Bind("Strong Winds", "Duration", 18f, "Approximate real-time duration of a full Strong Winds event."); StrongWindsMinimumWorldDay = config.Bind("Strong Winds", "Minimum world progression requirement", 6, "Earliest world day for natural Strong Winds."); StrongWindsWindStrengthMultiplier = config.Bind("Strong Winds", "Wind strength multiplier", 1f, "Overall multiplier for strong-wind force and debris."); EnableTreefall = config.Bind("Strong Winds", "Enable treefall", true, "Allows host-controlled native tree damage during severe winds."); TreefallChance = config.Bind("Strong Winds", "Treefall chance", 0.35f, "Chance for each eligible severe gust window to topple one nearby valid tree."); TreefallDistanceFromPlayer = config.Bind("Strong Winds", "Treefall distance from player", 55f, "Maximum tree candidate scan distance around active players."); MaxTreefallsPerPlayer = config.Bind("Strong Winds", "Maximum treefalls per player", 3, "Maximum host-triggered treefalls credited near each player per event."); MaxTreefallsGlobally = config.Bind("Strong Winds", "Maximum treefalls globally", 12, "Maximum host-triggered treefalls per Strong Winds or Broken Cycle event."); TreefallCooldownPerZoneSeconds = config.Bind("Strong Winds", "Treefall cooldown per zone", 120f, "Cooldown before another tree can be toppled in the same loaded zone."); ProtectedBaseRadius = config.Bind("Strong Winds", "Protected base radius", 32f, "Radius around beds, portals, workbenches, wards, and player pieces protected from treefall targeting."); FallingTreeDamageToPlayers = config.Bind("Strong Winds", "Falling-tree damage to players", 0.55f, "Reserved multiplier for vanilla fallen-tree player danger. Lower values keep storms survivable."); FallingTreeDamageToCreatures = config.Bind("Strong Winds", "Falling-tree damage to creatures", 0.75f, "Reserved multiplier for vanilla fallen-tree creature danger."); StrongWindStructureDamage = config.Bind("Strong Winds", "Structure damage setting", false, "If false, treefall targeting avoids protected player structures where detectable."); WindDebrisAmount = config.Bind("Strong Winds", "Debris amount", 1f, "Client-side windblown debris particle density."); StrongWindsDebugMode = config.Bind("Strong Winds", "Debug Mode", false, "Writes Strong Winds diagnostics to the log."); StrongWindsDebugIgnoreBaseProtection = config.Bind("Strong Winds", "Debug ignore base protection", false, "Allows strongwinds testtree to ignore base protection for controlled testing."); DebugLogging = config.Bind("Debug", "DebugLogging", false, "Writes concise event/state diagnostics to BepInEx LogOutput.log."); VerboseWaterTileBindingLogs = config.Bind("Debug", "VerboseWaterTileBindingLogs", false, "Logs every individual terrain-water tile. Leave false for normal play."); StartTestEventOnWorldLoad = config.Bind("Debug", "StartTestEventOnWorldLoad", false, "Starts a custom test flood whenever the host loads a world. Turn off after testing."); TestStartPhase = config.Bind("Debug", "TestStartPhase", "Omen", "Custom test phase: Omen, Rising, Peak, or Receding."); } internal FloodEventProfile GetProfile(FloodEventType type) { return type switch { FloodEventType.StormTide => StormTide, FloodEventType.FlashSurge => FlashSurge, FloodEventType.GreatFlood => GreatFlood, FloodEventType.Drought => Drought, FloodEventType.Wildfire => Wildfire, _ => null, }; } internal float GetFlashSurgeDrawdownMinimum() { return Mathf.Min(FlashSurgeDrawdownMinimumMeters.Value, FlashSurgeDrawdownMaximumMeters.Value); } internal float GetFlashSurgeDrawdownMaximum() { return Mathf.Max(FlashSurgeDrawdownMinimumMeters.Value, FlashSurgeDrawdownMaximumMeters.Value); } private static void RemoveLegacyDailyRollSettings(ConfigFile config) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown string[] array = new string[4] { "Storm Tide", "Flash Surge", "The Great Flood", "Drought" }; for (int i = 0; i < array.Length; i++) { config.Remove(new ConfigDefinition(array[i], "CooldownDays")); config.Remove(new ConfigDefinition(array[i], "DailyChance")); } } } internal enum FloodEventType { None, Custom, StormTide, FlashSurge, GreatFlood, Drought, Wildfire, StrongWinds } internal enum FloodPhase { Dormant, Omen, Rising, Peak, Receding } [Serializable] internal sealed class FloodState { internal int FormatVersion = 6; internal FloodPhase Phase; internal FloodEventType EventType; internal double PhaseStartedWorldSeconds; internal double PhaseEndsWorldSeconds; internal float PeakMeters = 3.5f; internal float DrawdownMeters; internal long EventNumber; internal long EventSeed; internal long LastCompletedDay = -99999L; internal long LastRollDay = -99999L; internal long LastStormTideDay = -99999L; internal long LastFlashSurgeDay = -99999L; internal long LastGreatFloodDay = -99999L; internal long LastDroughtDay = -99999L; internal bool ManualEvent; internal bool IsSevereDrought; internal bool SchedulerInitialized; internal double NextOrdinaryEventWorldSeconds; internal double NextGreatFloodWorldSeconds; internal double GreatFloodForceWorldSeconds; internal double GlobalRecoveryEndsWorldSeconds; internal long SchedulerCycle; internal float DrynessIndex; internal float WildfireOriginX; internal float WildfireOriginY; internal float WildfireOriginZ; internal double NextStrikeWorldSeconds; internal double LastDrynessUpdateWorldSeconds; internal double NextWildfireWorldSeconds; internal double WildfireForceWorldSeconds; internal double NextStrongWindsWorldSeconds; internal double StrongWindsRecoveryEndsWorldSeconds; internal long LastStrongWindsDay = -99999L; internal string Serialize() { string[] array = new string[34]; array[0] = FormatVersion.ToString(CultureInfo.InvariantCulture); int phase = (int)Phase; array[1] = phase.ToString(CultureInfo.InvariantCulture); array[2] = PhaseStartedWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[3] = PhaseEndsWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[4] = PeakMeters.ToString("R", CultureInfo.InvariantCulture); array[5] = DrawdownMeters.ToString("R", CultureInfo.InvariantCulture); array[6] = EventNumber.ToString(CultureInfo.InvariantCulture); array[7] = EventSeed.ToString(CultureInfo.InvariantCulture); array[8] = LastCompletedDay.ToString(CultureInfo.InvariantCulture); array[9] = LastRollDay.ToString(CultureInfo.InvariantCulture); array[10] = (ManualEvent ? "1" : "0"); phase = (int)EventType; array[11] = phase.ToString(CultureInfo.InvariantCulture); array[12] = LastStormTideDay.ToString(CultureInfo.InvariantCulture); array[13] = LastFlashSurgeDay.ToString(CultureInfo.InvariantCulture); array[14] = LastGreatFloodDay.ToString(CultureInfo.InvariantCulture); array[15] = LastDroughtDay.ToString(CultureInfo.InvariantCulture); array[16] = (IsSevereDrought ? "1" : "0"); array[17] = (SchedulerInitialized ? "1" : "0"); array[18] = NextOrdinaryEventWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[19] = NextGreatFloodWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[20] = GreatFloodForceWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[21] = GlobalRecoveryEndsWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[22] = SchedulerCycle.ToString(CultureInfo.InvariantCulture); array[23] = DrynessIndex.ToString("R", CultureInfo.InvariantCulture); array[24] = WildfireOriginX.ToString("R", CultureInfo.InvariantCulture); array[25] = WildfireOriginY.ToString("R", CultureInfo.InvariantCulture); array[26] = WildfireOriginZ.ToString("R", CultureInfo.InvariantCulture); array[27] = NextStrikeWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[28] = LastDrynessUpdateWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[29] = NextWildfireWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[30] = WildfireForceWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[31] = NextStrongWindsWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[32] = StrongWindsRecoveryEndsWorldSeconds.ToString("R", CultureInfo.InvariantCulture); array[33] = LastStrongWindsDay.ToString(CultureInfo.InvariantCulture); return string.Join("|", array); } internal static bool TryDeserialize(string data, out FloodState state) { state = null; if (string.IsNullOrWhiteSpace(data)) { return false; } string[] array = data.Split(new char[1] { '|' }); if (array.Length != 10 && array.Length != 14 && array.Length != 16 && array.Length != 23 && array.Length != 31 && array.Length != 34) { return false; } try { state = new FloodState { FormatVersion = int.Parse(array[0], CultureInfo.InvariantCulture), Phase = (FloodPhase)int.Parse(array[1], CultureInfo.InvariantCulture), PhaseStartedWorldSeconds = double.Parse(array[2], CultureInfo.InvariantCulture), PhaseEndsWorldSeconds = double.Parse(array[3], CultureInfo.InvariantCulture), PeakMeters = float.Parse(array[4], CultureInfo.InvariantCulture) }; if (array.Length == 23 || array.Length == 31 || array.Length == 34) { state.DrawdownMeters = float.Parse(array[5], CultureInfo.InvariantCulture); state.EventNumber = long.Parse(array[6], CultureInfo.InvariantCulture); state.EventSeed = long.Parse(array[7], CultureInfo.InvariantCulture); state.LastCompletedDay = long.Parse(array[8], CultureInfo.InvariantCulture); state.LastRollDay = long.Parse(array[9], CultureInfo.InvariantCulture); state.ManualEvent = array[10] == "1"; state.EventType = (FloodEventType)int.Parse(array[11], CultureInfo.InvariantCulture); state.LastStormTideDay = long.Parse(array[12], CultureInfo.InvariantCulture); state.LastFlashSurgeDay = long.Parse(array[13], CultureInfo.InvariantCulture); state.LastGreatFloodDay = long.Parse(array[14], CultureInfo.InvariantCulture); state.LastDroughtDay = long.Parse(array[15], CultureInfo.InvariantCulture); state.IsSevereDrought = array[16] == "1"; state.SchedulerInitialized = array[17] == "1"; state.NextOrdinaryEventWorldSeconds = double.Parse(array[18], CultureInfo.InvariantCulture); state.NextGreatFloodWorldSeconds = double.Parse(array[19], CultureInfo.InvariantCulture); state.GreatFloodForceWorldSeconds = double.Parse(array[20], CultureInfo.InvariantCulture); state.GlobalRecoveryEndsWorldSeconds = double.Parse(array[21], CultureInfo.InvariantCulture); state.SchedulerCycle = long.Parse(array[22], CultureInfo.InvariantCulture); if (array.Length == 31 || array.Length == 34) { state.DrynessIndex = Mathf.Clamp01(float.Parse(array[23], CultureInfo.InvariantCulture)); state.WildfireOriginX = float.Parse(array[24], CultureInfo.InvariantCulture); state.WildfireOriginY = float.Parse(array[25], CultureInfo.InvariantCulture); state.WildfireOriginZ = float.Parse(array[26], CultureInfo.InvariantCulture); state.NextStrikeWorldSeconds = double.Parse(array[27], CultureInfo.InvariantCulture); state.LastDrynessUpdateWorldSeconds = double.Parse(array[28], CultureInfo.InvariantCulture); state.NextWildfireWorldSeconds = double.Parse(array[29], CultureInfo.InvariantCulture); state.WildfireForceWorldSeconds = double.Parse(array[30], CultureInfo.InvariantCulture); } if (array.Length == 34) { state.NextStrongWindsWorldSeconds = double.Parse(array[31], CultureInfo.InvariantCulture); state.StrongWindsRecoveryEndsWorldSeconds = double.Parse(array[32], CultureInfo.InvariantCulture); state.LastStrongWindsDay = long.Parse(array[33], CultureInfo.InvariantCulture); } state.FormatVersion = 6; } else if (array.Length == 16) { state.DrawdownMeters = float.Parse(array[5], CultureInfo.InvariantCulture); state.EventNumber = long.Parse(array[6], CultureInfo.InvariantCulture); state.EventSeed = long.Parse(array[7], CultureInfo.InvariantCulture); state.LastCompletedDay = long.Parse(array[8], CultureInfo.InvariantCulture); state.LastRollDay = long.Parse(array[9], CultureInfo.InvariantCulture); state.ManualEvent = array[10] == "1"; state.EventType = (FloodEventType)int.Parse(array[11], CultureInfo.InvariantCulture); state.LastStormTideDay = long.Parse(array[12], CultureInfo.InvariantCulture); state.LastFlashSurgeDay = long.Parse(array[13], CultureInfo.InvariantCulture); state.LastGreatFloodDay = long.Parse(array[14], CultureInfo.InvariantCulture); state.LastDroughtDay = long.Parse(array[15], CultureInfo.InvariantCulture); state.FormatVersion = 6; } else if (array.Length == 14) { state.EventNumber = long.Parse(array[5], CultureInfo.InvariantCulture); state.EventSeed = long.Parse(array[6], CultureInfo.InvariantCulture); state.LastCompletedDay = long.Parse(array[7], CultureInfo.InvariantCulture); state.LastRollDay = long.Parse(array[8], CultureInfo.InvariantCulture); state.ManualEvent = array[9] == "1"; state.EventType = (FloodEventType)int.Parse(array[10], CultureInfo.InvariantCulture); state.LastStormTideDay = long.Parse(array[11], CultureInfo.InvariantCulture); state.LastFlashSurgeDay = long.Parse(array[12], CultureInfo.InvariantCulture); state.LastGreatFloodDay = long.Parse(array[13], CultureInfo.InvariantCulture); state.LastDroughtDay = state.LastCompletedDay; state.DrawdownMeters = 0f; state.FormatVersion = 6; } else { state.EventNumber = long.Parse(array[5], CultureInfo.InvariantCulture); state.EventSeed = long.Parse(array[6], CultureInfo.InvariantCulture); state.LastCompletedDay = long.Parse(array[7], CultureInfo.InvariantCulture); state.LastRollDay = long.Parse(array[8], CultureInfo.InvariantCulture); state.ManualEvent = array[9] == "1"; state.EventType = ((state.Phase != FloodPhase.Dormant) ? FloodEventType.Custom : FloodEventType.None); state.LastStormTideDay = state.LastCompletedDay; state.LastFlashSurgeDay = state.LastCompletedDay; state.LastGreatFloodDay = state.LastCompletedDay; state.LastDroughtDay = state.LastCompletedDay; state.DrawdownMeters = 0f; state.FormatVersion = 6; } return true; } catch { state = null; return false; } } } internal sealed class LightningStrikePayload { internal Vector3 Position; internal float Damage; internal bool IsDirectHit; internal long TargetPlayerId; internal int Ignite; internal long Seed; internal string Serialize() { return string.Join("|", Position.x.ToString("R", CultureInfo.InvariantCulture), Position.y.ToString("R", CultureInfo.InvariantCulture), Position.z.ToString("R", CultureInfo.InvariantCulture), Damage.ToString("R", CultureInfo.InvariantCulture), IsDirectHit ? "1" : "0", TargetPlayerId.ToString(CultureInfo.InvariantCulture), Ignite.ToString(CultureInfo.InvariantCulture), Seed.ToString(CultureInfo.InvariantCulture)); } internal static bool TryDeserialize(string data, out LightningStrikePayload payload) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) payload = null; if (string.IsNullOrWhiteSpace(data)) { return false; } string[] array = data.Split(new char[1] { '|' }); if (array.Length != 8) { return false; } try { payload = new LightningStrikePayload { Position = new Vector3(float.Parse(array[0], CultureInfo.InvariantCulture), float.Parse(array[1], CultureInfo.InvariantCulture), float.Parse(array[2], CultureInfo.InvariantCulture)), Damage = float.Parse(array[3], CultureInfo.InvariantCulture), IsDirectHit = (array[4] == "1"), TargetPlayerId = long.Parse(array[5], CultureInfo.InvariantCulture), Ignite = int.Parse(array[6], CultureInfo.InvariantCulture), Seed = long.Parse(array[7], CultureInfo.InvariantCulture) }; return true; } catch { payload = null; return false; } } } internal sealed class FloodStateStore { private readonly ManualLogSource _logger; private readonly string _folder; internal FloodStateStore(ManualLogSource logger) { _logger = logger; _folder = Path.Combine(Paths.ConfigPath, "marc.thefloods"); } internal FloodState Load(string worldName) { try { string path = GetPath(worldName); if (!File.Exists(path)) { return new FloodState(); } if (FloodState.TryDeserialize(File.ReadAllText(path), out var state)) { return state; } _logger.LogWarning((object)"The Floods: state file could not be read, beginning a fresh inactive state."); } catch (Exception ex) { _logger.LogError((object)("The Floods: could not load state: " + ex.Message)); } return new FloodState(); } internal void Save(string worldName, FloodState state) { try { Directory.CreateDirectory(_folder); string path = GetPath(worldName); string text = path + ".tmp"; File.WriteAllText(text, state.Serialize()); File.Copy(text, path, overwrite: true); File.Delete(text); } catch (Exception ex) { _logger.LogError((object)("The Floods: could not save state: " + ex.Message)); } } private string GetPath(string worldName) { string text = (string.IsNullOrWhiteSpace(worldName) ? "UnknownWorld" : worldName); char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { text = text.Replace(oldChar, '_'); } return Path.Combine(_folder, text + ".floods-state.txt"); } } internal sealed class StormApproachVisual { internal static readonly StormApproachVisual Inactive = new StormApproachVisual(); internal bool Active; internal Vector3 FrontDirection; internal float FrontProgress; internal float OverheadStrength; internal float WallStrength; internal float WindStrength; internal float SurgeMeters; internal long Seed; } internal sealed class FloodDirector { internal const string RpcState = "TheFloods_State_01"; internal const string RpcMessage = "TheFloods_Message_01"; internal const string RpcStrike = "TheFloods_Strike_01"; private readonly ManualLogSource _logger; private readonly FloodConfig _config; private readonly FloodWaterAdapter _water; private readonly FloodEnvironmentAdapter _environment; private readonly FloodVisuals _visuals; private readonly FloodStateStore _store; private readonly FloodLightningSystem _lightning; private readonly WildfireSystem _wildfires; private readonly StrongWindsSystem _strongWinds; private readonly StormAudioManager _audio; private FloodState _state = new FloodState(); private StormApproachVisual _stormApproach = StormApproachVisual.Inactive; private bool _loaded; private string _worldName; private float _lastSyncAt; private float _lastVerboseAt; private bool _autoTestStarted; private MethodInfo _findBiomeMethod; private MethodInfo _currentEnvironmentMethod; private FieldInfo _environmentNameField; private bool _environmentReflectionSearched; private MethodInfo _getSEManMethod; private MethodInfo _haveStatusEffectIntMethod; private MethodInfo _haveStatusEffectStringMethod; private MethodInfo _envManIsWetMethod; private bool _playerWetReflectionSearched; private bool _statusEffectReflectionSearched; private bool _envWetReflectionSearched; private static readonly int WetStatusHash = GetStableStatusHash("Wet"); private readonly Dictionary _rainEnvironmentCache = new Dictionary(StringComparer.OrdinalIgnoreCase); internal FloodState CurrentState => _state; internal bool IsWorldReady => _loaded; internal bool IsAuthoritative { get { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } } internal float CurrentStormStrength { get { if (!TryGetWorldSeconds(out var seconds)) { return 0f; } return GetStormStrength(seconds); } } internal float CurrentWildfireIntensity { get { if (!TryGetWorldSeconds(out var seconds)) { return 0f; } return GetWildfireIntensity(seconds); } } internal StormApproachVisual CurrentStormApproach => _stormApproach ?? StormApproachVisual.Inactive; internal FloodDirector(ManualLogSource logger, FloodConfig config, FloodWaterAdapter water, FloodEnvironmentAdapter environment, FloodVisuals visuals) { _logger = logger; _config = config; _water = water; _environment = environment; _visuals = visuals; _store = new FloodStateStore(logger); _lightning = new FloodLightningSystem(logger, config, visuals); _wildfires = new WildfireSystem(logger, config); _strongWinds = new StrongWindsSystem(logger, config); _audio = new StormAudioManager(logger, config); } internal void Tick() { if (!_config.Enabled.Value || (Object)(object)ZNet.instance == (Object)null) { _water.RestoreOriginalWaterLevel(); _environment.ReleaseForcedEnvironment(); } else { if (!TryGetWorldSeconds(out var seconds)) { return; } EnsureLoaded(seconds); ApplyLocalEffects(seconds); if (IsAuthoritative) { RunAuthoritativeState(seconds); if (Time.unscaledTime - _lastSyncAt > 4f) { BroadcastState(); } if (_config.DebugLogging.Value && Time.unscaledTime - _lastVerboseAt > 30f) { _lastVerboseAt = Time.unscaledTime; _logger.LogInfo((object)("The Floods: " + DescribeState(seconds))); } } } } internal void ReceiveState(string payload) { if (!FloodState.TryDeserialize(payload, out var state)) { _logger.LogWarning((object)"The Floods: ignored malformed state sync."); } else if (!IsAuthoritative) { _state = state; _loaded = true; } } internal void ReceiveStrike(string payload) { if (!LightningStrikePayload.TryDeserialize(payload, out var payload2)) { _logger.LogWarning((object)"The Floods: ignored malformed lightning strike sync."); return; } _lightning.RenderStrike(payload2); ApplyLocalLightningDamage(payload2); } internal void Dispose() { _lightning.Dispose(); _wildfires.Dispose(); _strongWinds.Dispose(); _audio.Dispose(); } internal string HandleCommand(string[] args) { //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) if (!TryGetWorldSeconds(out var seconds)) { return "The Floods: world clock is not ready yet."; } EnsureLoaded(seconds); if (args == null || args.Length == 0 || args[0].Equals("help", StringComparison.OrdinalIgnoreCase)) { return "The Floods: floods status | floods schedule | floods event stormtide|flashsurge|greatflood|drought|wildfire|strongwinds [omen|rise|spread|peak|recede|burnout] | floods strike | floods strikeme | floods dryness <0..1> | floods ignite [x z] | floods fireout | floods start omen|rise|peak|recede | floods set | floods fastforward | floods stop | floods probe | strongwinds start|stop|peak|status|testtree."; } switch (args[0].ToLowerInvariant()) { case "status": return DescribeState(seconds); case "schedule": return DescribeSchedule(seconds); case "event": { if (args.Length < 2) { return "Usage: floods event stormtide|flashsurge|greatflood|drought|wildfire|strongwinds [omen|rise|spread|peak|recede|burnout]"; } if (!TryParseEventType(args[1], out var type) || type == FloodEventType.Custom) { return "The Floods: choose stormtide, flashsurge, greatflood, drought, wildfire, or strongwinds."; } FloodPhase phase = ((args.Length <= 2) ? FloodPhase.Omen : ParsePhase(args[2])); if (type == FloodEventType.StrongWinds) { BeginPhase(FloodEventType.StrongWinds, phase, seconds, manual: true, 0f, rollProfileHeight: false); return "The Floods: Strong Winds started in " + phase.ToString() + "."; } FloodEventProfile profile = _config.GetProfile(type); if (profile == null) { return "The Floods: profile was not found."; } if (type == FloodEventType.Wildfire) { Vector3 val = FindIgnitionPointNearPlayer(seconds, allowFallback: true); BeginWildfireAt(val, phase, seconds, manual: true, "Smoke rises beyond the trees. Fire and flood are now both in the weather."); return "The Floods: Wildfire started in " + phase.ToString() + " at " + FormatVector(val) + "."; } float num = StartManualEvent(type, phase, seconds); string text = ((type == FloodEventType.Drought) ? ("Rolled drawdown: -" + Mathf.Abs(num).ToString("0.0", CultureInfo.InvariantCulture)) : ("Rolled height: +" + num.ToString("0.0", CultureInfo.InvariantCulture))); string text2 = ((type == FloodEventType.Drought) ? ("drawdown range " + profile.GetMinimumHeight().ToString("0.0", CultureInfo.InvariantCulture) + "–" + profile.GetMaximumHeight().ToString("0.0", CultureInfo.InvariantCulture) + "m") : ("range " + profile.GetMinimumHeight().ToString("0.0", CultureInfo.InvariantCulture) + "–" + profile.GetMaximumHeight().ToString("0.0", CultureInfo.InvariantCulture) + "m")); return "The Floods: " + profile.DisplayName + " started in " + phase.ToString() + ". " + text + " (" + text2 + ")."; } case "start": { FloodPhase phase2 = ((args.Length <= 1) ? FloodPhase.Omen : ParsePhase(args[1])); StartManualEvent(FloodEventType.Custom, phase2, seconds, _config.MaximumSurgeMeters.Value); return "The Floods: custom event started in " + phase2.ToString() + "."; } case "set": { if (args.Length < 2) { return "Usage: floods set "; } if (!float.TryParse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return "The Floods: use a number such as 2.5"; } float num2 = Mathf.Max(1f, _config.DebugMaximumSurgeMeters.Value); result2 = Mathf.Clamp(result2, 0f - num2, num2); StartManualEvent(FloodEventType.Custom, FloodPhase.Peak, seconds, result2); return "The Floods: forced custom water offset set to " + FormatSignedMeters(result2) + "."; } case "fastforward": if (_state.Phase == FloodPhase.Dormant) { return "The Floods: no active event to advance."; } AdvancePhase(seconds); return "The Floods: advanced to " + _state.Phase.ToString() + "."; case "stop": StopEvent(seconds, manualStop: true); return "The Floods: stopped and runtime water restored."; case "probe": LogWaterProbe(); return "The Floods: water/environment probe written to BepInEx LogOutput.log."; case "strike": return TriggerManualStrike(seconds, direct: false); case "strikeme": return TriggerManualStrike(seconds, direct: true); case "dryness": { if (args.Length < 2) { return "Usage: floods dryness <0..1>"; } if (!float.TryParse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return "The Floods: use a dryness value such as 0.75"; } _state.DrynessIndex = Mathf.Clamp01(result); _state.LastDrynessUpdateWorldSeconds = seconds; SaveAndBroadcast(); return "The Floods: dryness set to " + _state.DrynessIndex.ToString("0.00", CultureInfo.InvariantCulture) + "."; } case "ignite": return TriggerManualIgnition(args, seconds); case "fireout": ExtinguishWildfire(seconds, manual: true); return "The Floods: wildfire nodes extinguished."; default: return "The Floods: unknown command. Type floods help"; } } internal string HandleStrongWindsCommand(string[] args) { //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) if (!TryGetWorldSeconds(out var seconds)) { return "Strong Winds: world clock is not ready yet."; } EnsureLoaded(seconds); if (args == null || args.Length == 0 || args[0].Equals("help", StringComparison.OrdinalIgnoreCase)) { return "Strong Winds: strongwinds start | strongwinds stop | strongwinds peak | strongwinds status | strongwinds testtree"; } switch (args[0].ToLowerInvariant()) { case "start": BeginPhase(FloodEventType.StrongWinds, FloodPhase.Omen, seconds, manual: true, 0f, rollProfileHeight: false); return "Strong Winds: event started."; case "peak": BeginPhase(FloodEventType.StrongWinds, FloodPhase.Peak, seconds, manual: true, 0f, rollProfileHeight: false); return "Strong Winds: event forced to peak."; case "stop": if (_state.EventType == FloodEventType.StrongWinds) { StopEvent(seconds, manualStop: true); return "Strong Winds: event stopped."; } _strongWinds.ResetRuntime(); return "Strong Winds: no active Strong Winds event; runtime wind state cleared."; case "status": return "Strong Winds: intensity=" + GetStrongWindIntensity(seconds, GetStormStrength(seconds)).ToString("0.00", CultureInfo.InvariantCulture) + " treefalls=" + _strongWinds.TreefallStatus; case "testtree": return _strongWinds.TryDebugTreefall(GetLoadedPlayers(), GetEffectiveWindDirection(GetStormFrontDirection()), _config.StrongWindsDebugIgnoreBaseProtection.Value); default: return "Strong Winds: unknown command. Type strongwinds help"; } } private void EnsureLoaded(double now) { if (_loaded) { return; } _worldName = ZNet.instance.GetWorldName(); if (!string.IsNullOrWhiteSpace(_worldName)) { if (IsAuthoritative) { _state = _store.Load(_worldName); _logger.LogInfo((object)("The Floods: loaded state for world '" + _worldName + "'. " + DescribeState(now))); } _loaded = true; } } private void RunAuthoritativeState(double now) { if (!_autoTestStarted && _config.StartTestEventOnWorldLoad.Value) { _autoTestStarted = true; StartManualEvent(FloodEventType.Custom, ParsePhase(_config.TestStartPhase.Value), now, _config.MaximumSurgeMeters.Value); return; } UpdateDryness(now); if (_state.Phase != FloodPhase.Dormant && now >= _state.PhaseEndsWorldSeconds) { AdvancePhase(now); } RunLightningScheduler(now, GetStormStrength(now)); if (_state.Phase == FloodPhase.Dormant) { TryRunScheduledNaturalEvent(now); } } private void TryRunScheduledNaturalEvent(double now) { EnsureWaterCycleSchedule(now); if (GetWorldDay(now) < _config.MinimumWorldDay.Value || now < _state.GlobalRecoveryEndsWorldSeconds) { return; } if (CanStartGreatFlood(now)) { BeginPhase(FloodEventType.GreatFlood, FloodPhase.Omen, now, manual: false, 0f, rollProfileHeight: true); } else { if (TryRunStrongWindsSchedule(now)) { return; } if (now < _state.NextOrdinaryEventWorldSeconds) { TryRunWildfireSchedule(now); return; } FloodEventType floodEventType = SelectOrdinaryEventType(); if (floodEventType == FloodEventType.None) { _state.NextOrdinaryEventWorldSeconds = now + 1800.0; SaveAndBroadcast(); } else { BeginPhase(floodEventType, FloodPhase.Omen, now, manual: false, 0f, rollProfileHeight: true); } } } private void EnsureWaterCycleSchedule(double now) { if (!_state.SchedulerInitialized) { long worldDay = GetWorldDay(now); double num = Math.Max(60.0, _config.GameDaySeconds.Value); double num2 = now + (double)Math.Max(0L, _config.MinimumWorldDay.Value - worldDay) * num; float hours = RollSchedulerHours(_config.FirstOrdinaryEventMinimumHours.Value, _config.FirstOrdinaryEventMaximumHours.Value, "FirstOrdinary"); _state.GlobalRecoveryEndsWorldSeconds = num2; _state.NextOrdinaryEventWorldSeconds = num2 + HoursToSeconds(hours); ScheduleFirstGreatFlood(now); ScheduleNextWildfireCheck(now); ScheduleNextStrongWindsCheck(now); _state.SchedulerInitialized = true; SaveAndBroadcast(); if (_config.DebugLogging.Value) { _logger.LogInfo((object)("The Floods V0.8 scheduler initialized. " + DescribeSchedule(now))); } } } private void ScheduleFirstGreatFlood(double now) { double worldAgeHours = GetWorldAgeHours(now); float num = RollSchedulerHours(_config.GreatFloodFirstTargetMinimumWorldHours.Value, _config.GreatFloodFirstTargetMaximumWorldHours.Value, "FirstGreatTarget"); float num2 = Mathf.Max(0f, _config.GreatFloodFirstEligibleWorldHours.Value); float num3 = Mathf.Max(Mathf.Max(num2, num), _config.GreatFloodFirstForceByWorldHours.Value); double num4 = (double)num - worldAgeHours; if (num4 <= 0.0) { num4 = RollSchedulerHours(0.75f, 2.5f, "MatureWorldFirstGreat"); } double num5 = (double)num3 - worldAgeHours; if (num5 <= 0.0) { num5 = 3.0; } _state.NextGreatFloodWorldSeconds = now + HoursToSeconds((float)Math.Max(num4, (double)num2 - worldAgeHours)); _state.GreatFloodForceWorldSeconds = now + HoursToSeconds((float)Math.Max(num5, 1.0)); } private void ScheduleNextGreatFlood(double now) { float num = RollSchedulerHours(_config.GreatFloodRepeatMinimumHours.Value, _config.GreatFloodRepeatMaximumHours.Value, "RepeatGreat"); float hours = Mathf.Max(num, _config.GreatFloodRepeatForceByHours.Value); _state.NextGreatFloodWorldSeconds = now + HoursToSeconds(num); _state.GreatFloodForceWorldSeconds = now + HoursToSeconds(hours); } private bool CanStartGreatFlood(double now) { FloodEventProfile greatFlood = _config.GreatFlood; if (greatFlood == null || !greatFlood.Enabled.Value) { return false; } if (GetWorldAgeHours(now) < (double)Mathf.Max(0f, _config.GreatFloodFirstEligibleWorldHours.Value)) { return false; } if (!(now >= _state.NextGreatFloodWorldSeconds)) { return now >= _state.GreatFloodForceWorldSeconds; } return true; } private void ScheduleAfterNaturalEvent(FloodEventType completedType, double now) { float hours; switch (completedType) { case FloodEventType.FlashSurge: hours = RollSchedulerHours(_config.FlashSurgeRecoveryMinimumHours.Value, _config.FlashSurgeRecoveryMaximumHours.Value, "AfterFlash"); break; case FloodEventType.GreatFlood: hours = RollSchedulerHours(_config.GreatFloodRecoveryMinimumHours.Value, _config.GreatFloodRecoveryMaximumHours.Value, "AfterGreat"); ScheduleNextGreatFlood(now); break; default: hours = RollSchedulerHours(_config.OrdinaryRecoveryMinimumHours.Value, _config.OrdinaryRecoveryMaximumHours.Value, "AfterOrdinary"); break; } _state.GlobalRecoveryEndsWorldSeconds = now + HoursToSeconds(hours); _state.NextOrdinaryEventWorldSeconds = _state.GlobalRecoveryEndsWorldSeconds; ScheduleNextWildfireCheck(now); if (completedType == FloodEventType.StrongWinds) { _state.StrongWindsRecoveryEndsWorldSeconds = now + HoursToSeconds(Mathf.Max(0.1f, _config.StrongWindsCooldownHours.Value)); } ScheduleNextStrongWindsCheck(now); } private void ScheduleNextStrongWindsCheck(double now) { float num = Mathf.Max(0.1f, _config.StrongWindsCooldownHours.Value); float hours = RollSchedulerHours(num * 0.75f, num * 1.35f, "StrongWinds"); _state.NextStrongWindsWorldSeconds = now + HoursToSeconds(hours); } private bool TryRunStrongWindsSchedule(double now) { if (!_config.EnableStrongWinds.Value || _state.EventType != FloodEventType.None || _state.Phase != FloodPhase.Dormant) { return false; } if (GetWorldDay(now) < _config.StrongWindsMinimumWorldDay.Value || now < _state.StrongWindsRecoveryEndsWorldSeconds) { return false; } if (_state.NextStrongWindsWorldSeconds <= 0.0) { ScheduleNextStrongWindsCheck(now); SaveAndBroadcast(); return false; } if (now < _state.NextStrongWindsWorldSeconds) { return false; } _state.SchedulerCycle++; if (DeterministicRoll(_worldName + "|Floods|StrongWinds|" + _state.SchedulerCycle.ToString(CultureInfo.InvariantCulture)) <= Mathf.Clamp01(_config.StrongWindsEventChance.Value)) { BeginPhase(FloodEventType.StrongWinds, FloodPhase.Omen, now, manual: false, 0f, rollProfileHeight: false); return true; } ScheduleNextStrongWindsCheck(now); SaveAndBroadcast(); return false; } private void UpdateDryness(double now) { if (_state.LastDrynessUpdateWorldSeconds <= 0.0 || now < _state.LastDrynessUpdateWorldSeconds) { _state.LastDrynessUpdateWorldSeconds = now; return; } double num = Math.Min(30.0, Math.Max(0.0, now - _state.LastDrynessUpdateWorldSeconds)); _state.LastDrynessUpdateWorldSeconds = now; if (!(num <= 0.001)) { float drynessIndex = _state.DrynessIndex; float stormStrength = GetStormStrength(now); if (IsGroundWetForFire(now, stormStrength)) { float num2 = Mathf.Max(30f, _config.DrynessRainResetSeconds.Value); _state.DrynessIndex = Mathf.Clamp01(_state.DrynessIndex - (float)(num / (double)num2)); } else { float num3 = ((_state.EventType == FloodEventType.Drought && _state.Phase != FloodPhase.Dormant) ? Mathf.Max(1f, _config.DrynessRiseDroughtMultiplier.Value) : 1f); _state.DrynessIndex = Mathf.Clamp01(_state.DrynessIndex + (float)(num / 3600.0) * Mathf.Max(0f, _config.DrynessRisePerHour.Value) * num3); } if (Mathf.Abs(drynessIndex - _state.DrynessIndex) > 0.01f && Time.unscaledTime - _lastSyncAt > 8f) { SaveAndBroadcast(); } } } private void ScheduleNextWildfireCheck(double now) { float num = RollSchedulerHours(_config.SpontaneousWindowMinimumHours.Value, _config.SpontaneousWindowMaximumHours.Value, "WildfireWindow"); float num2 = Mathf.Max(num, Mathf.Max(_config.SpontaneousWindowMinimumHours.Value, _config.SpontaneousWindowMaximumHours.Value)); _state.NextWildfireWorldSeconds = now + HoursToSeconds(num); _state.WildfireForceWorldSeconds = now + HoursToSeconds(Mathf.Max(num2 * 4f, num)); } private void TryRunWildfireSchedule(double now) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) if (_state.EventType != FloodEventType.None || _state.Phase != FloodPhase.Dormant) { return; } FloodEventProfile wildfire = _config.Wildfire; if (wildfire == null || !wildfire.Enabled.Value) { return; } if (_state.NextWildfireWorldSeconds <= 0.0) { ScheduleNextWildfireCheck(now); SaveAndBroadcast(); } else { if ((_state.DrynessIndex < Mathf.Clamp01(_config.SpontaneousDrynessThreshold.Value) && now < _state.WildfireForceWorldSeconds) || (now < _state.NextWildfireWorldSeconds && now < _state.WildfireForceWorldSeconds)) { return; } Vector3 val = FindIgnitionPointNearPlayer(now, allowFallback: false); if (val == Vector3.zero) { ScheduleNextWildfireCheck(now); SaveAndBroadcast(); return; } float biomeFlammability = GetBiomeFlammability(val); float num = Mathf.Clamp01(_config.SpontaneousPerWindowChance.Value * Mathf.Clamp01(_state.DrynessIndex) * biomeFlammability); bool num2 = now >= _state.WildfireForceWorldSeconds && _state.DrynessIndex >= Mathf.Clamp01(_config.SpontaneousDrynessThreshold.Value); _state.SchedulerCycle++; float num3 = DeterministicRoll(_worldName + "|Floods|WildfireSpontaneous|" + _state.SchedulerCycle.ToString(CultureInfo.InvariantCulture)); if (num2 || num3 < num) { BeginWildfireAt(val, FloodPhase.Omen, now, manual: false, "Smoke rises beyond the trees. Drought has made the land ready to burn."); return; } ScheduleNextWildfireCheck(now); SaveAndBroadcast(); } } private void RunLightningScheduler(double now, float stormStrength) { //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) if (!_config.EnableLightningStrikes.Value || stormStrength < Mathf.Clamp01(_config.PlayerStrikeMinStrength.Value) || _state.Phase == FloodPhase.Omen || _state.Phase == FloodPhase.Dormant) { return; } if (_state.NextStrikeWorldSeconds <= 0.0 || _state.NextStrikeWorldSeconds < now - 300.0) { ScheduleNextStrike(now, stormStrength); SaveAndBroadcast(); } else { if (now < _state.NextStrikeWorldSeconds) { return; } Player val = PickLightningTarget(); if ((Object)(object)val == (Object)null) { ScheduleNextStrike(now + 10.0, stormStrength); SaveAndBroadcast(); return; } _state.SchedulerCycle++; bool flag = DeterministicRoll(_worldName + "|Floods|LightningDirect|" + _state.SchedulerCycle.ToString(CultureInfo.InvariantCulture)) < Mathf.Clamp01(_config.DirectHitChance.Value) && IsPlayerExposed(val); Vector3 val2 = (flag ? ((Component)val).transform.position : PickNearMissPoint(val)); float damage = (flag ? RollLightningDamage(val, stormStrength) : 0f); long targetPlayerId = (flag ? GetPlayerId(val) : 0); _state.SchedulerCycle++; long seed = StableHash(_worldName + "|Floods|Strike|" + _state.SchedulerCycle.ToString(CultureInfo.InvariantCulture) + "|" + now.ToString("R", CultureInfo.InvariantCulture)); int num = (ShouldLightningIgnite(val2, stormStrength, seed) ? 1 : 0); if (num == 1 && IsAuthoritative) { BeginWildfireAt(val2, FloodPhase.Omen, now, manual: false, "Dry lightning splits the sky. Fire takes hold where the land stayed thirsty."); } LightningStrikePayload payload = new LightningStrikePayload { Position = val2, Damage = damage, IsDirectHit = flag, TargetPlayerId = targetPlayerId, Ignite = num, Seed = seed }; BroadcastStrike(payload); ScheduleNextStrike(now, stormStrength); SaveAndBroadcast(); } } private void ScheduleNextStrike(double now, float stormStrength) { float num = Mathf.Max(3f, Mathf.Min(_config.StrikeGapMinSeconds.Value, _config.StrikeGapMaxSeconds.Value)); float num2 = Mathf.Max(num, Mathf.Max(_config.StrikeGapMinSeconds.Value, _config.StrikeGapMaxSeconds.Value)); _state.SchedulerCycle++; float num3 = DeterministicRoll(_worldName + "|Floods|StrikeGap|" + _state.SchedulerCycle.ToString(CultureInfo.InvariantCulture)); float num4 = Mathf.Lerp(num2, num, Mathf.Clamp01(stormStrength)); float num5 = Mathf.Lerp(0.75f, 1.25f, num3); _state.NextStrikeWorldSeconds = now + Math.Max(2.0, num4 * num5); } private Player PickLightningTarget() { List loadedPlayers = GetLoadedPlayers(); if (loadedPlayers.Count == 0) { return null; } List list = new List(); for (int i = 0; i < loadedPlayers.Count; i++) { if ((Object)(object)loadedPlayers[i] != (Object)null && IsPlayerExposed(loadedPlayers[i])) { list.Add(loadedPlayers[i]); } } if (list.Count == 0) { return null; } _state.SchedulerCycle++; int num = Mathf.FloorToInt(DeterministicRoll(_worldName + "|Floods|StrikeTarget|" + _state.SchedulerCycle.ToString(CultureInfo.InvariantCulture)) * (float)list.Count); return list[Mathf.Clamp(num, 0, list.Count - 1)]; } private Vector3 PickNearMissPoint(Player target) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (((Object)(object)target == (Object)null) ? Vector3.zero : ((Component)target).transform.position); float num = Mathf.Max(8f, _config.IgnitionMinRadius.Value * 0.25f); float num2 = Mathf.Max(num + 1f, Mathf.Min(35f, _config.IgnitionMaxRadius.Value * 0.45f)); float num3 = Random.Range(0f, (float)Math.PI * 2f); float num4 = Random.Range(num, num2); Vector3 val2 = val + new Vector3(Mathf.Cos(num3) * num4, 0f, Mathf.Sin(num3) * num4); if (!TryFindGround(val2, out var grounded)) { return val2; } return grounded; } private bool ShouldLightningIgnite(Vector3 point, float stormStrength, long seed) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!IsIgnitablePoint(point, requireDryness: true, stormStrength)) { return false; } float biomeFlammability = GetBiomeFlammability(point); float num = Mathf.Clamp01(_config.LightningIgnitionChance.Value * biomeFlammability * Mathf.Clamp01(_state.DrynessIndex)); return DeterministicRoll(_worldName + "|Floods|LightningIgnition|" + seed.ToString(CultureInfo.InvariantCulture)) < num; } private void BroadcastStrike(LightningStrikePayload payload) { if (ZRoutedRpc.instance != null && payload != null) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "TheFloods_Strike_01", new object[1] { payload.Serialize() }); } } private void ApplyLocalLightningDamage(LightningStrikePayload strike) { //IL_0059: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //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_00f1: 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_011f: Unknown result type (might be due to invalid IL or missing references) if (strike == null || !strike.IsDirectHit || strike.Damage <= 0.001f || (Object)(object)Player.m_localPlayer == (Object)null) { return; } Player localPlayer = Player.m_localPlayer; long playerId = GetPlayerId(localPlayer); bool flag = strike.TargetPlayerId != 0L && playerId == strike.TargetPlayerId; if (!flag && strike.TargetPlayerId == 0L) { Vector3 val = ((Component)localPlayer).transform.position - strike.Position; flag = ((Vector3)(ref val)).sqrMagnitude <= 9f; } if (!flag) { return; } float num = strike.Damage; if (_config.NonLethalLightning.Value) { float playerHealth = GetPlayerHealth(localPlayer); if (playerHealth > 1f) { num = Mathf.Min(num, playerHealth - 1f); } } HitData val2 = new HitData(); float playerHealth2 = GetPlayerHealth(localPlayer); val2.m_damage.m_lightning = Mathf.Max(0f, num); val2.m_point = strike.Position; val2.m_dir = Vector3.down; val2.m_pushForce = Mathf.Max(0f, _config.LightningPushForce.Value); val2.m_hitType = (HitType)0; ((Character)localPlayer).Damage(val2); if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, (num >= playerHealth2) ? "You are struck down by the storm." : "Lightning tears through you!", 0, (Sprite)null, false); } } private float RollLightningDamage(Player target, float stormStrength) { float num = Mathf.Lerp(Mathf.Max(0f, _config.MinLightningDamage.Value), Mathf.Max(_config.MinLightningDamage.Value, _config.MaxLightningDamage.Value), Mathf.Clamp01(stormStrength)); if ((Object)(object)target != (Object)null && IsPlayerWet(target)) { num *= Mathf.Max(0.1f, _config.WetDamageMultiplier.Value); } return num; } private string TriggerManualStrike(double now, bool direct) { //IL_0027: 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_002c: 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_00f2: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return "The Floods: no local player found for strike test."; } Vector3 val = (direct ? ((Component)localPlayer).transform.position : PickNearMissPoint(localPlayer)); float stormStrength = Mathf.Max(GetStormStrength(now), 0.9f); float damage = (direct ? RollLightningDamage(localPlayer, stormStrength) : 0f); LightningStrikePayload payload = new LightningStrikePayload { Position = val, Damage = damage, IsDirectHit = direct, TargetPlayerId = (direct ? GetPlayerId(localPlayer) : 0), Ignite = 0, Seed = StableHash(_worldName + "|Floods|ManualStrike|" + now.ToString("R", CultureInfo.InvariantCulture)) }; BroadcastStrike(payload); _state.NextStrikeWorldSeconds = now + (double)Mathf.Max(2f, _config.StrikeGraceSeconds.Value); SaveAndBroadcast(); if (!direct) { return "The Floods: near-miss lightning strike requested at " + FormatVector(val) + "."; } return "The Floods: direct lightning strike requested at your position for " + damage.ToString("0", CultureInfo.InvariantCulture) + " lightning damage."; } private string TriggerManualIgnition(string[] args, double now) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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) Vector3 grounded; if (args.Length >= 3) { if (!float.TryParse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return "Usage: floods ignite [x z]"; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(result, ((Object)(object)Player.m_localPlayer == (Object)null) ? 35f : ((Component)Player.m_localPlayer).transform.position.y, result2); if (!TryFindGround(val, out grounded)) { grounded = val; } } else { grounded = FindIgnitionPointNearPlayer(now, allowFallback: true); } _wildfires.Ignite(grounded, now, StableHash(_worldName + "|Floods|ManualIgnite|" + now.ToString("R", CultureInfo.InvariantCulture))); return "The Floods: test fire node ignited at " + FormatVector(grounded) + "."; } private void BeginWildfireAt(Vector3 origin, FloodPhase phase, double now, bool manual, string reason) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (origin == Vector3.zero) { origin = FindIgnitionPointNearPlayer(now, allowFallback: true); } _state.WildfireOriginX = origin.x; _state.WildfireOriginY = origin.y; _state.WildfireOriginZ = origin.z; BeginPhase(FloodEventType.Wildfire, phase, now, manual, 0f, rollProfileHeight: false); _wildfires.Ignite(origin, now, _state.EventSeed); if (!string.IsNullOrEmpty(reason)) { BroadcastMessage(reason); } } private void ExtinguishWildfire(double now, bool manual) { _wildfires.ExtinguishAll(); if (_state.EventType == FloodEventType.Wildfire) { StopEvent(now, manual); } else { SaveAndBroadcast(); } } private Vector3 FindIgnitionPointNearPlayer(double now, bool allowFallback) { //IL_002f: 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_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) List loadedPlayers = GetLoadedPlayers(); if (loadedPlayers.Count == 0 && (Object)(object)Player.m_localPlayer != (Object)null) { loadedPlayers.Add(Player.m_localPlayer); } if (loadedPlayers.Count == 0) { return Vector3.zero; } float num = Mathf.Max(5f, Mathf.Min(_config.IgnitionMinRadius.Value, _config.IgnitionMaxRadius.Value)); float num2 = Mathf.Max(num + 1f, Mathf.Max(_config.IgnitionMinRadius.Value, _config.IgnitionMaxRadius.Value)); for (int i = 0; i < 16; i++) { Player val = loadedPlayers[Random.Range(0, loadedPlayers.Count)]; if (!((Object)(object)val == (Object)null)) { float num3 = Random.Range(0f, (float)Math.PI * 2f); float num4 = Random.Range(num, num2); Vector3 candidate = ((Component)val).transform.position + new Vector3(Mathf.Cos(num3) * num4, 0f, Mathf.Sin(num3) * num4); if (TryFindGround(candidate, out var grounded) && (allowFallback || IsIgnitablePoint(grounded, requireDryness: true, GetStormStrength(now)))) { return grounded; } } } if (!allowFallback) { return Vector3.zero; } Player val2 = loadedPlayers[0]; Vector3 val3 = ((Component)val2).transform.position + ((Component)val2).transform.forward * num; if (!TryFindGround(val3, out var grounded2)) { return val3; } return grounded2; } private bool TryFindGround(Vector3 candidate, out Vector3 grounded) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) grounded = candidate; try { RaycastHit val = default(RaycastHit); if (Physics.Raycast(new Vector3(candidate.x, candidate.y + 120f, candidate.z), Vector3.down, ref val, 260f, -1, (QueryTriggerInteraction)1)) { grounded = ((RaycastHit)(ref val)).point; return true; } } catch { } return false; } private bool IsIgnitableForSpread(Vector3 point) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) double seconds; return IsIgnitablePoint(point, requireDryness: true, GetStormStrength(TryGetWorldSeconds(out seconds) ? seconds : 0.0)); } private bool IsIgnitablePoint(Vector3 point, bool requireDryness, float stormStrength) { //IL_004e: 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) if (requireDryness && _state.DrynessIndex < Mathf.Clamp01(_config.SpontaneousDrynessThreshold.Value)) { return false; } if (IsGroundWetForFire(TryGetWorldSeconds(out var seconds) ? seconds : 0.0, stormStrength)) { return false; } if (_water.IsPointUnderKnownWater(point)) { return false; } return GetBiomeFlammability(point) > 0.01f; } private bool IsGroundWetForFire(double now, float stormStrength) { if (IsWorldWetFromEnvMan()) { return true; } if ((_state.EventType == FloodEventType.StormTide || _state.EventType == FloodEventType.FlashSurge || _state.EventType == FloodEventType.GreatFlood) && _state.Phase != FloodPhase.Omen && stormStrength >= Mathf.Clamp01(_config.RainWetStormStrength.Value)) { return true; } string currentEnvironmentName = GetCurrentEnvironmentName(); if (IsRainEnvironmentName(currentEnvironmentName)) { if (!(stormStrength <= 0.001f) && !(stormStrength >= Mathf.Clamp01(_config.RainWetStormStrength.Value))) { return _state.EventType == FloodEventType.Wildfire; } return true; } return false; } private float GetBiomeFlammability(Vector3 point) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) string text = (GetBiomeName(point) ?? string.Empty).Replace(" ", string.Empty).Replace("_", string.Empty).ToLowerInvariant(); if (text.Contains("meadows")) { return Mathf.Max(0f, _config.MeadowsFlammability.Value); } if (text.Contains("blackforest")) { return Mathf.Max(0f, _config.BlackForestFlammability.Value); } if (text.Contains("plains")) { return Mathf.Max(0f, _config.PlainsFlammability.Value); } if (text.Contains("swamp")) { return Mathf.Max(0f, _config.SwampFlammability.Value); } if (text.Contains("mountain")) { return Mathf.Max(0f, _config.MountainFlammability.Value); } if (text.Contains("mistlands")) { return Mathf.Max(0f, _config.MistlandsFlammability.Value); } if (text.Contains("ashlands")) { return Mathf.Max(0f, _config.AshlandsFlammability.Value); } if (text.Contains("deepnorth")) { return Mathf.Max(0f, _config.DeepNorthFlammability.Value); } if (text.Contains("ocean")) { return 0f; } return Mathf.Max(0f, _config.OtherBiomeFlammability.Value); } private string GetBiomeName(Vector3 point) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) try { if (_findBiomeMethod == null) { _findBiomeMethod = AccessTools.Method(typeof(Heightmap), "FindBiome", new Type[1] { typeof(Vector3) }, (Type[])null); } if (_findBiomeMethod != null) { object obj = _findBiomeMethod.Invoke(null, new object[1] { point }); return (obj == null) ? string.Empty : obj.ToString(); } } catch { } return string.Empty; } private string GetCurrentEnvironmentName() { if ((Object)(object)EnvMan.instance == (Object)null) { return string.Empty; } try { if (!_environmentReflectionSearched) { _environmentReflectionSearched = true; _currentEnvironmentMethod = AccessTools.Method(typeof(EnvMan), "GetCurrentEnvironment", Type.EmptyTypes, (Type[])null); } object obj = ((_currentEnvironmentMethod == null) ? null : _currentEnvironmentMethod.Invoke(EnvMan.instance, null)); if (obj == null) { return string.Empty; } if (_environmentNameField == null) { _environmentNameField = AccessTools.Field(obj.GetType(), "m_name"); } return (((_environmentNameField == null) ? null : _environmentNameField.GetValue(obj)) as string) ?? string.Empty; } catch { return string.Empty; } } private bool IsRainEnvironmentName(string environmentName) { if (string.IsNullOrWhiteSpace(environmentName)) { return false; } if (_rainEnvironmentCache.TryGetValue(environmentName, out var value)) { return value; } string[] array = (_config.RainEnvironmentNames.Value ?? string.Empty).Split(new char[1] { ',' }); bool flag = false; for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0 && environmentName.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { flag = true; break; } } _rainEnvironmentCache[environmentName] = flag; return flag; } private Vector3 GetWindDirection() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)EnvMan.instance != (Object)null) { Vector3 windDir = EnvMan.instance.GetWindDir(); windDir.y = 0f; if (((Vector3)(ref windDir)).sqrMagnitude > 0.0001f) { return ((Vector3)(ref windDir)).normalized; } } } catch { } return Vector3.forward; } private List GetLoadedPlayers() { List list = new List(); try { MethodInfo methodInfo = AccessTools.Method(typeof(Player), "GetAllPlayers", Type.EmptyTypes, (Type[])null); if (((methodInfo == null) ? null : methodInfo.Invoke(null, null)) is IEnumerable enumerable) { foreach (object item in enumerable) { Player val = (Player)((item is Player) ? item : null); if ((Object)(object)val != (Object)null && !list.Contains(val)) { list.Add(val); } } } } catch { } if ((Object)(object)Player.m_localPlayer != (Object)null && !list.Contains(Player.m_localPlayer)) { list.Add(Player.m_localPlayer); } return list; } private bool IsPlayerExposed(Player player) { if ((Object)(object)player == (Object)null || !_config.RequireExposed.Value) { return true; } return !IsPlayerSheltered(player); } private bool IsPlayerSheltered(Player player) { if ((Object)(object)player == (Object)null) { return false; } try { MethodInfo methodInfo = AccessTools.Method(((object)player).GetType(), "InShelter", Type.EmptyTypes, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(player, null); if (obj is bool) { return (bool)obj; } } } catch { } return false; } private bool IsPlayerWet(Player player) { if ((Object)(object)player == (Object)null) { return false; } try { if (!_playerWetReflectionSearched) { _playerWetReflectionSearched = true; _getSEManMethod = AccessTools.Method(((object)player).GetType(), "GetSEMan", Type.EmptyTypes, (Type[])null); } object obj = ((_getSEManMethod == null) ? null : _getSEManMethod.Invoke(player, null)); if (obj != null) { if (!_statusEffectReflectionSearched) { _statusEffectReflectionSearched = true; Type type = obj.GetType(); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; _haveStatusEffectIntMethod = type.GetMethod("HaveStatusEffect", bindingAttr, null, new Type[1] { typeof(int) }, null); if (_haveStatusEffectIntMethod == null) { _haveStatusEffectStringMethod = type.GetMethod("HaveStatusEffect", bindingAttr, null, new Type[1] { typeof(string) }, null); } } if (_haveStatusEffectIntMethod != null) { object obj2 = _haveStatusEffectIntMethod.Invoke(obj, new object[1] { WetStatusHash }); if (obj2 is bool && (bool)obj2) { return true; } } else if (_haveStatusEffectStringMethod != null) { object obj3 = _haveStatusEffectStringMethod.Invoke(obj, new object[1] { "Wet" }); if (obj3 is bool && (bool)obj3) { return true; } } } } catch { } if (IsWorldWetFromEnvMan()) { return !IsPlayerSheltered(player); } return false; } private bool IsWorldWetFromEnvMan() { if ((Object)(object)EnvMan.instance == (Object)null) { return false; } try { if (!_envWetReflectionSearched) { _envWetReflectionSearched = true; BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; _envManIsWetMethod = typeof(EnvMan).GetMethod("IsWet", bindingAttr, null, Type.EmptyTypes, null); } if (_envManIsWetMethod != null) { object obj = _envManIsWetMethod.Invoke(EnvMan.instance, null); return obj is bool && (bool)obj; } } catch { } return false; } private static int GetStableStatusHash(string text) { if (string.IsNullOrEmpty(text)) { return 0; } int num = 5381; int num2 = num; for (int i = 0; i < text.Length; i += 2) { num = ((num << 5) + num) ^ text[i]; if (i == text.Length - 1) { break; } num2 = ((num2 << 5) + num2) ^ text[i + 1]; } return num + num2 * 1566083941; } private float GetPlayerHealth(Player player) { if ((Object)(object)player == (Object)null) { return 0f; } try { MethodInfo methodInfo = AccessTools.Method(((object)player).GetType(), "GetHealth", Type.EmptyTypes, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(player, null); if (obj != null) { return Convert.ToSingle(obj, CultureInfo.InvariantCulture); } } } catch { } return 9999f; } private static long GetPlayerId(Player player) { if ((Object)(object)player == (Object)null) { return 0L; } try { MethodInfo methodInfo = AccessTools.Method(((object)player).GetType(), "GetPlayerID", Type.EmptyTypes, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(player, null); if (obj != null) { return Convert.ToInt64(obj, CultureInfo.InvariantCulture); } } FieldInfo fieldInfo = AccessTools.Field(((object)player).GetType(), "m_playerID"); object obj2 = ((fieldInfo == null) ? null : fieldInfo.GetValue(player)); if (obj2 != null) { return Convert.ToInt64(obj2, CultureInfo.InvariantCulture); } } catch { } return StableHash(((Object)player).name + "|" + ((Object)player).GetInstanceID().ToString(CultureInfo.InvariantCulture)); } private static string FormatVector(Vector3 value) { return "(" + value.x.ToString("0.0", CultureInfo.InvariantCulture) + "," + value.y.ToString("0.0", CultureInfo.InvariantCulture) + "," + value.z.ToString("0.0", CultureInfo.InvariantCulture) + ")"; } private FloodEventType SelectOrdinaryEventType() { float num = (_config.StormTide.Enabled.Value ? Mathf.Max(0f, _config.StormTideWeight.Value) : 0f); float num2 = (_config.Drought.Enabled.Value ? Mathf.Max(0f, _config.DroughtWeight.Value) : 0f); float num3 = (_config.FlashSurge.Enabled.Value ? Mathf.Max(0f, _config.FlashSurgeWeight.Value) : 0f); float num4 = num + num2 + num3; if (num4 <= 0.0001f) { return FloodEventType.None; } _state.SchedulerCycle++; float num5 = DeterministicRoll(_worldName + "|Floods|OrdinaryType|" + _state.SchedulerCycle.ToString(CultureInfo.InvariantCulture) + "|" + _state.EventNumber.ToString(CultureInfo.InvariantCulture)) * num4; if (num5 < num) { return FloodEventType.StormTide; } num5 -= num; if (num5 < num2) { return FloodEventType.Drought; } return FloodEventType.FlashSurge; } private float RollSchedulerHours(float first, float second, string purpose) { float num = Mathf.Max(0.01f, Mathf.Min(first, second)); float num2 = Mathf.Max(num, Mathf.Max(first, second)); _state.SchedulerCycle++; float num3 = DeterministicRoll(_worldName + "|Floods|Scheduler|" + purpose + "|" + _state.SchedulerCycle.ToString(CultureInfo.InvariantCulture) + "|" + _state.EventNumber.ToString(CultureInfo.InvariantCulture)); return Mathf.Lerp(num, num2, num3); } private double GetWorldAgeHours(double now) { long worldDay = GetWorldDay(now); return Math.Max(0.0, (double)worldDay * Math.Max(60.0, _config.GameDaySeconds.Value) / 3600.0); } private static double HoursToSeconds(float hours) { return Math.Max(0.01, hours) * 3600.0; } private float StartManualEvent(FloodEventType eventType, FloodPhase phase, double now) { BeginPhase(eventType, phase, now, manual: true, 0f, rollProfileHeight: true); return _state.PeakMeters; } private void StartManualEvent(FloodEventType eventType, FloodPhase phase, double now, float peakMeters) { BeginPhase(eventType, phase, now, manual: true, peakMeters, rollProfileHeight: false); } private void BeginPhase(FloodEventType eventType, FloodPhase phase, double now, bool manual, float requestedPeakMeters, bool rollProfileHeight) { if (phase == FloodPhase.Dormant) { StopEvent(now, manual); return; } bool flag = _state.Phase == FloodPhase.Dormant || phase == FloodPhase.Omen || _state.EventType != eventType; if (flag) { _state.EventNumber++; _state.EventSeed = StableHash(_worldName + "|" + eventType.ToString() + "|" + _state.EventNumber + "|" + now.ToString("R", CultureInfo.InvariantCulture)); } _state.EventType = eventType; _state.Phase = phase; _state.PhaseStartedWorldSeconds = now; _state.PhaseEndsWorldSeconds = now + GetPhaseDurationSeconds(phase); if (flag) { bool severeDrought = false; float num = (rollProfileHeight ? RollEventPeakMeters(eventType, _state.EventSeed, out severeDrought) : requestedPeakMeters); float num2 = Mathf.Max(1f, _config.DebugMaximumSurgeMeters.Value); _state.PeakMeters = Mathf.Clamp(num, 0f - num2, num2); _state.IsSevereDrought = eventType == FloodEventType.Drought && rollProfileHeight && severeDrought; _state.DrawdownMeters = ((eventType == FloodEventType.FlashSurge && _config.EnableFlashSurgeDrawdown.Value) ? RollFlashSurgeDrawdownMeters(_state.EventSeed) : 0f); } else if (!rollProfileHeight) { float num3 = Mathf.Max(1f, _config.DebugMaximumSurgeMeters.Value); _state.PeakMeters = Mathf.Clamp(requestedPeakMeters, 0f - num3, num3); } _state.ManualEvent = manual; AnnouncePhase(eventType, phase); SaveAndBroadcast(); } private float RollEventPeakMeters(FloodEventType eventType, long eventSeed, out bool severeDrought) { severeDrought = false; FloodEventProfile profile = _config.GetProfile(eventType); if (profile == null) { return _config.MaximumSurgeMeters.Value; } float num = profile.GetMinimumHeight(); float num2 = profile.GetMaximumHeight(); if (eventType == FloodEventType.Drought) { float num3 = DeterministicRoll(_worldName + "|Floods|SevereDrought|" + eventSeed.ToString(CultureInfo.InvariantCulture)); severeDrought = num3 < Mathf.Clamp01(_config.SevereDroughtChance.Value); if (severeDrought) { num = Mathf.Min(_config.SevereDroughtMinimumMeters.Value, _config.SevereDroughtMaximumMeters.Value); num2 = Mathf.Max(_config.SevereDroughtMinimumMeters.Value, _config.SevereDroughtMaximumMeters.Value); } } float num4 = Mathf.Max(1f, _config.DebugMaximumSurgeMeters.Value); num = Mathf.Clamp(num, 0f, num4); num2 = Mathf.Clamp(num2, num, num4); float num5 = DeterministicRoll(_worldName + "|Floods|PeakHeight|" + eventType.ToString() + "|" + eventSeed.ToString(CultureInfo.InvariantCulture)); float num6 = Mathf.Lerp(num, num2, num5); if (eventType != FloodEventType.Drought) { return num6; } return 0f - num6; } private float RollFlashSurgeDrawdownMeters(long eventSeed) { if (!_config.EnableFlashSurgeDrawdown.Value) { return 0f; } float num = Mathf.Clamp(_config.GetFlashSurgeDrawdownMinimum(), 0f, Mathf.Max(1f, _config.DebugMaximumSurgeMeters.Value)); float num2 = Mathf.Clamp(_config.GetFlashSurgeDrawdownMaximum(), num, Mathf.Max(1f, _config.DebugMaximumSurgeMeters.Value)); float num3 = DeterministicRoll(_worldName + "|Floods|FlashDrawdown|" + eventSeed.ToString(CultureInfo.InvariantCulture)); return Mathf.Lerp(num, num2, num3); } private void AdvancePhase(double now) { FloodEventType eventType = ((_state.EventType == FloodEventType.None) ? FloodEventType.Custom : _state.EventType); switch (_state.Phase) { case FloodPhase.Omen: BeginPhase(eventType, FloodPhase.Rising, now, _state.ManualEvent, _state.PeakMeters, rollProfileHeight: false); break; case FloodPhase.Rising: BeginPhase(eventType, FloodPhase.Peak, now, _state.ManualEvent, _state.PeakMeters, rollProfileHeight: false); break; case FloodPhase.Peak: BeginPhase(eventType, FloodPhase.Receding, now, _state.ManualEvent, _state.PeakMeters, rollProfileHeight: false); break; case FloodPhase.Receding: StopEvent(now, _state.ManualEvent); break; } } private void StopEvent(double now, bool manualStop) { bool num = _state.Phase != FloodPhase.Dormant; FloodEventType eventType = _state.EventType; bool manualEvent = _state.ManualEvent; long worldDay = GetWorldDay(now); if (num && !manualEvent) { SetLastCompletedDay(eventType, worldDay); _state.LastCompletedDay = worldDay; EnsureWaterCycleSchedule(now); ScheduleAfterNaturalEvent(eventType, now); } _state.Phase = FloodPhase.Dormant; _state.EventType = FloodEventType.None; _state.PhaseStartedWorldSeconds = now; _state.PhaseEndsWorldSeconds = 0.0; _state.DrawdownMeters = 0f; _state.IsSevereDrought = false; _state.ManualEvent = false; _state.WildfireOriginX = 0f; _state.WildfireOriginY = 0f; _state.WildfireOriginZ = 0f; _water.RestoreOriginalWaterLevel(); _environment.ReleaseForcedEnvironment(); _wildfires.ExtinguishAll(); _strongWinds.ResetRuntime(); if (num) { string message = ((eventType != FloodEventType.Wildfire) ? (manualStop ? "The Floods have been silenced." : "The waters begin to settle.") : (manualStop ? "The wildfire has been smothered." : "The wildfire burns itself out.")); BroadcastMessage(message); } SaveAndBroadcast(); } private void ApplyLocalEffects(double now) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) float currentSurgeMeters = GetCurrentSurgeMeters(now); float stormStrength = GetStormStrength(now); float wildfireIntensity = GetWildfireIntensity(now); float strongWindIntensity = GetStrongWindIntensity(now, stormStrength); Vector3 stormFrontDirection = GetStormFrontDirection(); Vector3 effectiveWind = GetEffectiveWindDirection(stormFrontDirection); _stormApproach = BuildStormApproach(now, stormStrength, wildfireIntensity, strongWindIntensity, currentSurgeMeters, stormFrontDirection); _water.ApplySurge(currentSurgeMeters); _environment.Apply(_state.Phase, stormStrength); _environment.ApplyWildfire(wildfireIntensity); _lightning.UpdateAmbient(_state, Mathf.Max(stormStrength, strongWindIntensity * 0.72f)); _wildfires.Update(_state, now, wildfireIntensity, IsGroundWetForFire(now, stormStrength), IsPlayerWet(Player.m_localPlayer), _water, IsIgnitableForSpread, () => effectiveWind); _strongWinds.Update(_state, now, strongWindIntensity, effectiveWind, IsAuthoritative, GetLoadedPlayers()); _audio.Update(_state, stormStrength, wildfireIntensity, strongWindIntensity, currentSurgeMeters, _stormApproach); } internal float GetCurrentSurgeMeters(double now) { if (_state.Phase == FloodPhase.Dormant || _state.EventType == FloodEventType.Wildfire || _state.EventType == FloodEventType.StrongWinds) { return 0f; } float value = PhaseProgress(now); switch (_state.Phase) { case FloodPhase.Omen: if (_state.EventType == FloodEventType.FlashSurge && _state.DrawdownMeters > 0.001f) { return (0f - _state.DrawdownMeters) * Smooth01(value); } return _state.PeakMeters * 0.08f * Smooth01(value); case FloodPhase.Rising: if (_state.EventType != FloodEventType.FlashSurge || !(_state.DrawdownMeters > 0.001f)) { return _state.PeakMeters * Smooth01(value); } return Mathf.Lerp(0f - _state.DrawdownMeters, _state.PeakMeters, Smooth01(value)); case FloodPhase.Peak: return _state.PeakMeters; case FloodPhase.Receding: return _state.PeakMeters * (1f - Smooth01(value)); default: return 0f; } } private float GetStormStrength(double now) { if (_state.Phase == FloodPhase.Dormant || _state.EventType == FloodEventType.Drought || _state.EventType == FloodEventType.Wildfire) { return 0f; } float value = PhaseProgress(now); if (_state.EventType == FloodEventType.StrongWinds) { return _state.Phase switch { FloodPhase.Omen => Mathf.Lerp(0.12f, 0.35f, Smooth01(value)), FloodPhase.Rising => Mathf.Lerp(0.36f, 0.82f, Smooth01(value)), FloodPhase.Peak => 0.86f, FloodPhase.Receding => Mathf.Lerp(0.7f, 0.08f, Smooth01(value)), _ => 0f, }; } float num = _state.Phase switch { FloodPhase.Omen => Mathf.Lerp(0.16f, 0.42f, Smooth01(value)), FloodPhase.Rising => Mathf.Lerp(0.45f, 0.94f, Smooth01(value)), FloodPhase.Peak => 1f, FloodPhase.Receding => Mathf.Lerp(0.9f, 0.12f, Smooth01(value)), _ => 0f, }; float num2 = ((_state.EventType == FloodEventType.StormTide) ? 0.72f : 1f); return Mathf.Clamp01(num * num2); } private float GetWildfireIntensity(double now) { if (_state.Phase == FloodPhase.Dormant || _state.EventType != FloodEventType.Wildfire) { return 0f; } float value = PhaseProgress(now); return _state.Phase switch { FloodPhase.Omen => Mathf.Lerp(0.1f, 0.35f, Smooth01(value)), FloodPhase.Rising => Mathf.Lerp(0.38f, 0.9f, Smooth01(value)), FloodPhase.Peak => 1f, FloodPhase.Receding => Mathf.Lerp(0.75f, 0.08f, Smooth01(value)), _ => 0f, }; } private float GetStrongWindIntensity(double now, float stormStrength) { if (!_config.EnableStrongWinds.Value || _state.Phase == FloodPhase.Dormant) { return 0f; } float value = PhaseProgress(now); float num = 0f; if (_state.EventType == FloodEventType.StrongWinds) { switch (_state.Phase) { case FloodPhase.Omen: num = Mathf.Lerp(0.12f, 0.36f, Smooth01(value)); break; case FloodPhase.Rising: num = Mathf.Lerp(0.38f, 0.86f, Smooth01(value)); break; case FloodPhase.Peak: num = 1f; break; case FloodPhase.Receding: num = Mathf.Lerp(0.78f, 0.08f, Smooth01(value)); break; } } else if (_state.EventType == FloodEventType.GreatFlood) { num = Mathf.Lerp(0.3f, 1f, stormStrength); } else if (_state.EventType == FloodEventType.FlashSurge) { num = Mathf.Lerp(0.2f, 0.82f, stormStrength); } else if (_state.EventType == FloodEventType.StormTide || _state.EventType == FloodEventType.Custom) { num = stormStrength * 0.72f; } else if (_state.EventType == FloodEventType.Wildfire) { num = GetWildfireIntensity(now) * 0.3f; } return Mathf.Clamp01(num * Mathf.Max(0f, _config.StrongWindsWindStrengthMultiplier.Value)); } private Vector3 GetStormFrontDirection() { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) long num = ((_state.EventSeed == 0L) ? StableHash((_worldName ?? string.Empty) + "|StormFrontFallback") : _state.EventSeed); float num2 = DeterministicRoll((_worldName ?? string.Empty) + "|StormFront|" + num.ToString(CultureInfo.InvariantCulture)) * (float)Math.PI * 2f; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(Mathf.Cos(num2), 0f, Mathf.Sin(num2)); if (!(((Vector3)(ref val)).sqrMagnitude < 0.001f)) { return ((Vector3)(ref val)).normalized; } return Vector3.forward; } private Vector3 GetEffectiveWindDirection(Vector3 frontDirection) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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) Vector3 val = GetWindDirection(); val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = Vector3.forward; } Vector3 val2 = -frontDirection; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.001f) { val2 = val; } float num = 0f; if (_state.EventType == FloodEventType.StrongWinds || _state.EventType == FloodEventType.GreatFlood) { num = 0.86f; } else if (_state.EventType == FloodEventType.FlashSurge || _state.EventType == FloodEventType.StormTide || _state.EventType == FloodEventType.Custom) { num = 0.58f; } else if (_state.EventType == FloodEventType.Wildfire) { num = 0.35f; } Vector3 val3 = Vector3.Slerp(((Vector3)(ref val)).normalized, ((Vector3)(ref val2)).normalized, num); if (!(((Vector3)(ref val3)).sqrMagnitude < 0.001f)) { return ((Vector3)(ref val3)).normalized; } return ((Vector3)(ref val)).normalized; } private StormApproachVisual BuildStormApproach(double now, float stormStrength, float wildfireIntensity, float strongWindIntensity, float surgeMeters, Vector3 frontDirection) { //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) if (!_config.EnableApproachingStormFront.Value || _state.Phase == FloodPhase.Dormant) { return StormApproachVisual.Inactive; } if (_state.EventType != FloodEventType.StormTide && _state.EventType != FloodEventType.FlashSurge && _state.EventType != FloodEventType.GreatFlood && _state.EventType != FloodEventType.Custom && _state.EventType != FloodEventType.StrongWinds && wildfireIntensity <= 0.001f) { return StormApproachVisual.Inactive; } float value = PhaseProgress(now); float num = _state.Phase switch { FloodPhase.Omen => Mathf.Lerp(0.08f, 0.34f, Smooth01(value)), FloodPhase.Rising => Mathf.Lerp(0.36f, 0.82f, Smooth01(value)), FloodPhase.Peak => 1f, FloodPhase.Receding => Mathf.Lerp(0.82f, 0.12f, Smooth01(value)), _ => 0f, }; float overheadStrength = Mathf.Clamp01((num - 0.62f) / 0.38f); float num2 = Mathf.Clamp01(Mathf.Max(num, stormStrength * 0.55f + strongWindIntensity * 0.35f)); if (_state.EventType == FloodEventType.Wildfire) { num2 = Mathf.Max(num2, wildfireIntensity * 0.45f); } return new StormApproachVisual { Active = true, FrontDirection = frontDirection, FrontProgress = num, OverheadStrength = overheadStrength, WallStrength = num2, WindStrength = strongWindIntensity, SurgeMeters = surgeMeters, Seed = _state.EventSeed }; } private float PhaseProgress(double now) { double num = _state.PhaseEndsWorldSeconds - _state.PhaseStartedWorldSeconds; if (num <= 0.0001) { return 1f; } return Mathf.Clamp01((float)((now - _state.PhaseStartedWorldSeconds) / num)); } private double GetPhaseDurationSeconds(FloodPhase phase) { if (_state.EventType == FloodEventType.StrongWinds) { float num = Mathf.Max(180f, _config.StrongWindsDurationMinutes.Value * 60f); return phase switch { FloodPhase.Omen => num * 0.2f, FloodPhase.Rising => num * 0.35f, FloodPhase.Peak => num * 0.25f, FloodPhase.Receding => num * 0.2f, _ => 0.0, }; } FloodEventProfile profile = _config.GetProfile(_state.EventType); float num2 = ((profile == null) ? (phase switch { FloodPhase.Omen => _config.OmenDays.Value, FloodPhase.Rising => _config.RisingDays.Value, FloodPhase.Peak => _config.PeakDays.Value, FloodPhase.Receding => _config.RecedingDays.Value, _ => 0f, }) : (phase switch { FloodPhase.Omen => profile.OmenDays.Value, FloodPhase.Rising => profile.RisingDays.Value, FloodPhase.Peak => profile.PeakDays.Value, FloodPhase.Receding => profile.RecedingDays.Value, _ => 0f, })); return Math.Max(1.0, num2 * Math.Max(60f, _config.GameDaySeconds.Value)); } private void AnnouncePhase(FloodEventType type, FloodPhase phase) { float peakMeters = _state.PeakMeters; BroadcastMessage(type switch { FloodEventType.StormTide => phase switch { FloodPhase.Peak => (peakMeters >= 4f) ? "The storm tide is tearing at the land." : "The storm tide has swallowed the low coast.", FloodPhase.Rising => (peakMeters >= 4f) ? "A violent tide tears across the low coast." : "The tide climbs over the shore.", FloodPhase.Omen => "The wind turns cold. A storm tide is building.", _ => "The tide is turning. Keep clear of the shore.", }, FloodEventType.FlashSurge => phase switch { FloodPhase.Peak => (peakMeters >= 10f) ? "The coast is overwhelmed." : "The sea has leapt beyond the shore.", FloodPhase.Rising => (peakMeters >= 10f) ? "A wall of water races toward the shore." : "A flash surge strikes the coast.", FloodPhase.Omen => "The sea pulls back. An unnatural swell gathers.", _ => "The flash surge is losing its strength.", }, FloodEventType.GreatFlood => phase switch { FloodPhase.Peak => (peakMeters >= 13f) ? "THE BROKEN CYCLE HAS BEGUN." : ((peakMeters >= 10f) ? "The sea has claimed the lowlands." : "The lowlands lie beneath the storm tide."), FloodPhase.Rising => (peakMeters >= 13f) ? "The sea is swallowing the land." : "The lowlands begin to drown.", FloodPhase.Omen => (peakMeters >= 13f) ? "A black wall of cloud rises beyond the sea. The Floods are coming." : "A black wall of cloud rises beyond the sea. The Great Flood is coming.", _ => "The storm weakens. The Great Flood begins to recede.", }, FloodEventType.Drought => phase switch { FloodPhase.Peak => _state.IsSevereDrought ? "The severe drought has laid the coast bare." : "The drought has laid the coast bare.", FloodPhase.Rising => _state.IsSevereDrought ? "The shoreline is racing away, exposing the seafloor." : "The shoreline pulls back, exposing the seafloor.", FloodPhase.Omen => _state.IsSevereDrought ? "The sea is falling back farther than it should. A severe drought is coming." : "The sea has begun to retreat. An unnatural drought is coming.", _ => "The water is returning to the shore.", }, FloodEventType.Wildfire => phase switch { FloodPhase.Peak => "The wildfire is at its height. Fire races where water has been absent.", FloodPhase.Rising => "The wildfire is spreading through the dry ground.", FloodPhase.Omen => "Smoke rises beyond the trees. The dry land is ready to burn.", _ => "Rain, ash, and spent fuel begin to choke the wildfire.", }, FloodEventType.StrongWinds => phase switch { FloodPhase.Peak => "The gale is tearing through the forest.", FloodPhase.Rising => "The storm is coming.", FloodPhase.Omen => "Something moves through the trees.", _ => "The worst of the wind begins to pass.", }, _ => phase switch { FloodPhase.Peak => "The waters have reached their height.", FloodPhase.Rising => "The lowlands begin to drown.", FloodPhase.Omen => "A darkness gathers beyond the horizon. The Floods are coming.", _ => "The storm weakens. The Floods begin to recede.", }, }); } private void BroadcastMessage(string message) { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "TheFloods_Message_01", new object[1] { message }); } if (_config.DebugLogging.Value) { _logger.LogInfo((object)("The Floods message: " + message)); } } private void BroadcastState() { if (IsAuthoritative && ZRoutedRpc.instance != null) { _lastSyncAt = Time.unscaledTime; ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "TheFloods_State_01", new object[1] { _state.Serialize() }); } } private void SaveAndBroadcast() { if (IsAuthoritative && _loaded) { _store.Save(_worldName, _state); BroadcastState(); } } private string DescribeSchedule(double now) { if (!_state.SchedulerInitialized) { return "The Floods: V0.8 scheduler is waiting for the world clock."; } double num = Math.Max(0.0, _state.NextOrdinaryEventWorldSeconds - now) / 60.0; double num2 = Math.Max(0.0, _state.NextGreatFloodWorldSeconds - now) / 60.0; double num3 = Math.Max(0.0, _state.GreatFloodForceWorldSeconds - now) / 60.0; double num4 = Math.Max(0.0, _state.GlobalRecoveryEndsWorldSeconds - now) / 60.0; double num5 = Math.Max(0.0, _state.NextWildfireWorldSeconds - now) / 60.0; double num6 = Math.Max(0.0, _state.NextStrongWindsWorldSeconds - now) / 60.0; double num7 = Math.Max(0.0, _state.NextStrikeWorldSeconds - now); return "scheduler quiet=" + num4.ToString("0", CultureInfo.InvariantCulture) + "m nextOrdinary=" + num.ToString("0", CultureInfo.InvariantCulture) + "m nextGreatTarget=" + num2.ToString("0", CultureInfo.InvariantCulture) + "m greatForceBy=" + num3.ToString("0", CultureInfo.InvariantCulture) + "m nextWildfire=" + num5.ToString("0", CultureInfo.InvariantCulture) + "m nextStrongWinds=" + num6.ToString("0", CultureInfo.InvariantCulture) + "m nextStrike=" + num7.ToString("0", CultureInfo.InvariantCulture) + "sm cycle=" + _state.SchedulerCycle.ToString(CultureInfo.InvariantCulture); } private string DescribeState(double now) { long num = (TryGetWorldSeconds(out now) ? GetWorldDay(now) : (-1)); string text = ((_state.EventType == FloodEventType.FlashSurge && _state.DrawdownMeters > 0.001f) ? (" drawdown=" + _state.DrawdownMeters.ToString("0.00", CultureInfo.InvariantCulture) + "m") : string.Empty); return "event=" + GetEventDisplayName(_state.EventType) + " phase=" + _state.Phase.ToString() + " day=" + num + " waterOffset=" + GetCurrentSurgeMeters(now).ToString("0.00", CultureInfo.InvariantCulture) + "m peak=" + _state.PeakMeters.ToString("0.00", CultureInfo.InvariantCulture) + "m dryness=" + _state.DrynessIndex.ToString("0.00", CultureInfo.InvariantCulture) + " fireNodes=" + _wildfires.ActiveNodeCount.ToString(CultureInfo.InvariantCulture) + ((_state.EventType != FloodEventType.Drought) ? string.Empty : (_state.IsSevereDrought ? " drought=severe" : " drought=standard")) + text + GetActiveRangeDescription() + " storm=" + GetStormStrength(now).ToString("0.00", CultureInfo.InvariantCulture) + " wind=" + GetStrongWindIntensity(now, GetStormStrength(now)).ToString("0.00", CultureInfo.InvariantCulture) + " wildfire=" + GetWildfireIntensity(now).ToString("0.00", CultureInfo.InvariantCulture) + " manual=" + _state.ManualEvent + " eventNumber=" + _state.EventNumber; } private string GetActiveRangeDescription() { FloodEventProfile profile = _config.GetProfile(_state.EventType); if (profile == null) { return string.Empty; } if (_state.EventType == FloodEventType.Wildfire) { return string.Empty; } if (_state.EventType == FloodEventType.Drought) { float num = (_state.IsSevereDrought ? Mathf.Min(_config.SevereDroughtMinimumMeters.Value, _config.SevereDroughtMaximumMeters.Value) : profile.GetMinimumHeight()); float num2 = (_state.IsSevereDrought ? Mathf.Max(_config.SevereDroughtMinimumMeters.Value, _config.SevereDroughtMaximumMeters.Value) : profile.GetMaximumHeight()); return " drawdownRange=" + num.ToString("0.0", CultureInfo.InvariantCulture) + "–" + num2.ToString("0.0", CultureInfo.InvariantCulture) + "m"; } return " range=" + profile.GetMinimumHeight().ToString("0.0", CultureInfo.InvariantCulture) + "–" + profile.GetMaximumHeight().ToString("0.0", CultureInfo.InvariantCulture) + "m"; } private long GetLastCompletedDay(FloodEventType type) { return type switch { FloodEventType.StormTide => _state.LastStormTideDay, FloodEventType.FlashSurge => _state.LastFlashSurgeDay, FloodEventType.GreatFlood => _state.LastGreatFloodDay, FloodEventType.Drought => _state.LastDroughtDay, FloodEventType.StrongWinds => _state.LastStrongWindsDay, _ => _state.LastCompletedDay, }; } private void SetLastCompletedDay(FloodEventType type, long day) { switch (type) { case FloodEventType.StormTide: _state.LastStormTideDay = day; break; case FloodEventType.FlashSurge: _state.LastFlashSurgeDay = day; break; case FloodEventType.GreatFlood: _state.LastGreatFloodDay = day; break; case FloodEventType.Drought: _state.LastDroughtDay = day; break; case FloodEventType.StrongWinds: _state.LastStrongWindsDay = day; break; case FloodEventType.Wildfire: break; } } private bool TryGetWorldSeconds(out double seconds) { seconds = 0.0; if ((Object)(object)ZNet.instance == (Object)null) { return false; } try { seconds = (double)ZNet.instance.GetTime().Ticks / 10000000.0; return true; } catch { return false; } } private long GetWorldDay(double worldSeconds) { try { if ((Object)(object)EnvMan.instance != (Object)null) { MethodInfo methodInfo = AccessTools.Method(typeof(EnvMan), "GetCurrentDay", Type.EmptyTypes, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(EnvMan.instance, null); if (obj != null) { return Convert.ToInt64(obj, CultureInfo.InvariantCulture); } } } } catch { } return Math.Max(1L, (long)Math.Floor(worldSeconds / (double)Math.Max(60f, _config.GameDaySeconds.Value)) + 1); } private void LogWaterProbe() { //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) string[] obj = new string[7] { "ZoneSystem", "WaterVolume", "WaterSurface", "Ocean", "Floating", "Ship", "EnvMan" }; _logger.LogInfo((object)"[TheFloods] WATER PROBE BEGIN"); string[] array = obj; foreach (string text in array) { Type type = AccessTools.TypeByName(text); if (type == null) { _logger.LogInfo((object)("[TheFloods] WATER PROBE type missing: " + text)); continue; } IEnumerable source = from f in type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where HasWaterKeyword(f.Name) select f.FieldType.Name + " " + f.Name; IEnumerable source2 = from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where HasWaterKeyword(m.Name) select m.ReturnType.Name + " " + m.Name + "(" + string.Join(", ", from p in m.GetParameters() select p.ParameterType.Name) + ")"; _logger.LogInfo((object)("[TheFloods] WATER PROBE " + text + " fields: " + string.Join(" || ", source.ToArray()))); _logger.LogInfo((object)("[TheFloods] WATER PROBE " + text + " methods: " + string.Join(" || ", source2.ToArray()))); } _logger.LogInfo((object)("[TheFloods] WATER PROBE " + _water.BaselineDescription + " applied=" + _water.AppliedDescription)); Vector3 samplePoint = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero); _water.LogSurfaceProbe(samplePoint); _logger.LogInfo((object)"[TheFloods] WATER PROBE END"); } private static bool HasWaterKeyword(string text) { string text2 = text.ToLowerInvariant(); if (!text2.Contains("water") && !text2.Contains("ocean") && !text2.Contains("surface") && !text2.Contains("wave") && !text2.Contains("liquid") && !text2.Contains("env")) { return text2.Contains("force"); } return true; } private static FloodPhase ParsePhase(string raw) { switch ((raw ?? string.Empty).Trim().ToLowerInvariant()) { case "omen": return FloodPhase.Omen; case "rise": case "rising": case "spread": case "spreading": return FloodPhase.Rising; case "peak": case "high": return FloodPhase.Peak; case "recede": case "receding": case "burnout": case "burningout": return FloodPhase.Receding; default: return FloodPhase.Omen; } } private static bool TryParseEventType(string raw, out FloodEventType type) { switch ((raw ?? string.Empty).Trim().ToLowerInvariant().Replace(" ", string.Empty) .Replace("_", string.Empty) .Replace("-", string.Empty)) { case "tide": case "stormtide": type = FloodEventType.StormTide; return true; case "flashsurge": case "surge": type = FloodEventType.FlashSurge; return true; case "greatflood": case "flood": type = FloodEventType.GreatFlood; return true; case "drought": case "lowtide": type = FloodEventType.Drought; return true; case "fire": case "wildfire": type = FloodEventType.Wildfire; return true; case "wind": case "gale": case "strongwind": case "strongwinds": type = FloodEventType.StrongWinds; return true; case "custom": type = FloodEventType.Custom; return true; default: type = FloodEventType.None; return false; } } private string GetEventDisplayName(FloodEventType type) { FloodEventProfile profile = _config.GetProfile(type); if (profile != null) { return profile.DisplayName; } return type switch { FloodEventType.StrongWinds => "Strong Winds", FloodEventType.Custom => "Custom", _ => "None", }; } private static string FormatSignedMeters(float value) { return ((value >= 0f) ? "+" : "-") + Mathf.Abs(value).ToString("0.00", CultureInfo.InvariantCulture) + "m"; } private static float Smooth01(float value) { value = Mathf.Clamp01(value); return value * value * (3f - 2f * value); } private static long StableHash(string text) { long num = 1469598103934665603L; for (int i = 0; i < text.Length; i++) { num ^= text[i]; num *= 1099511628211L; } return num; } private static float DeterministicRoll(string source) { return (float)((ulong)StableHash(source) % 1000000uL) / 1000000f; } } internal sealed class FloodLightningSystem { private sealed class ActiveBolt { internal GameObject Root; internal List CoreLines = new List(); internal List GlowLines = new List(); internal Light Light; internal float CreatedAt; internal float EndsAt; internal float Seed; internal float NextFlickerAt; internal int FlickerCount; internal bool DirectHit; internal float Strength; internal Color GlowColour; internal Color CoreColour; } private sealed class PendingThunder { internal Vector3 Position; internal float PlayAt; internal float Distance; internal bool DirectHit; } private readonly ManualLogSource _logger; private readonly FloodConfig _config; private readonly FloodVisuals _visuals; private readonly List _bolts = new List(); private readonly List _pendingThunder = new List(); private Material _boltCoreMaterial; private Material _boltGlowMaterial; private Texture2D _softBoltTexture; private float _nextAmbientAt; internal FloodLightningSystem(ManualLogSource logger, FloodConfig config, FloodVisuals visuals) { _logger = logger; _config = config; _visuals = visuals; } internal void UpdateAmbient(FloodState state, float stormStrength) { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) UpdateBolts(); UpdatePendingThunder(); if (_config.EnableLightningStrikes.Value && _config.EnableAmbientBolts.Value && state != null && state.Phase != FloodPhase.Dormant && state.Phase != FloodPhase.Omen && !(stormStrength < 0.25f) && !((Object)(object)Player.m_localPlayer == (Object)null) && !(Time.unscaledTime < _nextAmbientAt)) { float num = Mathf.Max(0.1f, _config.AmbientBoltsPerMinuteAtPeak.Value) * Mathf.Clamp01(stormStrength); float num2 = Mathf.Clamp(60f / num, 4f, 90f); _nextAmbientAt = Time.unscaledTime + Random.Range(num2 * 0.55f, num2 * 1.45f); Vector3 val = PickAmbientPoint(((Component)Player.m_localPlayer).transform.position); SpawnBolt(val, stormStrength, direct: false, Random.Range(int.MinValue, int.MaxValue)); float num3 = Vector3.Distance(((Component)Player.m_localPlayer).transform.position, val); float num4 = Mathf.Clamp01(1f - num3 / 180f); _visuals.TriggerLightningFlash(Mathf.Lerp(0.04f, 0.2f, stormStrength) * Mathf.Lerp(0.45f, 1f, num4), 0.12f); ScheduleThunder(val, direct: false); } } internal void RenderStrike(LightningStrikePayload strike) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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) if (strike != null) { SpawnBolt(strike.Position, strike.IsDirectHit ? 1f : 0.82f, strike.IsDirectHit, (int)(strike.Seed & 0x7FFFFFFF)); float num = (strike.IsDirectHit ? 0.3f : 0.16f); if ((Object)(object)Player.m_localPlayer != (Object)null) { float num2 = Vector3.Distance(((Component)Player.m_localPlayer).transform.position, strike.Position); num *= Mathf.Clamp01(1.15f - num2 / 160f); } _visuals.TriggerLightningFlash(Mathf.Clamp(num, 0.04f, 0.42f), strike.IsDirectHit ? 0.14f : 0.11f); ScheduleThunder(strike.Position, strike.IsDirectHit); } } internal void Dispose() { for (int num = _bolts.Count - 1; num >= 0; num--) { DestroyBolt(_bolts[num]); } _bolts.Clear(); if ((Object)(object)_boltCoreMaterial != (Object)null) { Object.Destroy((Object)(object)_boltCoreMaterial); _boltCoreMaterial = null; } if ((Object)(object)_boltGlowMaterial != (Object)null) { Object.Destroy((Object)(object)_boltGlowMaterial); _boltGlowMaterial = null; } _pendingThunder.Clear(); if ((Object)(object)_softBoltTexture != (Object)null) { Object.Destroy((Object)(object)_softBoltTexture); _softBoltTexture = null; } } private Vector3 PickAmbientPoint(Vector3 center) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) float num = Random.Range(0f, (float)Math.PI * 2f); float num2 = Random.Range(45f, 135f); Vector3 val = center + new Vector3(Mathf.Cos(num) * num2, 0f, Mathf.Sin(num) * num2); if (!TryFindGround(val, out var grounded)) { return val; } return grounded; } private void SpawnBolt(Vector3 impact, float strength, bool direct, int seed) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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_0107: 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_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) try { while (_bolts.Count >= 3) { DestroyBolt(_bolts[0]); _bolts.RemoveAt(0); } GameObject val = new GameObject("TheFloods_LightningBolt"); val.transform.position = impact; Random random = new Random((seed == 0) ? Environment.TickCount : seed); ActiveBolt activeBolt = new ActiveBolt { Root = val, CreatedAt = Time.unscaledTime, EndsAt = Time.unscaledTime + Mathf.Clamp(Mathf.Max(_config.BoltDurationSeconds.Value, 0.42f), 0.3f, 1.2f), Seed = (float)((seed == 0) ? Environment.TickCount : seed) * 0.001f, DirectHit = direct, Strength = Mathf.Clamp01(strength), GlowColour = SelectBoltGlowColour(random), CoreColour = Color.white, NextFlickerAt = Time.unscaledTime + 0.12f, FlickerCount = ((!direct) ? 1 : 2) }; Vector3 val2 = impact + Vector3.up * Lerp(random, 150f, 245f); List list = BuildJaggedChannel(val2, impact, direct ? 24 : 18, direct ? 11f : 16f, random); AddBoltSegment(val, activeBolt, list, strength, isMain: true, random); int num = (direct ? Random.Range(4, 7) : Random.Range(3, 5)); for (int i = 0; i < num; i++) { int index = Random.Range(list.Count / 3, list.Count - 2); Vector3 val3 = list[index]; Vector3 val4 = val3 + new Vector3(Lerp(random, -36f, 36f), Lerp(random, -58f, -10f), Lerp(random, -36f, 36f)); if (TryFindGround(val4, out var grounded)) { val4 = grounded + Vector3.up * 0.1f; } List points = BuildJaggedChannel(val3, val4, Random.Range(8, 14), 8f, random); AddBoltSegment(val, activeBolt, points, strength * 0.78f, isMain: false, random); } Light val5 = val.AddComponent(); val5.type = (LightType)2; val5.color = Color.Lerp(new Color(0.86f, 0.93f, 1f, 1f), activeBolt.GlowColour, 0.38f); val5.range = Mathf.Clamp(_config.BoltLightRange.Value, 12f, 90f) * Mathf.Lerp(0.7f, 1f, Mathf.Clamp01(strength)); val5.intensity = Mathf.Clamp(_config.BoltLightIntensity.Value, 0.5f, 12f) * Mathf.Lerp(0.8f, 1f, Mathf.Clamp01(strength)); activeBolt.Light = val5; _bolts.Add(activeBolt); } catch (Exception ex) { if (_config.DebugLogging.Value) { _logger.LogWarning((object)("[TheFloods] Lightning bolt render failed: " + ex.Message)); } } } private List BuildJaggedChannel(Vector3 from, Vector3 to, int segments, float jitterScale, Random random) { //IL_0013: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) List list = new List(segments); for (int i = 0; i < segments; i++) { float num = (float)i / (float)(segments - 1); Vector3 val = Vector3.Lerp(from, to, num); float num2 = Mathf.Sin(num * (float)Math.PI) * jitterScale; val += new Vector3(Lerp(random, 0f - num2, num2), Lerp(random, (0f - num2) * 0.3f, num2 * 0.3f), Lerp(random, 0f - num2, num2)); list.Add(val); } return list; } private void AddBoltSegment(GameObject root, ActiveBolt bolt, List points, float strength, bool isMain, Random random) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0162: 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) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(isMain ? "Glow" : "ForkGlow"); val.transform.SetParent(root.transform, true); LineRenderer val2 = val.AddComponent(); val2.useWorldSpace = true; val2.alignment = (LineAlignment)0; val2.textureMode = (LineTextureMode)0; val2.numCapVertices = 4; val2.numCornerVertices = 3; ((Renderer)val2).material = GetBoltGlowMaterial(); val2.startColor = WithAlpha(bolt.GlowColour, isMain ? 0.82f : 0.7f); val2.endColor = WithAlpha(Color.Lerp(bolt.GlowColour, new Color(0.3f, 0.18f, 0.78f, 1f), 0.22f), isMain ? 0.48f : 0.4f); val2.startWidth = Mathf.Lerp(0.8f, 1.75f, Mathf.Clamp01(strength)) * (isMain ? 1f : 0.78f); val2.endWidth = Mathf.Lerp(0.42f, 0.95f, Mathf.Clamp01(strength)) * (isMain ? 1f : 0.7f); val2.positionCount = points.Count; for (int i = 0; i < points.Count; i++) { val2.SetPosition(i, points[i]); } bolt.GlowLines.Add(val2); GameObject val3 = new GameObject(isMain ? "Core" : "ForkCore"); val3.transform.SetParent(root.transform, true); LineRenderer val4 = val3.AddComponent(); val4.useWorldSpace = true; val4.alignment = (LineAlignment)0; val4.textureMode = (LineTextureMode)0; val4.numCapVertices = 3; val4.numCornerVertices = 2; ((Renderer)val4).material = GetBoltCoreMaterial(); val4.startColor = WithAlpha(Color.Lerp(bolt.CoreColour, bolt.GlowColour, 0.18f), 1f); val4.endColor = WithAlpha(Color.Lerp(bolt.CoreColour, bolt.GlowColour, 0.3f), 0.94f); val4.startWidth = Mathf.Lerp(0.16f, 0.38f, Mathf.Clamp01(strength)) * (isMain ? 1f : 0.68f); val4.endWidth = Mathf.Lerp(0.08f, 0.2f, Mathf.Clamp01(strength)) * (isMain ? 1f : 0.64f); val4.positionCount = points.Count; for (int j = 0; j < points.Count; j++) { val4.SetPosition(j, points[j]); } bolt.CoreLines.Add(val4); } private void UpdateBolts() { //IL_00db: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01af: 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_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) for (int num = _bolts.Count - 1; num >= 0; num--) { ActiveBolt activeBolt = _bolts[num]; if (activeBolt == null || (Object)(object)activeBolt.Root == (Object)null || Time.unscaledTime >= activeBolt.EndsAt) { DestroyBolt(activeBolt); _bolts.RemoveAt(num); } else { float num2 = Mathf.Max(0.01f, activeBolt.EndsAt - activeBolt.CreatedAt); float num3 = Mathf.Clamp01((Time.unscaledTime - activeBolt.CreatedAt) / num2); bool flag = num3 < 0.76f || Mathf.Sin((Time.unscaledTime + activeBolt.Seed) * 24f) > -0.55f; float num4 = ((num3 < 0.68f) ? 1f : Mathf.Pow(Mathf.Clamp01((1f - num3) / 0.32f), 0.85f)); Color val = WithAlpha(activeBolt.GlowColour, 0.78f * num4); Color val2 = WithAlpha(Color.Lerp(activeBolt.CoreColour, activeBolt.GlowColour, 0.16f), num4); for (int i = 0; i < activeBolt.GlowLines.Count; i++) { LineRenderer val3 = activeBolt.GlowLines[i]; if (!((Object)(object)val3 == (Object)null)) { ((Renderer)val3).enabled = flag; val3.startColor = val; val3.endColor = WithAlpha(val, val.a * 0.66f); } } for (int j = 0; j < activeBolt.CoreLines.Count; j++) { LineRenderer val4 = activeBolt.CoreLines[j]; if (!((Object)(object)val4 == (Object)null)) { ((Renderer)val4).enabled = flag; val4.startColor = val2; val4.endColor = WithAlpha(val2, val2.a * 0.88f); } } if ((Object)(object)activeBolt.Light != (Object)null) { activeBolt.Light.intensity = (flag ? 1f : 0.35f) * Mathf.Clamp(_config.BoltLightIntensity.Value, 0.5f, 12f) * Mathf.Lerp(0.6f, 1f, activeBolt.Strength) * Mathf.Pow(num4, 1.45f); activeBolt.Light.color = Color.Lerp(new Color(0.86f, 0.93f, 1f), activeBolt.GlowColour, 0.4f); } } } } private static Color WithAlpha(Color colour, float alpha) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) colour.a = Mathf.Clamp01(alpha); return colour; } private static Color SelectBoltGlowColour(Random random) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) float num = (float)random.NextDouble(); if (num < 0.48f) { return new Color(0.36f, 0.7f, 1f, 1f); } if (num < 0.82f) { return new Color(0.62f, 0.42f, 1f, 1f); } return new Color(0.9f, 0.94f, 1f, 1f); } private void ScheduleThunder(Vector3 impact, bool direct) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //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) if (_config.EnableThunderAudio.Value && !((Object)(object)Player.m_localPlayer == (Object)null)) { float num = Vector3.Distance(((Component)Player.m_localPlayer).transform.position, impact); if (!(num > 600f)) { float num2 = Mathf.Max(120f, _config.SpeedOfSoundMetersPerSecond.Value); _pendingThunder.Add(new PendingThunder { Position = impact, PlayAt = Time.unscaledTime + num / num2, Distance = num, DirectHit = direct }); } } } private void UpdatePendingThunder() { if (_pendingThunder.Count == 0) { return; } for (int num = _pendingThunder.Count - 1; num >= 0; num--) { PendingThunder pendingThunder = _pendingThunder[num]; if (!(Time.unscaledTime < pendingThunder.PlayAt)) { _pendingThunder.RemoveAt(num); PlayThunder(pendingThunder); } } } private void PlayThunder(PendingThunder pending) { //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) try { Type type = AccessTools.TypeByName("ZNetScene"); object obj = ((type == null) ? null : (AccessTools.Field(type, "m_instance")?.GetValue(null) ?? AccessTools.Property(type, "instance")?.GetValue(null))); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "GetPrefab", new Type[1] { typeof(string) }, (Type[])null)); GameObject val = null; if (obj != null && methodInfo != null) { string[] array = new string[4] { "sfx_thunder", "fx_lightning", "sfx_lightning", "vfx_lightning" }; foreach (string text in array) { object? obj2 = methodInfo.Invoke(obj, new object[1] { text }); GameObject val2 = (GameObject)((obj2 is GameObject) ? obj2 : null); if ((Object)(object)val2 != (Object)null) { val = val2; break; } } } if (!((Object)(object)val != (Object)null)) { return; } GameObject val3 = Object.Instantiate(val, pending.Position, Quaternion.identity); AudioSource[] componentsInChildren = val3.GetComponentsInChildren(true); float num = Mathf.Clamp01(_config.ThunderVolume.Value) * Mathf.Clamp01(1.05f - pending.Distance / 600f); float pitch = (pending.DirectHit ? Random.Range(0.85f, 1.05f) : Random.Range(0.65f, 0.95f)); for (int j = 0; j < componentsInChildren.Length; j++) { if (!((Object)(object)componentsInChildren[j] == (Object)null)) { AudioSource obj3 = componentsInChildren[j]; obj3.volume *= num; componentsInChildren[j].pitch = pitch; componentsInChildren[j].spatialBlend = 1f; componentsInChildren[j].minDistance = 20f; componentsInChildren[j].maxDistance = 1200f; componentsInChildren[j].rolloffMode = (AudioRolloffMode)0; } } Object.Destroy((Object)(object)val3, 12f); } catch (Exception ex) { if (_config.DebugLogging.Value) { _logger.LogWarning((object)("[TheFloods] Thunder playback failed: " + ex.Message)); } } } private void DestroyBolt(ActiveBolt bolt) { if (bolt != null && (Object)(object)bolt.Root != (Object)null) { Object.Destroy((Object)(object)bolt.Root); } } private Material GetBoltCoreMaterial() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_boltCoreMaterial != (Object)null) { return _boltCoreMaterial; } Shader val = Shader.Find("Custom/LitParticles"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Particles/Standard Unlit"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Sprites/Default"); } _boltCoreMaterial = new Material(val); _boltCoreMaterial.mainTexture = (Texture)(object)GetSoftParticleTexture(); _boltCoreMaterial.color = new Color(1f, 1f, 1f, 1f); ConfigureBlend(_boltCoreMaterial); return _boltCoreMaterial; } private Material GetBoltGlowMaterial() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_boltGlowMaterial != (Object)null) { return _boltGlowMaterial; } Shader val = Shader.Find("Custom/LitParticles"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Particles/Standard Unlit"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Sprites/Default"); } _boltGlowMaterial = new Material(val); _boltGlowMaterial.mainTexture = (Texture)(object)GetSoftParticleTexture(); _boltGlowMaterial.color = new Color(0.6f, 0.78f, 1f, 0.6f); ConfigureBlend(_boltGlowMaterial); return _boltGlowMaterial; } private Texture2D GetSoftParticleTexture() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //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_00ab: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_softBoltTexture != (Object)null) { return _softBoltTexture; } _softBoltTexture = new Texture2D(64, 64, (TextureFormat)4, false); ((Texture)_softBoltTexture).wrapMode = (TextureWrapMode)1; ((Texture)_softBoltTexture).filterMode = (FilterMode)1; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(31.5f, 31.5f); float num = 30.72f; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num2 = Vector2.Distance(new Vector2((float)j, (float)i), val); float num3 = Mathf.Clamp01(1f - num2 / num); num3 = Mathf.SmoothStep(0f, 1f, num3); _softBoltTexture.SetPixel(j, i, new Color(1f, 1f, 1f, num3)); } } _softBoltTexture.Apply(false, true); return _softBoltTexture; } private static void ConfigureBlend(Material material) { if (!((Object)(object)material == (Object)null)) { TrySetInt(material, "_SrcMode", 5); TrySetInt(material, "_DstMode", 1); TrySetInt(material, "_ZWrite", 0); TrySetInt(material, "_Mode", 2); material.renderQueue = 3000; } } private static void TrySetInt(Material material, string property, int value) { try { if (material.HasProperty(property)) { material.SetInt(property, value); } } catch { } } private static bool TryFindGround(Vector3 candidate, out Vector3 grounded) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) grounded = candidate; try { RaycastHit val = default(RaycastHit); if (Physics.Raycast(new Vector3(candidate.x, candidate.y + 140f, candidate.z), Vector3.down, ref val, 300f, -1, (QueryTriggerInteraction)1)) { grounded = ((RaycastHit)(ref val)).point; return true; } } catch { } return false; } private static float Lerp(Random random, float min, float max) { return Mathf.Lerp(min, max, (float)random.NextDouble()); } } internal sealed class StormAudioManager { private sealed class Track { internal readonly string FileName; internal AudioSource Source; internal AudioClip Clip; internal UnityWebRequest Request; internal bool LoadStarted; internal bool ErrorLogged; internal float TargetVolume; internal Track(string fileName) { FileName = fileName; } } private readonly ManualLogSource _logger; private readonly FloodConfig _config; private readonly Track _indoor = new Track("stormoutside.mp3"); private readonly Track _loudWind = new Track("loudwind.mp3"); private readonly Track _forestWind = new Track("windthroughtrees.mp3"); private GameObject _root; internal StormAudioManager(ManualLogSource logger, FloodConfig config) { _logger = logger; _config = config; } internal void Update(FloodState state, float stormStrength, float wildfireIntensity, float strongWindIntensity, float surgeMeters, StormApproachVisual approach) { if (!_config.EnableCustomStormAudio.Value || (Object)(object)ZNet.instance == (Object)null || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated())) { FadeAllToZero(); return; } EnsureSources(); UpdateLoad(_indoor); UpdateLoad(_loudWind); UpdateLoad(_forestWind); bool flag = state != null && state.Phase != FloodPhase.Dormant && (stormStrength > 0.05f || strongWindIntensity > 0.05f || Mathf.Abs(surgeMeters) > 0.25f || state.EventType == FloodEventType.StrongWinds || state.EventType == FloodEventType.GreatFlood); bool num = flag && IsStrictSealedShelter(); float num2 = Mathf.Clamp01(_config.MasterStormAudioVolume.Value); if (num) { _indoor.TargetVolume = num2 * Mathf.Clamp01(_config.IndoorStormAudioVolume.Value); _forestWind.TargetVolume = 0f; _loudWind.TargetVolume = 0f; } else if (flag) { float num3 = ((approach != null && approach.Active) ? approach.WallStrength : 0f); float num4 = GetForestAudioFactor(); if (wildfireIntensity > 0.05f) { num4 = Mathf.Max(num4, 0.9f); } float num5 = Mathf.Clamp01(Mathf.Max(strongWindIntensity * 0.85f, Mathf.Max(stormStrength * 0.55f, num3 * 0.65f))); float num6 = Mathf.Clamp01(Mathf.Max(strongWindIntensity, Mathf.Max(stormStrength * 0.95f, Mathf.Abs(surgeMeters) / 6f))); _indoor.TargetVolume = 0f; _forestWind.TargetVolume = num2 * Mathf.Clamp01(_config.OutdoorWindAudioVolume.Value) * num5 * num4 * Mathf.Lerp(1f, 0.45f, num6); _loudWind.TargetVolume = num2 * Mathf.Clamp01(_config.OutdoorWindAudioVolume.Value) * Mathf.SmoothStep(0f, 1f, num6); } else { _indoor.TargetVolume = 0f; _forestWind.TargetVolume = 0f; _loudWind.TargetVolume = 0f; } ApplyFade(_indoor); ApplyFade(_forestWind); ApplyFade(_loudWind); } internal void Dispose() { DisposeTrack(_indoor); DisposeTrack(_loudWind); DisposeTrack(_forestWind); if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); _root = null; } } private void FadeAllToZero() { _indoor.TargetVolume = 0f; _forestWind.TargetVolume = 0f; _loudWind.TargetVolume = 0f; ApplyFade(_indoor); ApplyFade(_forestWind); ApplyFade(_loudWind); } private void EnsureSources() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown if (!((Object)(object)_root != (Object)null)) { _root = new GameObject("TheBrokenCycle_StormAudio"); Object.DontDestroyOnLoad((Object)(object)_root); CreateSource(_indoor); CreateSource(_loudWind); CreateSource(_forestWind); StartLoad(_indoor); StartLoad(_loudWind); StartLoad(_forestWind); } } private void CreateSource(Track track) { track.Source = _root.AddComponent(); track.Source.loop = true; track.Source.playOnAwake = false; track.Source.spatialBlend = 0f; track.Source.volume = 0f; } private void StartLoad(Track track) { if (track.LoadStarted) { return; } track.LoadStarted = true; string text = FindAudioPath(track.FileName); if (string.IsNullOrEmpty(text)) { LogAudio("[TheBrokenCycle] Missing storm audio file: " + track.FileName, track); return; } try { string absoluteUri = new Uri(text).AbsoluteUri; track.Request = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, (AudioType)13); track.Request.SendWebRequest(); } catch (Exception ex) { LogAudio("[TheBrokenCycle] Could not start audio load for " + track.FileName + ": " + ex.Message, track); } } private void UpdateLoad(Track track) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 if ((Object)(object)track.Clip != (Object)null || track.Request == null || !track.Request.isDone) { return; } try { if ((int)track.Request.result != 1) { LogAudio("[TheBrokenCycle] Could not load " + track.FileName + ": " + track.Request.error, track); return; } track.Clip = DownloadHandlerAudioClip.GetContent(track.Request); if ((Object)(object)track.Source != (Object)null && (Object)(object)track.Clip != (Object)null) { track.Source.clip = track.Clip; track.Source.Play(); } } catch (Exception ex) { LogAudio("[TheBrokenCycle] Audio load failed for " + track.FileName + ": " + ex.Message, track); } finally { track.Request.Dispose(); track.Request = null; } } private void ApplyFade(Track track) { if (track != null && !((Object)(object)track.Source == (Object)null)) { if ((Object)(object)track.Clip != (Object)null && !track.Source.isPlaying) { track.Source.Play(); } float num = Mathf.Max(0.1f, _config.AudioFadeDuration.Value); track.Source.volume = Mathf.MoveTowards(track.Source.volume, Mathf.Clamp01(track.TargetVolume), Time.deltaTime / num); } } private void DisposeTrack(Track track) { if (track != null && track.Request != null) { track.Request.Dispose(); track.Request = null; } } private string FindAudioPath(string fileName) { string empty = string.Empty; try { empty = Path.GetDirectoryName(typeof(TheFloodsPlugin).Assembly.Location) ?? string.Empty; } catch { empty = string.Empty; } string[] array = new string[4] { Path.Combine(Paths.PluginPath, "TheBrokenCycle", "Audio", fileName), Path.Combine(Paths.PluginPath, "TheFloods", "Audio", fileName), Path.Combine(empty, "Audio", fileName), Path.Combine(empty, "TheBrokenCycle", "Audio", fileName) }; for (int i = 0; i < array.Length; i++) { if (!string.IsNullOrEmpty(array[i]) && File.Exists(array[i])) { return array[i]; } } return string.Empty; } private bool IsStrictSealedShelter() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } try { if (!localPlayer.InShelter()) { return false; } } catch { return false; } Vector3 position = ((Component)localPlayer).transform.position; if (!HasRoof(position)) { return false; } Collider[] array = Physics.OverlapSphere(position, 5.5f, -1, (QueryTriggerInteraction)2); int num = 0; bool flag = false; foreach (Collider val in array) { if (!((Object)(object)val == (Object)null)) { GameObject gameObject = ((Component)val).gameObject; string objectName = GetObjectName(gameObject); if (IsWallOrRoofName(objectName) || HasComponentNamed(gameObject, "Piece") || HasComponentNamed(gameObject, "WearNTear")) { num++; } if (IsDoorName(objectName) && IsClosedDoor(gameObject)) { flag = true; } } } return num >= 4 && flag; } private bool HasRoof(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) RaycastHit[] array = Physics.RaycastAll(position + Vector3.up * 0.35f, Vector3.up, 9f, -1, (QueryTriggerInteraction)2); for (int i = 0; i < array.Length; i++) { Collider collider = ((RaycastHit)(ref array[i])).collider; if (!((Object)(object)collider == (Object)null)) { string objectName = GetObjectName(((Component)collider).gameObject); if (objectName.Contains("roof") || objectName.Contains("thatch") || objectName.Contains("wood") || HasComponentNamed(((Component)collider).gameObject, "Piece")) { return true; } } } return false; } private bool IsClosedDoor(GameObject go) { Component componentNamedInParents = GetComponentNamedInParents(go, "Door"); if ((Object)(object)componentNamedInParents == (Object)null) { return false; } try { MethodInfo methodInfo = AccessTools.Method(((object)componentNamedInParents).GetType(), "IsOpen", Type.EmptyTypes, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(componentNamedInParents, null); return obj is bool && !(bool)obj; } FieldInfo fieldInfo = AccessTools.Field(((object)componentNamedInParents).GetType(), "m_open"); if (fieldInfo != null) { object value = fieldInfo.GetValue(componentNamedInParents); return value is bool && !(bool)value; } } catch { return false; } return false; } private float GetForestAudioFactor() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return 0.65f; } try { MethodInfo methodInfo = AccessTools.Method(typeof(Heightmap), "FindBiome", new Type[1] { typeof(Vector3) }, (Type[])null); object obj = ((methodInfo == null) ? null : methodInfo.Invoke(null, new object[1] { ((Component)localPlayer).transform.position })); string text = ((obj == null) ? string.Empty : obj.ToString().ToLowerInvariant()); if (text.Contains("blackforest") || text.Contains("meadows") || text.Contains("swamp") || text.Contains("mistlands")) { return 1f; } if (text.Contains("mountain") || text.Contains("plains")) { return 0.72f; } } catch { } return 0.65f; } private void LogAudio(string message, Track track) { if (_config.DebugAudioLogging.Value && track != null && !track.ErrorLogged) { track.ErrorLogged = true; _logger.LogWarning((object)message); } } private static bool HasComponentNamed(GameObject go, string typeName) { return (Object)(object)GetComponentNamedInParents(go, typeName) != (Object)null; } private static Component GetComponentNamedInParents(GameObject go, string typeName) { Transform val = (((Object)(object)go == (Object)null) ? null : go.transform); int num = 0; while (num < 6 && (Object)(object)val != (Object)null) { Component[] components = ((Component)val).GetComponents(); foreach (Component val2 in components) { if ((Object)(object)val2 != (Object)null && ((object)val2).GetType().Name.Equals(typeName, StringComparison.OrdinalIgnoreCase)) { return val2; } } num++; val = val.parent; } return null; } private static string GetObjectName(GameObject go) { if ((Object)(object)go == (Object)null) { return string.Empty; } string text = ((Object)go).name.ToLowerInvariant(); Transform parent = go.transform.parent; if ((Object)(object)parent != (Object)null) { text = text + " " + ((Object)parent).name.ToLowerInvariant(); } return text; } private static bool IsWallOrRoofName(string name) { if (!name.Contains("wall") && !name.Contains("roof") && !name.Contains("door") && !name.Contains("gate") && !name.Contains("beam")) { return name.Contains("floor"); } return true; } private static bool IsDoorName(string name) { if (!name.Contains("door")) { return name.Contains("gate"); } return true; } } internal sealed class StrongWindsSystem { private readonly ManualLogSource _logger; private readonly FloodConfig _config; private readonly List _treeCandidates = new List(); private readonly HashSet _candidateIds = new HashSet(); private readonly Dictionary _zoneCooldowns = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _fallsByPlayer = new Dictionary(); private GameObject _debrisRoot; private ParticleSystem _debris; private Material _debrisMaterial; private Texture2D _debrisTexture; private float _nextCandidateRefreshAt; private float _nextTreefallAt; private int _globalTreefalls; internal string TreefallStatus => _globalTreefalls.ToString(CultureInfo.InvariantCulture) + "/" + Mathf.Max(0, _config.MaxTreefallsGlobally.Value).ToString(CultureInfo.InvariantCulture) + " candidates=" + _treeCandidates.Count.ToString(CultureInfo.InvariantCulture); internal StrongWindsSystem(ManualLogSource logger, FloodConfig config) { _logger = logger; _config = config; } internal void Update(FloodState state, double now, float intensity, Vector3 wind, bool authoritative, List players) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) bool flag = intensity > 0.04f && state != null && state.Phase != FloodPhase.Dormant; UpdateDebris(flag ? intensity : 0f, wind); if (flag && authoritative && _config.EnableTreefall.Value && players != null && players.Count != 0 && !(intensity < 0.55f) && !(Time.unscaledTime < _nextTreefallAt)) { _nextTreefallAt = Time.unscaledTime + Random.Range(10f, 15f); RefreshTreeCandidates(players); if (_globalTreefalls < Mathf.Max(0, _config.MaxTreefallsGlobally.Value) && !(Random.value > Mathf.Clamp01(_config.TreefallChance.Value) * Mathf.Clamp01(intensity))) { TryCauseTreefall(players, wind, ignoreBaseProtection: false, intensity); } } } internal string TryDebugTreefall(List players, Vector3 wind, bool ignoreBaseProtection) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (players == null || players.Count == 0) { return "Strong Winds: no active players near loaded trees."; } RefreshTreeCandidates(players, force: true); if (!TryCauseTreefall(players, wind, ignoreBaseProtection, 1f)) { return "Strong Winds: no valid nearby tree passed safety checks."; } return "Strong Winds: test treefall triggered using native tree damage."; } internal void ResetRuntime() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) _treeCandidates.Clear(); _candidateIds.Clear(); _zoneCooldowns.Clear(); _fallsByPlayer.Clear(); _globalTreefalls = 0; _nextCandidateRefreshAt = 0f; _nextTreefallAt = 0f; UpdateDebris(0f, Vector3.forward); } internal void Dispose() { ResetRuntime(); if ((Object)(object)_debrisRoot != (Object)null) { Object.Destroy((Object)(object)_debrisRoot); _debrisRoot = null; } if ((Object)(object)_debrisMaterial != (Object)null) { Object.Destroy((Object)(object)_debrisMaterial); _debrisMaterial = null; } if ((Object)(object)_debrisTexture != (Object)null) { Object.Destroy((Object)(object)_debrisTexture); _debrisTexture = null; } } private void RefreshTreeCandidates(List players, bool force = false) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (!force && Time.unscaledTime < _nextCandidateRefreshAt) { return; } _nextCandidateRefreshAt = Time.unscaledTime + 6f; _treeCandidates.Clear(); _candidateIds.Clear(); float num = Mathf.Clamp(_config.TreefallDistanceFromPlayer.Value, 12f, 120f); for (int i = 0; i < players.Count; i++) { Player val = players[i]; if ((Object)(object)val == (Object)null) { continue; } Collider[] array = Physics.OverlapSphere(((Component)val).transform.position, num, -1, (QueryTriggerInteraction)1); for (int j = 0; j < array.Length; j++) { GameObject val2 = FindTreeRoot(((Object)(object)array[j] == (Object)null) ? null : ((Component)array[j]).gameObject); if (!((Object)(object)val2 == (Object)null)) { int instanceID = ((Object)val2).GetInstanceID(); if (_candidateIds.Add(instanceID)) { _treeCandidates.Add(val2); } } } } } private bool TryCauseTreefall(List players, Vector3 wind, bool ignoreBaseProtection, float intensity) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_010f: Unknown result type (might be due to invalid IL or missing references) GameObject val = PickTreeCandidate(players, wind, ignoreBaseProtection); if ((Object)(object)val == (Object)null) { return false; } long playerKey = GetPlayerKey(FindNearestPlayer(players, val.transform.position)); _fallsByPlayer.TryGetValue(playerKey, out var value); if (value >= Mathf.Max(0, _config.MaxTreefallsPerPlayer.Value)) { return false; } string zoneKey = GetZoneKey(val.transform.position); _zoneCooldowns[zoneKey] = Time.unscaledTime + Mathf.Max(10f, _config.TreefallCooldownPerZoneSeconds.Value); if (!DamageTree(val, wind, intensity)) { return false; } _globalTreefalls++; _fallsByPlayer[playerKey] = value + 1; if (_config.StrongWindsDebugMode.Value || _config.DebugLogging.Value) { _logger.LogInfo((object)("[TheBrokenCycle] Strong Winds toppled tree candidate '" + ((Object)val).name + "' at " + FormatVector(val.transform.position) + ".")); } return true; } private GameObject PickTreeCandidate(List players, Vector3 wind, bool ignoreBaseProtection) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) GameObject result = null; float num = float.MinValue; for (int i = 0; i < _treeCandidates.Count; i++) { GameObject val = _treeCandidates[i]; if (IsValidTreeCandidate(val, players, ignoreBaseProtection)) { Player val2 = FindNearestPlayer(players, val.transform.position); Vector3 val3 = (((Object)(object)val2 == (Object)null) ? wind : (val.transform.position - ((Component)val2).transform.position)); val3.y = 0f; float num2 = ((((Vector3)(ref val3)).sqrMagnitude < 0.001f) ? 0f : Mathf.Clamp01((Vector3.Dot(((Vector3)(ref val3)).normalized, ((Vector3)(ref wind)).normalized) + 1f) * 0.5f)) + Random.Range(0f, 0.35f); if (num2 > num) { num = num2; result = val; } } } return result; } private bool IsValidTreeCandidate(GameObject tree, List players, bool ignoreBaseProtection) { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)tree == (Object)null || !tree.activeInHierarchy) { return false; } string text = ((Object)tree).name.ToLowerInvariant(); if (text.Contains("log") || text.Contains("stump") || text.Contains("stub") || text.Contains("sapling") || text.Contains("small")) { return false; } if (!HasComponentNamed(tree, "TreeBase") && !HasComponentNamed(tree, "Destructible")) { return false; } Vector2 val3 = default(Vector2); for (int i = 0; i < players.Count; i++) { Player val = players[i]; if (!((Object)(object)val == (Object)null)) { Vector3 val2 = tree.transform.position - ((Component)val).transform.position; ((Vector2)(ref val3))..ctor(val2.x, val2.z); if (((Vector2)(ref val3)).sqrMagnitude < 36f && val2.y > 2f) { return false; } } } string zoneKey = GetZoneKey(tree.transform.position); if (_zoneCooldowns.TryGetValue(zoneKey, out var value) && Time.unscaledTime < value) { return false; } if (!ignoreBaseProtection && !_config.StrongWindStructureDamage.Value && IsProtectedBaseNearby(tree.transform.position)) { return false; } return true; } private bool DamageTree(GameObject tree, Vector3 wind, float intensity) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0067: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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_00fd: Unknown result type (might be due to invalid IL or missing references) Component damageComponent = GetDamageComponent(tree); if ((Object)(object)damageComponent == (Object)null) { return false; } MethodInfo methodInfo = AccessTools.Method(((object)damageComponent).GetType(), "Damage", new Type[1] { typeof(HitData) }, (Type[])null); if (methodInfo == null) { return false; } try { Vector3 val = ((((Vector3)(ref wind)).sqrMagnitude < 0.001f) ? Vector3.forward : ((Vector3)(ref wind)).normalized); HitData val2 = new HitData(); val2.m_point = tree.transform.position + Vector3.up * 2.5f; Vector3 val3 = val + Vector3.down * 0.18f; val2.m_dir = ((Vector3)(ref val3)).normalized; val2.m_pushForce = Mathf.Lerp(18f, 42f, Mathf.Clamp01(intensity)); val2.m_damage.m_chop = Mathf.Lerp(220f, 620f, Mathf.Clamp01(intensity)); val2.m_damage.m_blunt = 10f; val2.m_hitType = (HitType)0; methodInfo.Invoke(damageComponent, new object[1] { val2 }); return true; } catch (Exception ex) { if (_config.StrongWindsDebugMode.Value || _config.DebugLogging.Value) { _logger.LogWarning((object)("[TheBrokenCycle] Treefall damage failed: " + ex.Message)); } return false; } } private Component GetDamageComponent(GameObject tree) { string[] array = new string[3] { "TreeBase", "Destructible", "WearNTear" }; for (int i = 0; i < array.Length; i++) { Component componentNamed = GetComponentNamed(tree, array[i]); if ((Object)(object)componentNamed != (Object)null && AccessTools.Method(((object)componentNamed).GetType(), "Damage", new Type[1] { typeof(HitData) }, (Type[])null) != null) { return componentNamed; } } return null; } private bool IsProtectedBaseNearby(Vector3 position) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp(_config.ProtectedBaseRadius.Value, 4f, 80f); Collider[] array = Physics.OverlapSphere(position, num, -1, (QueryTriggerInteraction)2); for (int i = 0; i < array.Length; i++) { GameObject val = (((Object)(object)array[i] == (Object)null) ? null : ((Component)array[i]).gameObject); if (!((Object)(object)val == (Object)null)) { string text = ((Object)val).name.ToLowerInvariant(); if (text.Contains("bed") || text.Contains("portal") || text.Contains("workbench") || text.Contains("ward") || text.Contains("piece") || HasComponentNamed(val, "Piece") || HasComponentNamed(val, "WearNTear")) { return true; } } } return false; } private void UpdateDebris(float intensity, Vector3 wind) { //IL_00ae: 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_00dd: 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) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) { return; } if ((Object)(object)_debrisRoot == (Object)null) { CreateDebris(); } if (!((Object)(object)_debris == (Object)null)) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { Vector3 val = ((((Vector3)(ref wind)).sqrMagnitude < 0.001f) ? Vector3.forward : ((Vector3)(ref wind)).normalized); _debrisRoot.transform.position = ((Component)localPlayer).transform.position + Vector3.up * 2f - val * 18f; } EmissionModule emission = _debris.emission; ((EmissionModule)(ref emission)).rateOverTime = new MinMaxCurve(Mathf.Clamp01(intensity) * Mathf.Max(0f, _config.WindDebrisAmount.Value) * 65f); VelocityOverLifetimeModule velocityOverLifetime = _debris.velocityOverLifetime; if (((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled) { Vector3 val2 = ((((Vector3)(ref wind)).sqrMagnitude < 0.001f) ? Vector3.forward : ((Vector3)(ref wind)).normalized); float num = Mathf.Lerp(5f, 15f, Mathf.Clamp01(intensity)); ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).x = new MinMaxCurve(val2.x * num * 0.65f, val2.x * num); ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).z = new MinMaxCurve(val2.z * num * 0.65f, val2.z * num); } } } private void CreateDebris() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00da: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) _debrisRoot = new GameObject("TheBrokenCycle_WindDebris"); Object.DontDestroyOnLoad((Object)(object)_debrisRoot); _debris = _debrisRoot.AddComponent(); MainModule main = _debris.main; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(1.2f, 2.8f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.2f, 1f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.035f, 0.12f); ((MainModule)(ref main)).startColor = new MinMaxGradient(new Color(0.3f, 0.27f, 0.2f, 0.22f), new Color(0.72f, 0.7f, 0.62f, 0.18f)); ((MainModule)(ref main)).maxParticles = 180; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ShapeModule shape = _debris.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0; ((ShapeModule)(ref shape)).radius = 18f; EmissionModule emission = _debris.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f); VelocityOverLifetimeModule velocityOverLifetime = _debris.velocityOverLifetime; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)1; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).y = new MinMaxCurve(-0.35f, 1.1f); ParticleSystemRenderer component = ((Component)_debris).GetComponent(); if ((Object)(object)component != (Object)null) { ((Renderer)component).material = GetDebrisMaterial(); component.renderMode = (ParticleSystemRenderMode)0; } } private Material GetDebrisMaterial() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_debrisMaterial != (Object)null) { return _debrisMaterial; } Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Particles/Standard Unlit"); } _debrisMaterial = new Material(val); _debrisMaterial.mainTexture = (Texture)(object)GetDebrisTexture(); _debrisMaterial.color = new Color(0.7f, 0.66f, 0.52f, 0.35f); return _debrisMaterial; } private Texture2D GetDebrisTexture() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_debrisTexture != (Object)null) { return _debrisTexture; } _debrisTexture = new Texture2D(8, 8, (TextureFormat)4, false); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { float num = ((j > 1 && j < 6 && i > 1 && i < 6) ? 0.85f : 0f); _debrisTexture.SetPixel(j, i, new Color(1f, 1f, 1f, num)); } } _debrisTexture.Apply(false, true); return _debrisTexture; } private static GameObject FindTreeRoot(GameObject go) { Transform val = (((Object)(object)go == (Object)null) ? null : go.transform); int num = 0; while (num < 7 && (Object)(object)val != (Object)null) { GameObject gameObject = ((Component)val).gameObject; string text = ((Object)gameObject).name.ToLowerInvariant(); if ((text.Contains("tree") || text.Contains("beech") || text.Contains("fir") || text.Contains("pine") || text.Contains("birch") || text.Contains("oak")) && (HasComponentNamed(gameObject, "TreeBase") || HasComponentNamed(gameObject, "Destructible"))) { return gameObject; } num++; val = val.parent; } return null; } private static Component GetComponentNamed(GameObject go, string typeName) { if ((Object)(object)go == (Object)null) { return null; } Component[] componentsInChildren = go.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val != (Object)null && ((object)val).GetType().Name.Equals(typeName, StringComparison.OrdinalIgnoreCase)) { return val; } } return null; } private static bool HasComponentNamed(GameObject go, string typeName) { return (Object)(object)GetComponentNamed(go, typeName) != (Object)null; } private static Player FindNearestPlayer(List players, Vector3 position) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) Player result = null; float num = float.MaxValue; for (int i = 0; i < players.Count; i++) { Player val = players[i]; if (!((Object)(object)val == (Object)null)) { Vector3 val2 = ((Component)val).transform.position - position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = val; } } } return result; } private static long GetPlayerKey(Player player) { if ((Object)(object)player == (Object)null) { return 0L; } try { MethodInfo methodInfo = AccessTools.Method(((object)player).GetType(), "GetPlayerID", Type.EmptyTypes, (Type[])null); object obj = ((methodInfo == null) ? null : methodInfo.Invoke(player, null)); if (obj != null) { return Convert.ToInt64(obj, CultureInfo.InvariantCulture); } } catch { } return ((Object)player).GetInstanceID(); } private static string GetZoneKey(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.FloorToInt(position.x / 64f); int num2 = Mathf.FloorToInt(position.z / 64f); return num.ToString(CultureInfo.InvariantCulture) + ":" + num2.ToString(CultureInfo.InvariantCulture); } private static string FormatVector(Vector3 value) { return "(" + value.x.ToString("0.0", CultureInfo.InvariantCulture) + "," + value.y.ToString("0.0", CultureInfo.InvariantCulture) + "," + value.z.ToString("0.0", CultureInfo.InvariantCulture) + ")"; } } internal sealed class WildfireSystem { private sealed class FireNode { internal Vector3 Position; internal float Radius; internal float TargetRadius; internal float RemainingSeconds; internal float NextSpreadAt; internal float CreatedAt; internal GameObject Root; internal Light Light; internal ParticleSystem Particles; internal ParticleSystem SmokeParticles; internal ParticleSystem HeatHazeParticles; internal bool UsesVanillaVfx; internal GameObject EmberBed; internal Material EmberBedMaterial; internal float FlickerSeed; } private sealed class ScorchMark { internal GameObject Root; internal float EndsAt; } private readonly ManualLogSource _logger; private readonly FloodConfig _config; private readonly List _nodes = new List(); private readonly List _scorchMarks = new List(); private Material _fireMaterial; private Material _smokeMaterial; private Material _heatHazeMaterial; private Material _scorchMaterial; private Material _emberBedMaterialShared; private Texture2D _softParticleTexture; private Texture2D _flameTexture; private static GameObject _cachedVanillaFireVfx; private static bool _vanillaFireSearched; private long _seededEvent; private float _nextPlayerDamageAt; internal int ActiveNodeCount => _nodes.Count; internal WildfireSystem(ManualLogSource logger, FloodConfig config) { _logger = logger; _config = config; } internal void Ignite(Vector3 point, double now, long seed) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) _seededEvent = seed; SeedInitialFireFront(point, seed, null); } internal void Update(FloodState state, double now, float intensity, bool rainWet, bool localPlayerWet, FloodWaterAdapter water, Func canSpread, Func windProvider) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_00e6: 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_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) UpdateScorchMarks(); if (state != null && state.EventType == FloodEventType.Wildfire && state.Phase != FloodPhase.Dormant && _seededEvent != state.EventSeed) { _seededEvent = state.EventSeed; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(state.WildfireOriginX, state.WildfireOriginY, state.WildfireOriginZ); if (val != Vector3.zero) { SeedInitialFireFront(val, state.EventSeed, windProvider); } } if (_nodes.Count == 0) { return; } bool flag = state != null && state.EventType == FloodEventType.Wildfire && state.Phase != FloodPhase.Dormant; bool flag2 = flag && (state.Phase == FloodPhase.Rising || state.Phase == FloodPhase.Peak); bool flag3 = rainWet || (flag && state.Phase == FloodPhase.Receding) || (flag && intensity < 0.08f); float num = Mathf.Max(0.001f, Time.deltaTime); Vector3 wind = windProvider?.Invoke() ?? Vector3.forward; wind.y = 0f; if (((Vector3)(ref wind)).sqrMagnitude < 0.001f) { wind = Vector3.forward; } ((Vector3)(ref wind)).Normalize(); for (int num2 = _nodes.Count - 1; num2 >= 0; num2--) { FireNode fireNode = _nodes[num2]; if (fireNode == null) { _nodes.RemoveAt(num2); } else { bool flag4 = water?.IsPointUnderKnownWater(fireNode.Position) ?? false; float num3 = ((flag3 || flag4) ? (num * 5.5f) : num); fireNode.RemainingSeconds -= num3; fireNode.Radius = Mathf.MoveTowards(fireNode.Radius, fireNode.TargetRadius, num * Mathf.Max(0.4f, fireNode.TargetRadius * 0.55f)); UpdateVisual(fireNode, intensity, flag3 || flag4, wind); if (fireNode.RemainingSeconds <= 0f) { BurnOutNode(fireNode); _nodes.RemoveAt(num2); } else if (flag2 && _nodes.Count < GetEffectiveMaxNodes() && Time.unscaledTime >= fireNode.NextSpreadAt) { fireNode.NextSpreadAt = Time.unscaledTime + Mathf.Max(1f, _config.SpreadIntervalSeconds.Value); int num4 = ((_nodes.Count < 36) ? 3 : ((_nodes.Count >= 76) ? 1 : 2)); for (int i = 0; i < num4; i++) { if (_nodes.Count >= GetEffectiveMaxNodes()) { break; } TrySpread(fireNode, canSpread, windProvider); } } } } UpdateFireLightBudget(); ApplyPlayerDamage(localPlayerWet, water); } internal void ExtinguishAll() { for (int num = _nodes.Count - 1; num >= 0; num--) { DestroyNode(_nodes[num]); } _nodes.Clear(); _seededEvent = 0L; } internal void Dispose() { ExtinguishAll(); for (int num = _scorchMarks.Count - 1; num >= 0; num--) { DestroyScorch(_scorchMarks[num]); } _scorchMarks.Clear(); if ((Object)(object)_fireMaterial != (Object)null) { Object.Destroy((Object)(object)_fireMaterial); _fireMaterial = null; } if ((Object)(object)_smokeMaterial != (Object)null) { Object.Destroy((Object)(object)_smokeMaterial); _smokeMaterial = null; } if ((Object)(object)_heatHazeMaterial != (Object)null) { Object.Destroy((Object)(object)_heatHazeMaterial); _heatHazeMaterial = null; } if ((Object)(object)_scorchMaterial != (Object)null) { Object.Destroy((Object)(object)_scorchMaterial); _scorchMaterial = null; } if ((Object)(object)_emberBedMaterialShared != (Object)null) { Object.Destroy((Object)(object)_emberBedMaterialShared); _emberBedMaterialShared = null; } if ((Object)(object)_flameTexture != (Object)null) { Object.Destroy((Object)(object)_flameTexture); _flameTexture = null; } if ((Object)(object)_softParticleTexture != (Object)null) { Object.Destroy((Object)(object)_softParticleTexture); _softParticleTexture = null; } } private void SeedInitialFireFront(Vector3 origin, long seed, Func windProvider) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: 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_0145: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) if (_nodes.Count >= GetEffectiveMaxNodes()) { return; } Vector3 val = windProvider?.Invoke() ?? Vector3.forward; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = Vector3.forward; } ((Vector3)(ref val)).Normalize(); Vector3 val2 = Vector3.Cross(Vector3.up, val); Vector3 normalized = ((Vector3)(ref val2)).normalized; float num = Mathf.Clamp(Mathf.Max(2.75f, _config.SpreadStepMeters.Value), 2.75f, 5f); Random random = new Random((int)((seed == 0L) ? Environment.TickCount : (seed & 0x7FFFFFFF))); for (int i = 0; i < 2; i++) { if (_nodes.Count >= GetEffectiveMaxNodes()) { break; } int num2 = ((i == 0) ? 5 : 4); for (int j = -num2; j <= num2; j++) { if (_nodes.Count >= GetEffectiveMaxNodes()) { break; } float num3 = Mathf.Lerp((0f - num) * 0.22f, num * 0.22f, (float)random.NextDouble()); float num4 = ((i == 0) ? Mathf.Lerp((0f - num) * 0.16f, num * 0.2f, (float)random.NextDouble()) : ((0f - num) * 0.85f + Mathf.Lerp((0f - num) * 0.22f, num * 0.12f, (float)random.NextDouble()))); Vector3 val3 = origin + normalized * ((float)j * num + num3) + val * num4; if (TryFindGround(val3, out var grounded)) { val3 = grounded; } AddNode(val3, Mathf.Max(0.1f, _config.NodeLifeSeconds.Value) * Random.Range(0.85f, 1.15f), seed + (long)j * 31L + (long)i * 997L); } } } private void TrySpread(FireNode parent, Func canSpread, Func windProvider) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0190: 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_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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: 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) if (!(Random.value > Mathf.Clamp01(_config.SpreadChance.Value))) { Vector3 val = windProvider?.Invoke() ?? Vector3.forward; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { val = Random.insideUnitSphere; val.y = 0f; } val = ((((Vector3)(ref val)).sqrMagnitude < 0.001f) ? Vector3.forward : ((Vector3)(ref val)).normalized); float num = Mathf.Clamp01(_config.DownwindBias.Value); float num2 = Mathf.Lerp(105f, 38f, num); float num3 = Random.Range(0f - num2, num2); Vector3 val2 = Quaternion.Euler(0f, num3, 0f) * val; Vector3 val4; if (Random.value > num) { Vector3 val3 = Quaternion.Euler(0f, (Random.value < 0.5f) ? (-82f) : 82f, 0f) * val; val4 = Vector3.Slerp(val2, val3, Random.Range(0.2f, 0.55f)); val2 = ((Vector3)(ref val4)).normalized; } if (Vector3.Dot(val2, val) < -0.05f) { val4 = Vector3.Slerp(val2, val, 0.75f); val2 = ((Vector3)(ref val4)).normalized; } float num4 = Mathf.Max(1.5f, _config.SpreadStepMeters.Value); Vector3 val5 = parent.Position + val2 * Random.Range(num4 * 0.75f, num4 * 1.15f); if (!TryFindGround(val5, out var grounded)) { grounded = val5; } if (canSpread == null || canSpread(grounded)) { AddNode(grounded, Mathf.Max(0.1f, _config.NodeLifeSeconds.Value) * Random.Range(0.72f, 1.18f), Environment.TickCount); } } } private void ApplyPlayerDamage(bool wet, FloodWaterAdapter water) { //IL_002e: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null || Time.unscaledTime < _nextPlayerDamageAt) { return; } Player localPlayer = Player.m_localPlayer; if (wet || (water != null && water.IsPointUnderKnownWater(((Component)localPlayer).transform.position))) { return; } for (int i = 0; i < _nodes.Count; i++) { FireNode fireNode = _nodes[i]; if (fireNode != null) { Vector3 val = ((Component)localPlayer).transform.position - fireNode.Position; if (((Vector3)(ref val)).sqrMagnitude <= fireNode.Radius * fireNode.Radius) { _nextPlayerDamageAt = Time.unscaledTime + Mathf.Max(0.25f, _config.FireDamageIntervalSeconds.Value); HitData val2 = new HitData(); val2.m_damage.m_fire = Mathf.Max(0f, _config.PlayerFireDamagePerTick.Value); val2.m_point = ((Component)localPlayer).transform.position; val = ((Component)localPlayer).transform.position - fireNode.Position; val2.m_dir = ((Vector3)(ref val)).normalized; val2.m_pushForce = 0f; val2.m_hitType = (HitType)0; ((Character)localPlayer).Damage(val2); break; } } } } private void AddNode(Vector3 point, float lifeSeconds, long seed) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (_nodes.Count >= GetEffectiveMaxNodes()) { return; } if (TryFindGround(point, out var grounded)) { point = grounded; } float effectiveNodeRadius = GetEffectiveNodeRadius(); float num = Mathf.Max(1.4f, effectiveNodeRadius * 0.48f); for (int i = 0; i < _nodes.Count; i++) { FireNode fireNode = _nodes[i]; if (fireNode != null) { Vector3 val = fireNode.Position - point; if (((Vector3)(ref val)).sqrMagnitude < num * num) { return; } } } FireNode fireNode2 = new FireNode { Position = point, Radius = Mathf.Max(0.35f, effectiveNodeRadius * 0.32f), TargetRadius = effectiveNodeRadius, RemainingSeconds = lifeSeconds, CreatedAt = Time.unscaledTime, NextSpreadAt = Time.unscaledTime + Random.Range(1f, Mathf.Max(1f, _config.SpreadIntervalSeconds.Value)), FlickerSeed = Random.Range(0f, 100f) }; CreateNodeVisual(fireNode2, seed); _nodes.Add(fireNode2); } private void CreateNodeVisual(FireNode node, long seed) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: 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_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Expected O, but got Unknown //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_034b: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0387: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_040f: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_0440: Unknown result type (might be due to invalid IL or missing references) //IL_0445: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Expected O, but got Unknown //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0518: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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_0147: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = new GameObject("TheFloods_WildfireNode"); val.transform.position = node.Position; GameObject val2 = null; if ((Object)(object)val2 != (Object)null) { try { float num = Mathf.Max(0.6f, node.TargetRadius * 0.55f); Vector3[] array = (Vector3[])(object)new Vector3[3] { Vector3.zero, new Vector3(num, 0f, 0f), new Vector3((0f - num) * 0.5f, 0f, num * 0.866f) }; for (int i = 0; i < array.Length; i++) { GameObject obj = Object.Instantiate(val2, val.transform); obj.transform.localPosition = array[i]; obj.transform.localRotation = Quaternion.identity; obj.transform.localScale = Vector3.one * Mathf.Lerp(1.4f, 2.2f, Random.value); StripNetworkingComponents(obj); } node.Root = val; node.UsesVanillaVfx = true; CreateEmberBed(val, node); ParticleSystem smokeParticles = CreateSmokeSystem(val, node); Light val3 = val.AddComponent(); val3.type = (LightType)2; val3.color = new Color(1f, 0.42f, 0.12f, 1f); val3.range = Mathf.Max(4f, node.TargetRadius * 2.2f); val3.intensity = 1.1f; node.Light = val3; node.SmokeParticles = smokeParticles; return; } catch (Exception ex) { if (_config.DebugLogging.Value) { _logger.LogWarning((object)("[TheFloods] Vanilla fire VFX failed, falling back: " + ex.Message)); } } } ParticleSystem val4 = val.AddComponent(); MainModule main = val4.main; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.55f, 1.15f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(1.05f, 2.45f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.75f, 1.65f); ((MainModule)(ref main)).startColor = new MinMaxGradient(new Color(1f, 0.2f, 0.035f, 0.96f), new Color(1f, 0.82f, 0.24f, 0.88f)); ((MainModule)(ref main)).maxParticles = 240; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; EmissionModule emission = val4.emission; ((EmissionModule)(ref emission)).rateOverTime = new MinMaxCurve(125f, 185f); ShapeModule shape = val4.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4; ((ShapeModule)(ref shape)).radius = Mathf.Max(0.8f, GetEffectiveNodeRadius() * 0.95f); ((ShapeModule)(ref shape)).angle = 9f; ColorOverLifetimeModule colorOverLifetime = val4.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val5 = new Gradient(); val5.SetKeys((GradientColorKey[])(object)new GradientColorKey[4] { new GradientColorKey(new Color(1f, 0.95f, 0.7f), 0f), new GradientColorKey(new Color(1f, 0.55f, 0.15f), 0.4f), new GradientColorKey(new Color(0.85f, 0.2f, 0.05f), 0.8f), new GradientColorKey(new Color(0.2f, 0.04f, 0.02f), 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[4] { new GradientAlphaKey(0f, 0f), new GradientAlphaKey(0.85f, 0.2f), new GradientAlphaKey(0.55f, 0.55f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val5); SizeOverLifetimeModule sizeOverLifetime = val4.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, new AnimationCurve((Keyframe[])(object)new Keyframe[3] { new Keyframe(0f, 0.85f), new Keyframe(0.3f, 1f), new Keyframe(1f, 0.12f) })); VelocityOverLifetimeModule velocityOverLifetime = val4.velocityOverLifetime; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)1; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).y = new MinMaxCurve(0.6f, 1.4f); ParticleSystemRenderer component = ((Component)val4).GetComponent(); if ((Object)(object)component != (Object)null) { ((Renderer)component).material = GetFireMaterial(); component.renderMode = (ParticleSystemRenderMode)1; component.velocityScale = 0.24f; component.lengthScale = Mathf.Max(1f, _config.FlameStretchLength.Value); } CreateEmberBed(val, node); ParticleSystem smokeParticles2 = CreateSmokeSystem(val, node); ParticleSystem heatHazeParticles = CreateHeatHazeSystem(val, node); Light val6 = val.AddComponent(); val6.type = (LightType)2; val6.color = new Color(1f, 0.38f, 0.1f, 1f); val6.range = Mathf.Max(3f, node.TargetRadius * 1.5f); val6.intensity = 0.75f; node.Root = val; node.Light = val6; node.Particles = val4; node.SmokeParticles = smokeParticles2; node.HeatHazeParticles = heatHazeParticles; } catch (Exception ex2) { if (_config.DebugLogging.Value) { _logger.LogWarning((object)("[TheFloods] Wildfire fallback VFX failed: " + ex2.Message)); } } } private void CreateEmberBed(GameObject root, FireNode node) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown if (!_config.EmberBedEnabled.Value || (Object)(object)root == (Object)null || node == null) { return; } try { GameObject val = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)val).name = "TheFloods_EmberBed"; Collider component = val.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } val.transform.SetParent(root.transform, false); val.transform.localPosition = new Vector3(0f, 0.04f, 0f); val.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); float num = GetEmberBedRadius() * 2f; val.transform.localScale = new Vector3(num, num, 1f); MeshRenderer component2 = val.GetComponent(); if ((Object)(object)component2 != (Object)null) { Material emberBedMaterial = (((Renderer)component2).material = new Material(GetEmberBedMaterial())); ((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component2).receiveShadows = false; node.EmberBedMaterial = emberBedMaterial; } node.EmberBed = val; } catch (Exception ex) { if (_config.DebugLogging.Value) { _logger.LogWarning((object)("[TheFloods] Ember bed creation failed: " + ex.Message)); } } } private ParticleSystem CreateSmokeSystem(GameObject root, FireNode node) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Expected O, but got Unknown //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Smoke"); val.transform.SetParent(root.transform, false); val.transform.localPosition = Vector3.up * 0.65f; ParticleSystem val2 = val.AddComponent(); MainModule main = val2.main; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(4.5f, 8f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.55f, 1.35f); ((MainModule)(ref main)).startSize = new MinMaxCurve(4.5f, 9.5f); ((MainModule)(ref main)).startColor = new MinMaxGradient(new Color(0.1f, 0.085f, 0.075f, 0.3f), new Color(0.34f, 0.28f, 0.22f, 0.2f)); ((MainModule)(ref main)).maxParticles = 120; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; EmissionModule emission = val2.emission; ((EmissionModule)(ref emission)).rateOverTime = new MinMaxCurve(18f, 32f); ShapeModule shape = val2.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4; ((ShapeModule)(ref shape)).radius = Mathf.Max(0.9f, GetEmberBedRadius() * 0.58f); ((ShapeModule)(ref shape)).angle = 22f; ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val3 = new Gradient(); val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(new Color(0.1f, 0.095f, 0.085f), 0f), new GradientColorKey(new Color(0.28f, 0.26f, 0.23f), 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[3] { new GradientAlphaKey(0f, 0f), new GradientAlphaKey(0.25f, 0.28f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val3); SizeOverLifetimeModule sizeOverLifetime = val2.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, new AnimationCurve((Keyframe[])(object)new Keyframe[3] { new Keyframe(0f, 0.55f), new Keyframe(0.55f, 1.1f), new Keyframe(1f, 1.45f) })); VelocityOverLifetimeModule velocityOverLifetime = val2.velocityOverLifetime; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)1; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).y = new MinMaxCurve(0.55f, 1.25f); ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).x = new MinMaxCurve(-0.18f, 0.18f); ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).z = new MinMaxCurve(-0.18f, 0.18f); ParticleSystemRenderer component = ((Component)val2).GetComponent(); if ((Object)(object)component != (Object)null) { ((Renderer)component).material = GetSmokeMaterial(); component.renderMode = (ParticleSystemRenderMode)0; } return val2; } private ParticleSystem CreateHeatHazeSystem(GameObject root, FireNode node) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Expected O, but got Unknown //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HeatHaze"); val.transform.SetParent(root.transform, false); val.transform.localPosition = Vector3.up * 0.35f; ParticleSystem val2 = val.AddComponent(); MainModule main = val2.main; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(1.4f, 2.8f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.25f, 0.65f); ((MainModule)(ref main)).startSize = new MinMaxCurve(2.8f, 6.2f); ((MainModule)(ref main)).startColor = new MinMaxGradient(new Color(1f, 0.34f, 0.08f, 0.085f), new Color(1f, 0.72f, 0.3f, 0.045f)); ((MainModule)(ref main)).maxParticles = 48; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; EmissionModule emission = val2.emission; ((EmissionModule)(ref emission)).rateOverTime = new MinMaxCurve(10f, 18f); ShapeModule shape = val2.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4; ((ShapeModule)(ref shape)).radius = Mathf.Max(0.8f, node.TargetRadius * 0.95f); ((ShapeModule)(ref shape)).angle = 12f; SizeOverLifetimeModule sizeOverLifetime = val2.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, new AnimationCurve((Keyframe[])(object)new Keyframe[3] { new Keyframe(0f, 0.55f), new Keyframe(0.55f, 1.25f), new Keyframe(1f, 1.65f) })); ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val3 = new Gradient(); val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(new Color(1f, 0.28f, 0.06f), 0f), new GradientColorKey(new Color(1f, 0.68f, 0.26f), 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[4] { new GradientAlphaKey(0f, 0f), new GradientAlphaKey(0.11f, 0.2f), new GradientAlphaKey(0.035f, 0.72f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val3); VelocityOverLifetimeModule velocityOverLifetime = val2.velocityOverLifetime; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)1; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).y = new MinMaxCurve(0.75f, 1.55f); ParticleSystemRenderer component = ((Component)val2).GetComponent(); if ((Object)(object)component != (Object)null) { ((Renderer)component).material = GetHeatHazeMaterial(); component.renderMode = (ParticleSystemRenderMode)0; } return val2; } private void UpdateVisual(FireNode node, float intensity, bool suppressed, Vector3 wind) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_034e: 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) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_043e: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_0495: Unknown result type (might be due to invalid IL or missing references) //IL_049a: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03de: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03f7: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Unknown result type (might be due to invalid IL or missing references) //IL_04dc: Unknown result type (might be due to invalid IL or missing references) //IL_04e1: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_050d: Unknown result type (might be due to invalid IL or missing references) //IL_04fc: Unknown result type (might be due to invalid IL or missing references) //IL_0506: Unknown result type (might be due to invalid IL or missing references) //IL_0512: Unknown result type (might be due to invalid IL or missing references) //IL_0516: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Unknown result type (might be due to invalid IL or missing references) //IL_052a: Unknown result type (might be due to invalid IL or missing references) //IL_0536: Unknown result type (might be due to invalid IL or missing references) //IL_0543: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) if (node == null) { return; } if ((Object)(object)node.EmberBedMaterial != (Object)null) { float num = 0.5f + 0.5f * Mathf.PerlinNoise(node.FlickerSeed, Time.unscaledTime * 1.7f); float num2 = (suppressed ? 0.18f : Mathf.Clamp01(_config.EmberBedOpacity.Value)); Color color = node.EmberBedMaterial.color; color.a = num2 * Mathf.Lerp(0.7f, 1f, num) * Mathf.Lerp(0.6f, 1.1f, Mathf.Clamp01(intensity)); color.r = Mathf.Lerp(0.55f, 1f, Mathf.Clamp01(intensity)); color.g = Mathf.Lerp(0.1f, 0.3f, Mathf.Clamp01(intensity)) * (suppressed ? 0.5f : 1f); color.b = Mathf.Lerp(0.02f, 0.05f, Mathf.Clamp01(intensity)); node.EmberBedMaterial.color = color; } if ((Object)(object)node.Light != (Object)null) { float num3 = Random.Range(0.72f, 1.18f); if (node.UsesVanillaVfx) { node.Light.range = Mathf.Max(4f, node.Radius * 2.2f); node.Light.intensity = (suppressed ? 0.24f : 1.1f) * Mathf.Lerp(0.7f, 1.1f, Mathf.Clamp01(intensity)) * num3; } else { node.Light.range = Mathf.Max(2.5f, node.Radius * 1.5f); node.Light.intensity = (suppressed ? 0.18f : 0.78f) * Mathf.Lerp(0.65f, 1.15f, Mathf.Clamp01(intensity)) * num3; } } Vector3 val; if ((Object)(object)node.Particles != (Object)null) { float num4; if (!((Object)(object)Player.m_localPlayer == (Object)null)) { val = ((Component)Player.m_localPlayer).transform.position - node.Position; num4 = ((Vector3)(ref val)).sqrMagnitude; } else { num4 = 0f; } float num5 = num4; float num6 = Mathf.Max(5f, _config.MaxDetailedFireDistance.Value); bool flag = (Object)(object)Player.m_localPlayer == (Object)null || num5 <= num6 * num6; EmissionModule emission = node.Particles.emission; ((EmissionModule)(ref emission)).rateOverTime = (suppressed ? new MinMaxCurve(3f, 8f) : (flag ? new MinMaxCurve(125f, 185f) : new MinMaxCurve(30f, 55f))); VelocityOverLifetimeModule velocityOverLifetime = node.Particles.velocityOverLifetime; if (((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled) { Vector3 val2 = ((((Vector3)(ref wind)).sqrMagnitude < 0.001f) ? Vector3.zero : (((Vector3)(ref wind)).normalized * Mathf.Lerp(0.12f, 0.42f, Mathf.Clamp01(intensity)))); ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).x = new MinMaxCurve(val2.x * 0.55f, val2.x); ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).z = new MinMaxCurve(val2.z * 0.55f, val2.z); } } if ((Object)(object)node.SmokeParticles != (Object)null) { EmissionModule emission2 = node.SmokeParticles.emission; ((EmissionModule)(ref emission2)).rateOverTime = (suppressed ? new MinMaxCurve(5f, 10f) : new MinMaxCurve(18f, 32f)); VelocityOverLifetimeModule velocityOverLifetime2 = node.SmokeParticles.velocityOverLifetime; if (((VelocityOverLifetimeModule)(ref velocityOverLifetime2)).enabled) { Vector3 val3 = ((((Vector3)(ref wind)).sqrMagnitude < 0.001f) ? Vector3.forward : ((Vector3)(ref wind)).normalized); float num7 = Mathf.Lerp(0.6f, 1.2f, Mathf.Clamp01(intensity)); ((VelocityOverLifetimeModule)(ref velocityOverLifetime2)).x = new MinMaxCurve(val3.x * 0.6f, val3.x * num7); ((VelocityOverLifetimeModule)(ref velocityOverLifetime2)).z = new MinMaxCurve(val3.z * 0.6f, val3.z * num7); } } if ((Object)(object)node.HeatHazeParticles != (Object)null) { float num8; if (!((Object)(object)Player.m_localPlayer == (Object)null)) { val = ((Component)Player.m_localPlayer).transform.position - node.Position; num8 = ((Vector3)(ref val)).sqrMagnitude; } else { num8 = 0f; } float num9 = num8; float num10 = Mathf.Max(8f, _config.MaxDetailedFireDistance.Value); bool flag2 = (Object)(object)Player.m_localPlayer == (Object)null || num9 <= num10 * num10; EmissionModule emission3 = node.HeatHazeParticles.emission; ((EmissionModule)(ref emission3)).rateOverTime = (suppressed ? new MinMaxCurve(0f) : (flag2 ? new MinMaxCurve(12f, 22f) : new MinMaxCurve(3f, 7f))); VelocityOverLifetimeModule velocityOverLifetime3 = node.HeatHazeParticles.velocityOverLifetime; if (((VelocityOverLifetimeModule)(ref velocityOverLifetime3)).enabled) { Vector3 val4 = ((((Vector3)(ref wind)).sqrMagnitude < 0.001f) ? Vector3.zero : (((Vector3)(ref wind)).normalized * 0.35f)); ((VelocityOverLifetimeModule)(ref velocityOverLifetime3)).x = new MinMaxCurve(val4.x * 0.45f, val4.x); ((VelocityOverLifetimeModule)(ref velocityOverLifetime3)).z = new MinMaxCurve(val4.z * 0.45f, val4.z); } } } private void DestroyNode(FireNode node) { if (node != null) { if ((Object)(object)node.EmberBedMaterial != (Object)null) { Object.Destroy((Object)(object)node.EmberBedMaterial); node.EmberBedMaterial = null; } if ((Object)(object)node.Root != (Object)null) { Object.Destroy((Object)(object)node.Root); } } } private void BurnOutNode(FireNode node) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (node != null) { CreateScorchMark(node.Position, node.TargetRadius); } DestroyNode(node); } private void UpdateFireLightBudget() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) int num = 0; Vector3 val = (((Object)(object)Player.m_localPlayer == (Object)null) ? Vector3.zero : ((Component)Player.m_localPlayer).transform.position); for (int i = 0; i < _nodes.Count; i++) { FireNode fireNode = _nodes[i]; if (fireNode == null || (Object)(object)fireNode.Light == (Object)null) { continue; } int num2; if (!((Object)(object)Player.m_localPlayer == (Object)null)) { Vector3 val2 = val - fireNode.Position; if (!(((Vector3)(ref val2)).sqrMagnitude <= 3025f)) { num2 = 0; goto IL_0080; } } num2 = ((num < 8) ? 1 : 0); goto IL_0080; IL_0080: bool flag = (byte)num2 != 0; ((Behaviour)fireNode.Light).enabled = flag; if (flag) { num++; } } } private int GetEffectiveMaxNodes() { return Mathf.Clamp(_config.MaxFireNodes.Value, 20, 120); } private float GetEffectiveNodeRadius() { return Mathf.Clamp(_config.NodeRadius.Value * 1.25f, 3.2f, 5.2f); } private float GetEmberBedRadius() { return Mathf.Clamp(Mathf.Max(1.5f, _config.SpreadStepMeters.Value) * Mathf.Max(0.1f, _config.EmberBedRadiusMultiplier.Value), 2.5f, 9f); } private void CreateScorchMark(Vector3 position, float radius) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) try { while (_scorchMarks.Count >= 60) { DestroyScorch(_scorchMarks[0]); _scorchMarks.RemoveAt(0); } GameObject val = GameObject.CreatePrimitive((PrimitiveType)5); ((Object)val).name = "TheFloods_ScorchMark"; val.transform.position = position + Vector3.up * 0.035f; val.transform.rotation = Quaternion.Euler(90f, Random.Range(0f, 360f), 0f); float num = Mathf.Max(1.8f, radius * Random.Range(1.7f, 2.6f)); val.transform.localScale = new Vector3(num, num, 1f); Collider component = val.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } MeshRenderer component2 = val.GetComponent(); if ((Object)(object)component2 != (Object)null) { ((Renderer)component2).material = GetScorchMaterial(); } _scorchMarks.Add(new ScorchMark { Root = val, EndsAt = Time.unscaledTime + Random.Range(90f, 150f) }); } catch (Exception ex) { if (_config.DebugLogging.Value) { _logger.LogWarning((object)("[TheFloods] Scorch mark failed: " + ex.Message)); } } } private void UpdateScorchMarks() { for (int num = _scorchMarks.Count - 1; num >= 0; num--) { ScorchMark scorchMark = _scorchMarks[num]; if (scorchMark == null || (Object)(object)scorchMark.Root == (Object)null || Time.unscaledTime >= scorchMark.EndsAt) { DestroyScorch(scorchMark); _scorchMarks.RemoveAt(num); } } } private void DestroyScorch(ScorchMark mark) { if (mark != null && (Object)(object)mark.Root != (Object)null) { Object.Destroy((Object)(object)mark.Root); } } private Material GetFireMaterial() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_fireMaterial != (Object)null) { return _fireMaterial; } Shader val = Shader.Find("Custom/LitParticles"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Particles/Standard Unlit"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Sprites/Default"); } _fireMaterial = new Material(val); _fireMaterial.mainTexture = (Texture)(object)GetFlameTexture(); _fireMaterial.color = new Color(1f, 0.7f, 0.35f, 0.85f); ConfigureBlend(_fireMaterial, additive: true); return _fireMaterial; } private Material GetEmberBedMaterial() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_emberBedMaterialShared != (Object)null) { return _emberBedMaterialShared; } Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Unlit/Transparent"); } _emberBedMaterialShared = new Material(val); _emberBedMaterialShared.mainTexture = (Texture)(object)GetSoftParticleTexture(); _emberBedMaterialShared.color = new Color(0.85f, 0.22f, 0.04f, Mathf.Clamp01(_config.EmberBedOpacity.Value)); ConfigureBlend(_emberBedMaterialShared, additive: false); return _emberBedMaterialShared; } private static GameObject TryGetVanillaFireVfx() { if (_vanillaFireSearched) { return _cachedVanillaFireVfx; } _vanillaFireSearched = true; try { Type type = AccessTools.TypeByName("ZNetScene"); if (type == null) { return null; } FieldInfo fieldInfo = AccessTools.Field(type, "m_instance"); PropertyInfo propertyInfo = AccessTools.Property(type, "instance"); object obj = ((fieldInfo == null) ? null : fieldInfo.GetValue(null)); if (obj == null && propertyInfo != null) { obj = propertyInfo.GetValue(null, null); } if (obj == null) { return null; } MethodInfo methodInfo = AccessTools.Method(type, "GetPrefab", new Type[1] { typeof(string) }, (Type[])null); if (methodInfo == null) { return null; } string[] array = new string[7] { "vfx_FirePit", "vfx_firepit", "vfx_fire", "fx_fire_torch", "vfx_brazierceiling_fire", "vfx_brazierfloor_fire", "vfx_groundtorch_fire" }; for (int i = 0; i < array.Length; i++) { object? obj2 = methodInfo.Invoke(obj, new object[1] { array[i] }); GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null); if ((Object)(object)val != (Object)null) { _cachedVanillaFireVfx = val; return val; } } } catch { } return null; } private static void StripNetworkingComponents(GameObject go) { if ((Object)(object)go == (Object)null) { return; } try { Type[] array = new Type[6] { AccessTools.TypeByName("ZNetView"), AccessTools.TypeByName("ZSyncTransform"), AccessTools.TypeByName("Piece"), AccessTools.TypeByName("WearNTear"), AccessTools.TypeByName("Fireplace"), AccessTools.TypeByName("EffectArea") }; foreach (Type type in array) { if (type == null) { continue; } Component[] componentsInChildren = go.GetComponentsInChildren(type, true); for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)componentsInChildren[j] != (Object)null) { Object.Destroy((Object)(object)componentsInChildren[j]); } } } } catch { } } private Material GetSmokeMaterial() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_smokeMaterial != (Object)null) { return _smokeMaterial; } Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Particles/Standard Unlit"); } _smokeMaterial = new Material(val); _smokeMaterial.mainTexture = (Texture)(object)GetSoftParticleTexture(); _smokeMaterial.color = new Color(0.25f, 0.23f, 0.2f, 0.24f); ConfigureBlend(_smokeMaterial, additive: false); return _smokeMaterial; } private Material GetHeatHazeMaterial() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_heatHazeMaterial != (Object)null) { return _heatHazeMaterial; } Shader val = Shader.Find("Custom/LitParticles"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Particles/Standard Unlit"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Sprites/Default"); } _heatHazeMaterial = new Material(val); _heatHazeMaterial.mainTexture = (Texture)(object)GetSoftParticleTexture(); _heatHazeMaterial.color = new Color(1f, 0.42f, 0.12f, 0.08f); ConfigureBlend(_heatHazeMaterial, additive: false); return _heatHazeMaterial; } private Material GetScorchMaterial() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_scorchMaterial != (Object)null) { return _scorchMaterial; } Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Unlit/Transparent"); } _scorchMaterial = new Material(val); _scorchMaterial.mainTexture = (Texture)(object)GetSoftParticleTexture(); _scorchMaterial.color = new Color(0.025f, 0.02f, 0.016f, 0.34f); ConfigureBlend(_scorchMaterial, additive: false); return _scorchMaterial; } private Texture2D GetSoftParticleTexture() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //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_00ab: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_softParticleTexture != (Object)null) { return _softParticleTexture; } _softParticleTexture = new Texture2D(64, 64, (TextureFormat)4, false); ((Texture)_softParticleTexture).wrapMode = (TextureWrapMode)1; ((Texture)_softParticleTexture).filterMode = (FilterMode)1; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(31.5f, 31.5f); float num = 30.72f; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num2 = Vector2.Distance(new Vector2((float)j, (float)i), val); float num3 = Mathf.Clamp01(1f - num2 / num); num3 = Mathf.SmoothStep(0f, 1f, num3); _softParticleTexture.SetPixel(j, i, new Color(1f, 1f, 1f, num3)); } } _softParticleTexture.Apply(false, true); return _softParticleTexture; } private Texture2D GetFlameTexture() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_012f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_flameTexture != (Object)null) { return _flameTexture; } _flameTexture = new Texture2D(64, 64, (TextureFormat)4, false); ((Texture)_flameTexture).wrapMode = (TextureWrapMode)1; ((Texture)_flameTexture).filterMode = (FilterMode)1; for (int i = 0; i < 64; i++) { float num = (float)i / 63f; float num2 = Mathf.Lerp(0.46f, 0.04f, Mathf.Pow(num, 0.65f)); for (int j = 0; j < 64; j++) { float num3 = (float)j / 63f - 0.5f; float num4 = Mathf.Clamp01(1f - Mathf.Abs(num3) / num2); float num5 = Mathf.SmoothStep(0f, 1f, Mathf.Clamp01(num / 0.12f)) * Mathf.SmoothStep(0f, 1f, Mathf.Clamp01((1f - num) / 0.5f)); float num6 = Mathf.PerlinNoise((float)j * 0.12f, (float)i * 0.12f) * 0.35f + 0.65f; float num7 = Mathf.SmoothStep(0f, 1f, num4) * num5 * num6; _flameTexture.SetPixel(j, i, new Color(1f, 1f, 1f, Mathf.Clamp01(num7))); } } _flameTexture.Apply(false, true); return _flameTexture; } private static void ConfigureBlend(Material material, bool additive) { if (!((Object)(object)material == (Object)null)) { TrySetInt(material, "_SrcMode", 5); TrySetInt(material, "_DstMode", additive ? 1 : 10); TrySetInt(material, "_ZWrite", 0); TrySetInt(material, "_Mode", additive ? 2 : 3); material.renderQueue = 3000; } } private static void TrySetInt(Material material, string property, int value) { try { if (material.HasProperty(property)) { material.SetInt(property, value); } } catch { } } private static bool TryFindGround(Vector3 candidate, out Vector3 grounded) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) grounded = candidate; try { RaycastHit val = default(RaycastHit); if (Physics.Raycast(new Vector3(candidate.x, candidate.y + 120f, candidate.z), Vector3.down, ref val, 260f, -1, (QueryTriggerInteraction)1)) { grounded = ((RaycastHit)(ref val)).point; return true; } } catch { } return false; } } internal sealed class FloodWaterAdapter { private sealed class OceanTileBinding { internal WaterVolume Volume; internal Heightmap Heightmap; internal MeshRenderer Renderer; internal Collider Collider; internal Transform RendererTransform; internal Transform ColliderTransform; internal Vector3 RendererBaselineLocalPosition; internal Vector3 RendererBaselineWorldPosition; internal Vector3 ColliderBaselineLocalPosition; internal Vector3 ColliderCenterBaseline; internal float SurfaceOffsetBaseline; internal bool CanMoveRendererTransform; internal bool CanMoveColliderTransform; internal bool CanMoveColliderCenter; internal string DebugName; } private readonly ManualLogSource _logger; private readonly FloodConfig _config; private readonly Dictionary _oceanTiles = new Dictionary(); private FieldInfo _heightmapField; private FieldInfo _waterSurfaceField; private FieldInfo _colliderField; private FieldInfo _surfaceOffsetField; private bool _fieldsSearched; private bool _fieldsValid; private bool _fieldFailureLogged; private float _currentSurge; private float _lastScanAt = -999f; private bool _loggedActive; private bool _physicsSyncPending; internal string BaselineDescription => "ocean terrain-water tiles=" + _oceanTiles.Count.ToString(CultureInfo.InvariantCulture); internal string AppliedDescription => _currentSurge.ToString("0.000", CultureInfo.InvariantCulture) + "m"; internal FloodWaterAdapter(ManualLogSource logger, FloodConfig config) { _logger = logger; _config = config; } internal bool IsPointUnderKnownWater(Vector3 point) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (!_config.EnableLiveWaterLevel.Value) { return false; } DiscoverOceanTiles(force: false); foreach (OceanTileBinding value in _oceanTiles.Values) { if (value != null && !((Object)(object)value.Volume == (Object)null)) { float num = SafeReadSurface(value.Volume, point); if (!float.IsNaN(num) && point.y <= num + 0.15f) { return true; } } } return false; } internal void ApplySurge(float surgeMeters) { if (!_config.EnableLiveWaterLevel.Value) { RestoreOriginalWaterLevel(); return; } float num = Mathf.Max(1f, _config.DebugMaximumSurgeMeters.Value); _currentSurge = Mathf.Clamp(surgeMeters, 0f - num, num); DiscoverOceanTiles(force: false); ApplyFloodToBoundTiles(); if (Mathf.Abs(_currentSurge) > 0.001f && !_loggedActive) { _loggedActive = true; _logger.LogInfo((object)"[TheFloods] Terrain-water adapter active. Ocean tile surface offsets, visible water meshes, and water triggers now follow the signed water offset. No terrain was edited."); } } internal void RestoreOriginalWaterLevel() { _currentSurge = 0f; ApplyFloodToBoundTiles(); _loggedActive = false; } internal void Dispose() { RestoreOriginalWaterLevel(); SyncPhysicsIfNeeded(); } internal void ReapplyAfterNativeUpdate(WaterVolume volume) { if (!((Object)(object)volume == (Object)null) && _oceanTiles.TryGetValue(((Object)volume).GetInstanceID(), out var value) && value != null) { ApplyRendererLift(value); ApplyColliderLift(value); } } internal void ReapplyForFrame() { if (_config.EnableLiveWaterLevel.Value) { DiscoverOceanTiles(force: false); ApplyFloodToBoundTiles(); } } internal void ReapplyVisualsForRender() { if (!_config.EnableLiveWaterLevel.Value) { return; } foreach (OceanTileBinding value in _oceanTiles.Values) { if (value != null && !((Object)(object)value.Volume == (Object)null) && !((Object)(object)value.RendererTransform == (Object)null)) { ApplyRendererLift(value); } } } internal void SyncPhysicsIfNeeded() { if (_physicsSyncPending) { _physicsSyncPending = false; Physics.SyncTransforms(); } } internal void LogSurfaceProbe(Vector3 samplePoint) { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) DiscoverOceanTiles(force: true); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; try { WaterVolume[] array = Resources.FindObjectsOfTypeAll(); num = array.Length; foreach (WaterVolume volume in array) { if (IsOceanTerrainWater(volume, out var _)) { num2++; } } } catch { } foreach (OceanTileBinding value in _oceanTiles.Values) { if (value != null) { if (value.CanMoveRendererTransform) { num3++; } if (value.CanMoveColliderTransform) { num4++; } if (value.CanMoveColliderCenter) { num5++; } } } _logger.LogInfo((object)("[TheFloods] SURFACE PROBE BEGIN sample=" + FormatVector(samplePoint) + " surge=" + _currentSurge.ToString("0.000", CultureInfo.InvariantCulture) + " allWaterVolumes=" + num.ToString(CultureInfo.InvariantCulture) + " terrainWaterVolumes=" + num2.ToString(CultureInfo.InvariantCulture) + " boundTiles=" + _oceanTiles.Count.ToString(CultureInfo.InvariantCulture) + " rendererLiftable=" + num3.ToString(CultureInfo.InvariantCulture) + " colliderTransformLiftable=" + num4.ToString(CultureInfo.InvariantCulture) + " colliderCenterLiftable=" + num5.ToString(CultureInfo.InvariantCulture))); int num6 = 0; foreach (OceanTileBinding value2 in _oceanTiles.Values) { if (value2 != null && !((Object)(object)value2.Volume == (Object)null)) { float num7 = SafeReadSurface(value2.Volume, samplePoint); float surfaceOffset = GetSurfaceOffset(value2.Volume, value2.SurfaceOffsetBaseline); string text = (((Object)(object)value2.RendererTransform == (Object)null) ? "none" : ("name='" + ((Object)((Component)value2.RendererTransform).gameObject).name + "' y=" + value2.RendererTransform.position.y.ToString("0.000", CultureInfo.InvariantCulture) + " safe=" + value2.CanMoveRendererTransform)); string text2 = (((Object)(object)value2.Collider == (Object)null) ? "none" : ("type=" + ((object)value2.Collider).GetType().Name + " y=" + ((Component)value2.Collider).transform.position.y.ToString("0.000", CultureInfo.InvariantCulture) + " transformSafe=" + value2.CanMoveColliderTransform + " centerSafe=" + value2.CanMoveColliderCenter)); _logger.LogInfo((object)("[TheFloods] SURFACE TILE name='" + value2.DebugName + "' id=" + ((Object)value2.Volume).GetInstanceID() + " volumeY=" + ((Component)value2.Volume).transform.position.y.ToString("0.000", CultureInfo.InvariantCulture) + " surfaceOffset=" + surfaceOffset.ToString("0.000", CultureInfo.InvariantCulture) + " baselineOffset=" + value2.SurfaceOffsetBaseline.ToString("0.000", CultureInfo.InvariantCulture) + " sampledSurface=" + num7.ToString("0.000", CultureInfo.InvariantCulture) + " renderer=" + text + " collider=" + text2)); num6++; if (num6 >= 12) { break; } } } if (_oceanTiles.Count == 0) { _logger.LogWarning((object)"[TheFloods] SURFACE PROBE found zero terrain-linked WaterVolume tiles. Do not test more flood heights yet; send this probe so the classification can be widened safely."); } _logger.LogInfo((object)"[TheFloods] SURFACE PROBE END"); } private void DiscoverOceanTiles(bool force) { //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) if (!force && Time.unscaledTime - _lastScanAt < Mathf.Max(0.5f, _config.WaterSurfaceScanSeconds.Value)) { return; } _lastScanAt = Time.unscaledTime; if (!FindFields()) { return; } try { WaterVolume[] array = Resources.FindObjectsOfTypeAll(); foreach (WaterVolume val in array) { if (!IsOceanTerrainWater(val, out var heightmap)) { continue; } int instanceID = ((Object)val).GetInstanceID(); if (!_oceanTiles.ContainsKey(instanceID)) { object? value = _waterSurfaceField.GetValue(val); MeshRenderer val2 = (MeshRenderer)((value is MeshRenderer) ? value : null); object? value2 = _colliderField.GetValue(val); Collider val3 = (Collider)((value2 is Collider) ? value2 : null); Transform val4 = (((Object)(object)val2 == (Object)null) ? null : ((Component)val2).transform); Transform val5 = (((Object)(object)val3 == (Object)null) ? null : ((Component)val3).transform); OceanTileBinding oceanTileBinding = new OceanTileBinding { Volume = val, Heightmap = heightmap, Renderer = val2, Collider = val3, RendererTransform = val4, ColliderTransform = val5, RendererBaselineLocalPosition = (((Object)(object)val4 == (Object)null) ? Vector3.zero : val4.localPosition), RendererBaselineWorldPosition = (((Object)(object)val4 == (Object)null) ? Vector3.zero : val4.position), ColliderBaselineLocalPosition = (((Object)(object)val5 == (Object)null) ? Vector3.zero : val5.localPosition), ColliderCenterBaseline = GetColliderCenter(val3), SurfaceOffsetBaseline = GetSurfaceOffset(val, 0f), CanMoveRendererTransform = CanMoveWaterChild(val4, heightmap), CanMoveColliderTransform = CanMoveWaterChild(val5, heightmap), CanMoveColliderCenter = CanOffsetColliderCenter(val3), DebugName = (((Object)(object)((Component)val).gameObject == (Object)null) ? "unknown" : ((Object)((Component)val).gameObject).name) }; _oceanTiles.Add(instanceID, oceanTileBinding); if (_config.VerboseWaterTileBindingLogs.Value) { _logger.LogInfo((object)("[TheFloods] Bound terrain-water tile name='" + oceanTileBinding.DebugName + "' id=" + instanceID.ToString(CultureInfo.InvariantCulture) + " renderer='" + (((Object)(object)val4 == (Object)null) ? "none" : ((Object)((Component)val4).gameObject).name) + "' rendererSafe=" + oceanTileBinding.CanMoveRendererTransform + " collider='" + (((Object)(object)val5 == (Object)null) ? "none" : ((Object)((Component)val5).gameObject).name) + "' colliderTransformSafe=" + oceanTileBinding.CanMoveColliderTransform + " colliderCenterSafe=" + oceanTileBinding.CanMoveColliderCenter + " baseSurfaceOffset=" + oceanTileBinding.SurfaceOffsetBaseline.ToString("0.000", CultureInfo.InvariantCulture))); } } } } catch (Exception ex) { _logger.LogWarning((object)("[TheFloods] Terrain-water discovery failed: " + ex.Message)); } } private bool IsOceanTerrainWater(WaterVolume volume, out Heightmap heightmap) { //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_003d: Unknown result type (might be due to invalid IL or missing references) heightmap = null; if (!((Object)(object)volume == (Object)null) && !((Object)(object)((Component)volume).gameObject == (Object)null)) { Scene scene = ((Component)volume).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { if (!FindFields()) { return false; } try { if ((int)volume.GetLiquidType() != 0) { return false; } object? value = _heightmapField.GetValue(volume); heightmap = (Heightmap)((value is Heightmap) ? value : null); return (Object)(object)heightmap != (Object)null; } catch { return false; } } } return false; } private void ApplyFloodToBoundTiles() { if (!FindFields()) { return; } List list = null; foreach (KeyValuePair oceanTile in _oceanTiles) { OceanTileBinding value = oceanTile.Value; if (value == null || (Object)(object)value.Volume == (Object)null || (Object)(object)((Component)value.Volume).gameObject == (Object)null) { if (list == null) { list = new List(); } list.Add(oceanTile.Key); continue; } try { float num = (_config.EnableWaterSurfaceQueryPatch.Value ? (value.SurfaceOffsetBaseline + _currentSurge) : value.SurfaceOffsetBaseline); _surfaceOffsetField.SetValue(value.Volume, num); ApplyRendererLift(value); ApplyColliderLift(value); } catch (Exception ex) { if (_config.DebugLogging.Value) { _logger.LogWarning((object)("[TheFloods] Could not update water tile " + oceanTile.Key.ToString(CultureInfo.InvariantCulture) + ": " + ex.Message)); } } } if (list != null) { for (int i = 0; i < list.Count; i++) { _oceanTiles.Remove(list[i]); } } } private void ApplyRendererLift(OceanTileBinding binding) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (_config.EnableOceanRendererLift.Value && !((Object)(object)binding.RendererTransform == (Object)null) && binding.CanMoveRendererTransform) { Vector3 val = binding.RendererBaselineWorldPosition + Vector3.up * _currentSurge; Vector3 val2 = binding.RendererTransform.position - val; if (((Vector3)(ref val2)).sqrMagnitude > 1E-06f) { binding.RendererTransform.position = val; } } } private void ApplyColliderLift(OceanTileBinding binding) { //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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: 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_00ed: 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_00f3: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if (!_config.EnableWaterSurfaceQueryPatch.Value || (Object)(object)binding.Collider == (Object)null) { return; } Vector3 val2; if ((!((Object)(object)binding.ColliderTransform != (Object)null) || !((Object)(object)binding.Volume != (Object)null) || !((Object)(object)binding.ColliderTransform == (Object)(object)((Component)binding.Volume).transform)) && (Object)(object)binding.ColliderTransform != (Object)null && binding.CanMoveColliderTransform) { Vector3 val = binding.ColliderBaselineLocalPosition + Vector3.up * _currentSurge; val2 = binding.ColliderTransform.localPosition - val; if (((Vector3)(ref val2)).sqrMagnitude > 1E-06f) { binding.ColliderTransform.localPosition = val; _physicsSyncPending = true; } } else if (binding.CanMoveColliderCenter) { Vector3 val3 = binding.ColliderCenterBaseline + Vector3.up * _currentSurge; val2 = GetColliderCenter(binding.Collider) - val3; if (((Vector3)(ref val2)).sqrMagnitude > 1E-06f) { SetColliderCenter(binding.Collider, val3); _physicsSyncPending = true; } } } private bool FindFields() { if (_fieldsSearched) { return _fieldsValid; } _fieldsSearched = true; _heightmapField = AccessTools.Field(typeof(WaterVolume), "m_heightmap"); _waterSurfaceField = AccessTools.Field(typeof(WaterVolume), "m_waterSurface"); _colliderField = AccessTools.Field(typeof(WaterVolume), "m_collider"); _surfaceOffsetField = AccessTools.Field(typeof(WaterVolume), "m_surfaceOffset"); _fieldsValid = _heightmapField != null && _waterSurfaceField != null && _colliderField != null && _surfaceOffsetField != null; if (!_fieldsValid && !_fieldFailureLogged) { _fieldFailureLogged = true; _logger.LogWarning((object)("[TheFloods] Required WaterVolume fields were not found. Terrain-water flooding is disabled safely. Found heightmap=" + (_heightmapField != null) + " renderer=" + (_waterSurfaceField != null) + " collider=" + (_colliderField != null) + " surfaceOffset=" + (_surfaceOffsetField != null))); } return _fieldsValid; } private static bool CanMoveWaterChild(Transform candidate, Heightmap heightmap) { if ((Object)(object)candidate == (Object)null) { return false; } if ((Object)(object)heightmap == (Object)null || (Object)(object)((Component)heightmap).transform == (Object)null) { return true; } Transform transform = ((Component)heightmap).transform; if ((Object)(object)candidate == (Object)(object)transform) { return false; } return !transform.IsChildOf(candidate); } private static bool CanOffsetColliderCenter(Collider collider) { if (!(collider is BoxCollider) && !(collider is SphereCollider)) { return collider is CapsuleCollider; } return true; } private static Vector3 GetColliderCenter(Collider collider) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) BoxCollider val = (BoxCollider)(object)((collider is BoxCollider) ? collider : null); if ((Object)(object)val != (Object)null) { return val.center; } SphereCollider val2 = (SphereCollider)(object)((collider is SphereCollider) ? collider : null); if ((Object)(object)val2 != (Object)null) { return val2.center; } CapsuleCollider val3 = (CapsuleCollider)(object)((collider is CapsuleCollider) ? collider : null); if ((Object)(object)val3 != (Object)null) { return val3.center; } return Vector3.zero; } private static void SetColliderCenter(Collider collider, Vector3 center) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) BoxCollider val = (BoxCollider)(object)((collider is BoxCollider) ? collider : null); if ((Object)(object)val != (Object)null) { val.center = center; return; } SphereCollider val2 = (SphereCollider)(object)((collider is SphereCollider) ? collider : null); if ((Object)(object)val2 != (Object)null) { val2.center = center; return; } CapsuleCollider val3 = (CapsuleCollider)(object)((collider is CapsuleCollider) ? collider : null); if ((Object)(object)val3 != (Object)null) { val3.center = center; } } private float GetSurfaceOffset(WaterVolume volume, float fallback) { try { object value = _surfaceOffsetField.GetValue(volume); if (value is float) { return (float)value; } } catch { } return fallback; } private static float SafeReadSurface(WaterVolume volume, Vector3 point) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) try { return volume.GetWaterSurface(point, 1f); } catch { return float.NaN; } } private static string FormatVector(Vector3 value) { return "(" + value.x.ToString("0.0", CultureInfo.InvariantCulture) + "," + value.y.ToString("0.0", CultureInfo.InvariantCulture) + "," + value.z.ToString("0.0", CultureInfo.InvariantCulture) + ")"; } } internal sealed class FloodEnvironmentAdapter { private readonly ManualLogSource _logger; private readonly FloodConfig _config; private MethodInfo _forceMethod; private bool _methodSearched; private bool _forceRequested; private string _lastRequestedEnvironment = string.Empty; private float _lastAttempt; private bool _failureLogged; internal FloodEnvironmentAdapter(ManualLogSource logger, FloodConfig config) { _logger = logger; _config = config; } internal void Apply(FloodPhase phase, float stormStrength) { if (!_config.EnableNativeThunderstorm.Value) { ReleaseForcedEnvironment(); } else { if ((Object)(object)EnvMan.instance == (Object)null || !FindForceMethod()) { return; } if (phase != FloodPhase.Omen && stormStrength >= Mathf.Clamp01(_config.NativeStormStartStrength.Value)) { string text = _config.NativeStormEnvironment.Value ?? "ThunderStorm"; if (!_forceRequested || !string.Equals(_lastRequestedEnvironment, text, StringComparison.Ordinal) || !(Time.unscaledTime - _lastAttempt < 25f)) { TrySet(text); } } else if (_forceRequested) { ReleaseForcedEnvironment(); } } } internal void ApplyWildfire(float wildfireIntensity) { if (!(wildfireIntensity <= 0.001f)) { string text = _config.WildfireForcedEnvironment.Value ?? string.Empty; if (!string.IsNullOrWhiteSpace(text) && !((Object)(object)EnvMan.instance == (Object)null) && FindForceMethod() && (!_forceRequested || !string.Equals(_lastRequestedEnvironment, text, StringComparison.Ordinal) || !(Time.unscaledTime - _lastAttempt < 25f))) { TrySet(text); } } } internal void ReleaseForcedEnvironment() { if (_forceRequested && !((Object)(object)EnvMan.instance == (Object)null) && FindForceMethod()) { TrySet(string.Empty); _forceRequested = false; _lastRequestedEnvironment = string.Empty; } } private bool FindForceMethod() { if (_methodSearched) { return _forceMethod != null; } _methodSearched = true; _forceMethod = AccessTools.Method(typeof(EnvMan), "SetForceEnvironment", new Type[1] { typeof(string) }, (Type[])null); if (_forceMethod == null && !_failureLogged) { _failureLogged = true; _logger.LogWarning((object)"[TheFloods] Environment adapter could not find EnvMan.SetForceEnvironment(string). The black storm bank will still work."); } return _forceMethod != null; } private void TrySet(string environmentName) { try { _forceMethod.Invoke(EnvMan.instance, new object[1] { environmentName }); bool num = !string.Equals(_lastRequestedEnvironment, environmentName ?? string.Empty, StringComparison.Ordinal); _forceRequested = !string.IsNullOrEmpty(environmentName); _lastRequestedEnvironment = environmentName ?? string.Empty; _lastAttempt = Time.unscaledTime; if (num && _config.DebugLogging.Value) { _logger.LogInfo((object)("[TheFloods] Environment adapter requested '" + (string.IsNullOrEmpty(environmentName) ? "natural weather" : environmentName) + "'.")); } } catch (Exception ex) { if (!_failureLogged) { _failureLogged = true; _logger.LogWarning((object)("[TheFloods] Environment adapter failed: " + ex.Message)); } } } } internal sealed class FloodVisuals { private readonly FloodConfig _config; private Texture2D _skyGradient; private float _lightningEndsAt; private float _lightningStrength; private float _lightningDuration = 0.12f; private float _lightningSeedJitter = Random.Range(0f, 1000f); internal FloodVisuals(FloodConfig config) { _config = config; } internal void Draw(FloodState state, float stormStrength, float wildfireIntensity, StormApproachVisual approach, FloodConfig config) { //IL_024e: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) bool flag = approach != null && approach.Active && approach.WallStrength > 0.001f; if (state == null || state.Phase == FloodPhase.Dormant || (stormStrength <= 0.001f && wildfireIntensity <= 0.001f && !flag && _lightningEndsAt <= Time.unscaledTime) || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) || (Object)(object)Player.m_localPlayer == (Object)null) { return; } EnsureTextures(); Color color = GUI.color; try { float num = (flag ? Mathf.Clamp01(approach.OverheadStrength * 0.85f + approach.WallStrength * 0.35f) : 0f); float num2 = Mathf.Clamp01(stormStrength * config.SkyDarkening.Value); num2 = Mathf.Max(num2, num * Mathf.Clamp01(config.SkyDarkening.Value) * 0.46f); if (wildfireIntensity > 0.001f) { float num3 = Mathf.Clamp01(wildfireIntensity * config.WildfireSkyTintStrength.Value); if (num3 > 0.001f) { GUI.color = new Color(0.34f, 0.13f, 0.045f, num3 * 0.42f); GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_skyGradient); } } else if (num2 > 0.001f) { GUI.color = new Color(0.026f, 0.042f, 0.072f, num2 * 0.48f); GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_skyGradient); } if (_lightningEndsAt > Time.unscaledTime) { float num4 = Mathf.Pow(Mathf.Clamp01((_lightningEndsAt - Time.unscaledTime) / Mathf.Max(0.01f, _lightningDuration)), 0.55f) * (0.88f + 0.12f * Mathf.Abs(Mathf.Sin((Time.unscaledTime + _lightningSeedJitter) * 30f))) * _lightningStrength; GUI.color = new Color(0.92f, 0.95f, 1f, num4); GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)Texture2D.whiteTexture); } } finally { GUI.color = color; } } internal void TriggerLightningFlash(float strength, float duration) { if (_config.EnableDistantLightningFlashes.Value) { float num = Mathf.Clamp01(strength); if (num > _lightningStrength) { _lightningStrength = num; } _lightningDuration = Mathf.Clamp(duration, 0.06f, 0.35f); _lightningEndsAt = Mathf.Max(_lightningEndsAt, Time.unscaledTime + _lightningDuration); } } internal void Dispose() { if ((Object)(object)_skyGradient != (Object)null) { Object.Destroy((Object)(object)_skyGradient); _skyGradient = null; } } private void EnsureTextures() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_skyGradient != (Object)null)) { _skyGradient = new Texture2D(1, 256, (TextureFormat)4, false); ((Texture)_skyGradient).wrapMode = (TextureWrapMode)1; ((Texture)_skyGradient).filterMode = (FilterMode)1; for (int i = 0; i < 256; i++) { float num = (float)i / 255f; float num2 = Mathf.Pow(Mathf.Clamp01(1f - num), 1.35f); num2 = Mathf.SmoothStep(0f, 1f, num2); _skyGradient.SetPixel(0, i, new Color(1f, 1f, 1f, num2)); } _skyGradient.Apply(false, true); } } } internal static class TerminalReflection { internal static string ReadInput(Terminal terminal) { try { object inputObject = GetInputObject(terminal); if (inputObject == null) { return string.Empty; } PropertyInfo propertyInfo = AccessTools.Property(inputObject.GetType(), "text"); return (propertyInfo == null) ? string.Empty : ((propertyInfo.GetValue(inputObject, null) as string) ?? string.Empty); } catch { return string.Empty; } } internal static void ClearInput(Terminal terminal) { try { object inputObject = GetInputObject(terminal); if (inputObject != null) { PropertyInfo propertyInfo = AccessTools.Property(inputObject.GetType(), "text"); if (propertyInfo != null && propertyInfo.CanWrite) { propertyInfo.SetValue(inputObject, string.Empty, null); } } } catch { } } internal static void Write(Terminal terminal, string message) { try { MethodInfo methodInfo = AccessTools.Method(typeof(Terminal), "AddString", new Type[1] { typeof(string) }, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(terminal, new object[1] { message }); return; } MethodInfo methodInfo2 = typeof(Terminal).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "AddString" && m.GetParameters().Length != 0 && m.GetParameters()[0].ParameterType == typeof(string)); if (methodInfo2 != null) { ParameterInfo[] parameters = methodInfo2.GetParameters(); object[] array = new object[parameters.Length]; array[0] = message; for (int num = 1; num < parameters.Length; num++) { array[num] = (parameters[num].HasDefaultValue ? parameters[num].DefaultValue : GetDefault(parameters[num].ParameterType)); } methodInfo2.Invoke(terminal, array); } } catch { } } private static object GetInputObject(Terminal terminal) { string[] array = new string[2] { "m_input", "m_inputField" }; for (int i = 0; i < array.Length; i++) { FieldInfo fieldInfo = AccessTools.Field(typeof(Terminal), array[i]); if (fieldInfo != null) { return fieldInfo.GetValue(terminal); } } return null; } private static object GetDefault(Type type) { if (!type.IsValueType) { return null; } return Activator.CreateInstance(type); } } [HarmonyPatch(typeof(Terminal), "InputText")] internal static class TheFloodsTerminalPatch { private static bool Prefix(Terminal __instance) { try { return (Object)(object)TheFloodsPlugin.Instance == (Object)null || !TheFloodsPlugin.Instance.TryHandleConsoleCommand(__instance); } catch { return true; } } }