Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of REPO lucky block v1.2.0
REPO_lucky_block.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using REPOLib.Modules; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("REPO_lucky_block")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+37173992a6f2015f5c3debdb5967fae80505af17")] [assembly: AssemblyProduct("REPO_lucky_block")] [assembly: AssemblyTitle("REPO_lucky_block")] [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; } } } internal static class CategoryWeights { internal static ConfigEntry<float> Lucky; internal static ConfigEntry<float> Unlucky; internal static ConfigEntry<float> Chaotic; internal static ConfigEntry<float> Wacky; internal static void BindConfig(ConfigFile config) { Lucky = Bind(config, "Lucky", "good outcomes: loot, items, upgrades, heals"); Unlucky = Bind(config, "Unlucky", "bad outcomes: monsters, explosives, quota hikes"); Chaotic = Bind(config, "Chaotic", "level scramblers: loot scatter, meteors, earthquakes"); Wacky = Bind(config, "Wacky", "silly client-side effects (Private edition only)"); } private static ConfigEntry<float> Bind(ConfigFile config, string key, string what) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown return config.Bind<float>("Category Weights", key, 1f, new ConfigDescription("How often " + what + " roll, relative to the other categories. 1 = normal, 0.5 = half as often, 0 = never, 2 = twice as often.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>())); } internal static float Get(LuckyEventCategory category) { ConfigEntry<float> val = EntryFor(category); if (val == null) { return 1f; } return Mathf.Max(0f, val.Value); } internal static ConfigEntry<float> EntryFor(LuckyEventCategory category) { return (ConfigEntry<float>)(category switch { LuckyEventCategory.Lucky => Lucky, LuckyEventCategory.Unlucky => Unlucky, LuckyEventCategory.Chaotic => Chaotic, LuckyEventCategory.Wacky => Wacky, _ => null, }); } } internal static class EventHelpers { internal static ConfigEntry<float> ConfigTeleportValueLoss; private static FieldInfo _fValCurrent; private static FieldInfo _fValOriginal; private static FieldInfo _fValSet; private static FieldInfo _fExtCurrent; private static FieldInfo _fGrabbedObj; private static bool _reflected; private const float IMPACT_GRACE_SECONDS = 4f; private static Item _grenadeItem; internal static float TeleportValueLoss { get { if (ConfigTeleportValueLoss == null) { return 0.05f; } return Mathf.Clamp(ConfigTeleportValueLoss.Value, 0f, 0.5f); } } internal static void BindConfig(ConfigFile config) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown ConfigTeleportValueLoss = config.Bind<float>("General", "TeleportValueLoss", 0.05f, new ConfigDescription("How much value loot loses when an event moves it (Hoarder's Curse, Treasure Migration, Vacuum Pulse). 0.05 = 5%. The fall itself no longer breaks anything.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.5f), Array.Empty<object>())); } private static void EnsureReflection() { if (!_reflected) { _reflected = true; Type? typeFromHandle = typeof(ValuableObject); _fValCurrent = typeFromHandle.GetField("dollarValueCurrent", BindingFlags.Instance | BindingFlags.NonPublic); _fValOriginal = typeFromHandle.GetField("dollarValueOriginal", BindingFlags.Instance | BindingFlags.NonPublic); _fValSet = typeFromHandle.GetField("dollarValueSet", BindingFlags.Instance | BindingFlags.NonPublic); _fExtCurrent = typeof(RoundDirector).GetField("extractionPointCurrent", BindingFlags.Instance | BindingFlags.NonPublic); _fGrabbedObj = typeof(PhysGrabber).GetField("grabbedPhysGrabObject", BindingFlags.Instance | BindingFlags.NonPublic); } } internal static void Announce(string label) { LuckyFx.Broadcast("announce", label); } internal static List<PlayerAvatar> GetAllPlayers() { List<PlayerAvatar> list = new List<PlayerAvatar>(); foreach (PlayerAvatar item in SemiFunc.PlayerGetAll()) { if ((Object)(object)item != (Object)null) { list.Add(item); } } return list; } internal static void TeleportPlayer(PlayerAvatar avatar, Vector3 pos) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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)avatar == (Object)null) { return; } avatar.Spawn(pos, ((Component)avatar).transform.rotation); if ((Object)(object)avatar == (Object)(object)PlayerAvatar.instance) { TeleportLocalController(pos); } else if (SemiFunc.IsMultiplayer() && ModeManager.IsPrivate) { PhotonView component = ((Component)avatar).GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null) { LuckyFx.Broadcast("teleport", string.Format(CultureInfo.InvariantCulture, "{0},{1:F2},{2:F2},{3:F2}", component.ViewID, pos.x, pos.y, pos.z)); } } } internal static void TeleportLocalController(Vector3 pos) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) PlayerController instance = PlayerController.instance; if (!((Object)(object)instance == (Object)null)) { if ((Object)(object)instance.rb != (Object)null) { instance.rb.velocity = Vector3.zero; instance.rb.position = pos; } ((Component)instance).transform.position = pos; } } internal static void UpgradePlayer(PlayerAvatar avatar, string upgradeName, int amount = 1) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)avatar == (Object)null || (Object)(object)PunManager.instance == (Object)null) { return; } string text = SemiFunc.PlayerGetSteamID(avatar); if (string.IsNullOrEmpty(text)) { return; } if (SemiFunc.IsMultiplayer()) { PhotonView component = ((Component)PunManager.instance).GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null) { component.RPC("TesterUpgradeCommandRPC", (RpcTarget)0, new object[3] { text, upgradeName, amount }); } } else { PunManager.instance.TesterUpgradeCommandRPC(text, upgradeName, amount, default(PhotonMessageInfo)); } } internal static void HealPlayer(PlayerAvatar avatar, int amount) { if ((Object)(object)avatar != (Object)null && (Object)(object)avatar.playerHealth != (Object)null) { avatar.playerHealth.HealOther(amount, true); } } internal static List<Enemy> GetSpawnedEnemies() { List<Enemy> list = new List<Enemy>(); if ((Object)(object)EnemyDirector.instance == (Object)null) { return list; } foreach (EnemyParent item in EnemyDirector.instance.enemiesSpawned) { if (!((Object)(object)item == (Object)null)) { Enemy componentInChildren = ((Component)item).GetComponentInChildren<Enemy>(true); if ((Object)(object)componentInChildren != (Object)null && ((Component)componentInChildren).gameObject.activeInHierarchy) { list.Add(componentInChildren); } } } return list; } internal static void TeleportEnemy(Enemy enemy, Vector3 pos) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)enemy != (Object)null) { enemy.EnemyTeleported(pos); } } internal static List<ValuableObject> GetLooseValuables(bool includeInCart = true) { List<ValuableObject> list = new List<ValuableObject>(); List<GameObject> list2 = (((Object)(object)RoundDirector.instance != (Object)null) ? RoundDirector.instance.dollarHaulList : null); ValuableObject[] array = Object.FindObjectsOfType<ValuableObject>(); foreach (ValuableObject val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).GetComponent<LuckyBlock>() != (Object)null)) { LuckyBlockItem component = ((Component)val).GetComponent<LuckyBlockItem>(); if ((!((Object)(object)component != (Object)null) || !component.IsLucky) && (list2 == null || !list2.Contains(((Component)val).gameObject)) && (includeInCart || !IsInCart((Component)(object)val))) { list.Add(val); } } } return list; } internal static bool IsInCart(Component c) { if ((Object)(object)c == (Object)null) { return false; } PhysGrabObjectImpactDetector component = c.GetComponent<PhysGrabObjectImpactDetector>(); if ((Object)(object)component != (Object)null) { if (!component.inCart) { return component.isCart; } return true; } return false; } internal static float GetValuableValue(ValuableObject v) { EnsureReflection(); if ((Object)(object)v == (Object)null || _fValCurrent == null) { return 0f; } return (float)_fValCurrent.GetValue(v); } internal static void SetValuableValue(ValuableObject v, float value) { EnsureReflection(); if ((Object)(object)v == (Object)null || _fValCurrent == null) { return; } value = Mathf.Max(0f, Mathf.Round(value)); _fValCurrent.SetValue(v, value); _fValOriginal?.SetValue(v, value); _fValSet?.SetValue(v, true); if (SemiFunc.IsMultiplayer()) { PhotonView component = ((Component)v).GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null && component.ViewID != 0) { component.RPC("DollarValueSetRPC", (RpcTarget)1, new object[1] { value }); } } } internal static void TeleportPhysObject(PhysGrabObject o, Vector3 pos) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)o != (Object)null) { o.Teleport(pos, ((Component)o).transform.rotation); } } internal static void TeleportValuableSafe(ValuableObject v, Vector3 pos, bool snapToFloor = true) { //IL_006b: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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) if ((Object)(object)v == (Object)null) { return; } PhysGrabObject component = ((Component)v).GetComponent<PhysGrabObject>(); if ((Object)(object)component == (Object)null) { return; } PhysGrabObjectImpactDetector component2 = ((Component)v).GetComponent<PhysGrabObjectImpactDetector>(); if ((Object)(object)component2 != (Object)null) { component2.ImpactDisable(4f); } Rigidbody rb = component.rb; if ((Object)(object)rb != (Object)null && !rb.isKinematic) { rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } component.Teleport(snapToFloor ? FloorBelow(pos) : pos, ((Component)component).transform.rotation); float teleportValueLoss = TeleportValueLoss; if (teleportValueLoss > 0f) { float valuableValue = GetValuableValue(v); if (valuableValue > 0f) { SetValuableValue(v, valuableValue * (1f - teleportValueLoss)); } } } private static Vector3 FloorBelow(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) RaycastHit val = default(RaycastHit); if (!Physics.Raycast(pos + Vector3.up * 1.5f, Vector3.down, ref val, 6f, -1, (QueryTriggerInteraction)1)) { return pos; } return ((RaycastHit)(ref val)).point + Vector3.up * 0.35f; } internal static void DestroyValuable(ValuableObject v) { if (!((Object)(object)v == (Object)null)) { PhysGrabObjectImpactDetector component = ((Component)v).GetComponent<PhysGrabObjectImpactDetector>(); if ((Object)(object)component != (Object)null) { component.DestroyObject(true); } else { Object.Destroy((Object)(object)((Component)v).gameObject); } } } internal static ExtractionPoint GetActiveExtraction() { EnsureReflection(); if ((Object)(object)RoundDirector.instance == (Object)null || _fExtCurrent == null) { return null; } object? value = _fExtCurrent.GetValue(RoundDirector.instance); return (ExtractionPoint)((value is ExtractionPoint) ? value : null); } internal static void SetHaulGoal(ExtractionPoint ep, int value) { //IL_0052: 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) if ((Object)(object)ep == (Object)null) { return; } value = Mathf.Max(1, value); if (SemiFunc.IsMultiplayer()) { PhotonView component = ((Component)ep).GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null && component.ViewID != 0) { component.RPC("HaulGoalSetRPC", (RpcTarget)0, new object[1] { value }); } } else { ep.HaulGoalSetRPC(value, default(PhotonMessageInfo)); } } internal static List<Vector3> GetRandomLevelPoints(int count) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) List<LevelPoint> reachablePoints = LevelPointUtils.GetReachablePoints(LuckyBlockSpawner.MaxSpawnDistance); List<Vector3> list = new List<Vector3>(count); if (reachablePoints.Count == 0) { PlayerAvatar instance = PlayerAvatar.instance; return SpawnUtils.GetFloorRing(((Object)(object)instance != (Object)null) ? ((Component)instance).transform.position : Vector3.zero, count, 5f); } for (int i = 0; i < count; i++) { LevelPoint lp = reachablePoints[Random.Range(0, reachablePoints.Count)]; list.Add(LevelPointUtils.ToSpawnPosition(lp)); } return list; } private static Item FindGrenadeItem() { if ((Object)(object)_grenadeItem != (Object)null) { return _grenadeItem; } foreach (Item allItem in Items.AllItems) { string text = ((Object)allItem).name.ToLowerInvariant(); if (text.Contains("grenade") && !text.Contains("mine") && !text.Contains("human")) { _grenadeItem = allItem; break; } } return _grenadeItem; } internal static void SpawnGrenadeAt(Vector3 pos, float fuse) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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) Item val = FindGrenadeItem(); if ((Object)(object)val == (Object)null) { return; } GameObject val2 = (SemiFunc.IsMultiplayer() ? Items.SpawnItem(val, pos, Quaternion.identity) : Object.Instantiate<GameObject>(((PrefabRef<GameObject>)(object)val.prefab).Prefab, pos, Quaternion.identity)); if (!((Object)(object)val2 == (Object)null)) { ItemGrenade componentInChildren = val2.GetComponentInChildren<ItemGrenade>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.isSpawnedGrenade = true; componentInChildren.tickTime = fuse; } ItemToggle componentInChildren2 = val2.GetComponentInChildren<ItemToggle>(); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.toggleState = true; } } } internal static void ReleaseLocalGrab() { EnsureReflection(); PhysGrabber instance = PhysGrabber.instance; if (!((Object)(object)instance == (Object)null) && instance.grabbed && !(_fGrabbedObj == null)) { object? value = _fGrabbedObj.GetValue(instance); PhysGrabObject val = (PhysGrabObject)((value is PhysGrabObject) ? value : null); if (!((Object)(object)val == (Object)null)) { PhotonView component = ((Component)val).GetComponent<PhotonView>(); int num = (((Object)(object)component != (Object)null) ? component.ViewID : 0); instance.OverrideGrabRelease(num, 1f); } } } } public class EvTreasureMigration : LuckyEvent { public override string Id => "TreasureMigration"; public override string Label => "Treasure Migration — all loot scatters"; public override LuckyEventCategory Category => LuckyEventCategory.Chaotic; public override float DefaultWeight => 2f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetLooseValuables(includeInCart: false).Count > 2; } public override void Execute(LuckyEventContext ctx) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) List<ValuableObject> looseValuables = EventHelpers.GetLooseValuables(includeInCart: false); List<Vector3> randomLevelPoints = EventHelpers.GetRandomLevelPoints(looseValuables.Count); for (int i = 0; i < looseValuables.Count && i < randomLevelPoints.Count; i++) { EventHelpers.TeleportValuableSafe(looseValuables[i], randomLevelPoints[i]); } } } public class EvPositionSwap : LuckyEvent { public override string Id => "PositionSwap"; public override string Label => "Musical Chairs — everyone swaps positions"; public override LuckyEventCategory Category => LuckyEventCategory.Chaotic; public override float DefaultWeight => 3f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetAllPlayers().Count >= 2; } public override void Execute(LuckyEventContext ctx) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) List<PlayerAvatar> allPlayers = EventHelpers.GetAllPlayers(); List<Vector3> list = new List<Vector3>(allPlayers.Count); foreach (PlayerAvatar item in allPlayers) { list.Add(((Component)item).transform.position); } for (int i = 0; i < allPlayers.Count; i++) { EventHelpers.TeleportPlayer(allPlayers[i], list[(i + 1) % list.Count]); } } } public class EvMeteorShower : LuckyEvent { public override string Id => "MeteorShower"; public override string Label => "Meteor Shower — grenades rain on everyone"; public override LuckyEventCategory Category => LuckyEventCategory.Chaotic; public override float DefaultWeight => 2.5f; public override void Execute(LuckyEventContext ctx) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); foreach (PlayerAvatar allPlayer in EventHelpers.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null)) { Vector3 position = ((Component)allPlayer).transform.position; for (int i = 0; i < 3; i++) { ((Vector3)(ref val))..ctor(Random.Range(-2.5f, 2.5f), 0f, Random.Range(-2.5f, 2.5f)); EventHelpers.SpawnGrenadeAt(position + val + Vector3.up * 6f, 1.6f); } } } } } public class EvEarthquake : LuckyEvent { public override string Id => "Earthquake"; public override string Label => "Earthquake — everything gets launched"; public override LuckyEventCategory Category => LuckyEventCategory.Chaotic; public override float DefaultWeight => 3f; public override void Execute(LuckyEventContext ctx) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) PhysGrabObject[] array = Object.FindObjectsOfType<PhysGrabObject>(); Vector3 val2 = default(Vector3); foreach (PhysGrabObject val in array) { if (!((Object)(object)val == (Object)null) && !EventHelpers.IsInCart((Component)(object)val)) { Rigidbody component = ((Component)val).GetComponent<Rigidbody>(); if (!((Object)(object)component == (Object)null) && !component.isKinematic) { ((Vector3)(ref val2))..ctor(Random.Range(-1.5f, 1.5f), Random.Range(2f, 4f), Random.Range(-1.5f, 1.5f)); component.AddForce(val2, (ForceMode)2); } } } LuckyFx.Broadcast("shake", "5,1.5"); } } public class EvVacuumPulse : LuckyEvent { public override string Id => "VacuumPulse"; public override string Label => "Vacuum Pulse — loot flies to the block"; public override LuckyEventCategory Category => LuckyEventCategory.Chaotic; public override float DefaultWeight => 2f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetLooseValuables(includeInCart: false).Count > 1; } public override void Execute(LuckyEventContext ctx) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) List<ValuableObject> looseValuables = EventHelpers.GetLooseValuables(includeInCart: false); List<Vector3> floorRing = SpawnUtils.GetFloorRing(ctx.BlockPos, Mathf.Max(3, looseValuables.Count), 2.2f); int num = 0; foreach (ValuableObject item in looseValuables) { EventHelpers.TeleportValuableSafe(item, floorRing[num++ % floorRing.Count]); } } } public class EvEnemyScatter : LuckyEvent { public override string Id => "EnemyScatter"; public override string Label => "The Rapture — every enemy teleports away"; public override LuckyEventCategory Category => LuckyEventCategory.Chaotic; public override float DefaultWeight => 2f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetSpawnedEnemies().Count > 0; } public override void Execute(LuckyEventContext ctx) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) List<Enemy> spawnedEnemies = EventHelpers.GetSpawnedEnemies(); List<Vector3> randomLevelPoints = EventHelpers.GetRandomLevelPoints(spawnedEnemies.Count); for (int i = 0; i < spawnedEnemies.Count && i < randomLevelPoints.Count; i++) { EventHelpers.TeleportEnemy(spawnedEnemies[i], randomLevelPoints[i]); } } } public class EvZeroGLoot : LuckyEvent { public override string Id => "ZeroGLoot"; public override string Label => "Zero-G Loot — valuables float for 15s"; public override LuckyEventCategory Category => LuckyEventCategory.Chaotic; public override float DefaultWeight => 3f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetLooseValuables(includeInCart: false).Count > 0; } public override void Execute(LuckyEventContext ctx) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) foreach (ValuableObject looseValuable in EventHelpers.GetLooseValuables(includeInCart: false)) { PhysGrabObject component = ((Component)looseValuable).GetComponent<PhysGrabObject>(); if (!((Object)(object)component == (Object)null)) { component.OverrideZeroGravity(15f); Rigidbody component2 = ((Component)component).GetComponent<Rigidbody>(); if ((Object)(object)component2 != (Object)null && !component2.isKinematic) { component2.AddForce(Vector3.up * 1.2f, (ForceMode)2); } } } } } public class EvValuable : LuckyEvent { public override string Id => "Valuable"; public override string Label => "Random Valuable"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 14f; public override void Execute(LuckyEventContext ctx) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) SpawnUtils.SpawnRandomValuable(SpawnUtils.GetSpawnPositionInFront(ctx.Opener, 2.5f)); } } public class EvJackpot : LuckyEvent { public override string Id => "Jackpot"; public override string Label => "Jackpot — 3 Valuables"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 4f; public override void Execute(LuckyEventContext ctx) { //IL_0001: 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) foreach (Vector3 item in SpawnUtils.GetFloorRing(ctx.BlockPos, 3, 1.8f)) { SpawnUtils.SpawnRandomValuable(item); } } } public class EvItem : LuckyEvent { public override string Id => "Item"; public override string Label => "Random Item"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 10f; public override void Execute(LuckyEventContext ctx) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) SpawnUtils.SpawnRandomItem(SpawnUtils.GetSpawnPositionInFront(ctx.Opener, 2.5f)); } } public class EvToolChest : LuckyEvent { public override string Id => "ToolChest"; public override string Label => "Tool Chest — 2 Items"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 3f; public override void Execute(LuckyEventContext ctx) { //IL_0001: 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) foreach (Vector3 item in SpawnUtils.GetFloorRing(ctx.BlockPos, 2, 1.5f)) { SpawnUtils.SpawnRandomItem(item); } } } public class EvWeaponDrop : LuckyEvent { public override string Id => "WeaponDrop"; public override string Label => "Armory — Random Weapon"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 1f; public override void Execute(LuckyEventContext ctx) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) SpawnUtils.SpawnRandomWeapon(SpawnUtils.GetSpawnPositionInFront(ctx.Opener, 2.5f)); } } public class EvPotion : LuckyEvent { public override string Id => "Potion"; public override string Label => "Potion (breaks on floor)"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 6f; public override void Execute(LuckyEventContext ctx) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) SpawnUtils.SpawnPotion(SpawnUtils.GetSpawnPositionInFront(ctx.Opener, 2.5f)); } } public class EvLuckyCluster : LuckyEvent { public override string Id => "LuckyCluster"; public override string Label => "Lucky Cluster — 3 New Blocks"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 6f; public override void Execute(LuckyEventContext ctx) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) LuckyBlockManager.Instance?.SpawnBlocks(SpawnUtils.GetFloorRing(ctx.BlockPos, 3, 2f)); } } public class EvHealingWave : LuckyEvent { public override string Id => "HealingWave"; public override string Label => "Healing Wave — +50 HP everyone"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 5f; public override void Execute(LuckyEventContext ctx) { foreach (PlayerAvatar allPlayer in EventHelpers.GetAllPlayers()) { EventHelpers.HealPlayer(allPlayer, 50); } } } public abstract class EvUpgradeBase : LuckyEvent { public override LuckyEventCategory Category => LuckyEventCategory.Lucky; protected abstract string UpgradeName { get; } public override void Execute(LuckyEventContext ctx) { EventHelpers.UpgradePlayer(ctx.Opener, UpgradeName); } } public class EvUpgradeSpeed : EvUpgradeBase { public override string Id => "UpgradeSpeed"; public override string Label => "Adrenaline — Sprint Speed +1"; public override float DefaultWeight => 2.5f; protected override string UpgradeName => "Speed"; } public class EvUpgradeJump : EvUpgradeBase { public override string Id => "UpgradeJump"; public override string Label => "Moon Boots — Extra Jump +1"; public override float DefaultWeight => 2.5f; protected override string UpgradeName => "ExtraJump"; } public class EvUpgradeStamina : EvUpgradeBase { public override string Id => "UpgradeStamina"; public override string Label => "Iron Lungs — Stamina +1"; public override float DefaultWeight => 2.5f; protected override string UpgradeName => "Stamina"; } public class EvUpgradeHealth : EvUpgradeBase { public override string Id => "UpgradeHealth"; public override string Label => "Vitality — Max Health +1"; public override float DefaultWeight => 2.5f; protected override string UpgradeName => "Health"; } public class EvUpgradeStrength : EvUpgradeBase { public override string Id => "UpgradeStrength"; public override string Label => "Strong Arms — Grab Strength +1"; public override float DefaultWeight => 2f; protected override string UpgradeName => "Strength"; } public class EvUpgradeRange : EvUpgradeBase { public override string Id => "UpgradeRange"; public override string Label => "Long Reach — Grab Range +1"; public override float DefaultWeight => 2f; protected override string UpgradeName => "Range"; } public class EvEnemyFreeze : LuckyEvent { public override string Id => "EnemyFreeze"; public override string Label => "Deep Freeze — enemies frozen 10s"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 4f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetSpawnedEnemies().Count > 0; } public override void Execute(LuckyEventContext ctx) { foreach (Enemy spawnedEnemy in EventHelpers.GetSpawnedEnemies()) { spawnedEnemy.Freeze(10f); } } } public class EvGoldenTouch : LuckyEvent { public override string Id => "GoldenTouch"; public override string Label => "Golden Touch — all loot +25% value"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 3f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetLooseValuables().Count > 0; } public override void Execute(LuckyEventContext ctx) { foreach (ValuableObject looseValuable in EventHelpers.GetLooseValuables()) { float valuableValue = EventHelpers.GetValuableValue(looseValuable); if (valuableValue > 0f) { EventHelpers.SetValuableValue(looseValuable, valuableValue * 1.25f); } } } } public class EvScavengerHunt : LuckyEvent { public override string Id => "ScavengerHunt"; public override string Label => "Scavenger Hunt — one hidden valuable ×10"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 3f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetLooseValuables().Count > 0; } public override void Execute(LuckyEventContext ctx) { List<ValuableObject> looseValuables = EventHelpers.GetLooseValuables(includeInCart: false); if (looseValuables.Count == 0) { looseValuables = EventHelpers.GetLooseValuables(); } if (looseValuables.Count != 0) { ValuableObject v = looseValuables[Random.Range(0, looseValuables.Count)]; float valuableValue = EventHelpers.GetValuableValue(v); if (valuableValue > 0f) { EventHelpers.SetValuableValue(v, valuableValue * 10f); } } } } public class EvLuckyDiscount : LuckyEvent { public override string Id => "LuckyDiscount"; public override string Label => "Lucky Discount — quota −15%"; public override LuckyEventCategory Category => LuckyEventCategory.Lucky; public override float DefaultWeight => 2f; public override bool CanRun(LuckyEventContext ctx) { ExtractionPoint activeExtraction = EventHelpers.GetActiveExtraction(); if ((Object)(object)activeExtraction != (Object)null) { return activeExtraction.haulGoal > 0; } return false; } public override void Execute(LuckyEventContext ctx) { ExtractionPoint activeExtraction = EventHelpers.GetActiveExtraction(); if (!((Object)(object)activeExtraction == (Object)null)) { EventHelpers.SetHaulGoal(activeExtraction, Mathf.RoundToInt((float)activeExtraction.haulGoal * 0.85f)); } } } public class EvMonster : LuckyEvent { public override string Id => "Monster"; public override string Label => "Random Monster"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 8f; public override void Execute(LuckyEventContext ctx) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) SpawnUtils.SpawnRandomMonster(SpawnUtils.GetSpawnPositionInFront(ctx.Opener, 2.5f), (MonoBehaviour)(object)LuckyBlockPlugin.Instance); } } public class EvMonsterPack : LuckyEvent { public override string Id => "MonsterPack"; public override string Label => "Monster Pack — 2 Monsters"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 2.5f; public override void Execute(LuckyEventContext ctx) { //IL_0001: 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) foreach (Vector3 item in SpawnUtils.GetFloorRing(ctx.BlockPos, 2, 3f)) { SpawnUtils.SpawnRandomMonster(item, (MonoBehaviour)(object)LuckyBlockPlugin.Instance); } } } public class EvExplosiveFeet : LuckyEvent { public override string Id => "ExplosiveFeet"; public override string Label => "Explosive at Feet"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 7f; public override void Execute(LuckyEventContext ctx) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) SpawnUtils.SpawnRandomExplosive(SpawnUtils.GetSpawnPositionOnPlayer(ctx.Opener)); } } public class EvClusterSmall : LuckyEvent { public override string Id => "ClusterSmall"; public override string Label => "Small Cluster — 3 bombs around player"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 5f; public override void Execute(LuckyEventContext ctx) { SpawnUtils.SpawnExplosiveCluster(ctx.Opener); } } public class EvClusterLarge : LuckyEvent { public override string Id => "ClusterLarge"; public override string Label => "Large Cluster — 5 bombs around block"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 3f; public override void Execute(LuckyEventContext ctx) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) SpawnUtils.SpawnLargeExplosiveCluster(ctx.BlockPos); } } public class EvTumble : LuckyEvent { public override string Id => "Tumble"; public override string Label => "Knockdown — tumble lock 3s"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 4f; public override void Execute(LuckyEventContext ctx) { RandomEventRoller.ForceTumbleLock(ctx.Opener); } } public class EvTeleportRoulette : LuckyEvent { public override string Id => "TeleportRoulette"; public override string Label => "Teleport Roulette — opener sent somewhere"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 3f; public override void Execute(LuckyEventContext ctx) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) List<Vector3> randomLevelPoints = EventHelpers.GetRandomLevelPoints(1); if (randomLevelPoints.Count > 0) { EventHelpers.TeleportPlayer(ctx.Opener, randomLevelPoints[0]); } } } public class EvPiedPiper : LuckyEvent { public override string Id => "PiedPiper"; public override string Label => "Pied Piper — every enemy comes to YOU"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 2f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetSpawnedEnemies().Count > 0; } public override void Execute(LuckyEventContext ctx) { //IL_001a: 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) if ((Object)(object)ctx.Opener == (Object)null) { return; } List<Vector3> floorRing = SpawnUtils.GetFloorRing(((Component)ctx.Opener).transform.position, Mathf.Max(1, EventHelpers.GetSpawnedEnemies().Count), 4f); int num = 0; foreach (Enemy spawnedEnemy in EventHelpers.GetSpawnedEnemies()) { EventHelpers.TeleportEnemy(spawnedEnemy, floorRing[num++ % floorRing.Count]); } } } public class EvTaxman : LuckyEvent { public override string Id => "Taxman"; public override string Label => "The Taxman — cheapest valuable repossessed"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 3f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetLooseValuables(includeInCart: false).Count > 1; } public override void Execute(LuckyEventContext ctx) { ValuableObject val = null; float num = float.MaxValue; foreach (ValuableObject looseValuable in EventHelpers.GetLooseValuables(includeInCart: false)) { float valuableValue = EventHelpers.GetValuableValue(looseValuable); if (valuableValue > 0f && valuableValue < num) { num = valuableValue; val = looseValuable; } } if ((Object)(object)val != (Object)null) { EventHelpers.DestroyValuable(val); } } } public class EvReversePayday : LuckyEvent { public override string Id => "ReversePayday"; public override string Label => "Reverse Payday — quota +15%"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 2f; public override bool CanRun(LuckyEventContext ctx) { ExtractionPoint activeExtraction = EventHelpers.GetActiveExtraction(); if ((Object)(object)activeExtraction != (Object)null) { return activeExtraction.haulGoal > 0; } return false; } public override void Execute(LuckyEventContext ctx) { ExtractionPoint activeExtraction = EventHelpers.GetActiveExtraction(); if (!((Object)(object)activeExtraction == (Object)null)) { EventHelpers.SetHaulGoal(activeExtraction, Mathf.RoundToInt((float)activeExtraction.haulGoal * 1.15f)); } } } public class EvHoardersCurse : LuckyEvent { public override string Id => "HoardersCurse"; public override string Label => "Hoarder's Curse — all loot piles up in one room"; public override LuckyEventCategory Category => LuckyEventCategory.Unlucky; public override float DefaultWeight => 2f; public override bool CanRun(LuckyEventContext ctx) { return EventHelpers.GetLooseValuables(includeInCart: false).Count > 2; } public override void Execute(LuckyEventContext ctx) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0073: Unknown result type (might be due to invalid IL or missing references) List<Vector3> randomLevelPoints = EventHelpers.GetRandomLevelPoints(1); if (randomLevelPoints.Count == 0) { return; } Vector3 val = randomLevelPoints[0]; float num = 1.3499999f; int num2 = 0; Vector3 val2 = default(Vector3); foreach (ValuableObject looseValuable in EventHelpers.GetLooseValuables(includeInCart: false)) { int num3 = num2++; int num4 = num3 / 16; int num5 = num3 % 16; ((Vector3)(ref val2))..ctor((float)(num5 % 4) * 0.9f - num, (float)num4 * 0.8f, (float)(num5 / 4) * 0.9f - num); EventHelpers.TeleportValuableSafe(looseValuable, val + val2, snapToFloor: false); } } } public class EvBlackout : LuckyEvent { public override string Id => "Blackout"; public override string Label => "Blackout — lights out for 30s"; public override LuckyEventCategory Category => LuckyEventCategory.Wacky; public override float DefaultWeight => 3f; public override bool RequiresAllClients => true; public override void Execute(LuckyEventContext ctx) { LuckyFx.Broadcast("blackout", "30"); } } public class EvLowGravity : LuckyEvent { public override string Id => "LowGravity"; public override string Label => "Low Gravity — 20s of moon physics"; public override LuckyEventCategory Category => LuckyEventCategory.Wacky; public override float DefaultWeight => 3f; public override bool RequiresAllClients => true; public override void Execute(LuckyEventContext ctx) { LuckyFx.Broadcast("lowgrav", "20"); } } public class EvRaveLights : LuckyEvent { public override string Id => "RaveLights"; public override string Label => "Rave — rainbow lighting for 20s"; public override LuckyEventCategory Category => LuckyEventCategory.Wacky; public override float DefaultWeight => 2.5f; public override bool RequiresAllClients => true; public override void Execute(LuckyEventContext ctx) { LuckyFx.Broadcast("rave", "20"); } } public class EvFalseAlarm : LuckyEvent { public override string Id => "FalseAlarm"; public override string Label => "False Alarm — something is coming..."; public override LuckyEventCategory Category => LuckyEventCategory.Wacky; public override float DefaultWeight => 3f; public override bool RequiresAllClients => true; public override void Execute(LuckyEventContext ctx) { LuckyFx.Broadcast("falsealarm", ""); } } public class EvButterFingers : LuckyEvent { public override string Id => "ButterFingers"; public override string Label => "Butter Fingers — everyone drops their grab"; public override LuckyEventCategory Category => LuckyEventCategory.Wacky; public override float DefaultWeight => 3f; public override bool RequiresAllClients => true; public override void Execute(LuckyEventContext ctx) { LuckyFx.Broadcast("butterfingers", ""); } } public class EvTinyPlayers : LuckyEvent { public override string Id => "TinyPlayers"; public override string Label => "Honey I Shrunk the Crew — tiny for 30s"; public override LuckyEventCategory Category => LuckyEventCategory.Wacky; public override float DefaultWeight => 2f; public override bool RequiresAllClients => true; public override void Execute(LuckyEventContext ctx) { LuckyFx.Broadcast("avatarscale", "0.5,30"); } } public class EvGiantPlayers : LuckyEvent { public override string Id => "GiantPlayers"; public override string Label => "Growth Spurt — giant avatars for 30s"; public override LuckyEventCategory Category => LuckyEventCategory.Wacky; public override float DefaultWeight => 2f; public override bool RequiresAllClients => true; public override void Execute(LuckyEventContext ctx) { LuckyFx.Broadcast("avatarscale", "1.6,30"); } } public class EvDanceParty : LuckyEvent { public override string Id => "DanceParty"; public override string Label => "Dance Party — everybody boogie 15s"; public override LuckyEventCategory Category => LuckyEventCategory.Wacky; public override float DefaultWeight => 2.5f; public override bool RequiresAllClients => true; public override void Execute(LuckyEventContext ctx) { LuckyFx.Broadcast("danceparty", "15"); } } public enum LuckyEventCategory { Lucky, Unlucky, Chaotic, Wacky } public class LuckyEventContext { public PlayerAvatar Opener; public Vector3 BlockPos; } public abstract class LuckyEvent { internal ConfigEntry<float> ConfigWeight; public abstract string Id { get; } public abstract string Label { get; } public abstract LuckyEventCategory Category { get; } public abstract float DefaultWeight { get; } public virtual bool RequiresAllClients => false; public float BaseWeight { get { if (ConfigWeight == null) { return DefaultWeight; } return Mathf.Max(0f, ConfigWeight.Value); } } public float Weight => BaseWeight * CategoryWeights.Get(Category); public virtual bool CanRun(LuckyEventContext ctx) { return true; } public abstract void Execute(LuckyEventContext ctx); } public static class LuckyEventLog { internal static ConfigEntry<bool> ConfigEnabled; internal static ConfigEntry<int> ConfigMaxEntries; internal static ConfigEntry<float> ConfigDuration; public static bool Enabled { get { if (ConfigEnabled != null) { return ConfigEnabled.Value; } return true; } } public static int MaxEntries { get { if (ConfigMaxEntries == null) { return 3; } return Mathf.Max(1, ConfigMaxEntries.Value); } } public static float Duration { get { if (ConfigDuration == null) { return 60f; } return Mathf.Max(1f, ConfigDuration.Value); } } public static void BindConfig(ConfigFile config) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown ConfigEnabled = config.Bind<bool>("Event Log", "Enabled", true, "Keep a log of the most recent lucky block outcomes."); ConfigMaxEntries = config.Bind<int>("Event Log", "MaxEntries", 3, new ConfigDescription("How many recent events to keep at most.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>())); ConfigDuration = config.Bind<float>("Event Log", "DurationSeconds", 60f, new ConfigDescription("Events older than this drop off the log — except the newest one, which always stays.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f), Array.Empty<object>())); } public static List<RandomEventRoller.EventLogEntry> GetVisible() { List<RandomEventRoller.EventLogEntry> list = new List<RandomEventRoller.EventLogEntry>(); List<RandomEventRoller.EventLogEntry> eventLog = RandomEventRoller.EventLog; if (eventLog.Count == 0) { return list; } float realtimeSinceStartup = Time.realtimeSinceStartup; foreach (RandomEventRoller.EventLogEntry item in eventLog) { if (list.Count >= MaxEntries) { break; } if (realtimeSinceStartup - item.TimeLogged <= Duration) { list.Add(item); } } if (list.Count == 0) { list.Add(eventLog[0]); } return list; } } public static class LuckyEventRegistry { private static readonly List<LuckyEvent> _events = new List<LuckyEvent>(); private static bool _built; public static IReadOnlyList<LuckyEvent> All => _events; public static void Build() { if (_built) { return; } _built = true; Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { if (!type.IsAbstract && typeof(LuckyEvent).IsAssignableFrom(type)) { try { _events.Add((LuckyEvent)Activator.CreateInstance(type)); } catch (Exception ex) { Debug.LogError((object)("[LuckyBlock] Failed to create event '" + type.Name + "': " + ex.Message)); } } } _events.Sort(delegate(LuckyEvent a, LuckyEvent b) { int num = a.Category.CompareTo(b.Category); return (num == 0) ? string.CompareOrdinal(a.Id, b.Id) : num; }); Debug.Log((object)$"[LuckyBlock] Event registry built: {_events.Count} events."); } public static void BindConfig(ConfigFile config) { BindCategory(config, LuckyEventCategory.Lucky); BindCategory(config, LuckyEventCategory.Unlucky); BindCategory(config, LuckyEventCategory.Chaotic); BindCategory(config, LuckyEventCategory.Wacky); } private static void BindCategory(ConfigFile config, LuckyEventCategory category) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown string text = $"Events - {category}"; foreach (LuckyEvent @event in _events) { if (@event.Category == category) { string text2 = (@event.RequiresAllClients ? " Only rolls in Private edition or singleplayer." : ""); @event.ConfigWeight = config.Bind<float>(text, @event.Id, @event.DefaultWeight, new ConfigDescription(@event.Label + " — how often it rolls. 0 = never." + text2, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>())); } } } public static void Roll(LuckyEventContext ctx) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } List<LuckyEvent> list = new List<LuckyEvent>(); float num = 0f; foreach (LuckyEvent @event in _events) { if (IsEligible(@event, ctx)) { list.Add(@event); num += @event.Weight; } } if (list.Count == 0 || num <= 0f) { Debug.LogWarning((object)"[LuckyBlock] Roll: no eligible events — falling back to a valuable."); SpawnUtils.SpawnRandomValuable(SpawnUtils.GetSpawnPositionInFront(ctx.Opener, 2.5f)); return; } float num2 = Random.value * num; float num3 = 0f; LuckyEvent ev = list[list.Count - 1]; foreach (LuckyEvent item in list) { num3 += item.Weight; if (num2 < num3) { ev = item; break; } } Fire(ev, ctx); } public static void Fire(LuckyEvent ev, LuckyEventContext ctx) { try { ev.Execute(ctx); EventHelpers.Announce($"[{ev.Category}] {ev.Label}"); } catch (Exception arg) { Debug.LogError((object)$"[LuckyBlock] Event '{ev.Id}' failed: {arg}"); } } private static bool IsEligible(LuckyEvent ev, LuckyEventContext ctx) { if (ev.Weight <= 0f) { return false; } if (ev.RequiresAllClients && SemiFunc.IsMultiplayer() && !ModeManager.IsPrivate) { return false; } try { return ev.CanRun(ctx); } catch { return false; } } } public static class LuckyFx { public const string ANNOUNCE = "announce"; public const string BLACKOUT = "blackout"; public const string LOW_GRAVITY = "lowgrav"; public const string SHAKE = "shake"; public const string RAVE = "rave"; public const string FALSE_ALARM = "falsealarm"; public const string BUTTERFINGERS = "butterfingers"; public const string AVATAR_SCALE = "avatarscale"; public const string DANCE_PARTY = "danceparty"; public const string TELEPORT = "teleport"; private static bool _blackoutActive; private static bool _lowGravActive; private static bool _raveActive; private static bool _scaleActive; public static void Broadcast(string id, string args) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) string text = ((args != null && args.Length > 0) ? (id + "|" + args) : id); Run(text); if (SemiFunc.IsMultiplayer() && ModeManager.IsPrivate && LuckyBlockPlugin.FxEvent != null) { LuckyBlockPlugin.FxEvent.RaiseEvent((object)text, NetworkingEvents.RaiseOthers, SendOptions.SendReliable); } } public static void Run(string payload) { if (string.IsNullOrEmpty(payload)) { return; } int num = payload.IndexOf('|'); string text = ((num >= 0) ? payload.Substring(0, num) : payload); string text2 = ((num >= 0) ? payload.Substring(num + 1) : ""); try { switch (text) { case "announce": RandomEventRoller.LogEvent(text2, "[LuckyBlock]"); break; case "blackout": Start(Blackout(ParseF(text2, 0, 30f))); break; case "lowgrav": Start(LowGravity(ParseF(text2, 0, 20f))); break; case "shake": Start(Shake(ParseF(text2, 0, 6f), ParseF(text2, 1, 1.5f))); break; case "rave": Start(Rave(ParseF(text2, 0, 20f))); break; case "falsealarm": FalseAlarm(); break; case "butterfingers": EventHelpers.ReleaseLocalGrab(); break; case "avatarscale": Start(AvatarScale(ParseF(text2, 0, 0.5f), ParseF(text2, 1, 30f))); break; case "danceparty": DanceParty(ParseF(text2, 0, 15f)); break; case "teleport": TeleportSelf(text2); break; default: Debug.LogWarning((object)("[LuckyBlock] Unknown FX id '" + text + "'.")); break; } } catch (Exception ex) { Debug.LogError((object)("[LuckyBlock] FX '" + text + "' failed: " + ex.Message)); } } private static void Start(IEnumerator routine) { LuckyBlockPlugin.StartManagedCoroutine(routine); } private static float ParseF(string args, int index, float fallback) { if (string.IsNullOrEmpty(args)) { return fallback; } string[] array = args.Split(','); if (index >= array.Length) { return fallback; } if (!float.TryParse(array[index], NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return fallback; } return result; } private static IEnumerator Blackout(float duration) { if (_blackoutActive) { yield break; } _blackoutActive = true; List<KeyValuePair<Light, float>> dimmed = new List<KeyValuePair<Light, float>>(); Light[] array = Object.FindObjectsOfType<Light>(); foreach (Light val in array) { if (!((Object)(object)val == (Object)null) && !(val.intensity <= 0.01f)) { dimmed.Add(new KeyValuePair<Light, float>(val, val.intensity)); val.intensity = 0.02f; } } Color ambient = RenderSettings.ambientLight; RenderSettings.ambientLight = Color.black; yield return (object)new WaitForSeconds(duration); foreach (KeyValuePair<Light, float> item in dimmed) { if ((Object)(object)item.Key != (Object)null) { item.Key.intensity = item.Value; } } RenderSettings.ambientLight = ambient; _blackoutActive = false; } private static IEnumerator LowGravity(float duration) { if (!_lowGravActive) { _lowGravActive = true; Vector3 original = Physics.gravity; Physics.gravity = original * 0.25f; yield return (object)new WaitForSeconds(duration); Physics.gravity = original; _lowGravActive = false; } } private static IEnumerator Shake(float duration, float strength) { CameraShake shaker = Object.FindObjectOfType<CameraShake>(); float elapsed = 0f; while (elapsed < duration) { if ((Object)(object)shaker != (Object)null) { shaker.Shake(strength, 0.3f); } elapsed += 0.25f; yield return (object)new WaitForSeconds(0.25f); } } private static IEnumerator Rave(float duration) { if (!_raveActive) { _raveActive = true; Color original = RenderSettings.ambientLight; float elapsed = 0f; while (elapsed < duration) { RenderSettings.ambientLight = Color.HSVToRGB(Mathf.Repeat(elapsed * 0.5f, 1f), 0.9f, 0.8f); elapsed += Time.deltaTime; yield return null; } RenderSettings.ambientLight = original; _raveActive = false; } } private static void FalseAlarm() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) ChatManager instance = ChatManager.instance; if (!((Object)(object)instance == (Object)null)) { instance.PossessChatScheduleStart(9); instance.PossessChat((PossessChatID)0, "something is coming . . .", 0.06f, new Color(0.9f, 0.1f, 0.1f), 0f, false, 0, (UnityEvent)null); instance.PossessChat((PossessChatID)0, "nevermind. probably nothing", 0.05f, new Color(0.6f, 0.6f, 0.6f), 3f, false, 0, (UnityEvent)null); instance.PossessChatScheduleEnd(); } } private static IEnumerator AvatarScale(float scale, float duration) { if (_scaleActive) { yield break; } _scaleActive = true; List<KeyValuePair<Transform, Vector3>> scaled = new List<KeyValuePair<Transform, Vector3>>(); foreach (PlayerAvatar allPlayer in EventHelpers.GetAllPlayers()) { if (!((Object)(object)allPlayer == (Object)null) && !((Object)(object)allPlayer.playerAvatarVisuals == (Object)null)) { Transform transform = ((Component)allPlayer.playerAvatarVisuals).transform; scaled.Add(new KeyValuePair<Transform, Vector3>(transform, transform.localScale)); transform.localScale *= scale; } } yield return (object)new WaitForSeconds(duration); foreach (KeyValuePair<Transform, Vector3> item in scaled) { if ((Object)(object)item.Key != (Object)null) { item.Key.localScale = item.Value; } } _scaleActive = false; } private static void TeleportSelf(string args) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar instance = PlayerAvatar.instance; if (!((Object)(object)instance == (Object)null)) { PhotonView component = ((Component)instance).GetComponent<PhotonView>(); if (!((Object)(object)component == (Object)null) && (int)ParseF(args, 0, -1f) == component.ViewID) { EventHelpers.TeleportLocalController(new Vector3(ParseF(args, 1, 0f), ParseF(args, 2, 0f), ParseF(args, 3, 0f))); } } } private static void DanceParty(float duration) { MonoBehaviour instance = (MonoBehaviour)(object)LuckyBlockPlugin.Instance; if ((Object)(object)instance == (Object)null) { return; } foreach (PlayerAvatar allPlayer in EventHelpers.GetAllPlayers()) { RandomEventRoller.ForceBoomboxDance(allPlayer, duration, instance, "[LuckyBlock]"); } } } internal static class LevelPointUtils { private const float MIN_REACHABLE_SHARE = 0.25f; private static FieldInfo _fModuleConnected; private static bool _reflected; internal static bool IsGraphReady() { LevelGenerator instance = LevelGenerator.Instance; if ((Object)(object)instance == (Object)null || !instance.Generated) { return false; } EnsureReflection(); if (_fModuleConnected == null) { return true; } foreach (LevelPoint levelPathPoint in instance.LevelPathPoints) { if (!((Object)(object)levelPathPoint == (Object)null) && levelPathPoint.ModuleConnect && ((Component)levelPathPoint).gameObject.activeInHierarchy && !(bool)_fModuleConnected.GetValue(levelPathPoint)) { return false; } } return true; } internal static IEnumerator WaitForGraph(float timeout = 20f) { float waited = 0f; while (!IsGraphReady() && waited < timeout) { yield return (object)new WaitForSecondsRealtime(0.25f); waited += 0.25f; } yield return (object)new WaitForSecondsRealtime(0.25f); } internal static List<LevelPoint> GetReachablePoints(float maxDistanceFromTruck) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: 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) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) List<LevelPoint> list = new List<LevelPoint>(); LevelGenerator instance = LevelGenerator.Instance; if ((Object)(object)instance == (Object)null) { return list; } List<LevelPoint> list2 = new List<LevelPoint>(); foreach (LevelPoint levelPathPoint in instance.LevelPathPoints) { if (IsUsable(levelPathPoint)) { list2.Add(levelPathPoint); } } LevelPoint levelPathTruck = instance.LevelPathTruck; if ((Object)(object)levelPathTruck == (Object)null) { Debug.LogWarning((object)"[LuckyBlock] No truck level point — using the distance-free fallback filter."); return list2; } Vector3 position = ((Component)levelPathTruck).transform.position; Dictionary<LevelPoint, bool> dictionary = new Dictionary<LevelPoint, bool> { { levelPathTruck, true } }; Queue<LevelPoint> queue = new Queue<LevelPoint>(); queue.Enqueue(levelPathTruck); while (queue.Count > 0) { LevelPoint val = queue.Dequeue(); if ((Object)(object)val == (Object)null || val.ConnectedPoints == null) { continue; } foreach (LevelPoint connectedPoint in val.ConnectedPoints) { if (!((Object)(object)connectedPoint == (Object)null) && !dictionary.ContainsKey(connectedPoint)) { dictionary[connectedPoint] = true; queue.Enqueue(connectedPoint); if (IsUsable(connectedPoint) && !(Vector3.Distance(((Component)connectedPoint).transform.position, position) > maxDistanceFromTruck)) { list.Add(connectedPoint); } } } } if (list2.Count > 0 && (float)list.Count < (float)list2.Count * 0.25f) { List<LevelPoint> list3 = new List<LevelPoint>(); foreach (LevelPoint item in list2) { if ((Object)(object)item.Room != (Object)null && Vector3.Distance(((Component)item).transform.position, position) <= maxDistanceFromTruck) { list3.Add(item); } } Debug.LogWarning((object)($"[LuckyBlock] Only {list.Count}/{list2.Count} points reachable from the truck — " + $"graph looks incomplete, using {list3.Count} distance-filtered point(s) instead.")); if (list3.Count > 0) { return list3; } } Debug.Log((object)($"[LuckyBlock] Reachable level points: {list.Count}/{list2.Count} " + $"(within {maxDistanceFromTruck:F0}m of the truck).")); return list; } internal static int CountRooms() { LevelGenerator instance = LevelGenerator.Instance; if ((Object)(object)instance == (Object)null) { return 0; } Dictionary<RoomVolume, bool> dictionary = new Dictionary<RoomVolume, bool>(); foreach (LevelPoint levelPathPoint in instance.LevelPathPoints) { if ((Object)(object)levelPathPoint != (Object)null && (Object)(object)levelPathPoint.Room != (Object)null) { dictionary[levelPathPoint.Room] = true; } } return dictionary.Count; } internal static Vector3 ToSpawnPosition(LevelPoint lp) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0049: 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) RaycastHit val = default(RaycastHit); if (!Physics.Raycast(((Component)lp).transform.position + Vector3.up * 1.5f, Vector3.down, ref val, 6f, -1, (QueryTriggerInteraction)1)) { return ((Component)lp).transform.position + Vector3.up * 0.5f; } return ((RaycastHit)(ref val)).point + Vector3.up * 0.4f; } private static bool IsUsable(LevelPoint lp) { if ((Object)(object)lp == (Object)null) { return false; } if (!((Component)lp).gameObject.activeInHierarchy) { return false; } if (lp.Truck) { return false; } if ((Object)(object)((Component)lp).GetComponentInParent<StartRoom>() != (Object)null) { return false; } return true; } private static void EnsureReflection() { if (!_reflected) { _reflected = true; _fModuleConnected = typeof(LevelPoint).GetField("ModuleConnected", BindingFlags.Instance | BindingFlags.NonPublic); } } } public class LuckyBlock : MonoBehaviour { private PhysGrabObject _grab; private PhysGrabObjectImpactDetector _impact; private bool _triggered; private void Awake() { RandomEventRoller.Init(); _grab = ((Component)this).GetComponent<PhysGrabObject>(); _impact = ((Component)this).GetComponent<PhysGrabObjectImpactDetector>(); } private void Update() { if (!_triggered && SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_grab != (Object)null && _grab.grabbed) { Trigger(ResolveGrabber()); } } private void Open() { Trigger(ResolveGrabber()); } private void Trigger(PlayerAvatar grabber) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!_triggered) { _triggered = true; if ((Object)(object)grabber == (Object)null) { grabber = PlayerAvatar.instance; } Vector3 position = ((Component)this).transform.position; LuckyBlockEvents.Roll(grabber, position); if ((Object)(object)_impact != (Object)null) { _impact.DestroyObject(true); } else { Object.Destroy((Object)(object)((Component)this).gameObject); } } } private PlayerAvatar ResolveGrabber() { //IL_0069: 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_0077: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_grab != (Object)null && _grab.playerGrabbing != null && _grab.playerGrabbing.Count > 0) { PhysGrabber val = _grab.playerGrabbing[0]; if ((Object)(object)val != (Object)null && (Object)(object)val.playerAvatar != (Object)null) { return val.playerAvatar; } } List<PlayerAvatar> list = SemiFunc.PlayerGetAllPlayerAvatarWithinRange(8f, ((Component)this).transform.position, false, default(LayerMask)); if (list != null && list.Count > 0 && (Object)(object)list[0] != (Object)null) { return list[0]; } return PlayerAvatar.instance; } } public static class LuckyBlockEvents { private static LuckyEventContext MakeContext(PlayerAvatar player, Vector3 blockPos) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { player = PlayerAvatar.instance; } if (blockPos == Vector3.zero && (Object)(object)player != (Object)null) { blockPos = ((Component)player).transform.position; } return new LuckyEventContext { Opener = player, BlockPos = blockPos }; } public static void Roll(PlayerAvatar opener, Vector3 blockPos) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer()) { LuckyEventContext luckyEventContext = MakeContext(opener, blockPos); if (!((Object)(object)luckyEventContext.Opener == (Object)null)) { LuckyEventRegistry.Roll(luckyEventContext); } } } public static void TriggerSpecific(int eventIdx, PlayerAvatar player, Vector3 blockPos) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } LuckyEventContext luckyEventContext = MakeContext(player, blockPos); if (!((Object)(object)luckyEventContext.Opener == (Object)null)) { IReadOnlyList<LuckyEvent> all = LuckyEventRegistry.All; if (eventIdx >= 0 && eventIdx < all.Count) { LuckyEventRegistry.Fire(all[eventIdx], luckyEventContext); } else { LuckyEventRegistry.Roll(luckyEventContext); } } } } public class LuckyBlockItem : MonoBehaviour { private bool _isLucky; internal bool _consumed; private bool _activatedLocal; private PhysGrabObject _grab; private PhotonView _view; internal bool IsLucky => _isLucky; private void Awake() { RandomEventRoller.Init(); _grab = ((Component)this).GetComponent<PhysGrabObject>() ?? ((Component)this).GetComponentInParent<PhysGrabObject>(); _view = ((Component)this).GetComponent<PhotonView>() ?? ((Component)this).GetComponentInParent<PhotonView>(); } private void Update() { if (_isLucky && !_activatedLocal && !((Object)(object)_grab == (Object)null) && ModeManager.IsPrivate && _grab.grabbedLocal && SemiFunc.InputDown((InputKey)2)) { Activate(); } } internal void SetLucky() { MakeLucky(); if (SemiFunc.IsMultiplayer() && (Object)(object)_view != (Object)null && _view.ViewID != 0) { _view.RPC("SetLuckyRPC", (RpcTarget)4, Array.Empty<object>()); } } [PunRPC] private void SetLuckyRPC() { MakeLucky(); } private void MakeLucky() { _isLucky = true; LuckyBlockSkin.Apply(((Component)this).gameObject, 1f / 6f); } private void Open() { Activate(); } private void Activate() { if (!_activatedLocal) { _activatedLocal = true; int num = SemiFunc.PhotonViewIDPlayerAvatarLocal(); if (SemiFunc.IsMasterClientOrSingleplayer()) { ActivateOnHost(((Component)this).gameObject, num); } else if ((Object)(object)_view != (Object)null && _view.ViewID != 0) { _view.RPC("ActivateRPC", (RpcTarget)2, new object[1] { num }); } } } [PunRPC] private void ActivateRPC(int playerViewID) { ActivateOnHost(((Component)this).gameObject, playerViewID); } internal static void ActivateOnHost(GameObject item, int playerViewID) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)item == (Object)null || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } LuckyBlockItem component = item.GetComponent<LuckyBlockItem>(); if ((Object)(object)component != (Object)null) { if (component._consumed) { return; } component._consumed = true; } PlayerAvatar opener = ResolvePlayer(playerViewID); Vector3 position = item.transform.position; LuckyBlockEvents.Roll(opener, position); if (SemiFunc.IsMultiplayer()) { PhotonNetwork.Destroy(item); } else { Object.Destroy((Object)(object)item); } } private static PlayerAvatar ResolvePlayer(int viewID) { if (viewID > 0) { PhotonView val = PhotonView.Find(viewID); PlayerAvatar val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<PlayerAvatar>() : null); if ((Object)(object)val2 != (Object)null) { return val2; } } return PlayerAvatar.instance; } } [HarmonyPatch(typeof(ItemAttributes), "Awake")] internal static class LuckyBlockItem_AttachPatch { private static void Postfix(ItemAttributes __instance) { if (!((Object)(object)__instance == (Object)null)) { string text = (((Object)(object)__instance.item != (Object)null) ? __instance.item.itemName : null); string value = "Drone Battery"; if (((text != null && text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) || ((Object)((Component)__instance).gameObject).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) && (Object)(object)((Component)__instance).GetComponent<LuckyBlockItem>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<LuckyBlockItem>(); } } } } [HarmonyPatch(typeof(ItemAttributes), "GetItemNameLocalized")] internal static class LuckyBlockItem_NamePatch { private static void Postfix(ItemAttributes __instance, ref string __result) { LuckyBlockItem luckyBlockItem = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<LuckyBlockItem>() : null); if ((Object)(object)luckyBlockItem != (Object)null && luckyBlockItem.IsLucky) { __result = "Lucky Block"; } } } public class LuckyBlockManager : MonoBehaviour { public static LuckyBlockManager Instance { get; private set; } private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } } internal List<GameObject> SpawnBlocks(List<Vector3> positions) { List<GameObject> list = new List<GameObject>(); if (positions == null || positions.Count == 0) { return list; } if (SemiFunc.IsMultiplayer() && !SemiFunc.IsMasterClientOrSingleplayer()) { Debug.LogWarning((object)"[LuckyBlock] Only the host can spawn lucky blocks."); return list; } if (!ModeManager.IsPrivate) { return SpawnPublic(positions, list); } return SpawnPrivate(positions, list); } private List<GameObject> SpawnPrivate(List<Vector3> positions, List<GameObject> spawned) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) if ((Object)(object)SpawnUtils.GetLuckyItem() == (Object)null) { Debug.LogError((object)"[LuckyBlock] PRIVATE mode: base item 'Drone Battery' not found. Switch back to Public mode (F6 menu)."); return spawned; } foreach (Vector3 position in positions) { GameObject val = SpawnUtils.SpawnLuckyItem(position); if (!((Object)(object)val == (Object)null)) { LuckyBlockItem componentInChildren = val.GetComponentInChildren<LuckyBlockItem>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.SetLucky(); } else { Debug.LogError((object)"[LuckyBlock] spawned item has no LuckyBlockItem component."); } spawned.Add(val); Debug.Log((object)$"[LuckyBlock] Lucky ITEM spawned at {position:F1} (private edition)."); } } return spawned; } private List<GameObject> SpawnPublic(List<Vector3> positions, List<GameObject> spawned) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) foreach (Vector3 position in positions) { GameObject val = SpawnUtils.SpawnLuckyValuable(position); if ((Object)(object)val == (Object)null) { Debug.LogError((object)$"[LuckyBlock] Failed to spawn lucky valuable at {position:F1}."); continue; } if ((Object)(object)val.GetComponent<LuckyBlock>() == (Object)null) { val.AddComponent<LuckyBlock>(); } LuckyBlockSkin.Apply(val); if (SemiFunc.IsMultiplayer()) { PhotonView component = val.GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null && component.ViewID != 0 && LuckyBlockPlugin.SkinEvent != null) { LuckyBlockPlugin.SkinEvent.RaiseEvent((object)component.ViewID, NetworkingEvents.RaiseOthers, SendOptions.SendReliable); } } spawned.Add(val); Debug.Log((object)$"[LuckyBlock] Lucky six-pack spawned at {position:F1}."); } return spawned; } internal void ClearBlocks() { } } public enum LuckyBlockMode { PublicServer, PrivateServer } public static class ModeManager { internal static ConfigEntry<LuckyBlockMode> EditionConfig; public static LuckyBlockMode CurrentEdition { get { if (EditionConfig == null) { return LuckyBlockMode.PublicServer; } return EditionConfig.Value; } } public static bool IsPrivate => CurrentEdition == LuckyBlockMode.PrivateServer; public static void SetEdition(LuckyBlockMode mode) { if (EditionConfig != null) { EditionConfig.Value = mode; } } } [BepInPlugin("com.tonnom.luckyblock", "REPO_lucky_block", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class LuckyBlockPlugin : BaseUnityPlugin { private static MonoBehaviour _coroutineHost; private Harmony _harmony; public static LuckyBlockPlugin Instance { get; private set; } internal static NetworkedEvent SkinEvent { get; private set; } internal static NetworkedEvent FxEvent { get; private set; } private void Awake() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown Instance = this; _coroutineHost = (MonoBehaviour)(object)this; ((Component)this).gameObject.AddComponent<LuckyBlockManager>(); _harmony = new Harmony("com.tonnom.luckyblock"); _harmony.PatchAll(); SkinEvent = new NetworkedEvent("LuckyBlock Skin", (Action<EventData>)OnSkinEvent); FxEvent = new NetworkedEvent("LuckyBlock FX", (Action<EventData>)OnFxEvent); LuckyEventRegistry.Build(); LuckyProfileStore.Discover(); string text = ((BaseUnityPlugin)this).Info.Metadata.Version.ToString(); ((BaseUnityPlugin)this).Config.Bind<string>("Profiles", "ModVersion", text, new ConfigDescription("Currently installed REPO_lucky_block version.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[1] { text }), Array.Empty<object>())); LuckyProfileStore.BindConfig(((BaseUnityPlugin)this).Config); LuckySettingsMenu.BindConfig(((BaseUnityPlugin)this).Config); ModeManager.EditionConfig = ((BaseUnityPlugin)this).Config.Bind<LuckyBlockMode>("General", "Edition", LuckyBlockMode.PublicServer, "PublicServer = host-only, no client install needed (lucky block is a valuable, grab it). PrivateServer = everyone must install the mod (lucky block is a custom item, press E)."); LuckyBlockSpawner.BindConfig(((BaseUnityPlugin)this).Config); EventHelpers.BindConfig(((BaseUnityPlugin)this).Config); CategoryWeights.BindConfig(((BaseUnityPlugin)this).Config); LuckyEventRegistry.BindConfig(((BaseUnityPlugin)this).Config); LuckyProfileStore.ApplyIfChanged(); ((Component)this).gameObject.AddComponent<LuckyConfigWatcher>(); SceneManager.sceneLoaded += OnSceneLoaded; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[LuckyBlock] Plugin loaded — Manager alive: {(Object)(object)LuckyBlockManager.Instance != (Object)null}."); } private static void OnSkinEvent(EventData e) { if (((e != null) ? e.CustomData : null) is int viewID) { StartManagedCoroutine(SkinWhenReady(viewID)); } } private static IEnumerator SkinWhenReady(int viewID) { for (int i = 0; i < 120; i++) { PhotonView val = PhotonView.Find(viewID); if ((Object)(object)val != (Object)null) { LuckyBlockSkin.Apply(((Component)val).gameObject); break; } yield return null; } } private static void OnFxEvent(EventData e) { if (((e != null) ? e.CustomData : null) is string payload) { LuckyFx.Run(payload); } } internal static void StartManagedCoroutine(IEnumerator routine) { if ((Object)(object)_coroutineHost != (Object)null) { _coroutineHost.StartCoroutine(routine); } else { Debug.LogWarning((object)"[LuckyBlock] CoroutineHost missing — coroutine dropped."); } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown if ((int)mode == 0) { LuckyBlockManager.Instance?.ClearBlocks(); if ((Object)(object)Object.FindObjectOfType<LuckySettingsMenu>() == (Object)null) { GameObject val = new GameObject("LuckyBlock_SettingsMenu"); val.AddComponent<LuckySettingsMenu>(); Object.DontDestroyOnLoad((Object)val); } LuckyProfileStore.ApplyIfChanged(); LuckyBlockSpawner.ResetSpawnFlag(); StartManagedCoroutine(BackupSpawnCoroutine()); } } private static IEnumerator BackupSpawnCoroutine() { yield return (object)new WaitForSeconds(1f); if (!((Object)(object)RunManager.instance == (Object)null) && SemiFunc.RunIsLevel() && SemiFunc.IsMasterClientOrSingleplayer()) { yield return LuckyBlockSpawner.SpawnWhenGraphReady("BackupCoroutine"); } } } public class CoroutineHost : MonoBehaviour { } internal static class LuckyBlockSkin { private const string SKIN_NAME = "LuckyBlockSkin"; private static Texture2D _tex; private static Material _mat; private static Mesh _cubeMesh; internal static void Apply(GameObject valuable, float scale = 1f) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00cb: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)valuable == (Object)null || (Object)(object)valuable.transform.Find("LuckyBlockSkin") != (Object)null) { return; } Material material = GetMaterial(); Mesh cubeMesh = GetCubeMesh(); if (!((Object)(object)material == (Object)null) && !((Object)(object)cubeMesh == (Object)null)) { Bounds val = ComputeBounds(valuable); float num = Mathf.Max(new float[3] { ((Bounds)(ref val)).size.x, ((Bounds)(ref val)).size.y, ((Bounds)(ref val)).size.z }) * 1.05f; if (num <= 0.001f) { num = 0.5f; } num = Mathf.Clamp(num, 0.2f, 1f) * scale; GameObject val2 = new GameObject("LuckyBlockSkin"); val2.transform.SetParent(valuable.transform, false); val2.transform.localRotation = Quaternion.identity; val2.transform.position = ((Bounds)(ref val)).center; Vector3 lossyScale = valuable.transform.lossyScale; val2.transform.localScale = new Vector3(num / Mathf.Max(0.0001f, lossyScale.x), num / Mathf.Max(0.0001f, lossyScale.y), num / Mathf.Max(0.0001f, lossyScale.z)); val2.AddComponent<MeshFilter>().sharedMesh = cubeMesh; ((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterial = material; } } private static Bounds ComputeBounds(GameObject go) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) Bounds result = default(Bounds); bool flag = false; Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !(((Object)((Component)val).gameObject).name == "LuckyBlockSkin") && (val is MeshRenderer || val is SkinnedMeshRenderer)) { if (!flag) { result = val.bounds; flag = true; } else { ((Bounds)(ref result)).Encapsulate(val.bounds); } } } if (!flag) { ((Bounds)(ref result))..ctor(go.transform.position, Vector3.one * 0.5f); } return result; } private static Mesh GetCubeMesh() { if ((Object)(object)_cubeMesh != (Object)null) { return _cubeMesh; } GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); _cubeMesh = obj.GetComponent<MeshFilter>().sharedMesh; Object.Destroy((Object)(object)obj); return _cubeMesh; } private static Material GetMaterial() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_mat != (Object)null) { return _mat; } Texture2D texture = GetTexture(); Shader val = Shader.Find("Standard"); if ((Object)(object)val == (Object)null) { return null; } _mat = new Material(val) { name = "LuckyBlockMat", mainTexture = (Texture)(object)texture }; _mat.SetFloat("_Glossiness", 0.1f); _mat.SetFloat("_Metallic", 0f); _mat.EnableKeyword("_EMISSION"); _mat.SetColor("_EmissionColor", new Color(0.3f, 0.24f, 0f)); if ((Object)(object)texture != (Object)null) { _mat.SetTexture("_EmissionMap", (Texture)(object)texture); } return _mat; } private static Texture2D GetTexture() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if ((Object)(object)_tex != (Object)null) { return _tex; } _tex = new Texture2D(2, 2, (TextureFormat)4, false); string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)LuckyBlockPlugin.Instance).Info.Location), "lucky_block.png"); if (File.Exists(text)) { ImageConversion.LoadImage(_tex, File.ReadAllBytes(text)); ((Texture)_tex).filterMode = (FilterMode)0; ((Texture)_tex).wrapMode = (TextureWrapMode)1; _tex.Apply(); } else { Debug.LogError((object)("[LuckyBlock] Skin texture not found at '" + text + "'. Block will be untextured.")); } return _tex; } } [HarmonyPatch(typeof(SemiFunc), "OnLevelGenDone")] internal static class OnLevelGenDone_Patch { private static void Postfix() { try { if (!((Object)(object)RunManager.instance == (Object)null) && SemiFunc.RunIsLevel() && SemiFunc.IsMasterClientOrSingleplayer()) { LuckyBlockPlugin.StartManagedCoroutine(LuckyBlockSpawner.SpawnWhenGraphReady("OnLevelGenDone")); } } catch (Exception arg) { Debug.LogError((object)$"[LuckyBlock] Spawn postfix failed (ignored): {arg}"); } } } internal static class LuckyBlockSpawner { private const float MIN_BLOCK_SPACING = 4f; private const int NO_LEVEL = -1; private static int _spawnedForLevel = -1; internal static ConfigEntry<bool> ConfigEnabled; internal static ConfigEntry<float> ConfigMaxSpawnDistance; internal static ConfigEntry<float> ConfigDensityPercent; public static bool Enabled { get { if (ConfigEnabled != null) { return ConfigEnabled.Value; } return true; } } public static float MaxSpawnDistance { get { if (ConfigMaxSpawnDistance == null) { return 100f; } return ConfigMaxSpawnDistance.Value; } } public static float DensityPercent { get { if (ConfigDensityPercent == null) { return 30f; } return Mathf.Clamp(ConfigDensityPercent.Value, 1f, 1000f); } } internal static void BindConfig(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown ConfigEnabled = config.Bind<bool>("General", "SpawningEnabled", true, "Master on/off switch. When false, no Lucky Blocks spawn — the mod stays installed but does nothing."); ConfigMaxSpawnDistance = config.Bind<float>("General", "MaxSpawnDistanceFromTruck", 100f, new ConfigDescription("Blocks never spawn further than this many metres from the truck. Stops one showing up somewhere nobody will ever walk to.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 400f), Array.Empty<object>())); ConfigDensityPercent = config.Bind<float>("General", "DensityPercent", 30f, new ConfigDescription("How many Lucky Blocks spawn per level, as a percentage of that level's room count (rounded, minimum 1 block). E.g. 10 rooms at 30% = 3 blocks; at 1000% = 100 blocks (10 per room) for maximum chaos. 1% is the floor on purpose — use SpawningEnabled to turn the mod off entirely instead of setting this to 0.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 1000f), Array.Empty<object>())); } internal static void ResetSpawnFlag() { _spawnedForLevel = -1; } internal static IEnumerator SpawnWhenGraphReady(string caller) { yield return LevelPointUtils.WaitForGraph(); if ((Object)(object)RunManager.instance == (Object)null || !SemiFunc.RunIsLevel() || !SemiFunc.IsMasterClientOrSingleplayer()) { yield break; } try { SpawnForCurrentLevel(caller); } catch (Exception arg) { Debug.LogError((object)$"[LuckyBlock] Spawn ({caller}) failed (ignored): {arg}"); } } internal static void SpawnForCurrentLevel(string caller = "?") { //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: 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_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: 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_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) if (!Enabled) { Debug.Log((object)("[LuckyBlock] SpawnForCurrentLevel(" + caller + "): spawning disabled in config — skip.")); return; } int currentLevel = GetCurrentLevel(); if (_spawnedForLevel == currentLevel) { Debug.Log((object)$"[LuckyBlock] SpawnForCurrentLevel({caller}): already spawned for level {currentLevel} — skip."); return; } if ((Object)(object)LuckyBlockManager.Instance == (Object)null) { Debug.LogError((object)"[LuckyBlock] LuckyBlockManager.Instance is null — cannot spawn."); return; } _spawnedForLevel = currentLevel; int blockCount = GetBlockCount(); Debug.Log((object)$"[LuckyBlock] Spawning {blockCount} block(s) for level {currentLevel} (caller: {caller})."); List<LevelPoint> reachablePoints = LevelPointUtils.GetReachablePoints(MaxSpawnDistance); if (reachablePoints.Count == 0) { FallbackSpawn(blockCount); return; } for (int num = reachablePoints.Count - 1; num > 0; num--) { int index = Random.Range(0, num + 1); LevelPoint value = reachablePoints[num]; reachablePoints[num] = reachablePoints[index]; reachablePoints[index] = value; } List<Vector3> list = new List<Vector3>(); List<Vector3> list2 = new List<Vector3>(); foreach (LevelPoint item in reachablePoints) { if (list.Count >= blockCount) { break; } Vector3 val = LevelPointUtils.ToSpawnPosition(item); bool flag = false; foreach (Vector3 item2 in list2) { if (Vector3.Distance(val, item2) < 4f) { flag = true; break; } } if (!flag) { list.Add(val); list2.Add(val); } } if (list.Count < blockCount) { foreach (LevelPoint item3 in reachablePoints) { if (list.Count >= blockCount) { break; } Vector3 val2 = LevelPointUtils.ToSpawnPosition(item3); bool flag2 = false; foreach (Vector3 item4 in list2) { if (Vector3.Distance(val2, item4) < 0.5f) { flag2 = true; break; } } if (!flag2) { list.Add(val2); list2.Add(val2); } } } LuckyBlockManager.Instance.SpawnBlocks(list); Debug.Log((object)$"[LuckyBlock] Sent {list.Count}/{blockCount} block position(s) to manager."); } internal static GameObject SpawnOne(Vector3 pos) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)LuckyBlockManager.Instance == (Object)null) { Debug.LogError((object)"[LuckyBlock] SpawnOne: LuckyBlockManager.Instance is null."); return null; } List<GameObject> list = LuckyBlockManager.Instance.SpawnBlocks(new List<Vector3> { pos }); if (list.Count <= 0) { return null; } return list[0]; } internal static int GetCurrentLevel() { return Mathf.Clamp(SemiFunc.RunGetLevelsCompleted() + 1, 1, 20); } private static int GetBlockCount() { int num = LevelPointUtils.CountRooms(); if (num > 0) { return Mathf.Max(1, Mathf.RoundToInt((float)num * (DensityPercent / 100f))); } Debug.LogWarning((object)"[LuckyBlock] GetBlockCount: could not read the room count — using the fallback formula."); return FallbackBlockCount(GetCurrentLevel()); } private static int FallbackBlockCount(int level) { int[] array = new int[4] { 2, 5, 7, 9 }; int num = ((level <= array.Length) ? array[level - 1] : (array[^1] + (level - array.Length) * 2)); return Mathf.Max(1, num + Random.Range(-1, 2)); } private static void FallbackSpawn(int count) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) Debug.LogWarning((object)"[LuckyBlock] No interior LevelPathPoints — using fallback ring."); PlayerAvatar instance = PlayerAvatar.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)LuckyBlockManager.Instance == (Object)null)) { List<Vector3> list = new List<Vector3>(count); Vector3 val = default(Vector3); RaycastHit val2 = default(RaycastHit); for (int i = 0; i < count; i++) { float num = (float)i * (360f / (float)count) * ((float)Math.PI / 180f); float num2 = 6f + (float)i * 1.5f; ((Vector3)(ref val))..ctor(Mathf.Cos(num) * num2, 0f, Mathf.Sin(num) * num2); Vector3 item = (Physics.Raycast(((Component)instance).transform.position + val + Vector3.up * 5f, Vector3.down, ref val2, 12f) ? (((RaycastHit)(ref val2)).point + Vector3.up * 0.4f) : (((Component)instance).transform.position + val + Vector3.up * 0.4f)); list.Add(item); } LuckyBlockManager.Instance.SpawnBlocks(list); } } } public class LuckySettingsMenu : MonoBehaviour { private enum Page { Main, EventsPick, EventsList } private enum RowKind { Slider, ForwardNav, Other } internal static ConfigEntry<bool> ConfigEnabled; internal static ConfigEntry<KeyCode> ConfigToggleKey; private bool _open; private int _selectedIndex; private Page _page; private LuckyEventCategory _eventsCategory; private Vector2 _scroll = Vector2.zero; private string _status = ""; private float _statusUntil = -1f; private bool _profileDirty; private float _profileDirtyAt; private const float AUTOSAVE_DEBOUNCE = 0.5f; private const float WIN_W = 420f; private const float WIN_H = 560f; private const float ROW_H = 22f; private const float PAD = 8f; private const int FONT_SZ = 12; private const float HOLD_DELAY = 0.3f; private const float REPEAT_RATE = 0.05f; private float _upTimer; private float _downTimer; private float _enterTimer; private float _leftTimer; private float _rightTimer; private static readonly Color COL_SELECTED = new Color(1f, 0.85f, 0f); private sta