Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Empress Market Core v1.0.0
RepoMarketCore.dll
Decompiled 2 days agousing System; using System.Collections.Generic; using System.Diagnostics; 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 EmpressRepoMarketCore.Core; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Empress")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: AssemblyProduct("RepoMarketCore")] [assembly: AssemblyTitle("RepoMarketCore")] [assembly: AssemblyVersion("1.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace EmpressRepoMarketCore { [BepInPlugin("empress.repo.repomarketcore", "RepoMarketCore", "1.0.1")] public sealed class RepoMarketCorePlugin : BaseUnityPlugin { public const string PluginGuid = "empress.repo.repomarketcore"; public const string PluginName = "RepoMarketCore"; public const string PluginVersion = "1.0.1"; private static Harmony? _harmony; private static GameObject? _runtimeHost; private static bool _sceneHooked; internal static RepoMarketCorePlugin Instance { get; private set; } internal static ManualLogSourceProxy LogProxy { get; private set; } internal static ConfigEntry<bool> Enabled { get; private set; } internal static ConfigEntry<KeyboardShortcut> ToggleBoardKey { get; private set; } internal static ConfigEntry<KeyboardShortcut> CycleBoardPageKey { get; private set; } internal static ConfigEntry<bool> ShowBanner { get; private set; } internal static ConfigEntry<float> GlobalHaulMultiplier { get; private set; } internal static ConfigEntry<float> GlobalShopMultiplier { get; private set; } internal static ConfigEntry<float> VolatilityStrength { get; private set; } internal static ConfigEntry<int> CustomRunSeed { get; private set; } internal static ConfigEntry<string> ForceHaulMarket { get; private set; } internal static ConfigEntry<string> ForceShopMarket { get; private set; } internal static ConfigEntry<string> ForcePressure { get; private set; } internal static ConfigEntry<string> ForceSignal { get; private set; } private void Awake() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown Instance = this; LogProxy = new ManualLogSourceProxy(((BaseUnityPlugin)this).Logger); BindConfig(); if (!_sceneHooked) { SceneManager.sceneLoaded += HandleSceneLoaded; _sceneHooked = true; } if (_harmony == null) { _harmony = new Harmony("empress.repo.repomarketcore"); _harmony.PatchAll(); } EnsureRuntimeHost(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RepoMarketCore 1.0.1 loaded."); } private void OnDestroy() { if (Instance == this) { Instance = null; } } private void BindConfig() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if (Enabled == null) { Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable RepoMarketCore."); } if (ToggleBoardKey == null) { ToggleBoardKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleBoardKey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Toggle the Empress market board."); } if (CycleBoardPageKey == null) { CycleBoardPageKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "CycleBoardPageKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Cycle the Empress market board page."); } if (ShowBanner == null) { ShowBanner = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowBanner", true, "Show the market banner when a new level or shop market rolls."); } if (GlobalHaulMultiplier == null) { GlobalHaulMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "GlobalHaulMultiplier", 1f, "Global multiplier applied to all haul value adjustments."); } if (GlobalShopMultiplier == null) { GlobalShopMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "GlobalShopMultiplier", 1f, "Global multiplier applied to all shop price adjustments."); } if (VolatilityStrength == null) { VolatilityStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "VolatilityStrength", 1f, "Scales per-item market variance."); } if (CustomRunSeed == null) { CustomRunSeed = ((BaseUnityPlugin)this).Config.Bind<int>("Debug", "CustomRunSeed", 0, "Force a custom run seed. Set to 0 for random seeds."); } if (ForceHaulMarket == null) { ForceHaulMarket = ((BaseUnityPlugin)this).Config.Bind<string>("Debug", "ForceHaulMarket", string.Empty, "Force a haul market by id."); } if (ForceShopMarket == null) { ForceShopMarket = ((BaseUnityPlugin)this).Config.Bind<string>("Debug", "ForceShopMarket", string.Empty, "Force a shop market by id."); } if (ForcePressure == null) { ForcePressure = ((BaseUnityPlugin)this).Config.Bind<string>("Debug", "ForcePressure", string.Empty, "Force a market pressure by id."); } if (ForceSignal == null) { ForceSignal = ((BaseUnityPlugin)this).Config.Bind<string>("Debug", "ForceSignal", string.Empty, "Force a market signal by id."); } } private static void EnsureRuntimeHost() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown if ((Object)(object)_runtimeHost != (Object)null) { if ((Object)(object)_runtimeHost.GetComponent<RepoMarketRuntime>() == (Object)null) { _runtimeHost.AddComponent<RepoMarketRuntime>(); } } else { _runtimeHost = new GameObject("EmpressRepoMarketCoreRuntime"); Object.DontDestroyOnLoad((Object)(object)_runtimeHost); _runtimeHost.AddComponent<RepoMarketRuntime>(); } } private static void HandleSceneLoaded(Scene scene, LoadSceneMode mode) { EnsureRuntimeHost(); } } internal sealed class ManualLogSourceProxy { private readonly ManualLogSource _logger; public ManualLogSourceProxy(ManualLogSource logger) { _logger = logger; } public void Info(string message) { _logger.LogInfo((object)message); } public void Warning(string message) { _logger.LogWarning((object)message); } public void Error(string message) { _logger.LogError((object)message); } } [HarmonyPatch] internal static class RepoMarketPatches { [HarmonyPatch(typeof(ValuableObject), "DollarValueSetLogic")] [HarmonyPostfix] private static void ValuableObject_DollarValueSetLogic_Postfix(ValuableObject __instance) { RepoMarketRuntime.Instance?.ApplyHaulValue(__instance); } [HarmonyPatch(typeof(ShopManager), "ShopInitialize")] [HarmonyPrefix] private static void ShopManager_ShopInitialize_Prefix(ShopManager __instance) { RepoMarketRuntime.Instance?.ApplyShopState(__instance); } [HarmonyPatch(typeof(ShopManager), "UpgradeValueGet")] [HarmonyPostfix] private static void ShopManager_UpgradeValueGet_Postfix(ref float __result) { if ((Object)(object)RepoMarketRuntime.Instance != (Object)null) { __result = RepoMarketRuntime.Instance.ApplyUpgradePrice(__result); } } [HarmonyPatch(typeof(ShopManager), "HealthPackValueGet")] [HarmonyPostfix] private static void ShopManager_HealthPackValueGet_Postfix(ref float __result) { if ((Object)(object)RepoMarketRuntime.Instance != (Object)null) { __result = RepoMarketRuntime.Instance.ApplyHealthPrice(__result); } } [HarmonyPatch(typeof(ShopManager), "CrystalValueGet")] [HarmonyPostfix] private static void ShopManager_CrystalValueGet_Postfix(ref float __result) { if ((Object)(object)RepoMarketRuntime.Instance != (Object)null) { __result = RepoMarketRuntime.Instance.ApplyCrystalPrice(__result); } } } internal sealed class RepoMarketRuntime : MonoBehaviour { private const string RoomStateKey = "empress.marketcore.state"; private const string RoomLiveTotalsKey = "empress.marketcore.live"; private const float BaseShopItemValueMultiplier = 4f; private const int HistoryLimit = 10; private static readonly Color IdleAccentColor = new Color(0.84f, 0.76f, 0.54f); private static readonly Dictionary<string, FieldInfo?> ReflectedFields = new Dictionary<string, FieldInfo>(); private readonly HashSet<int> _adjustedValuables = new HashSet<int>(); private readonly List<RepoMarketState> _history = new List<RepoMarketState>(); private readonly RepoMarketMemory _memory = new RepoMarketMemory(); private RepoMarketState? _currentState; private string _contextKey = string.Empty; private string _roomIdentity = string.Empty; private string _lastResetMarker = string.Empty; private bool _boardVisible = true; private bool _loggedFirstUpdate; private bool _loggedFirstGuiRepaint; private RepoMarketBoardPage _boardPage; private float _bannerUntil; private float _nextRoomPollTime; private float _baseValueTotal; private float _marketValueTotal; private int _adjustedCount; private int _runSeed; private bool _runSeedReady; private bool _liveTotalsDirty; private float _nextLiveTotalsPublishTime; private Rect _windowRect = new Rect(0f, 0f, 420f, 380f); private GUIStyle? _windowStyle; private GUIStyle? _panelStyle; private GUIStyle? _titleStyle; private GUIStyle? _bodyStyle; private GUIStyle? _mutedStyle; private GUIStyle? _bannerPanelStyle; private GUIStyle? _bannerTitleStyle; private GUIStyle? _bannerBodyStyle; private GUIStyle? _sectionStyle; internal static RepoMarketRuntime? Instance { get; private set; } internal RepoMarketState? CurrentState => _currentState; private void Awake() { if ((Object)(object)Instance != (Object)null && Instance != this) { Object.Destroy((Object)(object)this); return; } Instance = this; _boardVisible = true; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); RepoMarketCorePlugin.LogProxy.Info("RepoMarketCore runtime host ready."); } private void OnDestroy() { if (Instance == this) { if (_loggedFirstUpdate || _loggedFirstGuiRepaint) { RepoMarketCorePlugin.LogProxy.Warning("RepoMarketCore active runtime host destroyed."); } Instance = null; } } private void Update() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (RepoMarketCorePlugin.Enabled.Value) { if (!_loggedFirstUpdate) { _loggedFirstUpdate = true; ManualLogSourceProxy logProxy = RepoMarketCorePlugin.LogProxy; Scene activeScene = SceneManager.GetActiveScene(); logProxy.Info($"RepoMarketCore first update tick. Scene '{((Scene)(ref activeScene)).name}', boardVisible={_boardVisible}."); } HandleInput(); HandleRunLifecycle(); HandleContext(); HandleLiveTotalsSync(); } } private void OnGUI() { //IL_00dc: 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_00e8: 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_0020: 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_0027: 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_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) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 if (!RepoMarketCorePlugin.Enabled.Value || Event.current == null) { return; } EnsureGuiStyles(); Color color = GUI.color; Color backgroundColor = GUI.backgroundColor; Color contentColor = GUI.contentColor; bool enabled = GUI.enabled; int depth = GUI.depth; try { GUI.color = Color.white; GUI.backgroundColor = Color.white; GUI.contentColor = Color.white; GUI.enabled = true; GUI.depth = -2000; if (!_loggedFirstGuiRepaint && (int)Event.current.type == 7) { _loggedFirstGuiRepaint = true; RepoMarketCorePlugin.LogProxy.Info("RepoMarketCore GUI repaint reached."); } if (_boardVisible) { DrawBoard(); } if (RepoMarketCorePlugin.ShowBanner.Value && Time.unscaledTime <= _bannerUntil) { DrawBanner(); } } catch (Exception arg) { RepoMarketCorePlugin.LogProxy.Error($"RepoMarketCore OnGUI error: {arg}"); } finally { GUI.color = color; GUI.backgroundColor = backgroundColor; GUI.contentColor = contentColor; GUI.enabled = enabled; GUI.depth = depth; } } internal void ApplyHaulValue(ValuableObject valuableObject) { //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_007e: Unknown result type (might be due to invalid IL or missing references) EnsureStateForCurrentScene(RepoMarketSceneKind.Haul); RepoMarketState currentState = _currentState; if (currentState == null || currentState.SceneKind != RepoMarketSceneKind.Haul) { return; } int instanceID = ((Object)valuableObject).GetInstanceID(); if (!_adjustedValuables.Contains(instanceID)) { _adjustedValuables.Add(instanceID); float num = ReadFieldValue(valuableObject, "dollarValueCurrent", 100f); float num2 = ReadFieldValue(valuableObject, "dollarValueOriginal", num); Type volumeType = ReadFieldValue<Type>(valuableObject, "volumeType", (Type)2); float num3 = Mathf.Max(num, num2); float haulMultiplier = currentState.haulMultiplier; haulMultiplier *= currentState.GetVolumeMultiplier(volumeType); haulMultiplier *= GetVolatilityMultiplier(currentState, instanceID); if (RollJackpot(currentState, instanceID)) { haulMultiplier *= currentState.jackpotMultiplier; } float num4 = RoundCurrency(num3 * haulMultiplier); WriteFieldValue(valuableObject, "dollarValueOriginal", num4); WriteFieldValue(valuableObject, "dollarValueCurrent", num4); WriteFieldValue(valuableObject, "dollarValueSet", value: true); _adjustedCount++; _baseValueTotal += num3; _marketValueTotal += num4; QueueLiveTotalsPublish(); } } internal void ApplyShopState(ShopManager shopManager) { EnsureStateForCurrentScene(RepoMarketSceneKind.Shop); RepoMarketState currentState = _currentState; if (currentState != null && currentState.SceneKind == RepoMarketSceneKind.Shop) { WriteFieldValue(shopManager, "itemValueMultiplier", 4f * currentState.shopItemMultiplier); } } internal float ApplyUpgradePrice(float value) { EnsureStateForCurrentScene(RepoMarketSceneKind.Shop); RepoMarketState currentState = _currentState; if (currentState == null || currentState.SceneKind != RepoMarketSceneKind.Shop) { return value; } return RoundPrice(value * currentState.shopUpgradeMultiplier); } internal float ApplyHealthPrice(float value) { EnsureStateForCurrentScene(RepoMarketSceneKind.Shop); RepoMarketState currentState = _currentState; if (currentState == null || currentState.SceneKind != RepoMarketSceneKind.Shop) { return value; } return RoundPrice(value * currentState.shopHealthMultiplier); } internal float ApplyCrystalPrice(float value) { EnsureStateForCurrentScene(RepoMarketSceneKind.Shop); RepoMarketState currentState = _currentState; if (currentState == null || currentState.SceneKind != RepoMarketSceneKind.Shop) { return value; } return RoundPrice(value * currentState.shopCrystalMultiplier); } private void HandleInput() { //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_0055: 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) KeyboardShortcut value = RepoMarketCorePlugin.ToggleBoardKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _boardVisible = !_boardVisible; RepoMarketCorePlugin.LogProxy.Info("RepoMarketCore board toggled " + (_boardVisible ? "on" : "off") + "."); } value = RepoMarketCorePlugin.CycleBoardPageKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _boardPage = (RepoMarketBoardPage)((int)(_boardPage + 1) % Enum.GetValues(typeof(RepoMarketBoardPage)).Length); RepoMarketCorePlugin.LogProxy.Info($"RepoMarketCore board page changed to {_boardPage}."); } } private void HandleRunLifecycle() { string text = ((PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null) ? PhotonNetwork.CurrentRoom.Name : "singleplayer"); if (!_roomIdentity.Equals(text, StringComparison.Ordinal)) { _roomIdentity = text; ClearRunSession(); } if (ShouldResetForNonGameplay()) { string text2 = _roomIdentity + ":" + GetCurrentLevelSafeName(); if (!_lastResetMarker.Equals(text2, StringComparison.Ordinal)) { _lastResetMarker = text2; ClearRunSession(); } } else { _lastResetMarker = string.Empty; } } private void HandleContext() { RepoMarketSceneKind sceneKind = GetSceneKind(); if (sceneKind == RepoMarketSceneKind.None) { ClearContext(); return; } string text = BuildContextKey(sceneKind); if (string.IsNullOrWhiteSpace(text)) { return; } if (SemiFunc.IsMasterClientOrSingleplayer()) { if (_currentState == null || !_contextKey.Equals(text, StringComparison.Ordinal)) { RepoMarketState state = RollState(sceneKind, text); PublishState(state); ApplyState(state); } } else if (_currentState == null || !_contextKey.Equals(text, StringComparison.Ordinal) || Time.unscaledTime >= _nextRoomPollTime) { _nextRoomPollTime = Time.unscaledTime + 0.5f; TryPullState(text); } } private void HandleLiveTotalsSync() { if (_liveTotalsDirty && !(Time.unscaledTime < _nextLiveTotalsPublishTime)) { PublishLiveTotals(); } } private RepoMarketState RollState(RepoMarketSceneKind sceneKind, string contextKey) { //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) EnsureRunSeedReady(); int num = Mathf.Max(1, SemiFunc.RunGetLevelsCompleted() + 1); int playerCount = GetPlayerCount(); string currentLevelName = GetCurrentLevelName(); Random random = new Random(CombineHash(_runSeed, ComputeStableSeed(contextKey, num, playerCount))); RepoPressureDefinition repoPressureDefinition = RepoMarketCatalog.PickPressure(random, RepoMarketCorePlugin.ForcePressure.Value, num, playerCount); RepoSignalDefinition repoSignalDefinition = RepoMarketCatalog.PickSignal(random, sceneKind, RepoMarketCorePlugin.ForceSignal.Value); float num2 = Mathf.Lerp(1f, 1.2f, Mathf.Clamp01((float)num / 12f)); float num3 = Mathf.Lerp(1f, 1.18f, Mathf.Clamp01((float)(playerCount - 1) / 3f)); float volatility = 0.06f * Mathf.Max(0.2f, RepoMarketCorePlugin.VolatilityStrength.Value) * repoPressureDefinition.VolatilityMultiplier * repoSignalDefinition.VolatilityMultiplier; RepoMarketState repoMarketState; if (sceneKind == RepoMarketSceneKind.Haul) { RepoHaulMarketDefinition repoHaulMarketDefinition = RepoMarketCatalog.PickHaul(random, RepoMarketCorePlugin.ForceHaulMarket.Value); float haulMultiplier = repoHaulMarketDefinition.BaseMultiplier * repoPressureDefinition.HaulMultiplier * repoSignalDefinition.HaulMultiplier * num2 * num3 * RepoMarketCorePlugin.GlobalHaulMultiplier.Value; float hotVolumeMultiplier = repoHaulMarketDefinition.HotMultiplier * repoSignalDefinition.HotMultiplierScale; float coldVolumeMultiplier = repoHaulMarketDefinition.ColdMultiplier * repoSignalDefinition.ColdMultiplierScale; float jackpotChance = Mathf.Clamp01(repoHaulMarketDefinition.JackpotChance * Mathf.Lerp(0.9f, 1.25f, Mathf.Clamp01((float)(playerCount - 1) / 3f)) + repoSignalDefinition.JackpotChanceBonus); float jackpotMultiplier = repoHaulMarketDefinition.JackpotMultiplier * repoSignalDefinition.JackpotMultiplierScale; repoMarketState = new RepoMarketState(); repoMarketState.contextKey = contextKey; repoMarketState.sceneKind = "Haul"; repoMarketState.marketId = repoHaulMarketDefinition.Id; repoMarketState.marketName = repoHaulMarketDefinition.DisplayName; repoMarketState.pressureId = repoPressureDefinition.Id; repoMarketState.pressureName = repoPressureDefinition.DisplayName; repoMarketState.signalId = repoSignalDefinition.Id; repoMarketState.signalName = repoSignalDefinition.DisplayName; repoMarketState.levelName = currentLevelName; repoMarketState.headline = repoHaulMarketDefinition.Headline; repoMarketState.subtitle = repoHaulMarketDefinition.Subtitle + " Pressure: " + repoPressureDefinition.Label + ". Signal: " + repoSignalDefinition.DisplayName + "."; repoMarketState.accentHex = ResolveAccentHex(repoHaulMarketDefinition.AccentHex, repoPressureDefinition.AccentHex, repoSignalDefinition.AccentHex); repoMarketState.signalHeadline = repoSignalDefinition.Headline; repoMarketState.signalSubtitle = repoSignalDefinition.Subtitle; RepoMarketState repoMarketState2 = repoMarketState; Type val = repoHaulMarketDefinition.HotVolume; repoMarketState2.hotVolume = ((object)(Type)(ref val)).ToString(); RepoMarketState repoMarketState3 = repoMarketState; val = repoHaulMarketDefinition.ColdVolume; repoMarketState3.coldVolume = ((object)(Type)(ref val)).ToString(); repoMarketState.levelNumber = num; repoMarketState.playerCount = playerCount; repoMarketState.runSeed = _runSeed; repoMarketState.haulMultiplier = haulMultiplier; repoMarketState.shopItemMultiplier = 1f; repoMarketState.shopUpgradeMultiplier = 1f; repoMarketState.shopHealthMultiplier = 1f; repoMarketState.shopCrystalMultiplier = 1f; repoMarketState.hotVolumeMultiplier = hotVolumeMultiplier; repoMarketState.coldVolumeMultiplier = coldVolumeMultiplier; repoMarketState.jackpotChance = jackpotChance; repoMarketState.jackpotMultiplier = jackpotMultiplier; repoMarketState.volatility = volatility; return repoMarketState; } RepoShopMarketDefinition repoShopMarketDefinition = RepoMarketCatalog.PickShop(random, RepoMarketCorePlugin.ForceShopMarket.Value); float num4 = repoPressureDefinition.ShopMultiplier * Mathf.Lerp(1f, 1.09f, Mathf.Clamp01((float)num / 10f)) * num3 * RepoMarketCorePlugin.GlobalShopMultiplier.Value; repoMarketState = new RepoMarketState(); repoMarketState.contextKey = contextKey; repoMarketState.sceneKind = "Shop"; repoMarketState.marketId = repoShopMarketDefinition.Id; repoMarketState.marketName = repoShopMarketDefinition.DisplayName; repoMarketState.pressureId = repoPressureDefinition.Id; repoMarketState.pressureName = repoPressureDefinition.DisplayName; repoMarketState.signalId = repoSignalDefinition.Id; repoMarketState.signalName = repoSignalDefinition.DisplayName; repoMarketState.levelName = currentLevelName; repoMarketState.headline = repoShopMarketDefinition.Headline; repoMarketState.subtitle = repoShopMarketDefinition.Subtitle + " Pressure: " + repoPressureDefinition.Label + ". Signal: " + repoSignalDefinition.DisplayName + "."; repoMarketState.accentHex = ResolveAccentHex(repoShopMarketDefinition.AccentHex, repoPressureDefinition.AccentHex, repoSignalDefinition.AccentHex); repoMarketState.signalHeadline = repoSignalDefinition.Headline; repoMarketState.signalSubtitle = repoSignalDefinition.Subtitle; repoMarketState.hotVolume = string.Empty; repoMarketState.coldVolume = string.Empty; repoMarketState.levelNumber = num; repoMarketState.playerCount = playerCount; repoMarketState.runSeed = _runSeed; repoMarketState.haulMultiplier = 1f; repoMarketState.shopItemMultiplier = repoShopMarketDefinition.ItemMultiplier * repoSignalDefinition.ShopItemMultiplier * num4; repoMarketState.shopUpgradeMultiplier = repoShopMarketDefinition.UpgradeMultiplier * repoSignalDefinition.ShopUpgradeMultiplier * num4; repoMarketState.shopHealthMultiplier = repoShopMarketDefinition.HealthMultiplier * repoSignalDefinition.ShopHealthMultiplier * num4; repoMarketState.shopCrystalMultiplier = repoShopMarketDefinition.CrystalMultiplier * repoSignalDefinition.ShopCrystalMultiplier * num4; repoMarketState.hotVolumeMultiplier = 1f; repoMarketState.coldVolumeMultiplier = 1f; repoMarketState.jackpotChance = 0f; repoMarketState.jackpotMultiplier = 1f; repoMarketState.volatility = volatility; return repoMarketState; } private void PublishState(RepoMarketState state) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null && SemiFunc.IsMasterClient()) { Hashtable val = new Hashtable { [(object)"empress.marketcore.state"] = state.Serialize() }; PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); } } private void PublishLiveTotals() { //IL_005b: 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_0074: Expected O, but got Unknown if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null || !SemiFunc.IsMasterClient() || _currentState == null) { _liveTotalsDirty = false; return; } RepoMarketLiveTotals repoMarketLiveTotals = new RepoMarketLiveTotals { contextKey = _contextKey, adjustedCount = _adjustedCount, baseValueTotal = _baseValueTotal, marketValueTotal = _marketValueTotal }; Hashtable val = new Hashtable { [(object)"empress.marketcore.live"] = repoMarketLiveTotals.Serialize() }; PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); _liveTotalsDirty = false; } private void TryPullState(string contextKey) { if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null && ((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).ContainsKey((object)"empress.marketcore.state") && ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties[(object)"empress.marketcore.state"] is string payload) { RepoMarketState repoMarketState = RepoMarketState.Deserialize(payload); if (repoMarketState != null && repoMarketState.contextKey.Equals(contextKey, StringComparison.Ordinal)) { ApplyState(repoMarketState); TryPullLiveTotals(contextKey); } } } private void TryPullLiveTotals(string contextKey) { if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null && ((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).ContainsKey((object)"empress.marketcore.live") && ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties[(object)"empress.marketcore.live"] is string payload) { RepoMarketLiveTotals repoMarketLiveTotals = RepoMarketLiveTotals.Deserialize(payload); if (repoMarketLiveTotals != null && repoMarketLiveTotals.contextKey.Equals(contextKey, StringComparison.Ordinal)) { ApplyLiveTotals(repoMarketLiveTotals); } } } private void ApplyState(RepoMarketState state) { bool num = _currentState == null || !_currentState.contextKey.Equals(state.contextKey, StringComparison.Ordinal) || !_currentState.marketId.Equals(state.marketId, StringComparison.Ordinal) || !_currentState.pressureId.Equals(state.pressureId, StringComparison.Ordinal) || !_currentState.signalId.Equals(state.signalId, StringComparison.Ordinal); _currentState = state; _contextKey = state.contextKey; if (num) { _adjustedValuables.Clear(); _adjustedCount = 0; _baseValueTotal = 0f; _marketValueTotal = 0f; _bannerUntil = Time.unscaledTime + 11f; QueueLiveTotalsPublish(immediate: true); _runSeed = state.runSeed; _runSeedReady = state.runSeed != 0; _history.Insert(0, state); if (_history.Count > 10) { _history.RemoveRange(10, _history.Count - 10); } _memory.RecordRunSeed(state.runSeed); _memory.RecordState(state); RepoMarketCorePlugin.LogProxy.Info($"{state.marketName} + {state.signalName} rolled for {state.levelName} with pressure {state.pressureName}. Seed {state.runSeed}."); } } private void ClearRunSession() { ClearContext(); _history.Clear(); _runSeed = 0; _runSeedReady = false; _liveTotalsDirty = false; _nextLiveTotalsPublishTime = 0f; _bannerUntil = 0f; _boardPage = RepoMarketBoardPage.Overview; } private void ClearContext() { _currentState = null; _contextKey = string.Empty; _adjustedValuables.Clear(); _adjustedCount = 0; _baseValueTotal = 0f; _marketValueTotal = 0f; } private void ApplyLiveTotals(RepoMarketLiveTotals totals) { _adjustedCount = totals.adjustedCount; _baseValueTotal = totals.baseValueTotal; _marketValueTotal = totals.marketValueTotal; } private void QueueLiveTotalsPublish(bool immediate = false) { if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null && SemiFunc.IsMasterClient() && _currentState != null && !string.IsNullOrWhiteSpace(_contextKey)) { _liveTotalsDirty = true; _nextLiveTotalsPublishTime = (immediate ? Time.unscaledTime : (Time.unscaledTime + 0.2f)); } } private RepoMarketSceneKind GetSceneKind() { if ((Object)(object)RunManager.instance == (Object)null) { return RepoMarketSceneKind.None; } if (SemiFunc.RunIsShop()) { return RepoMarketSceneKind.Shop; } if (SemiFunc.RunIsLevel() && !SemiFunc.RunIsArena()) { return RepoMarketSceneKind.Haul; } return RepoMarketSceneKind.None; } private bool ShouldResetForNonGameplay() { if ((Object)(object)GetCurrentLevel() == (Object)null) { return true; } if (SemiFunc.RunIsLobbyMenu() || SemiFunc.RunIsLobby() || SemiFunc.RunIsTutorial()) { return true; } if (!SemiFunc.IsMainMenu()) { return SemiFunc.IsSplashScreen(); } return true; } private string BuildContextKey(RepoMarketSceneKind sceneKind) { Level currentLevel = GetCurrentLevel(); if ((Object)(object)currentLevel == (Object)null) { return string.Empty; } string text = ((Object)currentLevel).name ?? "Unknown"; int num = Mathf.Max(1, SemiFunc.RunGetLevelsCompleted() + 1); int playerCount = GetPlayerCount(); return $"{sceneKind}:{num}:{playerCount}:{text}"; } private void EnsureRunSeedReady() { if (!_runSeedReady) { int value = RepoMarketCorePlugin.CustomRunSeed.Value; if (value != 0) { _runSeed = Mathf.Abs(value); } else { long ticks = DateTime.UtcNow.Ticks; int left = (int)(ticks ^ (ticks >> 32)); int hashCode = _roomIdentity.GetHashCode(); _runSeed = Mathf.Abs(CombineHash(left, hashCode)); } if (_runSeed == 0) { _runSeed = 1; } _runSeedReady = true; _memory.RecordRunSeed(_runSeed); } } private void EnsureStateForCurrentScene(RepoMarketSceneKind expectedSceneKind) { RepoMarketSceneKind sceneKind = GetSceneKind(); if (sceneKind != expectedSceneKind) { return; } string text = BuildContextKey(sceneKind); if (!string.IsNullOrWhiteSpace(text) && (_currentState == null || _currentState.SceneKind != expectedSceneKind || !_contextKey.Equals(text, StringComparison.Ordinal))) { if (SemiFunc.IsMasterClientOrSingleplayer()) { RepoMarketState state = RollState(sceneKind, text); PublishState(state); ApplyState(state); } else { TryPullState(text); } } } private void EnsureGuiStyles() { //IL_002d: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_00a5: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown //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_00c7: Expected O, but got Unknown //IL_00cc: Expected O, but got Unknown //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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown //IL_010a: 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_0119: Expected O, but got Unknown //IL_011e: Expected O, but got Unknown //IL_0129: 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_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_014d: 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_015c: Expected O, but got Unknown //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_0170: Expected O, but got Unknown //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Expected O, but got Unknown //IL_01d1: 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_01de: 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) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Expected O, but got Unknown //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0215: 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_023e: Expected O, but got Unknown //IL_0245: 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_0251: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Expected O, but got Unknown //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Expected O, but got Unknown //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Expected O, but got Unknown if (_windowStyle == null || _panelStyle == null || _bannerPanelStyle == null) { Texture2D background = MakeTexture(new Color(0.02f, 0.02f, 0.02f, 1f)); Texture2D background2 = MakeTexture(new Color(0.04f, 0.04f, 0.04f, 1f)); Texture2D background3 = MakeTexture(new Color(0.03f, 0.03f, 0.03f, 1f)); GUIStyle val = new GUIStyle(GUI.skin.window); val.normal.background = background; val.border = new RectOffset(10, 10, 10, 10); val.padding = new RectOffset(14, 14, 12, 12); val.margin = new RectOffset(0, 0, 0, 0); _windowStyle = val; GUIStyle val2 = new GUIStyle(GUI.skin.box); val2.normal.background = background2; val2.padding = new RectOffset(14, 14, 12, 12); val2.margin = new RectOffset(0, 0, 0, 0); val2.border = new RectOffset(8, 8, 8, 8); _panelStyle = val2; GUIStyle val3 = new GUIStyle(GUI.skin.box); val3.normal.background = background3; val3.padding = new RectOffset(18, 18, 14, 14); val3.margin = new RectOffset(0, 0, 0, 0); val3.border = new RectOffset(8, 8, 8, 8); _bannerPanelStyle = val3; GUIStyle val4 = new GUIStyle(GUI.skin.label) { fontSize = 20, fontStyle = (FontStyle)1, richText = true, wordWrap = true }; val4.normal.textColor = new Color(0.96f, 0.88f, 0.62f, 1f); _titleStyle = val4; GUIStyle val5 = new GUIStyle(GUI.skin.label) { fontSize = 14, richText = true, wordWrap = true }; val5.normal.textColor = Color.white; _bodyStyle = val5; GUIStyle val6 = new GUIStyle(_bodyStyle) { fontSize = 12 }; val6.normal.textColor = new Color(0.78f, 0.78f, 0.8f, 1f); _mutedStyle = val6; _bannerTitleStyle = new GUIStyle(_titleStyle) { alignment = (TextAnchor)1, fontSize = 22 }; _bannerBodyStyle = new GUIStyle(_bodyStyle) { alignment = (TextAnchor)1 }; _sectionStyle = new GUIStyle(_bodyStyle) { fontStyle = (FontStyle)1 }; } } private void DrawBoard() { //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_003e: 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_004d: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if (_windowStyle != null && _panelStyle != null && _titleStyle != null && _bodyStyle != null && _mutedStyle != null && _sectionStyle != null) { _windowRect = GetBoardRect(); DrawBoardBackdrop(_windowRect, _currentState?.AccentColor ?? IdleAccentColor); _windowRect = GUI.Window(418422, _windowRect, new WindowFunction(DrawBoardWindow), GUIContent.none, _windowStyle); } } private void DrawBoardWindow(int id) { //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) if (_panelStyle == null || _titleStyle == null || _bodyStyle == null || _mutedStyle == null || _sectionStyle == null) { return; } GUILayout.BeginVertical(_panelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Empress Market Core", _titleStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label((_currentState != null) ? $"Page: {_boardPage} | Seed: {_currentState.SeedLabel}" : $"Page: {_boardPage} | Status: Standby", _mutedStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(4f); if (_currentState == null) { DrawStandbyPage(); } else { switch (_boardPage) { case RepoMarketBoardPage.Overview: DrawOverviewPage(); break; case RepoMarketBoardPage.History: DrawHistoryPage(); break; case RepoMarketBoardPage.Records: DrawRecordsPage(); break; } } GUILayout.Space(6f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); KeyboardShortcut value = RepoMarketCorePlugin.ToggleBoardKey.Value; GUILayout.Label($"Press [{((KeyboardShortcut)(ref value)).MainKey}] to hide", _mutedStyle, Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); value = RepoMarketCorePlugin.CycleBoardPageKey.Value; GUILayout.Label($"Cycle: [{((KeyboardShortcut)(ref value)).MainKey}]", _mutedStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUILayout.EndVertical(); } private void DrawStandbyPage() { if (_bodyStyle != null && _mutedStyle != null && _sectionStyle != null) { RepoMarketSceneKind sceneKind = GetSceneKind(); string currentLevelName = GetCurrentLevelName(); string text = sceneKind switch { RepoMarketSceneKind.Haul => "Haul", RepoMarketSceneKind.Shop => "Shop", _ => "None", }; GUILayout.Label("RepoMarketCore is loaded and waiting for an active market context.", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(8f); GUILayout.Label("Status", _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Detected scene: " + text, _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Detected level: " + currentLevelName, _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Room identity: " + _roomIdentity, _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Board visible: {_boardVisible}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(6f); GUILayout.Label("When it should appear", _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("The market board becomes fully populated during haul levels and shops once the current run context is available.", _mutedStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("If you stay on this standby page inside a shop or haul level, the market state is not being rolled yet.", _mutedStyle, Array.Empty<GUILayoutOption>()); } } private void DrawOverviewPage() { if (_currentState != null && _bodyStyle != null && _mutedStyle != null && _sectionStyle != null) { GUILayout.Label(_currentState.marketName + " | " + _currentState.signalName + " | " + _currentState.pressureName, _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(_currentState.headline, _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(_currentState.signalHeadline, _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(_currentState.subtitle, _mutedStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(_currentState.signalSubtitle, _mutedStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(8f); if (_currentState.SceneKind == RepoMarketSceneKind.Haul) { GUILayout.Label("Haul Sheet", _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Run uplift: " + FormatDelta(_currentState.haulMultiplier), _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Hot demand: " + FormatVolume(_currentState.hotVolume) + " " + FormatDelta(_currentState.hotVolumeMultiplier), _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Cold demand: " + FormatVolume(_currentState.coldVolume) + " " + FormatDelta(_currentState.coldVolumeMultiplier), _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Jackpot chance: {_currentState.jackpotChance * 100f:0.#}% at x{_currentState.jackpotMultiplier:0.##}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Volatility lane: +/-{_currentState.volatility * 100f:0.#}%", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(6f); GUILayout.Label("Live Totals", _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Adjusted valuables: {_adjustedCount}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Base sheet: ${_baseValueTotal:0}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Market sheet: ${_marketValueTotal:0}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Swing: ${_marketValueTotal - _baseValueTotal:0}", _bodyStyle, Array.Empty<GUILayoutOption>()); } else { GUILayout.Label("Shop Sheet", _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Items: " + FormatDelta(_currentState.shopItemMultiplier), _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Upgrades: " + FormatDelta(_currentState.shopUpgradeMultiplier), _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Health: " + FormatDelta(_currentState.shopHealthMultiplier), _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("Crystals: " + FormatDelta(_currentState.shopCrystalMultiplier), _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Volatility lane: +/-{_currentState.volatility * 100f:0.#}%", _bodyStyle, Array.Empty<GUILayoutOption>()); } } } private void DrawHistoryPage() { if (_bodyStyle == null || _mutedStyle == null || _sectionStyle == null) { return; } GUILayout.Label("Recent Rolls", _sectionStyle, Array.Empty<GUILayoutOption>()); if (_history.Count == 0) { GUILayout.Label("No market history yet for this run.", _mutedStyle, Array.Empty<GUILayoutOption>()); return; } for (int i = 0; i < _history.Count; i++) { RepoMarketState repoMarketState = _history[i]; GUILayout.Label(repoMarketState.levelName + " | " + repoMarketState.marketName + " + " + repoMarketState.signalName + " + " + repoMarketState.pressureName, _bodyStyle, Array.Empty<GUILayoutOption>()); if (repoMarketState.SceneKind == RepoMarketSceneKind.Haul) { GUILayout.Label($"Haul {FormatDelta(repoMarketState.haulMultiplier)} | Jackpot {repoMarketState.jackpotChance * 100f:0.#}% | Seed {repoMarketState.SeedLabel}", _mutedStyle, Array.Empty<GUILayoutOption>()); continue; } GUILayout.Label("Items " + FormatDelta(repoMarketState.shopItemMultiplier) + " | Upgrades " + FormatDelta(repoMarketState.shopUpgradeMultiplier) + " | Seed " + repoMarketState.SeedLabel, _mutedStyle, Array.Empty<GUILayoutOption>()); } } private void DrawRecordsPage() { if (_bodyStyle != null && _mutedStyle != null && _sectionStyle != null) { RepoMarketMemoryData data = _memory.Data; GUILayout.Label("Empress Records", _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Runs tracked: {data.totalRuns}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Rolls tracked: {data.totalRolls}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Haul markets found: {data.discoveredHaulMarkets}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Shop climates found: {data.discoveredShopMarkets}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Signals found: {data.discoveredSignals}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Pressures found: {data.discoveredPressures}", _bodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(6f); GUILayout.Label("Best Sheets", _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label((data.bestHaulMultiplier > 0f) ? ("Best haul uplift: " + FormatDelta(data.bestHaulMultiplier)) : "Best haul uplift: none yet", _bodyStyle, Array.Empty<GUILayoutOption>()); if (!string.IsNullOrWhiteSpace(data.bestHaulSummary)) { GUILayout.Label(data.bestHaulSummary, _mutedStyle, Array.Empty<GUILayoutOption>()); } GUILayout.Label((!string.IsNullOrWhiteSpace(data.bestShopSummary)) ? ("Best shop discount: " + FormatDelta(data.bestShopDiscount)) : "Best shop discount: none yet", _bodyStyle, Array.Empty<GUILayoutOption>()); if (!string.IsNullOrWhiteSpace(data.bestShopSummary)) { GUILayout.Label(data.bestShopSummary, _mutedStyle, Array.Empty<GUILayoutOption>()); } } } private void DrawBanner() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (_currentState != null && _bannerPanelStyle != null && _bannerTitleStyle != null && _bannerBodyStyle != null) { Rect val = new Rect((float)Screen.width * 0.5f - 310f, 18f, 620f, 108f); DrawPanel(val, _currentState.AccentColor, 0.96f); GUILayout.BeginArea(val, _bannerPanelStyle); GUILayout.Label(_currentState.marketName + " + " + _currentState.signalName, _bannerTitleStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(_currentState.headline, _bannerBodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(_currentState.signalHeadline, _bannerBodyStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndArea(); } } private static void DrawPanel(Rect rect, Color accentColor, float alpha) { //IL_0000: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0060: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = new Color(0.02f, 0.02f, 0.02f, alpha); GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture); Rect val = new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, 5f, ((Rect)(ref rect)).height); GUI.color = new Color(accentColor.r, accentColor.g, accentColor.b, 0.95f); GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture); GUI.color = color; } private static void DrawBoardBackdrop(Rect rect, Color accentColor) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = Color.black; GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture, (ScaleMode)0, false); Rect val = new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, 5f, ((Rect)(ref rect)).height); GUI.color = new Color(accentColor.r, accentColor.g, accentColor.b, 1f); GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture, (ScaleMode)0, false); GUI.color = color; } private float GetBoardHeight() { if (_currentState == null) { return 380f; } int num = Mathf.Max(1, _history.Count); float num2; switch (_boardPage) { case RepoMarketBoardPage.Overview: { RepoMarketState? currentState = _currentState; num2 = ((currentState != null && currentState.SceneKind == RepoMarketSceneKind.Haul) ? 560f : 450f); break; } case RepoMarketBoardPage.History: num2 = 190f + (float)num * 46f; break; case RepoMarketBoardPage.Records: num2 = 520f; break; default: num2 = 520f; break; } return Mathf.Clamp(num2, 300f, Mathf.Max(300f, (float)Screen.height - 24f)); } private Rect GetBoardRect() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp((float)Screen.width * 0.34f, 320f, 430f); float num2 = Mathf.Max(12f, (float)Screen.width * 0.02f); return new Rect(Mathf.Max(8f, (float)Screen.width - num - num2), 18f, num, GetBoardHeight()); } private string GetCurrentLevelSafeName() { Level currentLevel = GetCurrentLevel(); if ((Object)(object)currentLevel == (Object)null) { return "none"; } return ((Object)currentLevel).name ?? "none"; } private static int GetPlayerCount() { if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null) { return Mathf.Max(1, PhotonNetwork.CurrentRoom.PlayerCount); } return 1; } private static string GetCurrentLevelName() { Level currentLevel = GetCurrentLevel(); if ((Object)(object)currentLevel == (Object)null) { return "Unknown Site"; } string narrativeName = currentLevel.NarrativeName; if (!string.IsNullOrWhiteSpace(narrativeName)) { return narrativeName; } return ((Object)currentLevel).name ?? "Unknown Site"; } private static Level? GetCurrentLevel() { if ((Object)(object)RunManager.instance == (Object)null) { return null; } return RunManager.instance.levelCurrent; } private static int ComputeStableSeed(string contextKey, int levelNumber, int playerCount) { int num = 17; foreach (char c in contextKey) { num = num * 31 + c; } num = num * 31 + levelNumber; return num * 31 + playerCount; } private static int CombineHash(int left, int right) { return (left * 397) ^ right; } private static float RoundCurrency(float value) { return Mathf.Max(5f, Mathf.Round(value / 5f) * 5f); } private static float RoundPrice(float value) { return Mathf.Max(1f, Mathf.Round(value)); } private static float GetVolatilityMultiplier(RepoMarketState state, int instanceId) { float num = Mathf.Clamp(state.volatility, 0f, 0.45f); if (num <= 0.001f) { return 1f; } float num2 = (float)((ComputeStableSeed(state.contextKey, instanceId, state.levelNumber) & 0x7FFFFFFF) % 10000) / 9999f * 2f - 1f; return Mathf.Clamp(1f + num2 * num, 0.65f, 1.7f); } private static bool RollJackpot(RepoMarketState state, int instanceId) { if (state.jackpotChance <= 0.001f) { return false; } return (float)((ComputeStableSeed(state.contextKey, instanceId, 97) & 0x7FFFFFFF) % 10000) / 9999f <= state.jackpotChance; } private static string ResolveAccentHex(string marketHex, string pressureHex, string signalHex) { if (!string.IsNullOrWhiteSpace(signalHex)) { return signalHex; } if (!string.IsNullOrWhiteSpace(pressureHex)) { return pressureHex; } return marketHex; } private static string FormatVolume(string volume) { if (string.Equals(volume, "VeryTall", StringComparison.OrdinalIgnoreCase)) { return "Very Tall"; } if (!string.IsNullOrWhiteSpace(volume)) { return volume; } return "None"; } private static string FormatDelta(float multiplier) { float num = (multiplier - 1f) * 100f; if (Mathf.Abs(num) < 0.05f) { return "flat"; } if (!(num > 0f)) { return $"{num:0.#}%"; } return $"+{num:0.#}%"; } private static Texture2D MakeTexture(Color color) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false); val.SetPixel(0, 0, color); val.Apply(); return val; } private static FieldInfo? GetFieldInfo(Type type, string fieldName) { string key = type.FullName + "|" + fieldName; if (ReflectedFields.TryGetValue(key, out FieldInfo value)) { return value; } Type type2 = type; FieldInfo fieldInfo = null; while (type2 != null) { fieldInfo = type2.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { break; } type2 = type2.BaseType; } ReflectedFields[key] = fieldInfo; return fieldInfo; } private static bool WriteFieldValue<T>(object? instance, string fieldName, T value) { if (instance == null) { return false; } try { FieldInfo fieldInfo = GetFieldInfo(instance.GetType(), fieldName); if (fieldInfo == null) { return false; } fieldInfo.SetValue(instance, value); return true; } catch { return false; } } private static T ReadFieldValue<T>(object? instance, string fieldName, T fallback) { if (instance == null) { return fallback; } try { FieldInfo fieldInfo = GetFieldInfo(instance.GetType(), fieldName); if (fieldInfo == null) { return fallback; } object value = fieldInfo.GetValue(instance); if (value is T result) { return result; } if (value == null) { return fallback; } return (T)Convert.ChangeType(value, typeof(T)); } catch { return fallback; } } } } namespace EmpressRepoMarketCore.Core { internal static class RepoMarketCatalog { public static readonly IReadOnlyList<RepoHaulMarketDefinition> HaulMarkets = new RepoHaulMarketDefinition[8] { new RepoHaulMarketDefinition { Id = "pocket_parade", DisplayName = "Pocket Parade", Headline = "Pocket Parade is paying for carry-friendly loot.", Subtitle = "Tiny hauls fly off the books while bulky junk gets side-eyed.", AccentHex = "#f4d35e", BaseMultiplier = 1.05f, HotVolume = (Type)0, HotMultiplier = 1.45f, ColdVolume = (Type)3, ColdMultiplier = 0.84f, JackpotChance = 0.04f, JackpotMultiplier = 1.8f }, new RepoHaulMarketDefinition { Id = "scrap_bloom", DisplayName = "Scrap Bloom", Headline = "Scrap Bloom rewards the everyday salvage grind.", Subtitle = "Small and medium finds are moving fast for once.", AccentHex = "#7bd389", BaseMultiplier = 1.08f, HotVolume = (Type)1, HotMultiplier = 1.28f, ColdVolume = (Type)6, ColdMultiplier = 0.88f, JackpotChance = 0.03f, JackpotMultiplier = 1.6f }, new RepoHaulMarketDefinition { Id = "luxury_lane", DisplayName = "Luxury Lane", Headline = "Luxury Lane wants dramatic centerpieces.", Subtitle = "Tall statement pieces are hot, tiny clutter is not.", AccentHex = "#d4af37", BaseMultiplier = 1.1f, HotVolume = (Type)5, HotMultiplier = 1.4f, ColdVolume = (Type)0, ColdMultiplier = 0.82f, JackpotChance = 0.08f, JackpotMultiplier = 2f }, new RepoHaulMarketDefinition { Id = "dockyard_dump", DisplayName = "Dockyard Dump", Headline = "Dockyard brokers are hoarding oversized cargo.", Subtitle = "Wide salvage is booming while delicate vertical pieces lag behind.", AccentHex = "#4ea8de", BaseMultiplier = 1.02f, HotVolume = (Type)4, HotMultiplier = 1.42f, ColdVolume = (Type)5, ColdMultiplier = 0.83f, JackpotChance = 0.02f, JackpotMultiplier = 1.5f }, new RepoHaulMarketDefinition { Id = "midnight_auction", DisplayName = "Midnight Auction", Headline = "Midnight Auction is chaotic and dangerously generous.", Subtitle = "Anything can spike, but medium movers have the spotlight tonight.", AccentHex = "#9d4edd", BaseMultiplier = 1.12f, HotVolume = (Type)2, HotMultiplier = 1.3f, ColdVolume = (Type)1, ColdMultiplier = 0.93f, JackpotChance = 0.12f, JackpotMultiplier = 2.25f }, new RepoHaulMarketDefinition { Id = "bulk_buyback", DisplayName = "Bulk Buyback", Headline = "Bulk Buyback is eating warehouse-sized salvage.", Subtitle = "Big pieces print money if your team can haul them out alive.", AccentHex = "#f97316", BaseMultiplier = 1.06f, HotVolume = (Type)3, HotMultiplier = 1.38f, ColdVolume = (Type)0, ColdMultiplier = 0.86f, JackpotChance = 0.05f, JackpotMultiplier = 1.9f }, new RepoHaulMarketDefinition { Id = "spire_mania", DisplayName = "Spire Mania", Headline = "Spire Mania is obsessed with awkward vertical junk.", Subtitle = "Very tall loot is absurdly profitable if you can stop dropping it.", AccentHex = "#fb7185", BaseMultiplier = 1.04f, HotVolume = (Type)6, HotMultiplier = 1.55f, ColdVolume = (Type)4, ColdMultiplier = 0.82f, JackpotChance = 0.06f, JackpotMultiplier = 2.1f }, new RepoHaulMarketDefinition { Id = "clean_room_premium", DisplayName = "Clean Room Premium", Headline = "Clean Room Premium favors neat, manageable salvage.", Subtitle = "Medium pieces cash out well while giant debris tanks the sheet.", AccentHex = "#8ecae6", BaseMultiplier = 1.09f, HotVolume = (Type)2, HotMultiplier = 1.24f, ColdVolume = (Type)3, ColdMultiplier = 0.79f, JackpotChance = 0.03f, JackpotMultiplier = 1.75f } }; public static readonly IReadOnlyList<RepoShopMarketDefinition> ShopMarkets = new RepoShopMarketDefinition[7] { new RepoShopMarketDefinition { Id = "warehouse_clearout", DisplayName = "Warehouse Clearout", Headline = "Warehouse Clearout is pushing everyday gear.", Subtitle = "Core items are cheap and stock managers are pretending this is normal.", AccentHex = "#84cc16", ItemMultiplier = 0.8f, UpgradeMultiplier = 0.94f, HealthMultiplier = 0.92f, CrystalMultiplier = 0.88f }, new RepoShopMarketDefinition { Id = "sponsor_drop", DisplayName = "Sponsor Drop", Headline = "Sponsor Drop is subsidizing upgrades.", Subtitle = "Some suit decided power creep is a marketing strategy.", AccentHex = "#22c55e", ItemMultiplier = 1f, UpgradeMultiplier = 0.72f, HealthMultiplier = 1.05f, CrystalMultiplier = 1.03f }, new RepoShopMarketDefinition { Id = "field_hospital", DisplayName = "Field Hospital", Headline = "Field Hospital put med prices on life support.", Subtitle = "Healing is cheap. Everything else can wait.", AccentHex = "#38bdf8", ItemMultiplier = 1.04f, UpgradeMultiplier = 1.06f, HealthMultiplier = 0.62f, CrystalMultiplier = 1.02f }, new RepoShopMarketDefinition { Id = "crystal_crash", DisplayName = "Crystal Crash", Headline = "Crystal Crash is flooding the shelf with charge packs.", Subtitle = "Crystal prices collapsed, which means someone else probably exploded.", AccentHex = "#a78bfa", ItemMultiplier = 0.97f, UpgradeMultiplier = 1.05f, HealthMultiplier = 1f, CrystalMultiplier = 0.58f }, new RepoShopMarketDefinition { Id = "smuggler_lane", DisplayName = "Smuggler Lane", Headline = "Smuggler Lane deals are sharp and suspicious.", Subtitle = "Items are dirt cheap, but premium systems cost extra hush money.", AccentHex = "#f59e0b", ItemMultiplier = 0.76f, UpgradeMultiplier = 1.16f, HealthMultiplier = 1.04f, CrystalMultiplier = 1.18f }, new RepoShopMarketDefinition { Id = "luxury_markup", DisplayName = "Luxury Markup", Headline = "Luxury Markup is openly mugging the whole crew.", Subtitle = "Everything got pricier because the market felt cute.", AccentHex = "#ef4444", ItemMultiplier = 1.24f, UpgradeMultiplier = 1.36f, HealthMultiplier = 1.18f, CrystalMultiplier = 1.21f }, new RepoShopMarketDefinition { Id = "maintenance_subsidy", DisplayName = "Maintenance Subsidy", Headline = "Maintenance Subsidy rewards crews that keep the rig alive.", Subtitle = "Practical gear and batteries are seeing a quiet discount wave.", AccentHex = "#06b6d4", ItemMultiplier = 0.88f, UpgradeMultiplier = 0.98f, HealthMultiplier = 0.84f, CrystalMultiplier = 0.91f } }; public static readonly IReadOnlyList<RepoPressureDefinition> PressureStates = new RepoPressureDefinition[5] { new RepoPressureDefinition { Id = "steady", DisplayName = "Steady", Label = "Steady demand", AccentHex = "#cbd5e1", HaulMultiplier = 1f, ShopMultiplier = 1f, VolatilityMultiplier = 1f }, new RepoPressureDefinition { Id = "heated", DisplayName = "Heated", Label = "Heated demand", AccentHex = "#f97316", HaulMultiplier = 1.08f, ShopMultiplier = 1.04f, VolatilityMultiplier = 1.18f }, new RepoPressureDefinition { Id = "jackpot", DisplayName = "Jackpot", Label = "Jackpot window", AccentHex = "#fde047", HaulMultiplier = 1.16f, ShopMultiplier = 0.96f, VolatilityMultiplier = 1.32f }, new RepoPressureDefinition { Id = "predatory", DisplayName = "Predatory", Label = "Predatory pricing", AccentHex = "#dc2626", HaulMultiplier = 0.94f, ShopMultiplier = 1.14f, VolatilityMultiplier = 1.24f }, new RepoPressureDefinition { Id = "fractured", DisplayName = "Fractured", Label = "Fractured market", AccentHex = "#9333ea", HaulMultiplier = 1.03f, ShopMultiplier = 1.02f, VolatilityMultiplier = 1.45f } }; public static readonly IReadOnlyList<RepoSignalDefinition> Signals = new RepoSignalDefinition[10] { new RepoSignalDefinition { Id = "vip_buyers", DisplayName = "VIP Buyers", Headline = "VIP Buyers are bidding above reason.", Subtitle = "High rollers are turning decent salvage into stupid money.", AccentHex = "#facc15", SceneKind = RepoMarketSceneKind.Haul, HaulMultiplier = 1.08f, HotMultiplierScale = 1.12f, ColdMultiplierScale = 0.96f, JackpotChanceBonus = 0.04f, JackpotMultiplierScale = 1.08f, VolatilityMultiplier = 1.1f }, new RepoSignalDefinition { Id = "freight_jam", DisplayName = "Freight Jam", Headline = "Freight Jam made bulk salvage harder to move.", Subtitle = "The market is jumpy and picky, which sounds familiar.", AccentHex = "#f97316", SceneKind = RepoMarketSceneKind.Haul, HaulMultiplier = 0.96f, HotMultiplierScale = 1.06f, ColdMultiplierScale = 0.88f, JackpotChanceBonus = -0.01f, JackpotMultiplierScale = 1f, VolatilityMultiplier = 1.28f }, new RepoSignalDefinition { Id = "smuggler_tip", DisplayName = "Smuggler Tip", Headline = "Smuggler Tip leaked a private shopping list.", Subtitle = "The right crates are suddenly worth a little too much.", AccentHex = "#06b6d4", SceneKind = RepoMarketSceneKind.Haul, HaulMultiplier = 1.04f, HotMultiplierScale = 1.18f, ColdMultiplierScale = 0.94f, JackpotChanceBonus = 0.02f, JackpotMultiplierScale = 1.03f, VolatilityMultiplier = 1.15f }, new RepoSignalDefinition { Id = "quiet_floor", DisplayName = "Quiet Floor", Headline = "Quiet Floor stabilized the auction feed.", Subtitle = "Less chaos, fewer moonshots, cleaner pricing.", AccentHex = "#94a3b8", SceneKind = RepoMarketSceneKind.Haul, HaulMultiplier = 1.02f, HotMultiplierScale = 1.04f, ColdMultiplierScale = 0.98f, JackpotChanceBonus = -0.015f, JackpotMultiplierScale = 0.98f, VolatilityMultiplier = 0.72f }, new RepoSignalDefinition { Id = "black_card", DisplayName = "Black Card Window", Headline = "Black Card Window has whales in the room.", Subtitle = "If a jackpot lands, it lands loud.", AccentHex = "#e879f9", SceneKind = RepoMarketSceneKind.Haul, HaulMultiplier = 1.05f, HotMultiplierScale = 1.08f, ColdMultiplierScale = 0.97f, JackpotChanceBonus = 0.06f, JackpotMultiplierScale = 1.22f, VolatilityMultiplier = 1.18f }, new RepoSignalDefinition { Id = "dock_rebate", DisplayName = "Dock Rebate", Headline = "Dock Rebate hit the gear lanes.", Subtitle = "Supplies are cheaper because somebody finally overstocked properly.", AccentHex = "#22c55e", SceneKind = RepoMarketSceneKind.Shop, ShopItemMultiplier = 0.86f, ShopUpgradeMultiplier = 0.96f, ShopHealthMultiplier = 0.9f, ShopCrystalMultiplier = 0.92f, VolatilityMultiplier = 1f }, new RepoSignalDefinition { Id = "grease_payment", DisplayName = "Grease Payment", Headline = "Grease Payment hit the back room.", Subtitle = "Discount shelves are open, but premium stock got a surcharge.", AccentHex = "#f59e0b", SceneKind = RepoMarketSceneKind.Shop, ShopItemMultiplier = 0.82f, ShopUpgradeMultiplier = 1.1f, ShopHealthMultiplier = 1f, ShopCrystalMultiplier = 1.08f, VolatilityMultiplier = 1.1f }, new RepoSignalDefinition { Id = "battery_flood", DisplayName = "Battery Flood", Headline = "Battery Flood crushed crystal margins.", Subtitle = "Charge is cheap. Everything else still hurts.", AccentHex = "#60a5fa", SceneKind = RepoMarketSceneKind.Shop, ShopItemMultiplier = 1f, ShopUpgradeMultiplier = 1.02f, ShopHealthMultiplier = 0.96f, ShopCrystalMultiplier = 0.68f, VolatilityMultiplier = 0.96f }, new RepoSignalDefinition { Id = "maintenance_night", DisplayName = "Maintenance Night", Headline = "Maintenance Night favors survival basics.", Subtitle = "Repairs and med stock are moving on a quiet discount.", AccentHex = "#2dd4bf", SceneKind = RepoMarketSceneKind.Shop, ShopItemMultiplier = 0.94f, ShopUpgradeMultiplier = 1.02f, ShopHealthMultiplier = 0.72f, ShopCrystalMultiplier = 0.9f, VolatilityMultiplier = 0.88f }, new RepoSignalDefinition { Id = "panic_markup", DisplayName = "Panic Markup", Headline = "Panic Markup sent merchants into goblin mode.", Subtitle = "They smelled desperation and priced accordingly.", AccentHex = "#ef4444", SceneKind = RepoMarketSceneKind.Shop, ShopItemMultiplier = 1.16f, ShopUpgradeMultiplier = 1.18f, ShopHealthMultiplier = 1.15f, ShopCrystalMultiplier = 1.12f, VolatilityMultiplier = 1.2f } }; public static RepoHaulMarketDefinition PickHaul(Random random, string forcedId) { return PickFrom(HaulMarkets, random, forcedId); } public static RepoShopMarketDefinition PickShop(Random random, string forcedId) { return PickFrom(ShopMarkets, random, forcedId); } public static RepoPressureDefinition PickPressure(Random random, string forcedId, int levelNumber, int playerCount) { if (!string.IsNullOrWhiteSpace(forcedId)) { foreach (RepoPressureDefinition pressureState in PressureStates) { if (pressureState.Id.Equals(forcedId, StringComparison.OrdinalIgnoreCase)) { return pressureState; } } } int num = random.Next(0, 100) + levelNumber * 2 + Math.Max(0, playerCount - 1) * 4; if (num >= 100) { return PressureStates[2]; } if (num >= 85) { return PressureStates[4]; } if (num >= 65) { return PressureStates[1]; } if (num >= 45) { return PressureStates[3]; } return PressureStates[0]; } public static RepoSignalDefinition PickSignal(Random random, RepoMarketSceneKind sceneKind, string forcedId) { List<RepoSignalDefinition> list = new List<RepoSignalDefinition>(); foreach (RepoSignalDefinition signal in Signals) { if (signal.SceneKind == sceneKind) { list.Add(signal); } } if (!string.IsNullOrWhiteSpace(forcedId)) { foreach (RepoSignalDefinition item in list) { if (item.Id.Equals(forcedId, StringComparison.OrdinalIgnoreCase)) { return item; } } } return list[random.Next(list.Count)]; } private static T PickFrom<T>(IReadOnlyList<T> list, Random random, string forcedId) where T : class { if (!string.IsNullOrWhiteSpace(forcedId)) { foreach (T item in list) { if (item is RepoHaulMarketDefinition repoHaulMarketDefinition && repoHaulMarketDefinition.Id.Equals(forcedId, StringComparison.OrdinalIgnoreCase)) { return item; } if (item is RepoShopMarketDefinition repoShopMarketDefinition && repoShopMarketDefinition.Id.Equals(forcedId, StringComparison.OrdinalIgnoreCase)) { return item; } } } return list[random.Next(list.Count)]; } } [Serializable] internal sealed class RepoMarketDiscoveryEntry { public string id = string.Empty; public string name = string.Empty; public string kind = string.Empty; public int timesSeen; public string lastSeenLevel = string.Empty; } [Serializable] internal sealed class RepoMarketMemoryData { public int totalRuns; public int totalRolls; public int discoveredHaulMarkets; public int discoveredShopMarkets; public int discoveredSignals; public int discoveredPressures; public int lastRunSeed; public float bestHaulMultiplier; public string bestHaulSummary = string.Empty; public float bestShopDiscount = 1f; public string bestShopSummary = string.Empty; public List<RepoMarketDiscoveryEntry> haulMarkets = new List<RepoMarketDiscoveryEntry>(); public List<RepoMarketDiscoveryEntry> shopMarkets = new List<RepoMarketDiscoveryEntry>(); public List<RepoMarketDiscoveryEntry> signals = new List<RepoMarketDiscoveryEntry>(); public List<RepoMarketDiscoveryEntry> pressures = new List<RepoMarketDiscoveryEntry>(); } internal sealed class RepoMarketMemory { private readonly string _filePath; public RepoMarketMemoryData Data { get; private set; } public RepoMarketMemory() { _filePath = Path.Combine(Paths.ConfigPath, "Empress.RepoMarketCore.market-memory.json"); Data = Load(); } public void RecordRunSeed(int runSeed) { if (runSeed != 0 && Data.lastRunSeed != runSeed) { Data.lastRunSeed = runSeed; Data.totalRuns++; Save(); } } public void RecordState(RepoMarketState state) { Data.totalRolls++; TouchEntry((state.SceneKind == RepoMarketSceneKind.Shop) ? Data.shopMarkets : Data.haulMarkets, state.marketId, state.marketName, state.levelName, "market"); TouchEntry(Data.signals, state.signalId, state.signalName, state.levelName, "signal"); TouchEntry(Data.pressures, state.pressureId, state.pressureName, state.levelName, "pressure"); Data.discoveredHaulMarkets = Data.haulMarkets.Count; Data.discoveredShopMarkets = Data.shopMarkets.Count; Data.discoveredSignals = Data.signals.Count; Data.discoveredPressures = Data.pressures.Count; if (state.SceneKind == RepoMarketSceneKind.Haul && state.haulMultiplier > Data.bestHaulMultiplier) { Data.bestHaulMultiplier = state.haulMultiplier; Data.bestHaulSummary = state.marketName + " + " + state.signalName + " + " + state.pressureName + " on " + state.levelName; } if (state.SceneKind == RepoMarketSceneKind.Shop && state.shopItemMultiplier < Data.bestShopDiscount) { Data.bestShopDiscount = state.shopItemMultiplier; Data.bestShopSummary = state.marketName + " + " + state.signalName + " + " + state.pressureName + " on " + state.levelName; } Save(); } private RepoMarketMemoryData Load() { try { if (!File.Exists(_filePath)) { return new RepoMarketMemoryData(); } string text = File.ReadAllText(_filePath); if (string.IsNullOrWhiteSpace(text)) { return new RepoMarketMemoryData(); } return JsonUtility.FromJson<RepoMarketMemoryData>(text) ?? new RepoMarketMemoryData(); } catch { return new RepoMarketMemoryData(); } } private void Save() { try { Directory.CreateDirectory(Path.GetDirectoryName(_filePath) ?? Paths.ConfigPath); File.WriteAllText(_filePath, JsonUtility.ToJson((object)Data, true)); } catch (Exception ex) { RepoMarketCorePlugin.LogProxy.Warning("[RepoMarketCore] Failed to save market memory: " + ex.Message); } } private static void TouchEntry(List<RepoMarketDiscoveryEntry> list, string id, string name, string levelName, string kind) { string id2 = id; if (!string.IsNullOrWhiteSpace(id2)) { RepoMarketDiscoveryEntry repoMarketDiscoveryEntry = list.FirstOrDefault((RepoMarketDiscoveryEntry candidate) => candidate.id == id2); if (repoMarketDiscoveryEntry == null) { repoMarketDiscoveryEntry = new RepoMarketDiscoveryEntry { id = id2, name = (string.IsNullOrWhiteSpace(name) ? id2 : name), kind = kind }; list.Add(repoMarketDiscoveryEntry); } repoMarketDiscoveryEntry.timesSeen++; repoMarketDiscoveryEntry.lastSeenLevel = levelName; } } } internal enum RepoMarketSceneKind { None, Haul, Shop } internal enum RepoMarketBoardPage { Overview, History, Records } internal sealed class RepoHaulMarketDefinition { public string Id { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; public string Headline { get; set; } = string.Empty; public string Subtitle { get; set; } = string.Empty; public string AccentHex { get; set; } = "#ffffff"; public float BaseMultiplier { get; set; } = 1f; public Type HotVolume { get; set; } = (Type)2; public float HotMultiplier { get; set; } = 1.15f; public Type ColdVolume { get; set; } = (Type)1; public float ColdMultiplier { get; set; } = 0.9f; public float JackpotChance { get; set; } public float JackpotMultiplier { get; set; } = 1.5f; } internal sealed class RepoShopMarketDefinition { public string Id { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; public string Headline { get; set; } = string.Empty; public string Subtitle { get; set; } = string.Empty; public string AccentHex { get; set; } = "#ffffff"; public float ItemMultiplier { get; set; } = 1f; public float UpgradeMultiplier { get; set; } = 1f; public float HealthMultiplier { get; set; } = 1f; public float CrystalMultiplier { get; set; } = 1f; } internal sealed class RepoPressureDefinition { public string Id { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; public string Label { get; set; } = string.Empty; public string AccentHex { get; set; } = "#ffffff"; public float HaulMultiplier { get; set; } = 1f; public float ShopMultiplier { get; set; } = 1f; public float VolatilityMultiplier { get; set; } = 1f; } internal sealed class RepoSignalDefinition { public string Id { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; public string Headline { get; set; } = string.Empty; public string Subtitle { get; set; } = string.Empty; public string AccentHex { get; set; } = "#ffffff"; public RepoMarketSceneKind SceneKind { get; set; } public float HaulMultiplier { get; set; } = 1f; public float HotMultiplierScale { get; set; } = 1f; public float ColdMultiplierScale { get; set; } = 1f; public float JackpotChanceBonus { get; set; } public float JackpotMultiplierScale { get; set; } = 1f; public float ShopItemMultiplier { get; set; } = 1f; public float ShopUpgradeMultiplier { get; set; } = 1f; public float ShopHealthMultiplier { get; set; } = 1f; public float ShopCrystalMultiplier { get; set; } = 1f; public float VolatilityMultiplier { get; set; } = 1f; } [Serializable] internal sealed class RepoMarketState { public string contextKey = string.Empty; public string sceneKind = "None"; public string marketId = string.Empty; public string marketName = string.Empty; public string pressureId = string.Empty; public string pressureName = string.Empty; public string signalId = string.Empty; public string signalName = string.Empty; public string levelName = string.Empty; public string headline = string.Empty; public string subtitle = string.Empty; public string accentHex = "#d5c18a"; public string signalHeadline = string.Empty; public string signalSubtitle = string.Empty; public string hotVolume = string.Empty; public string coldVolume = string.Empty; public int levelNumber; public int playerCount = 1; public int runSeed; public float haulMultiplier = 1f; public float shopItemMultiplier = 1f; public float shopUpgradeMultiplier = 1f; public float shopHealthMultiplier = 1f; public float shopCrystalMultiplier = 1f; public float hotVolumeMultiplier = 1f; public float coldVolumeMultiplier = 1f; public float jackpotChance; public float jackpotMultiplier = 1f; public float volatility = 0.06f; public RepoMarketSceneKind SceneKind { get { string text = sceneKind; if (!(text == "Haul")) { if (text == "Shop") { return RepoMarketSceneKind.Shop; } return RepoMarketSceneKind.None; } return RepoMarketSceneKind.Haul; } } public Color AccentColor { get { //IL_0020: 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) Color result = default(Color); if (ColorUtility.TryParseHtmlString(accentHex, ref result)) { return result; } return new Color(0.84f, 0.76f, 0.54f); } } public string SeedLabel { get { if (runSeed != 0) { return runSeed.ToString(); } return "N/A"; } } public string Serialize() { return JsonUtility.ToJson((object)this); } public static RepoMarketState? Deserialize(string payload) { if (string.IsNullOrWhiteSpace(payload)) { return null; } try { return JsonUtility.FromJson<RepoMarketState>(payload); } catch { return null; } } public float GetVolumeMultiplier(Type volumeType) { //IL_0015: 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_0031: 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) float num = 1f; if (TryParseVolume(hotVolume, out var volumeType2) && volumeType2 == volumeType) { num *= hotVolumeMultiplier; } if (TryParseVolume(coldVolume, out var volumeType3) && volumeType3 == volumeType) { num *= coldVolumeMultiplier; } return num; } public static bool TryParseVolume(string value, out Type volumeType) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected I4, but got Unknown if (Enum.TryParse<Type>(value, ignoreCase: true, out Type result)) { volumeType = (Type)(int)result; return true; } volumeType = (Type)2; return false; } } [Serializable] internal sealed class RepoMarketLiveTotals { public string contextKey = string.Empty; public int adjustedCount; public float baseValueTotal; public float marketValueTotal; public string Serialize() { return JsonUtility.ToJson((object)this); } public static RepoMarketLiveTotals? Deserialize(string payload) { if (string.IsNullOrWhiteSpace(payload)) { return null; } try { return JsonUtility.FromJson<RepoMarketLiveTotals>(payload); } catch { return null; } } } }