using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Extensions; using HarmonyLib; using Microsoft.CodeAnalysis; using Mirror; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; [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("GambleWithYourFriendsPvP")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("GambleWithYourFriendsPvP")] [assembly: AssemblyTitle("GambleWithYourFriendsPvP")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace GambleWithYourFriendsPvP { public static class BetClampPatches { [HarmonyPatch(typeof(MoneyManager), "TryChangeBalance")] [HarmonyPrefix] public static void HappyHourMultiplier(ref long amount, PlayerProfile changer, ChangeType changeType) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 if (NetworkServer.active && !((Object)(object)changer == (Object)null) && (int)changeType == 1 && amount > 0 && HappyHourSystem.IsActive) { long num = (long)((float)amount * 1.5f); if (num > amount) { Plugin.Log.LogInfo((object)$"[HappyHour] Boosting {changer.playerName}'s payout {amount} -> {num}"); amount = num; } } } [HarmonyPatch(typeof(MoneyManager), "TryChangeBalance")] [HarmonyPrefix] public static void HauntCurse(ref long amount, PlayerProfile changer, ChangeType changeType) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 if (NetworkServer.active && !((Object)(object)changer == (Object)null) && (int)changeType == 1 && amount > 0 && HauntSystem.IsHaunted(changer.steamId)) { long num = (long)((float)amount * 0.5f); Plugin.Log.LogInfo((object)$"[Haunt] Curse on {changer.playerName}: payout {amount} -> {num}"); amount = num; } } [HarmonyPatch(typeof(MoneyManager), "TryChangeBalance")] [HarmonyPrefix] public static void HotStreakMultiplier(ref long amount, PlayerProfile changer, ChangeType changeType) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((Object)(object)changer == (Object)null || (int)changeType != 1 || amount <= 0) { return; } ModState instance = ModState.Instance; if (!((Object)(object)instance == (Object)null) && instance.Ledgers.TryGetValue(changer.steamId, out var value) && value.BuffHotStreak) { long num = (long)((float)amount * 1.25f); if (num != amount) { Plugin.Log.LogInfo((object)$"[HotStreak] {changer.playerName}: payout {amount} -> {num}"); amount = num; } } } } public class BlackMarketBooth : MonoBehaviour { private TextMeshPro _signLabel; private TextMeshPro _itemLabel; public int SelectedItem { get; private set; } public void SetUI(TextMeshPro sign, TextMeshPro item) { _signLabel = sign; _itemLabel = item; RefreshLabels(); } public void RefreshLabels() { if ((Object)(object)_signLabel != (Object)null) { ((TMP_Text)_signLabel).text = "BLACK MARKET\nNO REFUNDS"; } if ((Object)(object)_itemLabel != (Object)null) { int num = SelectedItem % BlackMarketSystem.Names.Length; string arg = BlackMarketSystem.Names[num]; int num2 = BlackMarketSystem.Prices[num]; string arg2 = BlackMarketSystem.Effects[num]; ((TMP_Text)_itemLabel).text = $"{arg} - {num2}♦\n{arg2}"; } } public void Cycle() { SoundManager.Play(SoundManager.Cue.Click); SelectedItem = (SelectedItem + 1) % BlackMarketSystem.Names.Length; RefreshLabels(); } public void Buy() { ulong num = ResolveLocalSteamId(); if (num == 0L) { Plugin.Log.LogWarning((object)"[BlackMarket] No local steam id."); return; } SoundManager.Play(SoundManager.Cue.TakeLoan); int num2 = SelectedItem % BlackMarketSystem.Names.Length; Plugin.Log.LogInfo((object)$"[BlackMarket] Local player requesting purchase: item={num2}"); NetSync.ClientRequestBlackMarketPurchase(num, num2); } private void Update() { RefreshLabels(); } private static ulong ResolveLocalSteamId() { NetworkConnectionToServer connection = NetworkClient.connection; NetworkIdentity val = ((connection != null) ? ((NetworkConnection)connection).identity : null); if ((Object)(object)val != (Object)null) { PlayerProfile component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { return component.steamId; } } if ((Object)(object)MonoSingleton.Instance != (Object)null) { foreach (PlayerReferences player in MonoSingleton.Instance.players) { if ((Object)(object)player?.identity != (Object)null && player.identity.isLocalPlayer) { return player.profile?.steamId ?? 0; } } } return 0uL; } } public static class BlackMarketSpawner { public static IEnumerator SpawnRoutine() { yield return (object)new WaitForSeconds(3f); NetSync.RegisterAll(); LoanSharkSpawner.EnsureMaterialExternal(); if ((Object)(object)GameObject.Find("[PvP] BlackMarketKiosk") != (Object)null) { Plugin.Log.LogInfo((object)"[BlackMarketSpawner] Booth already exists, skipping."); yield break; } Vector3 playerPos = Vector3.zero; float deadline = Time.time + 8f; while (Time.time < deadline) { playerPos = FindLocalPlayerPos(); if (playerPos != Vector3.zero) { break; } yield return (object)new WaitForSeconds(0.5f); } Vector3 val = (Vector3)((playerPos != Vector3.zero) ? new Vector3(playerPos.x, playerPos.y - 1f, playerPos.z + 4f) : Vector3.zero); string arg = "player+4z (locked, no nudge)"; Plugin.Log.LogInfo((object)$"[BlackMarketSpawner] Anchor: {arg} at {val} (player at {playerPos})"); GameObject val2 = new GameObject("[PvP] BlackMarketKiosk"); val2.transform.position = val; val2.transform.rotation = Quaternion.identity; BuildVisuals(val2); BlackMarketBooth booth = val2.AddComponent(); Transform obj = val2.transform.Find("Sign/SignText"); TextMeshPro sign = ((obj != null) ? ((Component)obj).GetComponent() : null); Transform obj2 = val2.transform.Find("Desk/ItemText"); TextMeshPro item = ((obj2 != null) ? ((Component)obj2).GetComponent() : null); booth.SetUI(sign, item); LoanSharkSpawner.AddInteractableExternal(val2.transform, new Vector3(-0.6f, 1.1f, -0.6f), "CycleItem", "Cycle Item", new Color(0.3f, 0.7f, 0.95f), delegate { booth.Cycle(); }); LoanSharkSpawner.AddInteractableExternal(val2.transform, new Vector3(0.6f, 1.1f, -0.6f), "Buy", "Buy", new Color(0.95f, 0.25f, 0.25f), delegate { booth.Buy(); }); Plugin.Log.LogInfo((object)$"[BlackMarketSpawner] Booth placed at {val2.transform.position}."); } private static void BuildVisuals(GameObject root) { //IL_0039: 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_0077: 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_00da: 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_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_0120: 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_013f: 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_0189: 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_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: 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_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: 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_0227: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val).name = "Desk"; val.transform.SetParent(root.transform, false); val.transform.localPosition = new Vector3(0f, 0.5f, 0f); val.transform.localScale = new Vector3(2.5f, 1f, 1f); LoanSharkSpawner.ApplyMaterialExternal(val, new Color(0.25f, 0.18f, 0.08f, 1f), glow: false); GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val2).name = "Sign"; val2.transform.SetParent(root.transform, false); val2.transform.localPosition = new Vector3(0f, 2.2f, 0f); val2.transform.localScale = new Vector3(2.8f, 1.5f, 0.05f); LoanSharkSpawner.ApplyMaterialExternal(val2, new Color(0.75f, 0.55f, 0.15f, 1f), glow: true); GameObject val3 = new GameObject("SignText"); val3.transform.SetParent(val2.transform, false); val3.transform.localPosition = new Vector3(0f, 0f, -0.6f); val3.transform.localScale = new Vector3(0.4f, 2f / 3f, 20f); TextMeshPro obj = val3.AddComponent(); ((TMP_Text)obj).text = "BLACK MARKET\nNO REFUNDS"; ((TMP_Text)obj).fontSize = 4f; ((Graphic)obj).color = new Color(0.15f, 0.05f, 0f); ((TMP_Text)obj).alignment = (TextAlignmentOptions)514; GameObject val4 = new GameObject("ItemText"); val4.transform.SetParent(val.transform, false); val4.transform.localPosition = new Vector3(0f, 0.51f, 0f); val4.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); val4.transform.localScale = new Vector3(0.4f, 1f, 1f); TextMeshPro obj2 = val4.AddComponent(); ((TMP_Text)obj2).fontSize = 2f; ((Graphic)obj2).color = Color.white; ((TMP_Text)obj2).alignment = (TextAlignmentOptions)514; } private static Vector3 FindLocalPlayerPos() { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)MonoSingleton.Instance != (Object)null && MonoSingleton.Instance.players != null) { foreach (PlayerReferences player in MonoSingleton.Instance.players) { if ((Object)(object)player?.identity != (Object)null && player.identity.isLocalPlayer && (Object)(object)player.transform != (Object)null) { return player.transform.position; } } } return Vector3.zero; } } public static class BlackMarketSystem { public enum Item : byte { SnitchInsurance, MobBribe, SweetTalk, BandageKit, GhostRepellent, HotStreak, LiquidCourage, LoanSharkPatience } public static readonly int[] Prices = new int[8] { 12, 15, 20, 18, 10, 22, 25, 18 }; public static readonly string[] Names = new string[8] { "Snitch Insurance", "Mob Bribe", "Sweet Talk", "Bandage Kit", "Ghost Repellent", "Hot Streak", "Liquid Courage", "Loan Shark Patience" }; public static readonly string[] Effects = new string[8] { "Next snitch against you auto-fails.", "Immune to one Hire Goons attack.", "Your next loan today is 1.0x interest.", "Instantly clears wounded penalty + refund.", "Next haunt against you fizzles.", "+25% casino payouts for the rest of the day.", "Wagers you win pay 2x today.", "Loans don't default today (no wounding)." }; public static void TryPurchase(ulong steamId, int itemId) { if (!NetworkServer.active || itemId >= Prices.Length) { return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded) { return; } PlayerLedger orCreate = instance.GetOrCreate(steamId); if (orCreate.IsDead) { return; } int num = Prices[itemId]; string text = Names[itemId]; if (orCreate.PvpTickets < num) { NetSync.BroadcastToast($"{orCreate.DisplayName} couldn't afford {text} ({orCreate.PvpTickets}/{num} tickets)."); return; } orCreate.PvpTickets -= num; switch ((Item)(byte)itemId) { case Item.SnitchInsurance: if (orCreate.BuffSnitchInsurance) { orCreate.PvpTickets += num; NetSync.BroadcastToast(orCreate.DisplayName + " already has Snitch Insurance.", ToastSeverity.Average); return; } orCreate.BuffSnitchInsurance = true; NetSync.BroadcastToast($"{orCreate.DisplayName} bought Snitch Insurance (-{num}t). Next snitch auto-fails.", ToastSeverity.Mid); break; case Item.MobBribe: if (orCreate.BuffMobBribe) { orCreate.PvpTickets += num; NetSync.BroadcastToast(orCreate.DisplayName + " already has a Mob Bribe.", ToastSeverity.Average); return; } orCreate.BuffMobBribe = true; NetSync.BroadcastToast($"{orCreate.DisplayName} bought a Mob Bribe (-{num}t). Immune to one goons hit.", ToastSeverity.Mid); break; case Item.SweetTalk: if (orCreate.BuffSweetTalk) { orCreate.PvpTickets += num; NetSync.BroadcastToast(orCreate.DisplayName + " already has Sweet Talk queued.", ToastSeverity.Average); return; } orCreate.BuffSweetTalk = true; NetSync.BroadcastToast($"{orCreate.DisplayName} bought Sweet Talk (-{num}t). Next loan at 1.0x.", ToastSeverity.Mid); break; case Item.BandageKit: { long woundedPenaltyRefund = orCreate.WoundedPenaltyRefund; if (woundedPenaltyRefund > 0) { orCreate.WoundedPenaltyRefund = 0L; MoneyManager instance2 = NetworkSingleton.Instance; if (instance2 != null) { instance2.TryChangeBalance(woundedPenaltyRefund, (PlayerProfile)null, (ChangeType)4); } orCreate.Ledger += woundedPenaltyRefund; NetSync.BroadcastToast($"{orCreate.DisplayName} patched up with a Bandage Kit (-{num}t). Clawed back ${woundedPenaltyRefund}.", ToastSeverity.Mid); break; } orCreate.PvpTickets += num; NetSync.BroadcastToast(orCreate.DisplayName + " bought a Bandage Kit but had nothing to heal. Refunded.", ToastSeverity.Average); return; } case Item.GhostRepellent: if (orCreate.BuffGhostRepellent) { orCreate.PvpTickets += num; NetSync.BroadcastToast(orCreate.DisplayName + " already has Ghost Repellent.", ToastSeverity.Average); return; } orCreate.BuffGhostRepellent = true; NetSync.BroadcastToast($"{orCreate.DisplayName} bought Ghost Repellent (-{num}t). Next haunt fizzles.", ToastSeverity.Mid); break; case Item.HotStreak: if (orCreate.BuffHotStreak) { orCreate.PvpTickets += num; NetSync.BroadcastToast(orCreate.DisplayName + " is already on a Hot Streak.", ToastSeverity.Average); return; } orCreate.BuffHotStreak = true; NetSync.BroadcastToast($"{orCreate.DisplayName} bought Hot Streak (-{num}t). +25% payouts today.", ToastSeverity.Mid); break; case Item.LiquidCourage: if (orCreate.BuffLiquidCourage) { orCreate.PvpTickets += num; NetSync.BroadcastToast(orCreate.DisplayName + " is already loaded with Liquid Courage.", ToastSeverity.Average); return; } orCreate.BuffLiquidCourage = true; NetSync.BroadcastToast($"{orCreate.DisplayName} bought Liquid Courage (-{num}t). Wagers win double today.", ToastSeverity.Mid); break; case Item.LoanSharkPatience: if (orCreate.BuffLoanShark) { orCreate.PvpTickets += num; NetSync.BroadcastToast(orCreate.DisplayName + " already paid for Patience today.", ToastSeverity.Average); return; } orCreate.BuffLoanShark = true; NetSync.BroadcastToast($"{orCreate.DisplayName} bought Loan Shark Patience (-{num}t). No defaults today.", ToastSeverity.Mid); break; } Plugin.Log.LogInfo((object)$"[BlackMarket] {orCreate.DisplayName} bought {text} for {num} tickets. Remaining tickets: {orCreate.PvpTickets}."); NetSync.BroadcastLedgerUpdate(orCreate); } } public static class BodyPartPayoutPatches { [HarmonyPatch(typeof(MoneyManager), "TryChangeBalance")] [HarmonyPrefix] public static void Reduce(ref long amount, PlayerProfile changer, ChangeType changeType) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((Object)(object)changer == (Object)null || (int)changeType != 1 || amount <= 0) { return; } ModState instance = ModState.Instance; if (!((Object)(object)instance == (Object)null) && instance.Ledgers.TryGetValue(changer.steamId, out var value) && value.BodyPartsSold > 0) { float num = Math.Max(0f, 1f - 0.1f * (float)value.BodyPartsSold); long num2 = (long)((float)amount * num); if (num2 != amount) { Plugin.Log.LogInfo((object)$"[BodyParts] {changer.playerName} (-{10 * value.BodyPartsSold}% debuff): payout {amount} -> {num2}"); amount = num2; } } } } public static class BotHudPatches { [HarmonyPatch(typeof(MoneyDisplayAndFeedbacks), "GetCurrentPlayerIds")] [HarmonyPostfix] public static void GetCurrentPlayerIds_Postfix(ref HashSet __result) { if (!Plugin.BotsEnabled.Value) { return; } if (__result == null) { __result = new HashSet(); } int num = BotSystem.BotCountInUse(); for (int i = 0; i < num; i++) { ulong botSteamId = BotSystem.GetBotSteamId(i); if (botSteamId != 0L) { __result.Add(botSteamId); } } } [HarmonyPatch(typeof(MoneyDisplayAndFeedbacks), "GetPlayerDisplayName")] [HarmonyPrefix] public static bool GetPlayerDisplayName_Prefix(ulong steamId, ref string __result) { string botName = BotSystem.GetBotName(steamId); if (botName != null) { __result = botName; return false; } return true; } } public static class BotSystem { private static readonly ulong[] BotSteamIds = new ulong[3] { 7700000000000001uL, 7700000000000002uL, 7700000000000003uL }; private static readonly string[] DefaultBotNames = new string[3] { "Vinny", "Tony", "Sal" }; private static float _nextTick = 0f; private static bool _initialized = false; public static void Init() { if (!NetworkServer.active || !Plugin.BotsEnabled.Value || _initialized) { return; } NetSync.RegisterAll(); _initialized = true; int num = Mathf.Clamp(Plugin.BotCount.Value, 1, BotSteamIds.Length); ModState instance = ModState.Instance; if (!((Object)(object)instance == (Object)null)) { for (int i = 0; i < num; i++) { string text = DefaultBotNames[i]; PlayerLedger orCreate = instance.GetOrCreate(BotSteamIds[i], text); Plugin.Log.LogInfo((object)$"[BotSystem] Spawned bot: {text} (steamId {BotSteamIds[i]})"); NetSync.BroadcastLedgerUpdate(orCreate); } NetSync.BroadcastToast($"Test bots active: {num} rival" + ((num == 1) ? "" : "s") + " — gambling, loaning, and pestering you."); } } public static void PreviewInLobby() { if (NetworkServer.active && Plugin.BotsEnabled.Value) { NetSync.RegisterAll(); int num = Mathf.Clamp(Plugin.BotCount.Value, 1, BotSteamIds.Length); string text = string.Join(", ", DefaultBotNames, 0, num); NetSync.BroadcastToast($"[Bots enabled] {num} rival" + ((num == 1) ? "" : "s") + " will join at the casino: " + text); Plugin.Log.LogInfo((object)$"[BotSystem] Lobby preview: {num} bots will spawn at casino entry."); } } public static int BotCountInUse() { return Mathf.Clamp(Plugin.BotCount.Value, 1, BotSteamIds.Length); } public static ulong GetBotSteamId(int index) { if (index < 0 || index >= BotSteamIds.Length) { return 0uL; } return BotSteamIds[index]; } public static string GetBotName(ulong steamId) { for (int i = 0; i < BotSteamIds.Length; i++) { if (BotSteamIds[i] == steamId) { return DefaultBotNames[i]; } } return null; } public static void Reset() { _initialized = false; _nextTick = 0f; } public static void Tick() { if (!NetworkServer.active || !Plugin.BotsEnabled.Value || Time.time < _nextTick) { return; } _nextTick = Time.time + Random.Range(8f, 15f); ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded) { return; } int num = Mathf.Clamp(Plugin.BotCount.Value, 1, BotSteamIds.Length); for (int i = 0; i < num; i++) { if (!instance.Ledgers.TryGetValue(BotSteamIds[i], out var value) || value.IsDead) { continue; } float value2 = Random.value; if (value2 < 0.55f) { long num2 = Random.Range(-200, 300); value.Ledger += num2; NetSync.BroadcastLedgerUpdate(value); if (num2 >= 150) { NetSync.BroadcastToast($"{value.DisplayName} hit a winner (+${num2})."); } else if (num2 <= -150) { NetSync.BroadcastToast($"{value.DisplayName} ate a bad beat (${num2})."); } } else if (value2 < 0.7f) { if (value.ActiveLoanPrincipals.Count == 0) { long num3 = LoanSystem.GetMaxLoanForCurrentDay() / 4; if (num3 >= 25) { LoanSystem.TryGrantLoan(value.SteamId, num3); } } } else if (value2 < 0.85f) { List list = new List(); foreach (PlayerLedger value3 in instance.Ledgers.Values) { if (!value3.IsDead && value3.SteamId != value.SteamId && !IsBot(value3.SteamId)) { list.Add(value3); } } if (list.Count > 0) { PlayerLedger playerLedger = list[Random.Range(0, list.Count)]; int[] stakeChoices = WagerSystem.StakeChoices; long num4 = stakeChoices[Random.Range(0, stakeChoices.Length)]; if (value.Wealth >= num4 && playerLedger.Wealth >= num4) { WagerSystem.TryWager(value.SteamId, playerLedger.SteamId, num4); } } } else { if (!(value2 < 0.95f)) { continue; } List list2 = new List(); foreach (PlayerLedger value4 in instance.Ledgers.Values) { if (!value4.IsDead && value4.SteamId != value.SteamId && !IsBot(value4.SteamId)) { list2.Add(value4); } } if (list2.Count > 0) { PlayerLedger playerLedger2 = list2[Random.Range(0, list2.Count)]; SnitchingSystem.TrySnitch(value.SteamId, playerLedger2.SteamId); } } } } public static bool IsBot(ulong steamId) { for (int i = 0; i < BotSteamIds.Length; i++) { if (BotSteamIds[i] == steamId) { return true; } } return false; } } public static class CosmeticUnlockPatches { [HarmonyPatch(typeof(CosmeticsUnlockManager), "IsCosmeticUnlocked")] [HarmonyPrefix] public static bool IsCosmeticUnlocked_Prefix(ref bool __result) { __result = true; return false; } } public static class DaySummaryPatches { private static FieldInfo _fTicketSourcesRoot; private static FieldInfo _fEntryPrefab; private static FieldInfo _fEntrySourceText; private static FieldInfo _fEntryTicketsText; private static FieldInfo _fTitleText; private static FieldInfo _fTotalTicketsText; private static FieldInfo _fQuotaText; private static FieldInfo _fBalanceText; private static FieldInfo _fProfitText; private static bool _reflectionReady; private static void EnsureReflection() { if (!_reflectionReady) { Type? typeFromHandle = typeof(DaySummaryUI); _fTicketSourcesRoot = typeFromHandle.GetField("ticketSourcesRoot", BindingFlags.Instance | BindingFlags.NonPublic); _fEntryPrefab = typeFromHandle.GetField("ticketSourceEntryPrefab", BindingFlags.Instance | BindingFlags.NonPublic); _fTitleText = typeFromHandle.GetField("titleText", BindingFlags.Instance | BindingFlags.NonPublic); _fTotalTicketsText = typeFromHandle.GetField("totalTicketsText", BindingFlags.Instance | BindingFlags.NonPublic); _fQuotaText = typeFromHandle.GetField("quotaText", BindingFlags.Instance | BindingFlags.NonPublic); _fBalanceText = typeFromHandle.GetField("balanceText", BindingFlags.Instance | BindingFlags.NonPublic); _fProfitText = typeFromHandle.GetField("profitText", BindingFlags.Instance | BindingFlags.NonPublic); Type? typeFromHandle2 = typeof(DaySummaryTicketEntry); _fEntrySourceText = typeFromHandle2.GetField("sourceText", BindingFlags.Instance | BindingFlags.NonPublic); _fEntryTicketsText = typeFromHandle2.GetField("ticketsText", BindingFlags.Instance | BindingFlags.NonPublic); _reflectionReady = true; } } [HarmonyPatch(typeof(DaySummaryUI), "Show")] [HarmonyPostfix] public static void Show_Postfix(DaySummaryUI __instance) { try { EnsureReflection(); ((MonoBehaviour)__instance).StartCoroutine(InjectPvPStandings(__instance)); } catch (Exception arg) { Plugin.Log.LogError((object)$"[DaySummaryPatches] Show postfix error: {arg}"); } } [HarmonyPatch(typeof(DaySummaryUI), "AddTicketEntry")] [HarmonyPrefix] public static bool AddTicketEntry_Prefix() { return false; } private static IEnumerator InjectPvPStandings(DaySummaryUI ui) { yield return (object)new WaitForSeconds(6.5f); ModState state = ModState.Instance; if ((Object)(object)state == (Object)null || _fTicketSourcesRoot == null || _fEntryPrefab == null) { yield break; } object? value = _fTicketSourcesRoot.GetValue(ui); Transform ticketSourcesRoot = (Transform)((value is Transform) ? value : null); object? value2 = _fEntryPrefab.GetValue(ui); DaySummaryTicketEntry prefab = (DaySummaryTicketEntry)((value2 is DaySummaryTicketEntry) ? value2 : null); if ((Object)(object)ticketSourcesRoot == (Object)null || (Object)(object)prefab == (Object)null) { yield break; } for (int num = ticketSourcesRoot.childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)ticketSourcesRoot.GetChild(num)).gameObject); } try { object? obj = _fTitleText?.GetValue(ui); TextMeshProUGUI val = (TextMeshProUGUI)((obj is TextMeshProUGUI) ? obj : null); if ((Object)(object)val != (Object)null) { GameManager instance = NetworkSingleton.Instance; int num2 = (((Object)(object)instance != (Object)null) ? (instance.daysPassed + 1) : 0); ((TMP_Text)val).text = ((num2 > 0) ? $"PvP Standings · End of Day {num2}" : "PvP Standings"); } } catch { } ApplyPvPStatBar(ui, state, alsoSwapLabels: true); List ranked = new List(); foreach (PlayerLedger value3 in state.Ledgers.Values) { if (value3.SteamId != 0L && !string.IsNullOrEmpty(value3.DisplayName) && !(value3.DisplayName == "(unknown)")) { ranked.Add(value3); } } ranked.Sort((PlayerLedger a, PlayerLedger b) => b.Wealth.CompareTo(a.Wealth)); int rank = 1; foreach (PlayerLedger item in ranked) { DaySummaryTicketEntry val2 = Object.Instantiate(prefab, ticketSourcesRoot); val2.Setup(item.DisplayName, 0); string text = (item.IsDead ? "x" : (rank switch { 1 => "1st", 2 => "2nd", 3 => "3rd", _ => $"#{rank}", })); string text2 = (item.IsDead ? (text + " " + item.DisplayName + " DEAD") : ((!item.IsWounded) ? $"{text} {item.DisplayName} ♦{item.PvpTickets}" : $"{text} {item.DisplayName} wnd ♦{item.PvpTickets}")); long num3 = item.Wealth - item.LoanPaybackOwed; string text3 = CompactDollars(num3); try { object? obj3 = _fEntrySourceText?.GetValue(val2); TextMeshProUGUI val3 = (TextMeshProUGUI)((obj3 is TextMeshProUGUI) ? obj3 : null); object? obj4 = _fEntryTicketsText?.GetValue(val2); TextMeshProUGUI val4 = (TextMeshProUGUI)((obj4 is TextMeshProUGUI) ? obj4 : null); if ((Object)(object)val3 != (Object)null) { ((TMP_Text)val3).text = text2; if (item.IsDead) { ((Graphic)val3).color = new Color(0.6f, 0.2f, 0.2f); } else { switch (rank) { case 1: ((Graphic)val3).color = new Color(1f, 0.84f, 0f); break; case 2: ((Graphic)val3).color = new Color(0.85f, 0.85f, 0.9f); break; case 3: ((Graphic)val3).color = new Color(0.8f, 0.5f, 0.2f); break; } } } if ((Object)(object)val4 != (Object)null) { ((TMP_Text)val4).text = text3; long num4 = Plugin.StartingMoney.Value; if (item.IsDead) { ((Graphic)val4).color = new Color(0.6f, 0.2f, 0.2f); } else if (num3 > num4) { ((Graphic)val4).color = new Color(0.35f, 1f, 0.45f); } else if (num3 < num4) { ((Graphic)val4).color = new Color(1f, 0.45f, 0.45f); } else { ((Graphic)val4).color = Color.white; } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[DaySummaryPatches] entry text override failed: " + ex.Message)); } rank++; yield return (object)new WaitForSeconds(0.15f); } int num5 = 0; ulong winnerSteamId = 0uL; foreach (PlayerLedger item2 in ranked) { if (!item2.IsDead) { if (num5 == 0) { winnerSteamId = item2.SteamId; } num5++; } } int survivalAward = num5 * 2; int topEarnerAward = ((winnerSteamId != 0L) ? 3 : 0); int totalAward = survivalAward + topEarnerAward; if (survivalAward > 0) { DaySummaryTicketEntry obj5 = Object.Instantiate(prefab, ticketSourcesRoot); obj5.Setup($"Survived Day {(((Object)(object)ModState.Instance != (Object)null) ? ModState.Instance.CurrentDayIndex : 0)} ({num5} survivor" + ((num5 == 1) ? "" : "s") + ")", survivalAward); obj5.SetImmediate(); TintTicketEntry(obj5, ticketYellow: true); yield return (object)new WaitForSeconds(0.2f); } if (topEarnerAward > 0) { PlayerLedger playerLedger = ranked.Find((PlayerLedger x) => x.SteamId == winnerSteamId); string text4 = ((playerLedger != null) ? playerLedger.DisplayName : "?"); DaySummaryTicketEntry obj6 = Object.Instantiate(prefab, ticketSourcesRoot); obj6.Setup("Top Earner (" + text4 + ")", topEarnerAward); obj6.SetImmediate(); TintTicketEntry(obj6, ticketYellow: true); yield return (object)new WaitForSeconds(0.2f); } if (NetworkServer.active && totalAward > 0) { MoneyManager instance2 = NetworkSingleton.Instance; if ((Object)(object)instance2 != (Object)null) { try { instance2.TryChangeTicketBalance((long)totalAward); Plugin.Log.LogInfo((object)$"[DaySummaryPatches] PvP tickets granted: {totalAward} (survival {survivalAward} + top earner {topEarnerAward})"); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("[DaySummaryPatches] TryChangeTicketBalance failed: " + ex2.Message)); } } } try { object? obj7 = _fTotalTicketsText?.GetValue(ui); TextMeshProUGUI val5 = (TextMeshProUGUI)((obj7 is TextMeshProUGUI) ? obj7 : null); if ((Object)(object)val5 != (Object)null) { MoneyManager instance3 = NetworkSingleton.Instance; ((TMP_Text)val5).text = (((Object)(object)instance3 != (Object)null) ? instance3.ticketBalance : totalAward).ToString(); } } catch { } float pollUntil = Time.time + 8f; while (Time.time < pollUntil) { ApplyPvPStatBar(ui, state, alsoSwapLabels: false); yield return (object)new WaitForSeconds(0.25f); } } private static void ApplyPvPStatBar(DaySummaryUI ui, ModState state, bool alsoSwapLabels) { try { ulong num = ResolveLocalSteamIdStatic(); PlayerLedger value = null; if (num != 0L) { state.Ledgers.TryGetValue(num, out value); } int num2 = value?.TotalLoansTaken ?? 0; int num3 = value?.TotalSabotagesUsed ?? 0; int num4 = value?.TotalWagersWon ?? 0; if (alsoSwapLabels) { TextMeshProUGUI[] componentsInChildren = ((Component)ui).GetComponentsInChildren(true); foreach (TextMeshProUGUI val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((TMP_Text)val).text)) { switch (((TMP_Text)val).text.Trim().ToUpperInvariant()) { case "QUOTA": ((TMP_Text)val).text = "LOANS"; break; case "BALANCE": ((TMP_Text)val).text = "SABOTAGES"; break; case "PROFIT": ((TMP_Text)val).text = "WAGERS WON"; break; } } } } if (_fQuotaText?.GetValue(ui) is TextMeshProUGUI[] array) { TextMeshProUGUI[] componentsInChildren = array; foreach (TextMeshProUGUI val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null) { ((TMP_Text)val2).text = num2.ToString(); } } } object? obj = _fBalanceText?.GetValue(ui); TextMeshProUGUI val3 = (TextMeshProUGUI)((obj is TextMeshProUGUI) ? obj : null); if ((Object)(object)val3 != (Object)null) { ((TMP_Text)val3).text = num3.ToString(); } object? obj2 = _fProfitText?.GetValue(ui); TextMeshProUGUI val4 = (TextMeshProUGUI)((obj2 is TextMeshProUGUI) ? obj2 : null); if ((Object)(object)val4 != (Object)null) { ((TMP_Text)val4).text = num4.ToString(); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[DaySummaryPatches] ApplyPvPStatBar failed: " + ex.Message)); } } private static void TintTicketEntry(DaySummaryTicketEntry entry, bool ticketYellow) { //IL_0049: 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) try { object? obj = _fEntrySourceText?.GetValue(entry); TextMeshProUGUI val = (TextMeshProUGUI)((obj is TextMeshProUGUI) ? obj : null); object? obj2 = _fEntryTicketsText?.GetValue(entry); TextMeshProUGUI val2 = (TextMeshProUGUI)((obj2 is TextMeshProUGUI) ? obj2 : null); if ((Object)(object)val != (Object)null) { ((Graphic)val).color = new Color(0.95f, 0.85f, 0.4f); } if ((Object)(object)val2 != (Object)null) { ((Graphic)val2).color = new Color(1f, 0.84f, 0f); } } catch { } } private static ulong ResolveLocalSteamIdStatic() { if ((Object)(object)MonoSingleton.Instance != (Object)null && MonoSingleton.Instance.players != null) { foreach (PlayerReferences player in MonoSingleton.Instance.players) { if ((Object)(object)player?.identity != (Object)null && player.identity.isLocalPlayer) { return player.profile?.steamId ?? 0; } } } return 0uL; } private static string CompactDollars(long v) { string arg = ((v < 0) ? "-" : ""); long num = Math.Abs(v); if (num >= 1000000) { return $"{arg}${num / 1000000}M"; } if (num >= 1000) { return $"{arg}${num / 1000}K"; } return $"{arg}${num}"; } } public static class EndGame { public static void TriggerEndGame() { if (!NetworkServer.active) { return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded) { return; } instance.MarkGameEnded(); Plugin.Log.LogInfo((object)"[EndGame] Triggering end-game pipeline."); foreach (PlayerLedger value2 in instance.Ledgers.Values) { if (!value2.IsDead && value2.ActiveLoanPrincipal > 0) { long loanPaybackOwed = value2.LoanPaybackOwed; long num = Math.Min(Math.Max(0L, value2.Wealth), loanPaybackOwed); value2.Ledger -= num; value2.ActiveLoanPrincipal = 0L; Plugin.Log.LogInfo((object)$"[EndGame Clawback] {value2.DisplayName}: house took ${num}."); } } List list = new List(); foreach (PlayerLedger value3 in instance.Ledgers.Values) { if (!value3.IsDead) { list.Add(value3); } } list.Sort((PlayerLedger a, PlayerLedger b) => b.Wealth.CompareTo(a.Wealth)); long num2 = 0L; foreach (PlayerLedger item in list) { num2 += Math.Max(0L, item.Wealth); } int[] array = list.Count switch { 0 => new int[0], 1 => new int[1] { 100 }, 2 => new int[2] { 60, 40 }, _ => new int[3] { 50, 30, 20 }, }; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("RESULTS|"); for (int num3 = 0; num3 < list.Count; num3++) { PlayerLedger playerLedger = list[num3]; long value = 0L; if (num3 < array.Length) { value = (long)Math.Round((double)num2 * ((double)array[num3] / 100.0)); } stringBuilder.Append(EscapeCsv(playerLedger.DisplayName)).Append(','); stringBuilder.Append(playerLedger.Wealth).Append(','); stringBuilder.Append(value).Append(','); stringBuilder.Append((num3 + 1 == 1) ? "WIN" : "PLACED"); if (num3 < list.Count - 1) { stringBuilder.Append('|'); } } foreach (PlayerLedger value4 in instance.Ledgers.Values) { if (value4.IsDead) { stringBuilder.Append('|').Append(EscapeCsv(value4.DisplayName)).Append(",0,0,DEAD"); } } string text = stringBuilder.ToString(); Plugin.Log.LogInfo((object)("[EndGame] " + text)); NetSync.BroadcastEndGame(text); EndGameUI.ShowFinalStandings(text); ModState instance2 = ModState.Instance; if ((Object)(object)instance2 != (Object)null) { ((MonoBehaviour)instance2).StartCoroutine(DelayedSceneTransition()); } } private static IEnumerator DelayedSceneTransition() { yield return (object)new WaitForSeconds(6f); try { GameManager instance = NetworkSingleton.Instance; if ((Object)(object)instance != (Object)null) { Plugin.Log.LogInfo((object)"[EndGame] Transitioning everyone to LoseStateScene for the death cutscene."); instance.ServerSetScene((GameState)2); } else { Plugin.Log.LogWarning((object)"[EndGame] GameManager not found for scene transition."); } } catch (Exception arg) { Plugin.Log.LogError((object)$"[EndGame] Scene transition failed: {arg}"); } } private static string EscapeCsv(string s) { return (s ?? "?").Replace(',', '_').Replace('|', '/'); } } public enum ToastSeverity : byte { Average, Mid, Big } public class EndGameUI : MonoBehaviour { private class Toast { public string Text; public float Until; public ToastSeverity Severity; } private static readonly Queue _toasts = new Queue(); private string _standingsPayload; private bool _showStandings; private bool _showStats; private string _currentSceneName = ""; private GUIStyle _hudStyle; private GUIStyle _toastStyle; private GUIStyle _toastBigStyle; private GUIStyle _toastMidStyle; private GUIStyle _toastAvgStyle; private GUIStyle _standingStyle; private Texture2D _solidBlack; private Texture2D _solidRedish; private bool _forceLobbyControls; private int _hauntTargetIdx; private Vector2 _statsScroll; private Texture2D _zebraTex; private Texture2D _headerBarTex; private Texture2D _colHeaderTex; private GUIStyle _statsHeaderStyle; private GUIStyle _statsColHeaderStyle; private GUIStyle _statsCellStyle; private GUIStyle _statsCurrentStyle; private GUIStyle _statsRankStyle; private Vector2 _scroll; private GUIStyle _winnerStyle; private GUIStyle _placeStyle; private GUIStyle _deadStyle; private GUIStyle _bannerStyle; private Color _gold = new Color(1f, 0.84f, 0f); private Color _silver = new Color(0.85f, 0.85f, 0.9f); private Color _bronze = new Color(0.8f, 0.5f, 0.2f); private Color _deadCol = new Color(0.6f, 0.2f, 0.2f); private Texture2D _solidDark; public static EndGameUI Instance { get; private set; } private void Update() { //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) Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (name != _currentSceneName) { _currentSceneName = name; } } private void Awake() { Instance = this; } public static void PushToast(string text) { PushToast(text, ToastSeverity.Average); } public static void PushToast(string text, ToastSeverity severity) { _toasts.Enqueue(new Toast { Text = text, Until = Time.unscaledTime + 6f, Severity = severity }); Plugin.Log.LogInfo((object)$"[Toast {severity}] {text}"); } public static ulong GetLocalSteamId() { if ((Object)(object)MonoSingleton.Instance != (Object)null && MonoSingleton.Instance.players != null) { foreach (PlayerReferences player in MonoSingleton.Instance.players) { if ((Object)(object)player?.identity != (Object)null && player.identity.isLocalPlayer) { return player.profile?.steamId ?? 0; } } } return 0uL; } public static void TriggerShake(float intensity, float duration) { if (!((Object)(object)Instance == (Object)null)) { ((MonoBehaviour)Instance).StartCoroutine(Instance.ShakeRoutine(intensity, duration)); } } private IEnumerator ShakeRoutine(float intensity, float duration) { Camera cam = Camera.main; if (!((Object)(object)cam == (Object)null)) { Vector3 origLocal = ((Component)cam).transform.localPosition; float elapsed = 0f; while (elapsed < duration) { float num = 1f - elapsed / duration; ((Component)cam).transform.localPosition = origLocal + Random.insideUnitSphere * intensity * num; elapsed += Time.deltaTime; yield return null; } ((Component)cam).transform.localPosition = origLocal; } } public static void ShowFinalStandings(string payload) { if (!((Object)(object)Instance == (Object)null)) { Instance._standingsPayload = payload; Instance._showStandings = true; } } public static void DismissStandings() { if (!((Object)(object)Instance == (Object)null)) { Instance._showStandings = false; } } private void EnsureStyles() { //IL_0014: 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_0021: 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_0036: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_00aa: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_0101: 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_0124: Expected O, but got Unknown //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0160: 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_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Expected O, but got Unknown //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) if (_hudStyle == null) { GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 16 }; val.normal.textColor = Color.white; _hudStyle = val; GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 19, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; val2.normal.textColor = Color.white; val2.richText = true; _toastStyle = val2; _toastBigStyle = new GUIStyle(GUI.skin.label) { fontSize = 38, fontStyle = (FontStyle)1, alignment = (TextAnchor)4, richText = true }; _toastBigStyle.normal.textColor = new Color(1f, 0.25f, 0.25f); _toastMidStyle = new GUIStyle(_toastBigStyle) { fontSize = 28 }; _toastMidStyle.normal.textColor = new Color(1f, 0.6f, 0.15f); _toastAvgStyle = new GUIStyle(_toastBigStyle) { fontSize = 20 }; _toastAvgStyle.normal.textColor = new Color(1f, 0.9f, 0.3f); GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = 22, alignment = (TextAnchor)4 }; val3.normal.textColor = Color.white; _standingStyle = val3; _solidBlack = MakeTex(new Color(0f, 0f, 0f, 0.65f)); _solidRedish = MakeTex(new Color(0.7f, 0.05f, 0.05f, 0.25f)); } } private void OnGUI() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Invalid comparison between Unknown and I4 //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Invalid comparison between Unknown and I4 //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Invalid comparison between Unknown and I4 //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Invalid comparison between Unknown and I4 //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Invalid comparison between Unknown and I4 //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Invalid comparison between Unknown and I4 //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Invalid comparison between Unknown and I4 //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Invalid comparison between Unknown and I4 //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Invalid comparison between Unknown and I4 //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Invalid comparison between Unknown and I4 //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Invalid comparison between Unknown and I4 //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Invalid comparison between Unknown and I4 //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Invalid comparison between Unknown and I4 //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Invalid comparison between Unknown and I4 //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Invalid comparison between Unknown and I4 //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Invalid comparison between Unknown and I4 EnsureStyles(); if ((int)Event.current.type == 4 && (int)Event.current.keyCode == 9) { _showStats = !_showStats; Event.current.Use(); } if ((int)Event.current.type == 4 && (int)Event.current.keyCode == 283) { _forceLobbyControls = !_forceLobbyControls; Event.current.Use(); } if ((int)Event.current.type == 4 && (int)Event.current.keyCode == 285) { ulong num = ResolveLocalSteamId(); if (num != 0L) { NetSync.ClientRequestDebugGrantTickets(num, 100); Plugin.Log.LogInfo((object)"[Debug] F4 pressed — requesting +100 PvP tickets."); } Event.current.Use(); } if ((int)Event.current.type == 4 && ShouldShowLobbyControls()) { KeyCode keyCode = Event.current.keyCode; if ((int)keyCode == 61 || (int)keyCode == 43 || (int)keyCode == 270) { NetSync.ClientRequestSettingsChange(Math.Min(10, Plugin.DaysPerGame.Value + 1)); Event.current.Use(); } else if ((int)keyCode == 45 || (int)keyCode == 95 || (int)keyCode == 269) { NetSync.ClientRequestSettingsChange(Math.Max(1, Plugin.DaysPerGame.Value - 1)); Event.current.Use(); } else if ((int)keyCode == 48 || (int)keyCode == 256) { NetSync.ClientRequestSettingsChange(3); Event.current.Use(); } } if ((int)Event.current.type == 4) { ModState instance = ModState.Instance; ulong num2 = ResolveLocalSteamId(); if ((Object)(object)instance != (Object)null && num2 != 0L && instance.Ledgers.TryGetValue(num2, out var value) && value.IsDead) { List list = new List(); foreach (PlayerLedger value2 in instance.Ledgers.Values) { if (!value2.IsDead && value2.SteamId != num2) { list.Add(value2); } } if (list.Count > 0) { if ((int)Event.current.keyCode == 116) { _hauntTargetIdx = (_hauntTargetIdx + 1) % list.Count; Event.current.Use(); } else if ((int)Event.current.keyCode == 104) { PlayerLedger playerLedger = list[_hauntTargetIdx % list.Count]; NetSync.ClientRequestHaunt(num2, playerLedger.SteamId); Event.current.Use(); } } } } if (_showStandings && (int)Event.current.type == 4 && (int)Event.current.keyCode == 27) { _showStandings = false; Event.current.Use(); } DrawWoundedVignette(); DrawLocalHud(); DrawOtherPlayersHud(); DrawToasts(); if (_showStats) { DrawStatsPanel(); } if (ShouldShowLobbyControls()) { DrawLobbyControls(); } DrawGhostHauntPanel(); if (_showStandings) { DrawStandings(); } } private bool ShouldShowLobbyControls() { if (_forceLobbyControls) { return true; } string text = _currentSceneName ?? ""; if (text == "CasinoScene" || text == "LoseStateScene") { return false; } if (text.StartsWith("Splash")) { return false; } ModState instance = ModState.Instance; if ((Object)(object)instance != (Object)null && (instance.CurrentDayIndex > 0 || instance.GameEnded)) { return false; } return true; } private void DrawGhostHauntPanel() { //IL_00c4: 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_0145: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null) { return; } ulong num = ResolveLocalSteamId(); if (num == 0L || !instance.Ledgers.TryGetValue(num, out var value) || !value.IsDead) { return; } List list = new List(); foreach (PlayerLedger value2 in instance.Ledgers.Values) { if (!value2.IsDead && value2.SteamId != num) { list.Add(value2); } } if (list.Count != 0) { int num2 = 320; int num3 = 110; Rect val = default(Rect); ((Rect)(ref val))..ctor((float)(Screen.width - num2 - 20), (float)(Screen.height - num3 - 20), (float)num2, (float)num3); GUI.DrawTexture(val, (Texture)(object)_solidBlack); GUI.Label(new Rect(((Rect)(ref val)).x + 12f, ((Rect)(ref val)).y + 6f, (float)(num2 - 24), 24f), "☠ GHOST MODE ☠", _hudStyle); PlayerLedger playerLedger = list[_hauntTargetIdx % list.Count]; GUI.Label(new Rect(((Rect)(ref val)).x + 12f, ((Rect)(ref val)).y + 30f, (float)(num2 - 24), 22f), "Curse target: " + playerLedger.DisplayName, _hudStyle); if (GUI.Button(new Rect(((Rect)(ref val)).x + 12f, ((Rect)(ref val)).y + 60f, 130f, 36f), "Cycle [T]")) { _hauntTargetIdx = (_hauntTargetIdx + 1) % list.Count; } if (GUI.Button(new Rect(((Rect)(ref val)).x + 160f, ((Rect)(ref val)).y + 60f, 130f, 36f), "HAUNT [H]")) { NetSync.ClientRequestHaunt(num, playerLedger.SteamId); } } } private void EnsureStatsStyles() { //IL_0014: 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_0021: 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_002f: 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_0053: Expected O, but got Unknown //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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_009d: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //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_00e9: 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_00f7: 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_010c: Expected O, but got Unknown //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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0132: 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_0147: Expected O, but got Unknown //IL_015c: 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_01a4: Unknown result type (might be due to invalid IL or missing references) if (_statsHeaderStyle == null) { GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 22, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; val.normal.textColor = new Color(1f, 0.85f, 0.4f); _statsHeaderStyle = val; GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 13, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; val2.normal.textColor = new Color(0.75f, 0.75f, 0.85f); _statsColHeaderStyle = val2; GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = 14, alignment = (TextAnchor)4 }; val3.normal.textColor = Color.white; _statsCellStyle = val3; GUIStyle val4 = new GUIStyle(GUI.skin.label) { fontSize = 16, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; val4.normal.textColor = Color.white; _statsCurrentStyle = val4; GUIStyle val5 = new GUIStyle(GUI.skin.label) { fontSize = 14, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; val5.normal.textColor = Color.white; _statsRankStyle = val5; _zebraTex = MakeTex(new Color(1f, 1f, 1f, 0.04f)); _headerBarTex = MakeTex(new Color(0.18f, 0.08f, 0.22f, 0.95f)); _colHeaderTex = MakeTex(new Color(0.05f, 0.05f, 0.1f, 0.7f)); } } private void DrawStatsPanel() { //IL_0083: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_0622: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0310: 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_0337: 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_034d: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: 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_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_055c: Unknown result type (might be due to invalid IL or missing references) //IL_0509: Unknown result type (might be due to invalid IL or missing references) //IL_0520: Unknown result type (might be due to invalid IL or missing references) //IL_05ad: Unknown result type (might be due to invalid IL or missing references) //IL_05d0: Unknown result type (might be due to invalid IL or missing references) //IL_05a6: Unknown result type (might be due to invalid IL or missing references) //IL_05ab: Unknown result type (might be due to invalid IL or missing references) ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null) { return; } EnsureStatsStyles(); int value = Plugin.DaysPerGame.Value; int num = 200; int num2 = 100; int num3 = 130; int num4 = 30; int num5 = num + value * num2 + num3; int num6 = Math.Min(Screen.width - 60, num5 + num4 * 2); int num7 = 480; Rect val = default(Rect); ((Rect)(ref val))..ctor((float)(Screen.width / 2 - num6 / 2), (float)(Screen.height / 2 - num7 / 2), (float)num6, (float)num7); GUI.DrawTexture(val, (Texture)(object)_solidBlack); GUI.DrawTexture(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, (float)num6, 48f), (Texture)(object)_headerBarTex); string text = $"♦ DAILY STATS ♦ Day {instance.CurrentDayIndex + 1} of {value} (Tab to close)"; GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 12f, (float)num6, 26f), text, _statsHeaderStyle); List list = new List(instance.Ledgers.Values); list.Sort((PlayerLedger a, PlayerLedger b) => b.Wealth.CompareTo(a.Wealth)); float num8 = ((Rect)(ref val)).y + 56f; GUI.DrawTexture(new Rect(((Rect)(ref val)).x + 10f, num8, (float)(num6 - 20), 26f), (Texture)(object)_colHeaderTex); GUI.Label(new Rect(((Rect)(ref val)).x + (float)num4, num8 + 2f, (float)num, 22f), "PLAYER", _statsColHeaderStyle); for (int num9 = 0; num9 < value; num9++) { GUI.Label(new Rect(((Rect)(ref val)).x + (float)num4 + (float)num + (float)(num9 * num2), num8 + 2f, (float)num2, 22f), $"END DAY {num9 + 1}", _statsColHeaderStyle); } GUI.Label(new Rect(((Rect)(ref val)).x + (float)num4 + (float)num + (float)(value * num2), num8 + 2f, (float)num3, 22f), "CURRENT", _statsColHeaderStyle); float num10 = num8 + 30f; float num11 = (float)num7 - (num10 - ((Rect)(ref val)).y) - 14f; Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((Rect)(ref val)).x + 10f, num10, (float)(num6 - 20), num11); Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(0f, 0f, (float)(num5 + num4), (float)(list.Count * 32 + 4)); _statsScroll = GUI.BeginScrollView(val2, _statsScroll, val3); float num12 = 0f; int num13 = 1; Color contentColor = GUI.contentColor; Color contentColor2 = default(Color); Color contentColor3 = default(Color); Color contentColor4 = default(Color); foreach (PlayerLedger item in list) { if (num13 % 2 == 0) { GUI.DrawTexture(new Rect(0f, num12, (float)(num5 + num4 - 5), 30f), (Texture)(object)_zebraTex); } string text2; if (item.IsDead) { text2 = "☠"; contentColor2 = _deadCol; } else { switch (num13) { case 1: text2 = "1st"; contentColor2 = _gold; break; case 2: text2 = "2nd"; contentColor2 = _silver; break; case 3: text2 = "3rd"; contentColor2 = _bronze; break; default: text2 = $"#{num13}"; ((Color)(ref contentColor2))..ctor(0.7f, 0.7f, 0.75f); break; } } string text3 = ""; if (item.IsDead) { text3 = " [DEAD]"; } else if (item.IsWounded) { text3 = " [WND]"; } GUI.contentColor = contentColor2; GUI.Label(new Rect((float)(num4 - 10), num12 + 4f, 40f, 22f), text2, _statsRankStyle); GUI.contentColor = (item.IsDead ? _deadCol : Color.white); GUI.Label(new Rect((float)(num4 + 34), num12 + 4f, (float)(num - 30), 22f), item.DisplayName + text3, _statsCellStyle); long num14 = Plugin.StartingMoney.Value; for (int num15 = 0; num15 < value; num15++) { int num16 = num4 + num + num15 * num2 - 10; string text4; if (num15 < item.PerDaySnapshots.Count) { long num17 = Plugin.StartingMoney.Value + item.PerDaySnapshots[num15]; long num18 = num17 - num14; text4 = $"${num17}"; if (num18 > 0) { ((Color)(ref contentColor3))..ctor(0.35f, 1f, 0.45f); } else if (num18 < 0) { ((Color)(ref contentColor3))..ctor(1f, 0.45f, 0.45f); } else { ((Color)(ref contentColor3))..ctor(0.75f, 0.75f, 0.75f); } num14 = num17; } else { text4 = "—"; ((Color)(ref contentColor3))..ctor(0.4f, 0.4f, 0.4f); } GUI.contentColor = contentColor3; GUI.Label(new Rect((float)num16, num12 + 4f, (float)num2, 22f), text4, _statsCellStyle); } long num19 = Plugin.StartingMoney.Value; if (item.IsDead) { contentColor4 = _deadCol; } else if (item.Wealth > num19) { ((Color)(ref contentColor4))..ctor(0.4f, 1f, 0.5f); } else if (item.Wealth < num19) { ((Color)(ref contentColor4))..ctor(1f, 0.5f, 0.5f); } else { contentColor4 = Color.white; } GUI.contentColor = contentColor4; GUI.Label(new Rect((float)(num4 + num + value * num2 - 10), num12 + 2f, (float)num3, 24f), $"${item.Wealth}", _statsCurrentStyle); num12 += 30f; num13++; } GUI.contentColor = contentColor; GUI.EndScrollView(); } private void DrawLobbyControls() { //IL_0024: 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_008d: 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_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) int num = 320; int num2 = 96; Rect val = default(Rect); ((Rect)(ref val))..ctor((float)(Screen.width - num - 20), 220f, (float)num, (float)num2); GUI.DrawTexture(val, (Texture)(object)_solidBlack); GUI.Label(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 6f, (float)(num - 20), 24f), "GAME SETUP (Host) — F2 hide/show", _hudStyle); GUI.Label(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 30f, (float)(num - 20), 24f), $"Days per game: {Plugin.DaysPerGame.Value} keys: + / − / 0", _hudStyle); if (GUI.Button(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 58f, 70f, 30f), "− [-]")) { NetSync.ClientRequestSettingsChange(Math.Max(1, Plugin.DaysPerGame.Value - 1)); } if (GUI.Button(new Rect(((Rect)(ref val)).x + 90f, ((Rect)(ref val)).y + 58f, 70f, 30f), "+ [=]")) { NetSync.ClientRequestSettingsChange(Math.Min(10, Plugin.DaysPerGame.Value + 1)); } if (GUI.Button(new Rect(((Rect)(ref val)).x + 180f, ((Rect)(ref val)).y + 58f, 120f, 30f), "Reset 3 [0]")) { NetSync.ClientRequestSettingsChange(3); } } private void DrawLocalHud() { //IL_003f: 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_00ad: 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_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Expected O, but got Unknown //IL_019c: 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) ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null) { return; } ulong num = ResolveLocalSteamId(); if (num != 0L && instance.Ledgers.TryGetValue(num, out var value)) { GUI.DrawTexture(new Rect(20f, 20f, 360f, 100f), (Texture)(object)_solidBlack); GUI.Label(new Rect(30f, 25f, 350f, 24f), $"DAY {instance.CurrentDayIndex + 1} / {Plugin.DaysPerGame.Value}", _hudStyle); GUI.Label(new Rect(30f, 47f, 350f, 24f), string.Format("Wealth: ${0} Ledger: {1}{2}", value.Wealth, (value.Ledger >= 0) ? "+" : "", value.Ledger), _hudStyle); string text = ((value.ActiveLoanPrincipal > 0) ? $"Loan: owe ${value.LoanPaybackOwed} (took ${value.ActiveLoanPrincipal} day {value.ActiveLoanDayIndex + 1})" : "No active loan"); if (value.IsWounded) { text += " [WOUNDED]"; } if (value.IsDead) { text = "[YOU ARE DEAD]"; } GUI.Label(new Rect(30f, 69f, 350f, 24f), text, _hudStyle); GUIStyle val = new GUIStyle(_hudStyle); val.normal.textColor = new Color(0.4f, 0.9f, 1f); val.fontStyle = (FontStyle)1; GUI.Label(new Rect(30f, 91f, 350f, 24f), $"♦ PvP Tickets: {value.PvpTickets}", val); } } private void DrawOtherPlayersHud() { //IL_00bc: 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_0198: Unknown result type (might be due to invalid IL or missing references) ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null) { return; } ulong num = ResolveLocalSteamId(); List list = new List(); foreach (PlayerLedger value in instance.Ledgers.Values) { if (value.SteamId != num) { list.Add(value); } } list.Sort((PlayerLedger a, PlayerLedger b) => b.Wealth.CompareTo(a.Wealth)); float num2 = 110f; int num3 = 0; foreach (PlayerLedger item in list) { float num4 = 48f; GUI.DrawTexture(new Rect(20f, num2, 360f, num4), (Texture)(object)_solidBlack); string text = $"#{num3 + 2} {item.DisplayName}"; if (item.IsDead) { text += " [DEAD]"; } else if (item.IsWounded) { text += " [WOUNDED]"; } GUI.Label(new Rect(30f, num2 + 4f, 350f, 22f), text, _hudStyle); string text2 = $"Wealth: ${item.Wealth}"; if (item.ActiveLoanPrincipal > 0) { text2 += $" Loan: -${item.LoanPaybackOwed}"; } GUI.Label(new Rect(30f, num2 + 24f, 350f, 22f), text2, _hudStyle); num2 += num4 + 4f; num3++; if (num3 >= 6) { break; } } } private void DrawToasts() { //IL_009f: 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_00d4: 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_010f: Unknown result type (might be due to invalid IL or missing references) float unscaledTime = Time.unscaledTime; while (_toasts.Count > 0 && _toasts.Peek().Until < unscaledTime) { _toasts.Dequeue(); } int num = 110; int num2 = 0; foreach (Toast toast in _toasts) { GUIStyle val = ((toast.Severity == ToastSeverity.Big) ? _toastBigStyle : ((toast.Severity == ToastSeverity.Mid) ? _toastMidStyle : _toastAvgStyle)); float num3 = Mathf.Clamp01(toast.Until - unscaledTime); int num4 = val.fontSize + 12; int width = Screen.width; Color color = GUI.color; GUI.color = new Color(0f, 0f, 0f, num3 * 0.85f); GUI.Label(new Rect(3f, (float)(num + 3), (float)width, (float)num4), toast.Text, val); GUI.color = new Color(1f, 1f, 1f, num3); GUI.Label(new Rect(0f, (float)num, (float)width, (float)num4), toast.Text, val); GUI.color = color; num += num4 + 4; num2++; if (num2 > 5) { break; } } } private void DrawWoundedVignette() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null) { return; } ulong num = ResolveLocalSteamId(); if (num != 0L && instance.Ledgers.TryGetValue(num, out var value) && (value.IsWounded || value.IsDead)) { GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_solidRedish); if (value.IsDead) { GUI.Label(new Rect(0f, (float)(Screen.height / 2 - 30), (float)Screen.width, 60f), "YOU ARE DEAD", _standingStyle); } } } private void EnsureStandingsStyles() { //IL_0014: 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_0021: 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_002f: 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_0045: Expected O, but got Unknown //IL_0050: 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_005d: 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_006b: 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_0080: Expected O, but got Unknown //IL_008b: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00db: 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_00f1: Expected O, but got Unknown //IL_0106: Unknown result type (might be due to invalid IL or missing references) if (_winnerStyle == null) { GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 28, fontStyle = (FontStyle)1, alignment = (TextAnchor)3 }; val.normal.textColor = _gold; _winnerStyle = val; GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 22, fontStyle = (FontStyle)1, alignment = (TextAnchor)3 }; val2.normal.textColor = Color.white; _placeStyle = val2; GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = 18, alignment = (TextAnchor)3 }; val3.normal.textColor = _deadCol; _deadStyle = val3; GUIStyle val4 = new GUIStyle(GUI.skin.label) { fontSize = 44, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; val4.normal.textColor = _gold; _bannerStyle = val4; _solidDark = MakeTex(new Color(0.05f, 0.05f, 0.08f, 0.92f)); } } private void DrawStandings() { //IL_004b: 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_0082: 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_00ef: 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_0423: Unknown result type (might be due to invalid IL or missing references) //IL_022a: 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_0243: 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_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_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: 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_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Unknown result type (might be due to invalid IL or missing references) EnsureStandingsStyles(); int num = 760; int num2 = 560; Rect val = default(Rect); ((Rect)(ref val))..ctor((float)(Screen.width / 2 - num / 2), (float)(Screen.height / 2 - num2 / 2), (float)num, (float)num2); GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_solidBlack); GUI.DrawTexture(val, (Texture)(object)_solidDark); GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 18f, (float)num, 60f), "FINAL STANDINGS", _bannerStyle); GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 72f, (float)num, 26f), "the mob has collected. the survivor is decided.", _hudStyle); if (string.IsNullOrEmpty(_standingsPayload)) { GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 110f, (float)num, 30f), "(awaiting results...)", _placeStyle); return; } string[] array = _standingsPayload.Split('|'); List<(string, string, string, string)> list = new List<(string, string, string, string)>(); string[] array2 = array; foreach (string text in array2) { if (!(text == "RESULTS") && !string.IsNullOrEmpty(text)) { string[] array3 = text.Split(','); if (array3.Length >= 4) { list.Add((array3[0], array3[1], array3[2], array3[3])); } } } float num3 = ((Rect)(ref val)).y + 120f; int num4 = 1; Rect val4 = default(Rect); foreach (var item in list) { if (item.Item4 == "DEAD") { GUI.Label(new Rect(((Rect)(ref val)).x + 40f, num3, (float)(num - 60), 36f), " ☠ " + item.Item1 + " — KILLED BY THE MOB", _deadStyle); num3 += 38f; continue; } GUIStyle val2; string text2; Color val3; switch (num4) { case 1: val2 = _winnerStyle; text2 = "WINNER"; val3 = _gold; break; case 2: val2 = _placeStyle; text2 = "2nd"; val3 = _silver; break; case 3: val2 = _placeStyle; text2 = "3rd"; val3 = _bronze; break; default: val2 = _placeStyle; text2 = $"{num4}th"; val3 = Color.gray; break; } ((Rect)(ref val4))..ctor(((Rect)(ref val)).x + 30f, num3, (float)(num - 60), (float)((num4 == 1) ? 56 : 42)); GUI.DrawTexture(val4, (Texture)(object)MakeTex(new Color(val3.r * 0.35f, val3.g * 0.35f, val3.b * 0.35f, 0.5f))); string text3 = ((num4 == 1) ? (" " + text2 + " " + item.Item1 + " · $" + item.Item2 + " · payout $" + item.Item3) : (" " + text2 + " " + item.Item1 + " $" + item.Item2 + " payout $" + item.Item3)); GUI.Label(new Rect(((Rect)(ref val4)).x + 8f, ((Rect)(ref val4)).y + 4f, ((Rect)(ref val4)).width - 16f, ((Rect)(ref val4)).height - 8f), text3, val2); num3 += (float)((num4 == 1) ? 64 : 50); num4++; } GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + (float)num2 - 36f, (float)num, 26f), "press [Esc] to dismiss", _hudStyle); } private static Texture2D MakeTex(Color c) { //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_000a: 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_0017: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, c); val.Apply(); return val; } private static ulong ResolveLocalSteamId() { if ((Object)(object)MonoSingleton.Instance != (Object)null && MonoSingleton.Instance.players != null) { foreach (PlayerReferences player in MonoSingleton.Instance.players) { if ((Object)(object)player?.identity != (Object)null && player.identity.isLocalPlayer) { return player.profile?.steamId ?? 0; } } } return 0uL; } } public static class GameFlowPatches { private static bool _endGameSent; [HarmonyPatch(typeof(GameManager), "ProgressGameRoutine")] [HarmonyPrefix] public static void StripQuotaBeforeProgress() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 if (NetworkServer.active && Plugin.StripQuota.Value) { GameManager instance = NetworkSingleton.Instance; if (!((Object)(object)instance == (Object)null) && (int)instance.state == 1 && instance.currentQuota != 0L) { Plugin.Log.LogInfo((object)$"[Quota Strip] Zeroing quota (was {instance.currentQuota}) before progress."); instance.NetworkcurrentQuota = 0L; } } } [HarmonyPatch(typeof(GameManager), "ProgressNextQuota")] [HarmonyPrefix] public static bool InterceptQuotaProgress(GameManager __instance) { if (!NetworkServer.active) { return true; } int daysPassed = __instance.daysPassed; int value = Plugin.DaysPerGame.Value; if (daysPassed >= value && !_endGameSent) { _endGameSent = true; Plugin.Log.LogInfo((object)$"[Hard Stop] {daysPassed} days played, target was {value}. Triggering end-game."); EndGame.TriggerEndGame(); return false; } return true; } [HarmonyPatch(typeof(GameManager), "LobbyInitializeRoutine")] [HarmonyPostfix] public static void ResetOnLobby() { _endGameSent = false; Plugin.Log.LogInfo((object)"[Game Flow] Lobby init — resetting end-game guard."); } } public static class HauntSystem { public const float DurationSeconds = 30f; public const float CooldownSeconds = 60f; public const float Multiplier = 0.5f; private static readonly Dictionary _hauntExpiry = new Dictionary(); private static readonly Dictionary _ghostCooldown = new Dictionary(); public static void TryHaunt(ulong ghostId, ulong targetId) { if (!NetworkServer.active) { return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded || ghostId == targetId) { return; } PlayerLedger orCreate = instance.GetOrCreate(ghostId); PlayerLedger orCreate2 = instance.GetOrCreate(targetId); if (!orCreate.IsDead) { NetSync.BroadcastToast(orCreate.DisplayName + " isn't dead — can't haunt."); return; } if (orCreate2.IsDead) { NetSync.BroadcastToast(orCreate2.DisplayName + " is already dead."); return; } if (_ghostCooldown.TryGetValue(ghostId, out var value)) { float num = Time.time - value; if (num < 60f) { NetSync.BroadcastToast($"{orCreate.DisplayName}'s ectoplasm needs {60f - num:F0}s to recharge."); return; } } if (orCreate2.BuffGhostRepellent) { orCreate2.BuffGhostRepellent = false; NetSync.BroadcastToast(orCreate2.DisplayName + "'s Ghost Repellent dispersed " + orCreate.DisplayName + "'s spirit.", ToastSeverity.Mid); NetSync.BroadcastLedgerUpdate(orCreate2); return; } _ghostCooldown[ghostId] = Time.time; _hauntExpiry[targetId] = Time.time + 30f; orCreate.PvpTickets++; Plugin.Log.LogInfo((object)$"[Haunt] {orCreate.DisplayName} (ghost) haunts {orCreate2.DisplayName} for {30f}s."); NetSync.BroadcastLedgerUpdate(orCreate); NetSync.BroadcastToast("☠\ufe0e " + orCreate.DisplayName + "'s spirit haunts " + orCreate2.DisplayName + " — their luck just curdled."); } public static bool IsHaunted(ulong steamId) { if (!_hauntExpiry.TryGetValue(steamId, out var value)) { return false; } if (Time.time >= value) { _hauntExpiry.Remove(steamId); return false; } return true; } } public static class LedgerTrackerPatches { [HarmonyPatch(typeof(MoneyManager), "AddBalance")] [HarmonyPostfix] public static void OnAdd(long amount, PlayerProfile changer, ChangeType changeType) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active) { AttributeDelta(Math.Abs(amount), changer, changeType); } } [HarmonyPatch(typeof(MoneyManager), "RemoveBalance")] [HarmonyPostfix] public static void OnRemove(long amount, PlayerProfile changer, ChangeType changeType) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active) { AttributeDelta(-Math.Abs(amount), changer, changeType); } } private static void AttributeDelta(long signedDelta, PlayerProfile changer, ChangeType changeType) { //IL_000a: 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_000f: Invalid comparison between Unknown and I4 //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)changer == (Object)null) && ((int)changeType == 0 || (int)changeType == 1)) { PlayerLedger playerLedger = ModState.Instance?.GetOrCreate(changer.steamId, changer.playerName); if (playerLedger != null && !playerLedger.IsDead) { playerLedger.Ledger += signedDelta; Plugin.Log.LogInfo((object)string.Format("[Ledger] {0}: {1}{2} ({3}) => total {4}", playerLedger.DisplayName, (signedDelta >= 0) ? "+" : "", signedDelta, changeType, playerLedger.Ledger)); NetSync.BroadcastLedgerUpdate(playerLedger); } } } } public class LoanShark : MonoBehaviour { private TextMeshPro _amountLabel; private TextMeshPro _signLabel; public long SelectedAmount { get; private set; } public void SetUI(TextMeshPro signLabel, TextMeshPro amountLabel) { _signLabel = signLabel; _amountLabel = amountLabel; RefreshLabels(); } public void RefreshLabels() { if (SelectedAmount <= 0) { int maxLoanForCurrentDay = LoanSystem.GetMaxLoanForCurrentDay(); SelectedAmount = maxLoanForCurrentDay / 4; } int maxLoanForCurrentDay2 = LoanSystem.GetMaxLoanForCurrentDay(); if (SelectedAmount > maxLoanForCurrentDay2) { SelectedAmount = maxLoanForCurrentDay2; } if ((Object)(object)_signLabel != (Object)null) { ((TMP_Text)_signLabel).text = "LOAN SHARK\nFAST CASH\nFAIR TERMS*"; } if (!((Object)(object)_amountLabel != (Object)null)) { return; } float num = Plugin.LoanInterest.Value; ModState instance = ModState.Instance; if ((Object)(object)instance != (Object)null) { ulong num2 = 0uL; NetworkConnectionToServer connection = NetworkClient.connection; NetworkIdentity val = ((connection != null) ? ((NetworkConnection)connection).identity : null); if ((Object)(object)val != (Object)null) { PlayerProfile component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { num2 = component.steamId; } } if (num2 != 0L && instance.Ledgers.TryGetValue(num2, out var value)) { num = value.NextLoanInterestRate; } } ((TMP_Text)_amountLabel).text = $"${SelectedAmount} -> Owe ${Math.Round((float)SelectedAmount * num)} ({num}x)"; } public void Cycle() { SoundManager.Play(SoundManager.Cue.Click); int maxLoanForCurrentDay = LoanSystem.GetMaxLoanForCurrentDay(); int[] array = new int[4] { maxLoanForCurrentDay / 10, maxLoanForCurrentDay / 4, maxLoanForCurrentDay / 2, maxLoanForCurrentDay }; int num = 0; for (int i = 0; i < array.Length; i++) { if (array[i] == SelectedAmount) { num = i; break; } } num = (num + 1) % array.Length; SelectedAmount = array[num]; RefreshLabels(); } private void Update() { RefreshLabels(); } public void SellPart() { ulong num = ResolveLocalSteamId(); if (num == 0L) { Plugin.Log.LogWarning((object)"[LoanShark] No local steam id for SellPart."); return; } Plugin.Log.LogInfo((object)"[LoanShark] Local player requesting body part sale for loan relief."); SoundManager.Play(SoundManager.Cue.PayBack); NetSync.ClientRequestBodyPartSale(num); } public void PayBack() { ulong num = ResolveLocalSteamId(); if (num == 0L) { Plugin.Log.LogWarning((object)"[LoanShark] No local steam id."); return; } Plugin.Log.LogInfo((object)"[LoanShark] Local player requesting loan payback."); SoundManager.Play(SoundManager.Cue.PayBack); NetSync.ClientRequestLoanPayback(num); } public void Take() { ulong num = ResolveLocalSteamId(); if (num == 0L) { Plugin.Log.LogWarning((object)"[LoanShark] Could not resolve local steam id; cannot request loan."); return; } Plugin.Log.LogInfo((object)$"[LoanShark] Local player requesting ${SelectedAmount} loan."); SoundManager.Play(SoundManager.Cue.TakeLoan); NetSync.ClientRequestLoan(num, SelectedAmount); } private static ulong ResolveLocalSteamId() { NetworkConnectionToServer connection = NetworkClient.connection; NetworkIdentity val = ((connection != null) ? ((NetworkConnection)connection).identity : null); if ((Object)(object)val != (Object)null) { PlayerProfile component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { return component.steamId; } } if ((Object)(object)MonoSingleton.Instance != (Object)null) { foreach (PlayerReferences player in MonoSingleton.Instance.players) { if ((Object)(object)player?.identity != (Object)null && player.identity.isLocalPlayer) { return player.profile?.steamId ?? 0; } } } return 0uL; } } public static class LoanSharkSpawner { private static Material _urpMat; public static IEnumerator SpawnRoutine() { yield return (object)new WaitForSeconds(3f); NetSync.RegisterAll(); if ((Object)(object)GameObject.Find("[PvP] LoanSharkKiosk") != (Object)null) { Plugin.Log.LogInfo((object)"[LoanSharkSpawner] Kiosk already exists in scene, skipping."); yield break; } Plugin.Log.LogInfo((object)"[LoanSharkSpawner] v0.2.1 spawn routine starting. Looking for nearest casino landmark..."); Vector3 playerPos = Vector3.zero; float deadline = Time.time + 8f; while (Time.time < deadline) { playerPos = FindLocalPlayerPos(); if (playerPos != Vector3.zero) { break; } yield return (object)new WaitForSeconds(0.5f); } Vector3 val = playerPos; string text = "player"; GameBase val2 = null; float num = float.MaxValue; GameBase[] array = Object.FindObjectsOfType(); foreach (GameBase val3 in array) { Vector3 val4 = ((Component)val3).transform.position - playerPos; float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; val2 = val3; } } if ((Object)(object)val2 != (Object)null) { Vector3 position = ((Component)val2).transform.position; Vector3 val5 = playerPos - position; val5.y = 0f; if (((Vector3)(ref val5)).sqrMagnitude > 0.01f) { ((Vector3)(ref val5)).Normalize(); val = position + val5 * 4f; text = ((object)val2).GetType().Name; } } if (playerPos != Vector3.zero) { val.y = playerPos.y - 1f; } Plugin.Log.LogInfo((object)$"[LoanSharkSpawner] Anchor: {text} at {val} (player at {playerPos}, dist^2 {num:F1})"); NetSync.BroadcastToast("Booths anchored to nearest game: " + text, ToastSeverity.Average); Vector3 candidate = val + new Vector3(0f, 0f, 7f); candidate = NudgeClearOfColliders(candidate); GameObject val6 = new GameObject("[PvP] LoanSharkKiosk"); val6.transform.position = candidate; val6.transform.rotation = Quaternion.Euler(0f, 180f, 0f); EnsureMaterial(); BuildKioskVisuals(val6); LoanShark shark = val6.AddComponent(); Transform obj = val6.transform.Find("Desk/AmountText"); TextMeshPro amountLabel = ((obj != null) ? ((Component)obj).GetComponent() : null); shark.SetUI(null, amountLabel); AddInteractable(val6.transform, new Vector3(-0.85f, 1.1f, -0.6f), "CycleAmount", "Change Amount", new Color(1f, 0.85f, 0.2f), delegate { shark.Cycle(); }); AddInteractable(val6.transform, new Vector3(0f, 1.1f, -0.6f), "PayBack", "Pay Back Loan", new Color(0.4f, 0.7f, 1f), delegate { shark.PayBack(); }); AddInteractable(val6.transform, new Vector3(0.85f, 1.1f, -0.6f), "TakeLoan", "Take Loan", new Color(0.2f, 0.9f, 0.2f), delegate { shark.Take(); }); AddInteractable(val6.transform, new Vector3(1.3f, 1.1f, -0.6f), "SellPart", "Sell Body Part", new Color(0.7f, 0f, 0.3f), delegate { shark.SellPart(); }); Plugin.Log.LogInfo((object)$"[LoanSharkSpawner] Kiosk placed at {val6.transform.position}."); SpawnWagerBooth(val); SpawnMobFavorsBooth(val); } private static void SpawnMobFavorsBooth(Vector3 anchor) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_002a: 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_0063: 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_00c5: 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_0128: 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_0166: 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_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0341: 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_038a: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)GameObject.Find("[PvP] MobFavorsBooth") != (Object)null)) { GameObject val = new GameObject("[PvP] MobFavorsBooth"); val.transform.position = NudgeClearOfColliders(anchor + new Vector3(3f, 0f, 7f)); val.transform.rotation = Quaternion.Euler(0f, 180f, 0f); GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val2).name = "Desk"; val2.transform.SetParent(val.transform, false); val2.transform.localPosition = new Vector3(0f, 0.5f, 0f); val2.transform.localScale = new Vector3(2.5f, 1f, 1f); ApplyMaterial(val2, new Color(0.15f, 0.15f, 0.15f, 1f)); GameObject val3 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val3).name = "Sign"; val3.transform.SetParent(val.transform, false); val3.transform.localPosition = new Vector3(0f, 2f, 0f); val3.transform.localScale = new Vector3(2.5f, 1.4f, 0.05f); ApplyMaterial(val3, new Color(0.6f, 0.05f, 0.05f, 1f), glow: true); AddPodium(val.transform, new Color(0.6f, 0.05f, 0.05f, 1f)); AddNeonStrip(val.transform, new Vector3(0f, 1.05f, -0.51f), new Vector3(2.6f, 0.05f, 0.04f), new Color(1f, 0.1f, 0.1f)); GameObject val4 = new GameObject("SignText"); val4.transform.SetParent(val3.transform, false); val4.transform.localPosition = new Vector3(0f, 0f, -0.6f); val4.transform.localScale = new Vector3(0.4f, 0.71428573f, 20f); TextMeshPro val5 = val4.AddComponent(); ((TMP_Text)val5).text = "MOB FAVORS\nSNITCH (FREE)\nSABOTAGE ($500)"; ((TMP_Text)val5).fontSize = 3f; ((Graphic)val5).color = Color.white; ((TMP_Text)val5).alignment = (TextAlignmentOptions)514; GameObject val6 = new GameObject("TargetText"); val6.transform.SetParent(val2.transform, false); val6.transform.localPosition = new Vector3(0f, 0.51f, 0f); val6.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); val6.transform.localScale = new Vector3(0.4f, 1f, 1f); TextMeshPro val7 = val6.AddComponent(); ((TMP_Text)val7).fontSize = 2f; ((Graphic)val7).color = Color.white; ((TMP_Text)val7).alignment = (TextAlignmentOptions)514; MobFavorsBooth booth = val.AddComponent(); booth.SetUI(val5, val7); AddInteractable(val.transform, new Vector3(-0.9f, 1.1f, -0.6f), "CycleTarget", "Change Target", new Color(0.5f, 0.5f, 0.5f), delegate { booth.CycleTarget(); }); AddInteractable(val.transform, new Vector3(0f, 1.1f, -0.6f), "Snitch", "Snitch", new Color(1f, 0.85f, 0.2f), delegate { booth.Snitch(); }); AddInteractable(val.transform, new Vector3(0.9f, 1.1f, -0.6f), "Sabotage", "Hire Goons", new Color(0.9f, 0.1f, 0.1f), delegate { booth.Sabotage(); }); Plugin.Log.LogInfo((object)$"[MobFavorsBoothSpawner] Booth placed at {val.transform.position}."); } } private static void SpawnWagerBooth(Vector3 anchor) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_002a: 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_0063: 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_00c5: 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_0128: 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_0166: 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) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: 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_01c1: 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_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_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_023d: 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_025c: 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_0290: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)GameObject.Find("[PvP] WagerBoothKiosk") != (Object)null)) { GameObject val = new GameObject("[PvP] WagerBoothKiosk"); val.transform.position = NudgeClearOfColliders(anchor + new Vector3(-3f, 0f, 7f)); val.transform.rotation = Quaternion.Euler(0f, 180f, 0f); GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val2).name = "Desk"; val2.transform.SetParent(val.transform, false); val2.transform.localPosition = new Vector3(0f, 0.5f, 0f); val2.transform.localScale = new Vector3(2.5f, 1f, 1f); ApplyMaterial(val2, new Color(0.1f, 0.1f, 0.4f, 1f)); GameObject val3 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val3).name = "Sign"; val3.transform.SetParent(val.transform, false); val3.transform.localPosition = new Vector3(0f, 2f, 0f); val3.transform.localScale = new Vector3(2.5f, 1.2f, 0.05f); ApplyMaterial(val3, new Color(0.3f, 0.5f, 0.8f, 1f)); GameObject val4 = new GameObject("SignText"); val4.transform.SetParent(val3.transform, false); val4.transform.localPosition = new Vector3(0f, 0f, -0.6f); val4.transform.localScale = new Vector3(0.4f, 5f / 6f, 20f); TextMeshPro val5 = val4.AddComponent(); ((TMP_Text)val5).text = "WAGER BOOTH\nCOIN FLIP 50/50"; ((TMP_Text)val5).fontSize = 4f; ((Graphic)val5).color = Color.white; ((TMP_Text)val5).alignment = (TextAlignmentOptions)514; GameObject val6 = new GameObject("TargetText"); val6.transform.SetParent(val2.transform, false); val6.transform.localPosition = new Vector3(-0.5f, 0.51f, 0f); val6.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); val6.transform.localScale = new Vector3(0.4f, 1f, 1f); TextMeshPro val7 = val6.AddComponent(); ((TMP_Text)val7).fontSize = 2f; ((Graphic)val7).color = Color.white; ((TMP_Text)val7).alignment = (TextAlignmentOptions)514; GameObject val8 = new GameObject("StakeText"); val8.transform.SetParent(val2.transform, false); val8.transform.localPosition = new Vector3(0.5f, 0.51f, 0f); val8.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); val8.transform.localScale = new Vector3(0.4f, 1f, 1f); TextMeshPro val9 = val8.AddComponent(); ((TMP_Text)val9).fontSize = 2f; ((Graphic)val9).color = Color.white; ((TMP_Text)val9).alignment = (TextAlignmentOptions)514; WagerBooth booth = val.AddComponent(); booth.SetUI(val5, val7, val9); AddInteractable(val.transform, new Vector3(-0.8f, 1.1f, -0.6f), "CycleTarget", "Change Opponent", new Color(0.4f, 0.7f, 1f), delegate { booth.CycleTarget(); }); AddInteractable(val.transform, new Vector3(0f, 1.1f, -0.6f), "CycleStake", "Change Stake", new Color(1f, 0.85f, 0.2f), delegate { booth.CycleStake(); }); AddInteractable(val.transform, new Vector3(0.8f, 1.1f, -0.6f), "Confirm", "Coin Flip!", new Color(0.2f, 0.9f, 0.2f), delegate { booth.Confirm(); }); Plugin.Log.LogInfo((object)$"[WagerBoothSpawner] Booth placed at {val.transform.position}."); } } public static void ApplyMaterialExternal(GameObject go, Color color, bool glow) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) EnsureMaterial(); ApplyMaterial(go, color, glow); } public static void EnsureMaterialExternal() { EnsureMaterial(); } public static Vector3 NudgeClearOfCollidersExternal(Vector3 candidate) { //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) return NudgeClearOfColliders(candidate); } public static void AddInteractableExternal(Transform parent, Vector3 localPos, string name, string prompt, Color color, Action onUse) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) AddInteractable(parent, localPos, name, prompt, color, onUse); } private static Vector3 NudgeClearOfColliders(Vector3 candidate) { //IL_000b: 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_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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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) int num = 5; for (int i = 0; i < num; i++) { bool flag = false; Collider[] array = Physics.OverlapBox(candidate + new Vector3(0f, 1.5f, 0f), new Vector3(1.4f, 1.3f, 0.5f), Quaternion.identity); foreach (Collider val in array) { if (!((Object)(object)val == (Object)null) && !val.isTrigger && !((Object)(object)((Component)val).GetComponentInParent() != (Object)null)) { flag = true; break; } } if (!flag) { if (i > 0) { Plugin.Log.LogInfo((object)$"[LoanSharkSpawner] Nudged spawn forward {i}m to clear obstacle."); } return candidate; } candidate += new Vector3(0f, 0f, 1f); } Plugin.Log.LogWarning((object)$"[LoanSharkSpawner] Couldn't find a clear spot after {num} attempts; using {candidate}."); return candidate; } private static void BuildKioskVisuals(GameObject root) { //IL_0039: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_00cf: 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_0126: 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_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: 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_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: 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_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_0215: Unknown result type (might be due to invalid IL or missing references) //IL_022a: 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_0249: Unknown result type (might be due to invalid IL or missing references) //IL_0253: 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) //IL_0283: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val).name = "Desk"; val.transform.SetParent(root.transform, false); val.transform.localPosition = new Vector3(0f, 0.5f, 0f); val.transform.localScale = new Vector3(2f, 1f, 1f); ApplyMaterial(val, new Color(0.4f, 0.1f, 0.1f, 1f)); AddPodium(root.transform, new Color(0.8f, 0.6f, 0.2f, 1f)); AddNeonStrip(root.transform, new Vector3(0f, 1.05f, -0.51f), new Vector3(2.1f, 0.05f, 0.04f), new Color(1f, 0.7f, 0.1f)); GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)val2).name = "Sign"; val2.transform.SetParent(root.transform, false); val2.transform.localPosition = new Vector3(0f, 2f, 0f); val2.transform.localScale = new Vector3(2f, 1.2f, 0.05f); ApplyMaterial(val2, new Color(0.8f, 0.6f, 0.2f, 1f), glow: true); GameObject val3 = new GameObject("SignText"); val3.transform.SetParent(val2.transform, false); val3.transform.localPosition = new Vector3(0f, 0f, -0.6f); val3.transform.localScale = new Vector3(0.5f, 5f / 6f, 20f); TextMeshPro obj = val3.AddComponent(); ((TMP_Text)obj).text = "LOAN SHARK\nFAST CASH\n*FAIR TERMS"; ((TMP_Text)obj).fontSize = 4f; ((Graphic)obj).color = Color.black; ((TMP_Text)obj).alignment = (TextAlignmentOptions)514; GameObject val4 = new GameObject("AmountText"); val4.transform.SetParent(val.transform, false); val4.transform.localPosition = new Vector3(0f, 0.51f, 0f); val4.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); val4.transform.localScale = new Vector3(0.5f, 1f, 1f); TextMeshPro obj2 = val4.AddComponent(); ((TMP_Text)obj2).fontSize = 2f; ((Graphic)obj2).color = Color.white; ((TMP_Text)obj2).alignment = (TextAlignmentOptions)514; } private static Vector3 FindLocalPlayerPos() { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)MonoSingleton.Instance != (Object)null && MonoSingleton.Instance.players != null) { foreach (PlayerReferences player in MonoSingleton.Instance.players) { if ((Object)(object)player?.identity != (Object)null && player.identity.isLocalPlayer && (Object)(object)player.transform != (Object)null) { return player.transform.position; } } } return Vector3.zero; } private static void EnsureMaterial() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown if (!((Object)(object)_urpMat != (Object)null)) { Shader val = Shader.Find("Universal Render Pipeline/Lit"); if ((Object)(object)val == (Object)null) { val = Shader.Find("Universal Render Pipeline/Simple Lit"); } if ((Object)(object)val == (Object)null) { val = Shader.Find("Standard"); } if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[LoanSharkSpawner] No shader found."); return; } _urpMat = new Material(val); Plugin.Log.LogInfo((object)("[LoanSharkSpawner] Using shader: " + ((Object)val).name)); } } private static void ApplyMaterial(GameObject go, Color color, bool glow = false) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_003c: 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_007c: 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) MeshRenderer component = go.GetComponent(); if ((Object)(object)component == (Object)null) { return; } if ((Object)(object)_urpMat != (Object)null) { Material val = new Material(_urpMat); if (val.HasProperty("_BaseColor")) { val.SetColor("_BaseColor", color); } if (val.HasProperty("_Color")) { val.SetColor("_Color", color); } if (glow && val.HasProperty("_EmissionColor")) { val.EnableKeyword("_EMISSION"); val.SetColor("_EmissionColor", color * 2.5f); } ((Renderer)component).material = val; } else { ((Renderer)component).material.color = color; } } private static void AddNeonStrip(Transform parent, Vector3 localPos, Vector3 localScale, Color color) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = "Neon"; obj.transform.SetParent(parent, false); obj.transform.localPosition = localPos; obj.transform.localScale = localScale; Collider component = obj.GetComponent(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } ApplyMaterial(obj, color, glow: true); } private static void AddPodium(Transform parent, Color color) { //IL_0033: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = "Podium"; obj.transform.SetParent(parent, false); obj.transform.localPosition = new Vector3(0f, 0.05f, 0f); obj.transform.localScale = new Vector3(3.2f, 0.1f, 1.6f); ApplyMaterial(obj, color * 0.4f); } private static void AddInteractable(Transform parent, Vector3 localPos, string name, string prompt, Color color, Action onUse) { //IL_0020: 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_0046: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = name; obj.transform.SetParent(parent, false); obj.transform.localPosition = localPos; obj.transform.localScale = new Vector3(0.4f, 0.4f, 0.1f); ApplyMaterial(obj, color); PvPInteractable pvPInteractable = obj.AddComponent(); pvPInteractable.InteractableName = prompt; pvPInteractable.TooltipMessage = "Press [E] to " + prompt; pvPInteractable.Action = onUse; Plugin.Log.LogInfo((object)("[LoanSharkSpawner] Bound interactable: " + name + " -> '" + prompt + "'")); } } public class PvPInteractable : MonoBehaviour, IInteractable { public Action Action; private bool _isInteractable = true; public bool IsInteractable { get { return _isInteractable; } set { _isInteractable = value; this.OnInteractableChanged?.Invoke((IInteractable)(object)this); } } public bool MeetRequirements { get; set; } = true; public bool IsBeingHovered { get; set; } public bool IsBeingHold { get; set; } public float HoldProgress { get; set; } public bool HoldInteract { get; set; } public float HoldDuration { get; set; } = 0.25f; public string TooltipMessage { get; set; } = "Press [E] to Interact"; public string InteractableName { get; set; } = "Loan Shark"; public CursorType CursorType { get; set; } = (CursorType)1; public event Action OnInteractableChanged; public void OnInteract(PlayerInteract playerInteract) { Plugin.Log.LogInfo((object)("[PvPInteractable] " + InteractableName + " OnInteract fired.")); try { Action?.Invoke(); } catch (Exception arg) { Plugin.Log.LogError((object)$"[PvPInteractable] Action error: {arg}"); } } public void ServerOnInteract(PlayerInteract playerInteract) { } public void RpcOnInteract(PlayerInteract playerInteract) { } public void OnHover(PlayerInteract playerInteract) { IsBeingHovered = true; } public void ServerOnHover(PlayerInteract playerInteract) { } public void OnHoverExit(PlayerInteract playerInteract) { IsBeingHovered = false; } public void ServerOnHoverExit(PlayerInteract playerInteract) { } public void OnHold(PlayerInteract playerInteract) { } public void ServerOnHold(PlayerInteract playerInteract) { } public void OnHoldExit(PlayerInteract playerInteract) { } public void ServerOnHoldExit(PlayerInteract playerInteract) { } } public static class LoanSystem { public const int MinLoan = 25; public const int BaseMaxLoan = 500; private static readonly string[] BodyParts = new string[4] { "an eye", "your teeth", "a finger", "a kidney" }; public static int GetMaxLoanForCurrentDay() { int num = ModState.Instance?.CurrentDayIndex ?? 0; return 500 * (int)Math.Pow(2.0, num); } public static void TryGrantLoan(ulong steamId, long requestedAmount) { if (!NetworkServer.active) { Plugin.Log.LogWarning((object)"[Loan] TryGrantLoan called on non-server"); return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded) { return; } PlayerLedger orCreate = instance.GetOrCreate(steamId, ResolveProfile(steamId)?.playerName); if (orCreate.IsDead) { Plugin.Log.LogInfo((object)("[Loan] Refused: " + orCreate.DisplayName + " is dead.")); return; } int count = orCreate.ActiveLoanPrincipals.Count; if (count >= 3) { Plugin.Log.LogInfo((object)("[Loan] " + orCreate.DisplayName + " tried a 4th loan today. The mob has had enough.")); long num = Math.Max(0L, orCreate.Wealth); if (num > 0) { MoneyManager instance2 = NetworkSingleton.Instance; if (instance2 != null) { instance2.TryChangeBalance(-num, (PlayerProfile)null, (ChangeType)4); } orCreate.Ledger -= num; } orCreate.ActiveLoanPrincipals.Clear(); orCreate.ActiveLoanInterestRates.Clear(); orCreate.ActiveLoanPrincipal = 0L; orCreate.IsDead = true; NetSync.BroadcastToast(orCreate.DisplayName + " got greedy — the mob cut them down on the spot."); NetSync.BroadcastLedgerUpdate(orCreate); return; } int maxLoanForCurrentDay = GetMaxLoanForCurrentDay(); float num2 = orCreate.NextLoanInterestRate; if (orCreate.BuffSweetTalk) { orCreate.BuffSweetTalk = false; num2 = 1f; NetSync.BroadcastToast(orCreate.DisplayName + " sweet-talked the shark — loan at 1.0x.", ToastSeverity.Mid); } long num3 = count switch { 0 => Mathf.Clamp((int)requestedAmount, 25, maxLoanForCurrentDay), 1 => (long)maxLoanForCurrentDay * 2L, _ => (long)maxLoanForCurrentDay * 5L, }; if ((Object)(object)ResolveProfile(steamId) == (Object)null) { Plugin.Log.LogWarning((object)$"[Loan] No PlayerProfile found for steamId {steamId}. Aborting."); return; } MoneyManager instance3 = NetworkSingleton.Instance; if (!((Object)(object)instance3 == (Object)null)) { instance3.TryChangeBalance(num3, (PlayerProfile)null, (ChangeType)4); orCreate.Ledger += num3; orCreate.ActiveLoanPrincipals.Add(num3); orCreate.ActiveLoanInterestRates.Add(num2); orCreate.ActiveLoanPrincipal = SumPrincipals(orCreate); orCreate.ActiveLoanDayIndex = instance.CurrentDayIndex; orCreate.LoansTakenThisDay++; orCreate.TotalLoansTaken++; Plugin.Log.LogInfo((object)$"[Loan] {orCreate.DisplayName} borrowed ${num3} @ {num2}x (stack {orCreate.ActiveLoanPrincipals.Count}/3). Total owed: ${orCreate.LoanPaybackOwed}."); NetSync.BroadcastLedgerUpdate(orCreate); NetSync.BroadcastToast($"{orCreate.DisplayName} took a ${num3} loan from the shark. Pay back ${orCreate.LoanPaybackOwed} or else."); } } public static void TrySellBodyPart(ulong steamId) { if (!NetworkServer.active) { return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded) { return; } PlayerLedger orCreate = instance.GetOrCreate(steamId); if (orCreate.IsDead) { return; } bool flag = orCreate.ActiveLoanPrincipals.Count > 0; bool flag2 = orCreate.WoundedPenaltyRefund > 0; if (!flag && !flag2) { NetSync.BroadcastToast(orCreate.DisplayName + ": nothing to fix. No active loan and no wounded penalty to claw back."); return; } if (orCreate.BodyPartsSold >= BodyParts.Length) { orCreate.IsDead = true; Plugin.Log.LogInfo((object)("[Loan] " + orCreate.DisplayName + " tried a 5th body-part sale — the shark takes everything. DEAD.")); NetSync.BroadcastToast(orCreate.DisplayName + " had nothing left to give. The shark took it all.", ToastSeverity.Big); NetSync.BroadcastShake(orCreate.SteamId, 0.6f, 0.55f); NetSync.BroadcastLedgerUpdate(orCreate); return; } string text = BodyParts[orCreate.BodyPartsSold]; orCreate.BodyPartsSold++; _ = orCreate.ActiveLoanPrincipals.Count; long loanPaybackOwed = orCreate.LoanPaybackOwed; orCreate.ActiveLoanPrincipals.Clear(); orCreate.ActiveLoanInterestRates.Clear(); orCreate.ActiveLoanPrincipal = 0L; orCreate.ActiveLoanDayIndex = -1; orCreate.LoansResolvedThisDay++; TryMarPlayer(steamId, orCreate.BodyPartsSold); int num = 10 * orCreate.BodyPartsSold; long num2 = 0L; if (flag2) { num2 = orCreate.WoundedPenaltyRefund; orCreate.WoundedPenaltyRefund = 0L; MoneyManager instance2 = NetworkSingleton.Instance; if (instance2 != null) { instance2.TryChangeBalance(num2, (PlayerProfile)null, (ChangeType)4); } orCreate.Ledger += num2; } string text2 = ((flag && num2 > 0) ? $"cleared ${loanPaybackOwed} debt + clawed back ${num2} wounded penalty" : ((!flag) ? $"clawed back ${num2} of wounded penalty" : $"cleared ${loanPaybackOwed} of debt")); Plugin.Log.LogInfo((object)$"[Loan] {orCreate.DisplayName} sold {text} — {text2}. Payouts now -{num}%."); NetSync.BroadcastToast($"{orCreate.DisplayName} sold {text} — {text2}. Casino payouts -{num}% for the rest of the match.", ToastSeverity.Big); NetSync.BroadcastShake(orCreate.SteamId, 0.45f, 0.4f); NetSync.BroadcastLedgerUpdate(orCreate); } private static void TryMarPlayer(ulong steamId, int partsSold) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown try { if ((Object)(object)MonoSingleton.Instance == (Object)null) { return; } OrganManager instance = NetworkSingleton.Instance; foreach (PlayerReferences player in MonoSingleton.Instance.players) { if ((Object)(object)player?.profile == (Object)null || player.profile.steamId != steamId) { continue; } PlayerOrgans val = (((Object)(object)player.identity != (Object)null) ? ((Component)player.identity).GetComponent() : null); if (!((Object)(object)val == (Object)null)) { bool flag = partsSold < 1; bool flag2 = partsSold < 2; if ((Object)(object)instance != (Object)null) { instance.ServerToggleOrgan(val, (OrganType)0, flag); instance.ServerToggleOrgan(val, (OrganType)3, flag2); break; } val.ServerSetBodyParts(new PlayerOrganData { leftEye = flag, rightEye = true, body = true, mouth = flag2 }); } break; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[BodyParts] Visual mar failed: " + ex.Message)); } } public static void TryPayBack(ulong steamId) { if (!NetworkServer.active) { Plugin.Log.LogWarning((object)"[Loan] TryPayBack called off-server"); return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded) { return; } PlayerLedger orCreate = instance.GetOrCreate(steamId); if (orCreate.IsDead) { return; } if (orCreate.ActiveLoanPrincipals.Count == 0) { NetSync.BroadcastToast(orCreate.DisplayName + ": no loan to pay back."); return; } long loanPaybackOwed = orCreate.LoanPaybackOwed; if (orCreate.Wealth < loanPaybackOwed) { NetSync.BroadcastToast($"{orCreate.DisplayName} can't afford the ${loanPaybackOwed} payback (clears entire stack)."); return; } MoneyManager instance2 = NetworkSingleton.Instance; if (instance2 != null) { instance2.TryChangeBalance(-loanPaybackOwed, (PlayerProfile)null, (ChangeType)4); } orCreate.Ledger -= loanPaybackOwed; int count = orCreate.ActiveLoanPrincipals.Count; orCreate.ActiveLoanPrincipals.Clear(); orCreate.ActiveLoanInterestRates.Clear(); orCreate.ActiveLoanPrincipal = 0L; orCreate.ActiveLoanDayIndex = -1; orCreate.LoansResolvedThisDay++; orCreate.PvpTickets += 2; Plugin.Log.LogInfo((object)$"[Loan] {orCreate.DisplayName} cleared loan stack ({count}). Paid ${loanPaybackOwed}. Next loan today @ {Plugin.LoanInterestDiscount.Value}x discount. (+2 PvP tickets)"); NetSync.BroadcastLedgerUpdate(orCreate); NetSync.BroadcastToast($"{orCreate.DisplayName} squared up with the shark (-${loanPaybackOwed}). Discount on next loan today."); } public static void ResolveDayEnd(int dayIndex, bool isFinalDay) { if (!NetworkServer.active) { return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null) { return; } foreach (PlayerLedger value in instance.Ledgers.Values) { if (value.IsDead || value.ActiveLoanPrincipal <= 0) { continue; } long loanPaybackOwed = value.LoanPaybackOwed; long wealth = value.Wealth; if (wealth >= loanPaybackOwed) { MoneyManager instance2 = NetworkSingleton.Instance; if (instance2 != null) { instance2.TryChangeBalance(-loanPaybackOwed, (PlayerProfile)null, (ChangeType)4); } value.Ledger -= loanPaybackOwed; value.ActiveLoanPrincipals.Clear(); value.ActiveLoanInterestRates.Clear(); Plugin.Log.LogInfo((object)$"[Loan Resolve] {value.DisplayName} paid back ${loanPaybackOwed} (owed on ${value.ActiveLoanPrincipal} principal)."); NetSync.BroadcastToast($"{value.DisplayName} repaid the loan shark ${loanPaybackOwed}."); value.ActiveLoanPrincipal = 0L; value.ActiveLoanDayIndex = -1; value.LoansResolvedThisDay++; } else if (value.BuffLoanShark) { Plugin.Log.LogInfo((object)("[Loan Resolve] " + value.DisplayName + " got a Patience extension — no default.")); NetSync.BroadcastToast(value.DisplayName + " negotiated a Patience extension. Loan rolls over.", ToastSeverity.Mid); } else { long num = Math.Max(0L, wealth); if (num > 0) { MoneyManager instance3 = NetworkSingleton.Instance; if (instance3 != null) { instance3.TryChangeBalance(-num, (PlayerProfile)null, (ChangeType)4); } value.Ledger -= num; } value.ActiveLoanPrincipals.Clear(); value.ActiveLoanInterestRates.Clear(); value.ActiveLoanPrincipal = 0L; value.ActiveLoanDayIndex = -1; if (isFinalDay) { value.IsDead = true; Plugin.Log.LogInfo((object)("[Loan Resolve] " + value.DisplayName + " DIED — defaulted on final day.")); NetSync.BroadcastToast(value.DisplayName + " couldn't pay. The mob collected. RIP."); } else { value.IsWounded = true; Plugin.Log.LogInfo((object)$"[Loan Resolve] {value.DisplayName} WOUNDED — defaulted on day {dayIndex + 1}."); NetSync.BroadcastToast(value.DisplayName + " got worked over. Wounded tomorrow: bankroll halved for the next day."); } } NetSync.BroadcastLedgerUpdate(value); } } public static long SumPrincipals(PlayerLedger l) { long num = 0L; foreach (long activeLoanPrincipal in l.ActiveLoanPrincipals) { num += activeLoanPrincipal; } return num; } private static PlayerProfile ResolveProfile(ulong steamId) { if ((Object)(object)MonoSingleton.Instance == (Object)null) { return null; } foreach (PlayerReferences player in MonoSingleton.Instance.players) { if ((Object)(object)player?.profile != (Object)null && player.profile.steamId == steamId) { return player.profile; } } return null; } } public class MobFavorsBooth : MonoBehaviour { public int TargetIdx; private TextMeshPro _signLabel; private TextMeshPro _targetLabel; public void SetUI(TextMeshPro sign, TextMeshPro target) { _signLabel = sign; _targetLabel = target; Refresh(); } public void Refresh() { if ((Object)(object)_signLabel != (Object)null) { ((TMP_Text)_signLabel).text = "MOB FAVORS\nSNITCH (FREE, RNG)\nSABOTAGE ($500)"; } List otherPlayers = GetOtherPlayers(); string text = ((otherPlayers.Count == 0) ? "(no targets)" : otherPlayers[TargetIdx % otherPlayers.Count].DisplayName); if ((Object)(object)_targetLabel != (Object)null) { ((TMP_Text)_targetLabel).text = "TARGET\n" + text; } } private void Update() { Refresh(); } public void CycleTarget() { SoundManager.Play(SoundManager.Cue.Click); List otherPlayers = GetOtherPlayers(); if (otherPlayers.Count != 0) { TargetIdx = (TargetIdx + 1) % otherPlayers.Count; Refresh(); } } public void Snitch() { SoundManager.Play(SoundManager.Cue.Click); List otherPlayers = GetOtherPlayers(); if (otherPlayers.Count != 0) { PlayerLedger playerLedger = otherPlayers[TargetIdx % otherPlayers.Count]; ulong num = ResolveLocalSteamId(); if (num != 0L) { Plugin.Log.LogInfo((object)("[MobFavorsBooth] Snitch attempt on " + playerLedger.DisplayName)); NetSync.ClientRequestSnitch(num, playerLedger.SteamId); } } } public void Sabotage() { SoundManager.Play(SoundManager.Cue.Click); List otherPlayers = GetOtherPlayers(); if (otherPlayers.Count != 0) { PlayerLedger playerLedger = otherPlayers[TargetIdx % otherPlayers.Count]; ulong num = ResolveLocalSteamId(); if (num != 0L) { Plugin.Log.LogInfo((object)("[MobFavorsBooth] Sabotage attempt on " + playerLedger.DisplayName)); NetSync.ClientRequestSabotage(num, playerLedger.SteamId); } } } private static List GetOtherPlayers() { List list = new List(); ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null) { return list; } ulong num = ResolveLocalSteamId(); foreach (PlayerLedger value in instance.Ledgers.Values) { if (value.SteamId != num && !value.IsDead) { list.Add(value); } } return list; } private static ulong ResolveLocalSteamId() { NetworkConnectionToServer connection = NetworkClient.connection; NetworkIdentity val = ((connection != null) ? ((NetworkConnection)connection).identity : null); if ((Object)(object)val == (Object)null) { return 0uL; } PlayerProfile component = ((Component)val).GetComponent(); if (!((Object)(object)component != (Object)null)) { return 0uL; } return component.steamId; } } public class PlayerLedger { public ulong SteamId; public string DisplayName = "?"; public long Ledger; public long ActiveLoanPrincipal; public int ActiveLoanDayIndex = -1; public readonly List ActiveLoanPrincipals = new List(); public readonly List ActiveLoanInterestRates = new List(); public bool IsWounded; public bool IsDead; public readonly List PerDaySnapshots = new List(); public int LoansResolvedThisDay; public int LoansTakenThisDay; public int TotalLoansTaken; public int TotalSabotagesUsed; public int TotalWagersWon; public int PvpTickets; public int BodyPartsSold; public long WoundedPenaltyRefund; public bool BuffSnitchInsurance; public bool BuffMobBribe; public bool BuffSweetTalk; public bool BuffGhostRepellent; public bool BuffHotStreak; public bool BuffLiquidCourage; public bool BuffLoanShark; public long Wealth => Plugin.StartingMoney.Value + Ledger; public float NextLoanInterestRate { get { switch (ActiveLoanPrincipals.Count) { case 0: if (LoansResolvedThisDay <= 0) { return Plugin.LoanInterest.Value; } return Plugin.LoanInterestDiscount.Value; case 1: return 2.5f; case 2: return 5f; default: return 5f; } } } public long LoanPaybackOwed { get { long num = 0L; for (int i = 0; i < ActiveLoanPrincipals.Count; i++) { num += (long)Math.Round((float)ActiveLoanPrincipals[i] * ActiveLoanInterestRates[i]); } return num; } } public float CurrentInterestMultiplier { get { if (ActiveLoanInterestRates.Count <= 0) { return NextLoanInterestRate; } return ActiveLoanInterestRates[0]; } } } public class ModState : MonoBehaviour { public readonly Dictionary Ledgers = new Dictionary(); private bool _endGameTriggered; private bool _playedCasinoSinceLastHome; private static LobbySettings _cachedLobbySettings; public static ModState Instance { get; private set; } public int CurrentDayIndex { get; private set; } public bool GameEnded { get; private set; } public bool IsServer => NetworkServer.active; public void NotePlayedInCasino() { _playedCasinoSinceLastHome = true; } public void ResetSession() { Plugin.Log.LogInfo((object)"ModState session reset."); CurrentDayIndex = 0; GameEnded = false; _endGameTriggered = false; _playedCasinoSinceLastHome = false; Ledgers.Clear(); BotSystem.Reset(); } private void Update() { HappyHourSystem.Tick(); BotSystem.Tick(); } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; Plugin.Log.LogInfo((object)"ModState online."); } public PlayerLedger GetOrCreate(ulong steamId, string displayName = null) { if (steamId == 0L) { if (!Ledgers.TryGetValue(0uL, out var value)) { value = new PlayerLedger { SteamId = 0uL, DisplayName = "(unknown)" }; Ledgers[0uL] = value; } return value; } if (string.IsNullOrEmpty(displayName) || displayName == steamId.ToString()) { string text = ResolveLobbyName(steamId); if (!string.IsNullOrEmpty(text)) { displayName = text; } } if (!Ledgers.TryGetValue(steamId, out var value2)) { value2 = new PlayerLedger { SteamId = steamId, DisplayName = (displayName ?? steamId.ToString()) }; if (Plugin.DebugStartingPvpTickets != null && Plugin.DebugStartingPvpTickets.Value > 0 && !BotSystem.IsBot(steamId)) { value2.PvpTickets = Plugin.DebugStartingPvpTickets.Value; Plugin.Log.LogInfo((object)$"[Debug] Granted {value2.PvpTickets} starting PvP tickets to {steamId}."); } Ledgers[steamId] = value2; Plugin.Log.LogInfo((object)$"Ledger created for {value2.DisplayName} ({steamId})."); } else if (!string.IsNullOrEmpty(displayName) && value2.DisplayName != displayName && !displayName.All(char.IsDigit)) { value2.DisplayName = displayName; } return value2; } public void OnHomeSceneEntered() { if (!IsServer || GameEnded) { return; } if (!_playedCasinoSinceLastHome) { Plugin.Log.LogInfo((object)"[Day] HomeScene entered but no casino day was played; ignoring."); return; } _playedCasinoSinceLastHome = false; EnsureAllPlayersTracked(); Plugin.Log.LogInfo((object)$"Day {CurrentDayIndex + 1} ended. Snapshotting ledgers and resolving loans."); LoanSystem.ResolveDayEnd(CurrentDayIndex, CurrentDayIndex >= Plugin.DaysPerGame.Value - 1); foreach (PlayerLedger value in Ledgers.Values) { value.PerDaySnapshots.Add(value.Ledger); } CurrentDayIndex++; if (CurrentDayIndex >= Plugin.DaysPerGame.Value && !_endGameTriggered) { _endGameTriggered = true; Plugin.Log.LogInfo((object)"Final day complete. Triggering end-game."); EndGame.TriggerEndGame(); } else { GrantDailyBankroll(); } } private void GrantDailyBankroll() { if (!IsServer) { return; } long num = Plugin.StartingMoney.Value * (long)Math.Pow(2.0, CurrentDayIndex); Plugin.Log.LogInfo((object)$"[Daily] Granting day-{CurrentDayIndex + 1} bankroll of ${num} to each living player."); List list = new List(); foreach (PlayerLedger value2 in Ledgers.Values) { if (!value2.IsDead) { list.Add(value2); } } list.Sort((PlayerLedger a, PlayerLedger b) => b.Wealth.CompareTo(a.Wealth)); Dictionary dictionary = new Dictionary(); for (int num2 = 0; num2 < list.Count; num2++) { dictionary[list[num2].SteamId] = num2 switch { 2 => 1, 1 => 2, 0 => 3, _ => 1, }; } foreach (PlayerLedger value3 in Ledgers.Values) { if (!value3.IsDead) { long num3 = (value3.IsWounded ? (num / 2) : num); if (value3.BodyPartsSold > 0) { num3 = (long)((float)num3 * (1f - 0.1f * (float)value3.BodyPartsSold)); } bool isWounded = value3.IsWounded; value3.Ledger += num3; value3.LoansResolvedThisDay = 0; value3.LoansTakenThisDay = 0; Plugin.Log.LogInfo((object)$"[Daily] {value3.DisplayName}: +${num3} (wounded={isWounded}) -> ledger {value3.Ledger}"); MoneyManager instance = NetworkSingleton.Instance; if (instance != null) { instance.TryChangeBalance(num3, (PlayerProfile)null, (ChangeType)4); } value3.WoundedPenaltyRefund = 0L; if (isWounded) { value3.IsWounded = false; value3.WoundedPenaltyRefund = num - num3; NetSync.BroadcastToast($"{value3.DisplayName} woke up bandaged. Bankroll halved (+${num3} instead of +${num}). Visit the shark and sell a body part today to claw it back.", ToastSeverity.Mid); } else { NetSync.BroadcastToast($"{value3.DisplayName}: +${num3} bankroll for Day {CurrentDayIndex + 1}!"); } if (value3.BodyPartsSold > 0) { int num4 = 10 * value3.BodyPartsSold; string text = ((value3.BodyPartsSold == 1) ? "part" : "parts"); NetSync.BroadcastToast($"{value3.DisplayName} is missing {value3.BodyPartsSold} body {text} — payouts -{num4}% today.", ToastSeverity.Mid); } if (value3.ActiveLoanPrincipal > 0) { NetSync.BroadcastToast($"{value3.DisplayName} still owes the shark ${value3.LoanPaybackOwed}. Get to the casino.", ToastSeverity.Mid); } value3.BuffHotStreak = false; value3.BuffLiquidCourage = false; value3.BuffLoanShark = false; if (dictionary.TryGetValue(value3.SteamId, out var value)) { value3.PvpTickets += value; Plugin.Log.LogInfo((object)$"[Tickets] {value3.DisplayName} earned {value} PvP ticket(s) from day-end rank."); } NetSync.BroadcastLedgerUpdate(value3); } } } public void EnsureAllPlayersTracked() { if ((Object)(object)MonoSingleton.Instance == (Object)null) { return; } foreach (PlayerReferences player in MonoSingleton.Instance.players) { if (!((Object)(object)player?.profile == (Object)null)) { GetOrCreate(player.profile.steamId, player.profile.playerName); } } } public static string ResolveLobbyName(ulong steamId) { if ((Object)(object)_cachedLobbySettings == (Object)null) { _cachedLobbySettings = Resources.Load("LobbySettings"); } if ((Object)(object)_cachedLobbySettings == (Object)null || _cachedLobbySettings.players == null) { return null; } return _cachedLobbySettings.GetPlayerBySteamId(steamId)?.playerName; } public void MarkGameEnded() { GameEnded = true; } } public static class NetSync { public struct LoanRequestMessage : NetworkMessage { public ulong SteamId; public long Amount; } public struct LedgerUpdateMessage : NetworkMessage { public ulong SteamId; public string DisplayName; public long Ledger; public long ActiveLoanPrincipal; public int ActiveLoanDayIndex; public byte Flags; public int TotalLoansTaken; public int TotalSabotagesUsed; public int TotalWagersWon; public int PvpTickets; public int BodyPartsSold; public long WoundedPenaltyRefund; public byte BuffFlags; } public struct ToastMessage : NetworkMessage { public string Text; public byte Severity; } public struct ShakeMessage : NetworkMessage { public ulong TargetSteamId; public float Intensity; public float Duration; } public struct EndGameMessage : NetworkMessage { public string Payload; } public struct WagerRequestMessage : NetworkMessage { public ulong ChallengerSteamId; public ulong TargetSteamId; public long Stake; } public struct SettingsSyncMessage : NetworkMessage { public int DaysPerGame; } public struct SabotageRequestMessage : NetworkMessage { public ulong AttackerSteamId; public ulong TargetSteamId; } public struct SnitchRequestMessage : NetworkMessage { public ulong SnitchSteamId; public ulong TargetSteamId; } public struct LoanPaybackRequestMessage : NetworkMessage { public ulong SteamId; } public struct BodyPartSaleRequestMessage : NetworkMessage { public ulong SteamId; } public struct BlackMarketPurchaseRequestMessage : NetworkMessage { public ulong SteamId; public int ItemId; } public struct DebugGrantTicketsRequestMessage : NetworkMessage { public ulong SteamId; public int Amount; } public struct HauntRequestMessage : NetworkMessage { public ulong GhostSteamId; public ulong TargetSteamId; } private static bool _registered; public static void RegisterAll() { if (!_registered) { _registered = true; Writer.write = delegate(NetworkWriter w, LoanRequestMessage m) { NetworkWriterExtensions.WriteULong(w, m.SteamId); NetworkWriterExtensions.WriteLong(w, m.Amount); }; Reader.read = (NetworkReader r) => new LoanRequestMessage { SteamId = NetworkReaderExtensions.ReadULong(r), Amount = NetworkReaderExtensions.ReadLong(r) }; Writer.write = delegate(NetworkWriter w, LedgerUpdateMessage m) { NetworkWriterExtensions.WriteULong(w, m.SteamId); NetworkWriterExtensions.WriteString(w, m.DisplayName ?? ""); NetworkWriterExtensions.WriteLong(w, m.Ledger); NetworkWriterExtensions.WriteLong(w, m.ActiveLoanPrincipal); NetworkWriterExtensions.WriteInt(w, m.ActiveLoanDayIndex); w.WriteByte(m.Flags); NetworkWriterExtensions.WriteInt(w, m.TotalLoansTaken); NetworkWriterExtensions.WriteInt(w, m.TotalSabotagesUsed); NetworkWriterExtensions.WriteInt(w, m.TotalWagersWon); NetworkWriterExtensions.WriteInt(w, m.PvpTickets); NetworkWriterExtensions.WriteInt(w, m.BodyPartsSold); NetworkWriterExtensions.WriteLong(w, m.WoundedPenaltyRefund); w.WriteByte(m.BuffFlags); }; Reader.read = (NetworkReader r) => new LedgerUpdateMessage { SteamId = NetworkReaderExtensions.ReadULong(r), DisplayName = NetworkReaderExtensions.ReadString(r), Ledger = NetworkReaderExtensions.ReadLong(r), ActiveLoanPrincipal = NetworkReaderExtensions.ReadLong(r), ActiveLoanDayIndex = NetworkReaderExtensions.ReadInt(r), Flags = r.ReadByte(), TotalLoansTaken = NetworkReaderExtensions.ReadInt(r), TotalSabotagesUsed = NetworkReaderExtensions.ReadInt(r), TotalWagersWon = NetworkReaderExtensions.ReadInt(r), PvpTickets = NetworkReaderExtensions.ReadInt(r), BodyPartsSold = NetworkReaderExtensions.ReadInt(r), WoundedPenaltyRefund = NetworkReaderExtensions.ReadLong(r), BuffFlags = r.ReadByte() }; Writer.write = delegate(NetworkWriter w, ToastMessage m) { NetworkWriterExtensions.WriteString(w, m.Text ?? ""); w.WriteByte(m.Severity); }; Reader.read = (NetworkReader r) => new ToastMessage { Text = NetworkReaderExtensions.ReadString(r), Severity = r.ReadByte() }; Writer.write = delegate(NetworkWriter w, ShakeMessage m) { NetworkWriterExtensions.WriteULong(w, m.TargetSteamId); NetworkWriterExtensions.WriteFloat(w, m.Intensity); NetworkWriterExtensions.WriteFloat(w, m.Duration); }; Reader.read = (NetworkReader r) => new ShakeMessage { TargetSteamId = NetworkReaderExtensions.ReadULong(r), Intensity = NetworkReaderExtensions.ReadFloat(r), Duration = NetworkReaderExtensions.ReadFloat(r) }; Writer.write = delegate(NetworkWriter w, EndGameMessage m) { NetworkWriterExtensions.WriteString(w, m.Payload ?? ""); }; Reader.read = (NetworkReader r) => new EndGameMessage { Payload = NetworkReaderExtensions.ReadString(r) }; Writer.write = delegate(NetworkWriter w, WagerRequestMessage m) { NetworkWriterExtensions.WriteULong(w, m.ChallengerSteamId); NetworkWriterExtensions.WriteULong(w, m.TargetSteamId); NetworkWriterExtensions.WriteLong(w, m.Stake); }; Reader.read = (NetworkReader r) => new WagerRequestMessage { ChallengerSteamId = NetworkReaderExtensions.ReadULong(r), TargetSteamId = NetworkReaderExtensions.ReadULong(r), Stake = NetworkReaderExtensions.ReadLong(r) }; Writer.write = delegate(NetworkWriter w, SettingsSyncMessage m) { NetworkWriterExtensions.WriteInt(w, m.DaysPerGame); }; Reader.read = (NetworkReader r) => new SettingsSyncMessage { DaysPerGame = NetworkReaderExtensions.ReadInt(r) }; Writer.write = delegate(NetworkWriter w, SabotageRequestMessage m) { NetworkWriterExtensions.WriteULong(w, m.AttackerSteamId); NetworkWriterExtensions.WriteULong(w, m.TargetSteamId); }; Reader.read = (NetworkReader r) => new SabotageRequestMessage { AttackerSteamId = NetworkReaderExtensions.ReadULong(r), TargetSteamId = NetworkReaderExtensions.ReadULong(r) }; Writer.write = delegate(NetworkWriter w, SnitchRequestMessage m) { NetworkWriterExtensions.WriteULong(w, m.SnitchSteamId); NetworkWriterExtensions.WriteULong(w, m.TargetSteamId); }; Reader.read = (NetworkReader r) => new SnitchRequestMessage { SnitchSteamId = NetworkReaderExtensions.ReadULong(r), TargetSteamId = NetworkReaderExtensions.ReadULong(r) }; Writer.write = delegate(NetworkWriter w, LoanPaybackRequestMessage m) { NetworkWriterExtensions.WriteULong(w, m.SteamId); }; Reader.read = (NetworkReader r) => new LoanPaybackRequestMessage { SteamId = NetworkReaderExtensions.ReadULong(r) }; Writer.write = delegate(NetworkWriter w, HauntRequestMessage m) { NetworkWriterExtensions.WriteULong(w, m.GhostSteamId); NetworkWriterExtensions.WriteULong(w, m.TargetSteamId); }; Reader.read = (NetworkReader r) => new HauntRequestMessage { GhostSteamId = NetworkReaderExtensions.ReadULong(r), TargetSteamId = NetworkReaderExtensions.ReadULong(r) }; Writer.write = delegate(NetworkWriter w, BodyPartSaleRequestMessage m) { NetworkWriterExtensions.WriteULong(w, m.SteamId); }; Reader.read = (NetworkReader r) => new BodyPartSaleRequestMessage { SteamId = NetworkReaderExtensions.ReadULong(r) }; Writer.write = delegate(NetworkWriter w, BlackMarketPurchaseRequestMessage m) { NetworkWriterExtensions.WriteULong(w, m.SteamId); NetworkWriterExtensions.WriteInt(w, m.ItemId); }; Reader.read = (NetworkReader r) => new BlackMarketPurchaseRequestMessage { SteamId = NetworkReaderExtensions.ReadULong(r), ItemId = NetworkReaderExtensions.ReadInt(r) }; Writer.write = delegate(NetworkWriter w, DebugGrantTicketsRequestMessage m) { NetworkWriterExtensions.WriteULong(w, m.SteamId); NetworkWriterExtensions.WriteInt(w, m.Amount); }; Reader.read = (NetworkReader r) => new DebugGrantTicketsRequestMessage { SteamId = NetworkReaderExtensions.ReadULong(r), Amount = NetworkReaderExtensions.ReadInt(r) }; if (NetworkServer.active) { NetworkServer.RegisterHandler((Action)OnServerLoanRequest, false); NetworkServer.RegisterHandler((Action)OnServerWagerRequest, false); NetworkServer.RegisterHandler((Action)OnServerSettingsChange, false); NetworkServer.RegisterHandler((Action)OnServerSabotageRequest, false); NetworkServer.RegisterHandler((Action)OnServerSnitchRequest, false); NetworkServer.RegisterHandler((Action)OnServerLoanPaybackRequest, false); NetworkServer.RegisterHandler((Action)OnServerBodyPartSaleRequest, false); NetworkServer.RegisterHandler((Action)OnServerBlackMarketPurchase, false); NetworkServer.RegisterHandler((Action)OnServerDebugGrantTickets, false); NetworkServer.RegisterHandler((Action)OnServerHauntRequest, false); Plugin.Log.LogInfo((object)"[NetSync] Server handlers registered."); } if (NetworkClient.active) { NetworkClient.RegisterHandler((Action)OnClientLedgerUpdate, true); NetworkClient.RegisterHandler((Action)OnClientShake, true); NetworkClient.RegisterHandler((Action)OnClientToast, true); NetworkClient.RegisterHandler((Action)OnClientEndGame, true); NetworkClient.RegisterHandler((Action)OnClientSettingsSync, true); Plugin.Log.LogInfo((object)"[NetSync] Client handlers registered."); } } } private static ulong ResolveSenderSteamId(NetworkConnectionToClient conn, ulong claimed) { if (claimed != 0L) { return claimed; } if (conn == null) { return 0uL; } NetworkIdentity identity = ((NetworkConnection)conn).identity; if ((Object)(object)identity == (Object)null) { return 0uL; } PlayerProfile component = ((Component)identity).GetComponent(); if ((Object)(object)component != (Object)null && component.steamId != 0L) { return component.steamId; } if ((Object)(object)MonoSingleton.Instance != (Object)null) { foreach (PlayerReferences player in MonoSingleton.Instance.players) { if ((Object)(object)player?.identity != (Object)null && (Object)(object)player.identity == (Object)(object)identity) { return player.profile?.steamId ?? 0; } } } return 0uL; } private static void OnServerLoanRequest(NetworkConnectionToClient conn, LoanRequestMessage msg) { Plugin.Log.LogInfo((object)$"[NetSync] Loan request: steamId={msg.SteamId} amount={msg.Amount}"); LoanSystem.TryGrantLoan(ResolveSenderSteamId(conn, msg.SteamId), msg.Amount); } private static void OnServerWagerRequest(NetworkConnectionToClient conn, WagerRequestMessage msg) { Plugin.Log.LogInfo((object)$"[NetSync] Wager request: {msg.ChallengerSteamId} vs {msg.TargetSteamId} stake={msg.Stake}"); WagerSystem.TryWager(ResolveSenderSteamId(conn, msg.ChallengerSteamId), msg.TargetSteamId, msg.Stake); } private static void OnServerSettingsChange(NetworkConnectionToClient conn, SettingsSyncMessage msg) { int num = Mathf.Clamp(msg.DaysPerGame, 1, 10); Plugin.StripQuota.Value = true; Plugin.DaysPerGame.Value = num; Plugin.Log.LogInfo((object)$"[NetSync] Settings changed: DaysPerGame={num}"); BroadcastSettings(); } private static void OnServerSabotageRequest(NetworkConnectionToClient conn, SabotageRequestMessage msg) { Plugin.Log.LogInfo((object)$"[NetSync] Sabotage request: {msg.AttackerSteamId} -> {msg.TargetSteamId}"); SabotageSystem.TrySabotage(ResolveSenderSteamId(conn, msg.AttackerSteamId), msg.TargetSteamId); } private static void OnServerSnitchRequest(NetworkConnectionToClient conn, SnitchRequestMessage msg) { Plugin.Log.LogInfo((object)$"[NetSync] Snitch request: {msg.SnitchSteamId} -> {msg.TargetSteamId}"); SnitchingSystem.TrySnitch(ResolveSenderSteamId(conn, msg.SnitchSteamId), msg.TargetSteamId); } private static void OnServerLoanPaybackRequest(NetworkConnectionToClient conn, LoanPaybackRequestMessage msg) { Plugin.Log.LogInfo((object)$"[NetSync] Loan payback request: {msg.SteamId}"); LoanSystem.TryPayBack(ResolveSenderSteamId(conn, msg.SteamId)); } private static void OnServerBodyPartSaleRequest(NetworkConnectionToClient conn, BodyPartSaleRequestMessage msg) { Plugin.Log.LogInfo((object)$"[NetSync] Body part sale request: {msg.SteamId}"); LoanSystem.TrySellBodyPart(ResolveSenderSteamId(conn, msg.SteamId)); } private static void OnServerBlackMarketPurchase(NetworkConnectionToClient conn, BlackMarketPurchaseRequestMessage msg) { Plugin.Log.LogInfo((object)$"[NetSync] Black Market purchase: steamId={msg.SteamId} item={msg.ItemId}"); BlackMarketSystem.TryPurchase(ResolveSenderSteamId(conn, msg.SteamId), msg.ItemId); } private static void OnServerDebugGrantTickets(NetworkConnectionToClient conn, DebugGrantTicketsRequestMessage msg) { if (Plugin.DebugStartingPvpTickets == null || Plugin.DebugStartingPvpTickets.Value <= 0) { Plugin.Log.LogWarning((object)"[NetSync] Debug grant rejected — DebugStartingPvpTickets is 0."); return; } ulong num = ResolveSenderSteamId(conn, msg.SteamId); if (num != 0L) { ModState instance = ModState.Instance; if (!((Object)(object)instance == (Object)null)) { PlayerLedger orCreate = instance.GetOrCreate(num); orCreate.PvpTickets += msg.Amount; Plugin.Log.LogInfo((object)$"[Debug] Granted +{msg.Amount} PvP tickets to {orCreate.DisplayName}. Total: {orCreate.PvpTickets}."); BroadcastToast($"[Debug] {orCreate.DisplayName} +{msg.Amount} PvP tickets (total {orCreate.PvpTickets}).", ToastSeverity.Mid); BroadcastLedgerUpdate(orCreate); } } } private static void OnServerHauntRequest(NetworkConnectionToClient conn, HauntRequestMessage msg) { Plugin.Log.LogInfo((object)$"[NetSync] Haunt request: {msg.GhostSteamId} -> {msg.TargetSteamId}"); HauntSystem.TryHaunt(ResolveSenderSteamId(conn, msg.GhostSteamId), msg.TargetSteamId); } private static void OnClientLedgerUpdate(LedgerUpdateMessage msg) { PlayerLedger playerLedger = ModState.Instance?.GetOrCreate(msg.SteamId, msg.DisplayName); if (playerLedger != null) { playerLedger.Ledger = msg.Ledger; playerLedger.ActiveLoanPrincipal = msg.ActiveLoanPrincipal; playerLedger.ActiveLoanDayIndex = msg.ActiveLoanDayIndex; playerLedger.IsWounded = (msg.Flags & 1) != 0; playerLedger.IsDead = (msg.Flags & 2) != 0; playerLedger.TotalLoansTaken = msg.TotalLoansTaken; playerLedger.TotalSabotagesUsed = msg.TotalSabotagesUsed; playerLedger.TotalWagersWon = msg.TotalWagersWon; playerLedger.PvpTickets = msg.PvpTickets; playerLedger.BodyPartsSold = msg.BodyPartsSold; playerLedger.WoundedPenaltyRefund = msg.WoundedPenaltyRefund; UnpackBuffs(msg.BuffFlags, playerLedger); } } private static byte PackBuffs(PlayerLedger l) { byte b = 0; if (l.BuffSnitchInsurance) { b |= 1; } if (l.BuffMobBribe) { b |= 2; } if (l.BuffSweetTalk) { b |= 4; } if (l.BuffGhostRepellent) { b |= 8; } if (l.BuffHotStreak) { b |= 0x10; } if (l.BuffLiquidCourage) { b |= 0x20; } if (l.BuffLoanShark) { b |= 0x40; } return b; } private static void UnpackBuffs(byte b, PlayerLedger l) { l.BuffSnitchInsurance = (b & 1) != 0; l.BuffMobBribe = (b & 2) != 0; l.BuffSweetTalk = (b & 4) != 0; l.BuffGhostRepellent = (b & 8) != 0; l.BuffHotStreak = (b & 0x10) != 0; l.BuffLiquidCourage = (b & 0x20) != 0; l.BuffLoanShark = (b & 0x40) != 0; } private static void OnClientShake(ShakeMessage msg) { ulong localSteamId = EndGameUI.GetLocalSteamId(); if (localSteamId != 0L && localSteamId == msg.TargetSteamId) { EndGameUI.TriggerShake(msg.Intensity, msg.Duration); } } private static void OnClientToast(ToastMessage msg) { EndGameUI.PushToast(msg.Text, (ToastSeverity)msg.Severity); string text = msg.Text ?? string.Empty; if (text.Contains("WAGER:") && text.EndsWith("wins!")) { SoundManager.Play(SoundManager.Cue.WagerWin); } else if (text.Contains("hired goons")) { SoundManager.Play(SoundManager.Cue.Sabotage); } else if (text.Contains("snitch") || text.Contains("Snitch")) { SoundManager.Play(SoundManager.Cue.SnitchSuccess); } else if (text.Contains("didn't buy")) { SoundManager.Play(SoundManager.Cue.SnitchFail); } else if (text.Contains("HAPPY HOUR")) { SoundManager.Play(SoundManager.Cue.HappyHourStart); } else if (text.Contains("RIP")) { SoundManager.Play(SoundManager.Cue.Death); } } private static void OnClientSettingsSync(SettingsSyncMessage msg) { Plugin.DaysPerGame.Value = msg.DaysPerGame; Plugin.Log.LogInfo((object)$"[NetSync] Received settings sync: DaysPerGame={msg.DaysPerGame}"); } private static void OnClientEndGame(EndGameMessage msg) { EndGameUI.ShowFinalStandings(msg.Payload); } public static void BroadcastLedgerUpdate(PlayerLedger ledger) { if (NetworkServer.active) { byte b = 0; if (ledger.IsWounded) { b |= 1; } if (ledger.IsDead) { b |= 2; } NetworkServer.SendToAll(new LedgerUpdateMessage { SteamId = ledger.SteamId, DisplayName = ledger.DisplayName, Ledger = ledger.Ledger, ActiveLoanPrincipal = ledger.ActiveLoanPrincipal, ActiveLoanDayIndex = ledger.ActiveLoanDayIndex, Flags = b, TotalLoansTaken = ledger.TotalLoansTaken, TotalSabotagesUsed = ledger.TotalSabotagesUsed, TotalWagersWon = ledger.TotalWagersWon, PvpTickets = ledger.PvpTickets, BodyPartsSold = ledger.BodyPartsSold, WoundedPenaltyRefund = ledger.WoundedPenaltyRefund, BuffFlags = PackBuffs(ledger) }, 0, false); PushLedgerToBaseHUD(ledger); } } public static void PushLedgerToBaseHUD(PlayerLedger ledger) { if (!NetworkServer.active) { return; } MoneyDisplayAndFeedbacks instance = NetworkSingleton.Instance; if ((Object)(object)instance == (Object)null) { return; } try { ((SyncIDictionary)(object)instance.PlayerProfitHistory)[ledger.SteamId] = ledger.Ledger - ledger.LoanPaybackOwed; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[NetSync] PushLedgerToBaseHUD failed: " + ex.Message)); } } public static void BroadcastToast(string text) { BroadcastToast(text, ToastSeverity.Average); } public static void BroadcastToast(string text, ToastSeverity severity) { if (NetworkServer.active) { NetworkServer.SendToAll(new ToastMessage { Text = text, Severity = (byte)severity }, 0, false); } } public static void BroadcastShake(ulong targetSteamId, float intensity, float duration) { if (NetworkServer.active) { NetworkServer.SendToAll(new ShakeMessage { TargetSteamId = targetSteamId, Intensity = intensity, Duration = duration }, 0, false); } } public static void BroadcastEndGame(string payload) { if (NetworkServer.active) { NetworkServer.SendToAll(new EndGameMessage { Payload = payload }, 0, false); } } public static void ClientRequestLoan(ulong steamId, long amount) { if (NetworkClient.active) { NetworkClient.Send(new LoanRequestMessage { SteamId = steamId, Amount = amount }, 0); } } public static void ClientRequestWager(ulong challenger, ulong target, long stake) { if (NetworkClient.active) { NetworkClient.Send(new WagerRequestMessage { ChallengerSteamId = challenger, TargetSteamId = target, Stake = stake }, 0); } } public static void ClientRequestSabotage(ulong attacker, ulong target) { if (NetworkClient.active) { NetworkClient.Send(new SabotageRequestMessage { AttackerSteamId = attacker, TargetSteamId = target }, 0); } } public static void ClientRequestSnitch(ulong snitch, ulong target) { if (NetworkClient.active) { NetworkClient.Send(new SnitchRequestMessage { SnitchSteamId = snitch, TargetSteamId = target }, 0); } } public static void ClientRequestLoanPayback(ulong steamId) { if (NetworkClient.active) { NetworkClient.Send(new LoanPaybackRequestMessage { SteamId = steamId }, 0); } } public static void ClientRequestBodyPartSale(ulong steamId) { if (NetworkClient.active) { NetworkClient.Send(new BodyPartSaleRequestMessage { SteamId = steamId }, 0); } } public static void ClientRequestBlackMarketPurchase(ulong steamId, int itemId) { if (NetworkClient.active) { NetworkClient.Send(new BlackMarketPurchaseRequestMessage { SteamId = steamId, ItemId = itemId }, 0); } } public static void ClientRequestDebugGrantTickets(ulong steamId, int amount) { if (NetworkClient.active) { NetworkClient.Send(new DebugGrantTicketsRequestMessage { SteamId = steamId, Amount = amount }, 0); } } public static void ClientRequestHaunt(ulong ghost, ulong target) { if (NetworkClient.active) { NetworkClient.Send(new HauntRequestMessage { GhostSteamId = ghost, TargetSteamId = target }, 0); } } public static void ClientRequestSettingsChange(int daysPerGame) { if (NetworkClient.active) { NetworkClient.Send(new SettingsSyncMessage { DaysPerGame = daysPerGame }, 0); } } public static void BroadcastSettings() { if (NetworkServer.active) { NetworkServer.SendToAll(new SettingsSyncMessage { DaysPerGame = Plugin.DaysPerGame.Value }, 0, false); } } } public static class PhoneBoothPatches { private static readonly HashSet _autoAnsweredIds = new HashSet(); private static MethodInfo _serverFirstInteraction; [HarmonyPatch(typeof(PhoneBooth), "Update")] [HarmonyPostfix] public static void Update_Postfix(PhoneBooth __instance) { if (NetworkServer.active) { int instanceID = ((Object)__instance).GetInstanceID(); if (!_autoAnsweredIds.Contains(instanceID)) { _autoAnsweredIds.Add(instanceID); ((MonoBehaviour)__instance).StartCoroutine(DelayedAutoAnswer(__instance)); } } } private static IEnumerator DelayedAutoAnswer(PhoneBooth phone) { yield return (object)new WaitForSeconds(1f); if ((Object)(object)phone == (Object)null) { yield break; } if (_serverFirstInteraction == null) { _serverFirstInteraction = typeof(PhoneBooth).GetMethod("ServerFirstInteraction", BindingFlags.Instance | BindingFlags.NonPublic); } try { _serverFirstInteraction?.Invoke(phone, null); Plugin.Log.LogInfo((object)"[PhoneBoothPatches] Auto-answered phone — vehicle doors should open."); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[PhoneBoothPatches] Auto-answer failed: " + ex.Message)); } } public static void ResetDedupe() { _autoAnsweredIds.Clear(); } } [BepInPlugin("com.chals.gamblepvp", "Gamble PvP", "0.6.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.chals.gamblepvp"; public const string PluginName = "Gamble PvP"; public const string PluginVersion = "0.6.0"; public static ConfigEntry LoanInterest; public static ConfigEntry LoanInterestDiscount; public static ConfigEntry StartingMoney; public static ConfigEntry DaysPerGame; public static ConfigEntry WoundedBetCapPerTx; public static ConfigEntry StripQuota; public static ConfigEntry BotsEnabled; public static ConfigEntry BotCount; public static ConfigEntry DebugStartingPvpTickets; public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } public static Harmony Harmony { get; private set; } private void Awake() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; Harmony = new Harmony("com.chals.gamblepvp"); Log.LogInfo((object)"[Gamble PvP] v0.6.0 loading..."); LoanInterest = ((BaseUnityPlugin)this).Config.Bind("Loans", "InterestMultiplier", 1.5f, "Repayment multiplier for first loan of the day."); LoanInterestDiscount = ((BaseUnityPlugin)this).Config.Bind("Loans", "InterestMultiplierAfterPayback", 1.25f, "Repayment multiplier for subsequent same-day loans (good-customer discount)."); StartingMoney = ((BaseUnityPlugin)this).Config.Bind("Game", "StartingMoneyPerPlayer", 1000, "Starting stake per player."); DaysPerGame = ((BaseUnityPlugin)this).Config.Bind("Game", "DaysPerGame", 3, "Days before game ends."); WoundedBetCapPerTx = ((BaseUnityPlugin)this).Config.Bind("Wounded", "MaxLossPerTxWhenWounded", 50, "Wounded bet cap (approx)."); StripQuota = ((BaseUnityPlugin)this).Config.Bind("Game", "StripQuotaCheck", true, "Disable mob-kills-you-on-miss-quota check."); BotsEnabled = ((BaseUnityPlugin)this).Config.Bind("Bots", "Enabled", false, "Spawn AI rivals so you can test PvP solo. Server/host only."); BotCount = ((BaseUnityPlugin)this).Config.Bind("Bots", "Count", 2, "How many bots to spawn (1-3). They gamble, take loans, wager you, and snitch on you."); DebugStartingPvpTickets = ((BaseUnityPlugin)this).Config.Bind("Debug", "StartingPvpTickets", 0, "Grants this many PvP tickets when a real player's ledger is first created. Also enables the F4 hotkey to add 100 tickets on demand. Set 0 to disable."); GameObject val = new GameObject("[GamblePvP] Host"); Object.DontDestroyOnLoad((Object)val); val.AddComponent(); val.AddComponent(); SceneManager.sceneLoaded += OnSceneLoaded; try { Harmony.PatchAll(typeof(GameFlowPatches)); Harmony.PatchAll(typeof(BetClampPatches)); Harmony.PatchAll(typeof(LedgerTrackerPatches)); Harmony.PatchAll(typeof(DaySummaryPatches)); Harmony.PatchAll(typeof(PhoneBoothPatches)); Harmony.PatchAll(typeof(BotHudPatches)); Harmony.PatchAll(typeof(SplashSkipPatches)); Harmony.PatchAll(typeof(CosmeticUnlockPatches)); Harmony.PatchAll(typeof(BodyPartPayoutPatches)); Harmony.PatchAll(typeof(SpawnBoxPatches)); Log.LogInfo((object)"Harmony patches applied."); } catch (Exception arg) { Log.LogError((object)$"Harmony patch failed: {arg}"); } Log.LogInfo((object)string.Format("[{0}] ready. Settings: interest={1}, days={2}, starting=${3}, stripQuota={4}.", "Gamble PvP", LoanInterest.Value, DaysPerGame.Value, StartingMoney.Value, StripQuota.Value)); } private static IEnumerator DelayedBotPreview() { yield return (object)new WaitForSeconds(4f); BotSystem.PreviewInLobby(); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { Log.LogInfo((object)("Scene loaded: " + ((Scene)(ref scene)).name)); if (((Scene)(ref scene)).name == "CasinoScene") { ModState instance = ModState.Instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(LoanSharkSpawner.SpawnRoutine()); } ModState.Instance?.NotePlayedInCasino(); BotSystem.Init(); } else if (((Scene)(ref scene)).name == "HomeScene") { ModState.Instance?.OnHomeSceneEntered(); ModState instance2 = ModState.Instance; if (instance2 != null) { ((MonoBehaviour)instance2).StartCoroutine(DelayedBotPreview()); } ModState instance3 = ModState.Instance; if (instance3 != null) { ((MonoBehaviour)instance3).StartCoroutine(BlackMarketSpawner.SpawnRoutine()); } SpawnBoxPatches.ResetDedupe(); } else if (((Scene)(ref scene)).name == "MainMenuScene" || ((Scene)(ref scene)).name == "NetworkSetupScene") { ModState.Instance?.ResetSession(); PhoneBoothPatches.ResetDedupe(); SpawnBoxPatches.ResetDedupe(); } } } public static class SabotageSystem { public const int SabotageCost = 500; public const int SabotageDamage = 750; public const float CooldownSeconds = 90f; private static readonly Dictionary _lastSabotageBy = new Dictionary(); public static void TrySabotage(ulong attackerId, ulong targetId) { if (!NetworkServer.active) { return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded) { return; } if (attackerId == targetId) { NetSync.BroadcastToast("Can't sabotage yourself."); return; } if (_lastSabotageBy.TryGetValue(attackerId, out var value)) { float num = Time.time - value; if (num < 90f) { NetSync.BroadcastToast($"Goons need {90f - num:F0}s rest."); return; } } PlayerLedger orCreate = instance.GetOrCreate(attackerId); PlayerLedger orCreate2 = instance.GetOrCreate(targetId); if (orCreate.IsDead || orCreate2.IsDead) { NetSync.BroadcastToast("Sabotage refused: someone's dead."); return; } if (orCreate.Wealth < 500) { NetSync.BroadcastToast($"{orCreate.DisplayName} can't afford the ${500} fee."); return; } _lastSabotageBy[attackerId] = Time.time; MoneyManager instance2 = NetworkSingleton.Instance; if (instance2 != null) { instance2.TryChangeBalance(-500L, (PlayerProfile)null, (ChangeType)4); } orCreate.Ledger -= 500L; if (orCreate2.BuffMobBribe) { orCreate2.BuffMobBribe = false; NetSync.BroadcastToast($"{orCreate2.DisplayName}'s Mob Bribe absorbed the hit — {orCreate.DisplayName} wasted ${500} on goons.", ToastSeverity.Mid); NetSync.BroadcastLedgerUpdate(orCreate2); } else { orCreate2.Ledger -= 750L; } orCreate.TotalSabotagesUsed++; orCreate.PvpTickets++; Plugin.Log.LogInfo((object)$"[Sabotage] {orCreate.DisplayName} paid ${500} to hit {orCreate2.DisplayName} for ${750}."); NetSync.BroadcastLedgerUpdate(orCreate); NetSync.BroadcastLedgerUpdate(orCreate2); NetSync.BroadcastToast($"{orCreate.DisplayName} hired goons to rough up {orCreate2.DisplayName} (-${750}).", ToastSeverity.Big); NetSync.BroadcastShake(orCreate2.SteamId, 0.4f, 0.35f); } } public static class SnitchingSystem { public const float CooldownSeconds = 30f; public const float WealthSeizureFraction = 0.25f; public const float FinderFeeFraction = 0.1f; public const float FalseAccusationFineFraction = 0.1f; private static readonly Dictionary _lastSnitchBy = new Dictionary(); public static void TrySnitch(ulong snitchId, ulong targetId) { if (!NetworkServer.active) { return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded) { return; } if (snitchId == targetId) { NetSync.BroadcastToast("Can't snitch on yourself."); return; } if (_lastSnitchBy.TryGetValue(snitchId, out var value)) { float num = Time.time - value; if (num < 30f) { NetSync.BroadcastToast($"Mob's ear is busy. Wait {30f - num:F0}s."); return; } } PlayerLedger orCreate = instance.GetOrCreate(snitchId); PlayerLedger orCreate2 = instance.GetOrCreate(targetId); if (orCreate.IsDead || orCreate2.IsDead) { return; } _lastSnitchBy[snitchId] = Time.time; orCreate.TotalSabotagesUsed++; bool buffSnitchInsurance = orCreate2.BuffSnitchInsurance; if (buffSnitchInsurance) { orCreate2.BuffSnitchInsurance = false; NetSync.BroadcastToast(orCreate2.DisplayName + "'s Snitch Insurance kicked in — the mob laughed in " + orCreate.DisplayName + "'s face.", ToastSeverity.Mid); NetSync.BroadcastLedgerUpdate(orCreate2); } if (!buffSnitchInsurance && Random.value < 0.5f) { long num2 = (long)((float)Math.Max(0L, orCreate2.Wealth) * 0.25f); long num3 = (long)((float)num2 * 0.1f); MoneyManager instance2 = NetworkSingleton.Instance; if (instance2 != null) { instance2.TryChangeBalance(num3, (PlayerProfile)null, (ChangeType)4); } orCreate2.Ledger -= num2; orCreate.Ledger += num3; orCreate.PvpTickets++; Plugin.Log.LogInfo((object)$"[Snitch] BELIEVED: {orCreate.DisplayName} reported {orCreate2.DisplayName}. Seizure=${num2}, finder's fee=${num3}."); NetSync.BroadcastToast($"The mob believed {orCreate.DisplayName}! {orCreate2.DisplayName} loses ${num2}. {orCreate.DisplayName} gets ${num3} finder's fee.", ToastSeverity.Big); NetSync.BroadcastShake(orCreate2.SteamId, 0.4f, 0.35f); } else { long num4 = (long)((float)Math.Max(0L, orCreate.Wealth) * 0.1f); MoneyManager instance3 = NetworkSingleton.Instance; if (instance3 != null) { instance3.TryChangeBalance(-num4, (PlayerProfile)null, (ChangeType)4); } orCreate.Ledger -= num4; Plugin.Log.LogInfo((object)$"[Snitch] DISBELIEVED: {orCreate.DisplayName} pays ${num4} false-accusation fine."); NetSync.BroadcastToast($"The mob didn't buy {orCreate.DisplayName}'s snitch. Pays ${num4} fine.", ToastSeverity.Mid); NetSync.BroadcastShake(orCreate.SteamId, 0.25f, 0.2f); } NetSync.BroadcastLedgerUpdate(orCreate); NetSync.BroadcastLedgerUpdate(orCreate2); } } public static class HappyHourSystem { public const float DurationSeconds = 30f; public const float MinIntervalSeconds = 60f; public const float MaxIntervalSeconds = 120f; public const float Multiplier = 1.5f; private static float _nextCheckTime = -1f; private static float _endTime = -1f; private static bool _warned; public static bool IsActive { get; private set; } public static void Tick() { //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) if (!NetworkServer.active) { return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded) { return; } Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "CasinoScene") { IsActive = false; return; } float time = Time.time; if (_nextCheckTime < 0f) { _nextCheckTime = time + Random.Range(60f, 120f); } if (!IsActive) { if (time >= _nextCheckTime) { IsActive = true; _endTime = time + 30f; _warned = false; Plugin.Log.LogInfo((object)"[HappyHour] STARTED"); NetSync.BroadcastToast($"*** HAPPY HOUR! Payouts +{50f:F0}% for {30f:F0}s ***"); } return; } float num = _endTime - time; if (!_warned && num <= 10f) { _warned = true; NetSync.BroadcastToast($"Happy Hour ends in {num:F0}s — bet now!"); } if (num <= 0f) { IsActive = false; Plugin.Log.LogInfo((object)"[HappyHour] ENDED"); NetSync.BroadcastToast("Happy Hour is over."); _nextCheckTime = time + Random.Range(60f, 120f); } } } public static class SoundManager { public enum Cue { Click, TakeLoan, PayBack, WagerWin, WagerLose, Sabotage, SnitchSuccess, SnitchFail, HappyHourStart, Death } private static AudioSource _src; private static readonly Dictionary _buffers = new Dictionary(); private static int SampleRate { get { if (AudioSettings.outputSampleRate <= 0) { return 44100; } return AudioSettings.outputSampleRate; } } private static void EnsureSrc() { //IL_0013: 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_001e: Expected O, but got Unknown if (!((Object)(object)_src != (Object)null)) { GameObject val = new GameObject("[PvP] SoundManager"); Object.DontDestroyOnLoad((Object)val); _src = val.AddComponent(); _src.playOnAwake = false; _src.spatialBlend = 0f; _src.volume = 1f; _src.bypassEffects = true; _src.bypassListenerEffects = true; _src.bypassReverbZones = true; _src.ignoreListenerPause = true; _src.priority = 0; Plugin.Log.LogInfo((object)"[SoundManager] AudioSource created."); } } public static void Play(Cue c) { } private static float[] GetOrBuildBuffer(Cue c, out float secondsOut) { float sec; switch (c) { case Cue.Click: sec = 0.05f; break; case Cue.TakeLoan: sec = 0.45f; break; case Cue.PayBack: sec = 0.55f; break; case Cue.WagerWin: sec = 0.7f; break; case Cue.WagerLose: sec = 0.7f; break; case Cue.Sabotage: sec = 0.8f; break; case Cue.SnitchSuccess: sec = 0.6f; break; case Cue.SnitchFail: sec = 1f; break; case Cue.HappyHourStart: sec = 1f; break; case Cue.Death: sec = 1.2f; break; default: sec = 0.1f; break; } secondsOut = sec; if (_buffers.TryGetValue(c, out var value)) { return value; } int sampleRate = SampleRate; int num = Math.Max(1, (int)(sec * (float)sampleRate)); value = new float[num]; Func func = c switch { Cue.Click => (float t) => Square(t, 880f) * Env(t, sec, 0.005f, 0f) * 0.4f, Cue.TakeLoan => (float t) => (Sine(t, 110f) + Sine(t, 55f) * 0.6f) * Env(t, sec, 0.01f, 0.25f) * 0.7f, Cue.PayBack => (float t) => (Sine(t, 880f) + Sine(t, 1320f) * 0.6f + Sine(t, 1760f) * 0.4f) * Env(t, sec, 0.02f, 0.4f) * 0.4f, Cue.WagerWin => (float t) => Sine(t, 440f + 600f * t) * Env(t, sec, 0.05f, 0.5f) * 0.6f, Cue.WagerLose => (float t) => Sine(t, 880f - 700f * t) * Env(t, sec, 0.05f, 0.5f) * 0.6f, Cue.Sabotage => (float t) => Noise() * Env(t, sec, 0.05f, 0.5f) * 0.5f + Sine(t, 60f) * Env(t, sec, 0.05f, 0.4f) * 0.6f, Cue.SnitchSuccess => (float t) => Square(t, 1200f) * ((Mathf.Sin(t * 30f) > 0f) ? 1f : 0f) * Env(t, sec, 0.02f, 0.4f) * 0.5f, Cue.SnitchFail => (float t) => Saw(t, 200f - 100f * t) * Env(t, sec, 0.05f, 0.7f) * 0.5f, Cue.HappyHourStart => (float t) => (Sine(t, 523f) + Sine(t, 659f) * 0.8f + Sine(t, 784f) * 0.7f) * Env(t, sec, 0.05f, 0.7f) * 0.4f, Cue.Death => (float t) => Noise() * Env(t, sec, 0.01f, 1f) * 0.6f + Sine(t, 40f) * Env(t, sec, 0.02f, 1f) * 0.8f, _ => (float t) => 0f, }; for (int num2 = 0; num2 < num; num2++) { float arg = (float)num2 / (float)sampleRate; value[num2] = Mathf.Clamp(func(arg), -1f, 1f); } _buffers[c] = value; return value; } private static AudioClip BuildClip(Cue c) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown float secondsOut; float[] buf = GetOrBuildBuffer(c, out secondsOut); int sampleRate = SampleRate; int n = buf.Length; int pos = 0; PCMReaderCallback val = (PCMReaderCallback)delegate(float[] outBuf) { for (int i = 0; i < outBuf.Length; i++) { if (pos < n) { outBuf[i] = buf[pos++]; } else { outBuf[i] = 0f; } } }; AudioClip val2 = AudioClip.Create("pvp_tone", n, 1, sampleRate, true, val); Plugin.Log.LogInfo((object)$"[SoundManager] Built clip (streaming): samples={n}, sr={sampleRate}, clipSamples={val2.samples}, clipFreq={val2.frequency}"); return val2; } private static AudioClip Tone(float seconds, Func sample) { int sampleRate = SampleRate; int num = Math.Max(1, (int)(seconds * (float)sampleRate)); float[] array = new float[num]; for (int i = 0; i < num; i++) { float arg = (float)i / (float)sampleRate; array[i] = Mathf.Clamp(sample(arg), -1f, 1f); } AudioClip val = AudioClip.Create("pvp_tone", num, 1, sampleRate, false); bool flag = val.SetData(array, 0); Plugin.Log.LogInfo((object)$"[SoundManager] Built clip: samples={num} sr={sampleRate} expectedLen={seconds:F3}s setData={flag}"); return val; } private static float Sine(float t, float hz) { return Mathf.Sin(MathF.PI * 2f * hz * t); } private static float Square(float t, float hz) { return Mathf.Sign(Sine(t, hz)); } private static float Saw(float t, float hz) { return t * hz % 1f * 2f - 1f; } private static float Noise() { return Random.value * 2f - 1f; } private static float Env(float t, float total, float attack, float release) { if (t < attack) { return t / attack; } if (t > total - release) { return Mathf.Max(0f, (total - t) / release); } return 1f; } } public static class SpawnBoxPatches { private static readonly HashSet _autoWoken = new HashSet(); private static MethodInfo _wakeMethod; private static FieldInfo _assignedField; [HarmonyPatch(typeof(SpawnBoxPlayerRagdollTrigger), "AssignPlayer")] [HarmonyPostfix] public static void AssignPlayer_Postfix(SpawnBoxPlayerRagdollTrigger __instance) { if (NetworkServer.active && !((Object)(object)__instance == (Object)null)) { int instanceID = ((Object)__instance).GetInstanceID(); if (!_autoWoken.Contains(instanceID)) { _autoWoken.Add(instanceID); ((MonoBehaviour)__instance).StartCoroutine(WaitAndWake(__instance)); } } } private static IEnumerator WaitAndWake(SpawnBoxPlayerRagdollTrigger box) { if (_assignedField == null) { _assignedField = typeof(SpawnBoxPlayerRagdollTrigger).GetField("assignedPlayer", BindingFlags.Instance | BindingFlags.NonPublic); } if (_wakeMethod == null) { _wakeMethod = typeof(SpawnBoxPlayerRagdollTrigger).GetMethod("WakePlayerUp", BindingFlags.Instance | BindingFlags.NonPublic); } if (_assignedField == null || _wakeMethod == null) { Plugin.Log.LogWarning((object)"[SpawnBoxPatches] Reflection lookup failed."); yield break; } for (float elapsed = 0f; elapsed < 5f; elapsed += 0.1f) { if (!((Object)(object)box != (Object)null)) { break; } if (_assignedField.GetValue(box) != null) { break; } yield return (object)new WaitForSeconds(0.1f); } if ((Object)(object)box == (Object)null) { yield break; } if (_assignedField.GetValue(box) == null) { Plugin.Log.LogWarning((object)"[SpawnBoxPatches] Timed out waiting for assignedPlayer."); yield break; } yield return (object)new WaitForSeconds(0.15f); try { _wakeMethod.Invoke(box, null); Plugin.Log.LogInfo((object)"[SpawnBoxPatches] Auto-woke player from spawn box."); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[SpawnBoxPatches] Auto-wake failed: " + ex.Message)); } } public static void ResetDedupe() { _autoWoken.Clear(); } } public static class SplashSkipPatches { [HarmonyPatch(typeof(OfflineSplashCoinFlip), "Awake")] [HarmonyPostfix] public static void Awake_Postfix(OfflineSplashCoinFlip __instance) { try { __instance.OnChooseNo(); Plugin.Log.LogInfo((object)"[SplashSkip] Skipped the coin-flip splash."); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[SplashSkip] failed: " + ex.Message)); } } } public class WagerBooth : MonoBehaviour { public int StakeIdx = 1; public int TargetIdx; private TextMeshPro _signLabel; private TextMeshPro _targetLabel; private TextMeshPro _stakeLabel; public void SetUI(TextMeshPro sign, TextMeshPro target, TextMeshPro stake) { _signLabel = sign; _targetLabel = target; _stakeLabel = stake; Refresh(); } public void Refresh() { if ((Object)(object)_signLabel != (Object)null) { ((TMP_Text)_signLabel).text = "WAGER BOOTH\nCOIN FLIP 50/50"; } List otherPlayers = GetOtherPlayers(); string text = ((otherPlayers.Count == 0) ? "(no opponents)" : otherPlayers[TargetIdx % otherPlayers.Count].DisplayName); if ((Object)(object)_targetLabel != (Object)null) { ((TMP_Text)_targetLabel).text = "VS\n" + text; } if ((Object)(object)_stakeLabel != (Object)null) { ((TMP_Text)_stakeLabel).text = $"STAKE\n${WagerSystem.StakeChoices[StakeIdx % WagerSystem.StakeChoices.Length]}"; } } private void Update() { Refresh(); } public void CycleTarget() { SoundManager.Play(SoundManager.Cue.Click); List otherPlayers = GetOtherPlayers(); if (otherPlayers.Count != 0) { TargetIdx = (TargetIdx + 1) % otherPlayers.Count; Refresh(); } } public void CycleStake() { SoundManager.Play(SoundManager.Cue.Click); StakeIdx = (StakeIdx + 1) % WagerSystem.StakeChoices.Length; Refresh(); } public void Confirm() { List otherPlayers = GetOtherPlayers(); if (otherPlayers.Count == 0) { Plugin.Log.LogInfo((object)"[WagerBooth] No opponents to wager against."); return; } ulong num = ResolveLocalSteamId(); if (num == 0L) { Plugin.Log.LogWarning((object)"[WagerBooth] Couldn't resolve local Steam ID."); return; } PlayerLedger playerLedger = otherPlayers[TargetIdx % otherPlayers.Count]; long num2 = WagerSystem.StakeChoices[StakeIdx % WagerSystem.StakeChoices.Length]; Plugin.Log.LogInfo((object)$"[WagerBooth] Requesting wager: me({num}) vs {playerLedger.DisplayName}({playerLedger.SteamId}) for ${num2}"); NetSync.ClientRequestWager(num, playerLedger.SteamId, num2); } private static List GetOtherPlayers() { List list = new List(); ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null) { return list; } ulong num = ResolveLocalSteamId(); foreach (PlayerLedger value in instance.Ledgers.Values) { if (value.SteamId != num && !value.IsDead) { list.Add(value); } } return list; } private static ulong ResolveLocalSteamId() { NetworkConnectionToServer connection = NetworkClient.connection; NetworkIdentity val = ((connection != null) ? ((NetworkConnection)connection).identity : null); if ((Object)(object)val == (Object)null) { return 0uL; } PlayerProfile component = ((Component)val).GetComponent(); if (!((Object)(object)component != (Object)null)) { return 0uL; } return component.steamId; } } public static class WagerSystem { private static readonly Dictionary _lastWagerByChallenger = new Dictionary(); public const float CooldownSeconds = 60f; public static int[] StakeChoices => new int[4] { 50, 100, 250, 500 }; public static void TryWager(ulong challengerSteamId, ulong targetSteamId, long stake) { if (!NetworkServer.active) { Plugin.Log.LogWarning((object)"[Wager] called off-server"); return; } ModState instance = ModState.Instance; if ((Object)(object)instance == (Object)null || instance.GameEnded) { return; } if (challengerSteamId == targetSteamId) { Plugin.Log.LogInfo((object)"[Wager] Refused: self-challenge."); return; } if (_lastWagerByChallenger.TryGetValue(challengerSteamId, out var value)) { float num = Time.time - value; if (num < 60f) { Plugin.Log.LogInfo((object)$"[Wager] Cooldown: {challengerSteamId} must wait {60f - num:F0}s."); NetSync.BroadcastToast($"Wager refused: cooldown ({60f - num:F0}s remaining)."); return; } } PlayerLedger orCreate = instance.GetOrCreate(challengerSteamId); PlayerLedger orCreate2 = instance.GetOrCreate(targetSteamId); if (orCreate.IsDead || orCreate2.IsDead) { NetSync.BroadcastToast("Wager refused: someone's dead."); return; } if (orCreate.Wealth < stake) { NetSync.BroadcastToast($"{orCreate.DisplayName} can't cover the ${stake} wager."); return; } if (orCreate2.Wealth < stake) { NetSync.BroadcastToast($"{orCreate2.DisplayName} can't cover the ${stake} wager."); return; } _lastWagerByChallenger[challengerSteamId] = Time.time; bool num2 = Random.value < 0.5f; PlayerLedger playerLedger = (num2 ? orCreate : orCreate2); PlayerLedger playerLedger2 = (num2 ? orCreate2 : orCreate); long num3 = (playerLedger.BuffLiquidCourage ? (stake * 2) : stake); if (playerLedger.BuffLiquidCourage) { Plugin.Log.LogInfo((object)$"[LiquidCourage] {playerLedger.DisplayName}: wager pays {stake} -> {num3}"); } playerLedger.Ledger += num3; playerLedger2.Ledger -= stake; playerLedger.TotalWagersWon++; playerLedger.PvpTickets++; Plugin.Log.LogInfo((object)$"[Wager] {orCreate.DisplayName} vs {orCreate2.DisplayName} for ${stake}. {playerLedger.DisplayName} wins!"); NetSync.BroadcastLedgerUpdate(playerLedger); NetSync.BroadcastLedgerUpdate(playerLedger2); ToastSeverity severity = ((stake < 250) ? ToastSeverity.Mid : ToastSeverity.Big); NetSync.BroadcastToast($"WAGER: {orCreate.DisplayName} vs {orCreate2.DisplayName} for ${stake}. {playerLedger.DisplayName} wins!", severity); NetSync.BroadcastShake(playerLedger2.SteamId, 0.35f, 0.3f); } } }