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 ScorchedVoxels v0.20.72
ScorchedVoxels.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.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using R2API.Networking; using R2API.Networking.Interfaces; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.Navigation; using RoR2.Orbs; using RoR2.Projectile; using RoR2.Stats; using RoR2.UI; using TMPro; using Unity.Collections; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.Profiling; using UnityEngine.Rendering; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ScorchedVoxels")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.20.72.0")] [assembly: AssemblyInformationalVersion("0.20.72+a4d65434dd33f229551efc8d9b06c8cae4d20476")] [assembly: AssemblyProduct("ScorchedVoxels")] [assembly: AssemblyTitle("ScorchedVoxels")] [assembly: AssemblyVersion("0.20.72.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ScorchedVoxels { internal class ArcadeColorGrid { private class Tile { public int idx; public UiTile ui; public Image sprite; public Image swatch; public UiKit.Label badge; } public const float TileW = 96f; public const float TileH = 112f; public const float Gap = 8f; private const float SpriteScale = 6f; private readonly List<Tile> tiles = new List<Tile>(); private string profileKey; public Action onChanged; public int PickedCount => UserLifetimeStats.ArcadeColors(profileKey).Count; public float Build(RectTransform content, float contentW, string userProfileKey) { profileKey = userProfileKey; tiles.Clear(); int num = Mathf.Max(2, Mathf.FloorToInt((contentW + 8f) / 104f)); float num2 = (0f - ((float)num * 96f + (float)(num - 1) * 8f)) * 0.5f; for (int i = 0; i < 16; i++) { int num3 = i % num; int num4 = i / num; float x = num2 + (float)num3 * 104f + 48f; float y = 0f - ((float)num4 * 120f + 56f); tiles.Add(BuildTile(content, i, x, y)); } Refresh(); return (float)((16 + num - 1) / num) * 120f; } private Tile BuildTile(RectTransform content, int idx, float x, float y) { //IL_0047: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) Tile tile = new Tile { idx = idx }; tile.ui = new UiTile($"color_{idx}", content, new Vector2(96f, 112f), new Vector2(x, y), (UnityAction)delegate { OnTileClicked(idx); }); GameObject val = new GameObject("commando"); val.transform.SetParent(((Component)tile.ui.Face).transform, false); tile.sprite = val.AddComponent<Image>(); ((Graphic)tile.sprite).raycastTarget = false; RectTransform rectTransform = ((Graphic)tile.sprite).rectTransform; rectTransform.pivot = new Vector2(0.5f, 0f); rectTransform.anchorMin = new Vector2(0.5f, 0f); rectTransform.anchorMax = new Vector2(0.5f, 0f); rectTransform.sizeDelta = new Vector2(36f, 66f); rectTransform.anchoredPosition = new Vector2(0f, 26f); if (CommandoSprites.Ready) { tile.sprite.sprite = CommandoSprites.CommandoFrame(idx, 0f); } else { ((Behaviour)tile.sprite).enabled = false; tile.swatch = UiKit.CreateImage("swatch", ((Component)tile.ui.Face).transform, CommandoSprites.Tint(idx)); ((Graphic)tile.swatch).raycastTarget = false; RectTransform rectTransform2 = ((Graphic)tile.swatch).rectTransform; rectTransform2.pivot = new Vector2(0.5f, 0f); rectTransform2.anchorMin = new Vector2(0.5f, 0f); rectTransform2.anchorMax = new Vector2(0.5f, 0f); rectTransform2.sizeDelta = new Vector2(36f, 66f); rectTransform2.anchoredPosition = new Vector2(0f, 26f); } UiKit.Label label = UiKit.CreateLabel($"label_{idx}", ((Component)tile.ui.Face).transform, 11f, UiKit.TextPale, (TextAnchor)4); label.Rect.anchorMin = new Vector2(0f, 0f); label.Rect.anchorMax = new Vector2(1f, 0f); label.Rect.pivot = new Vector2(0.5f, 0f); label.Rect.sizeDelta = new Vector2(-6f, 20f); label.Rect.anchoredPosition = new Vector2(0f, 3f); label.ClipSingleLine(); label.Text = CommandoSprites.ColorwayNames[idx]; tile.badge = UiKit.CreateLabel($"badge_{idx}", ((Component)tile.ui.Face).transform, 16f, UiKit.Gold, (TextAnchor)4); tile.badge.Rect.anchorMin = new Vector2(1f, 1f); tile.badge.Rect.anchorMax = new Vector2(1f, 1f); tile.badge.Rect.sizeDelta = new Vector2(22f, 22f); tile.badge.Rect.anchoredPosition = new Vector2(-14f, -14f); tile.badge.Bold(); tile.badge.Text = ""; return tile; } private void OnTileClicked(int idx) { List<int> list = new List<int>(UserLifetimeStats.ArcadeColors(profileKey)); if (list.Contains(idx)) { list.Remove(idx); } else if (list.Count < 3) { list.Add(idx); } else { list[2] = idx; } UserLifetimeStats.SetArcadeColors(profileKey, list); Refresh(); onChanged?.Invoke(); } public void Refresh() { IReadOnlyList<int> readOnlyList = UserLifetimeStats.ArcadeColors(profileKey); foreach (Tile tile in tiles) { int num = -1; for (int i = 0; i < readOnlyList.Count; i++) { if (readOnlyList[i] == tile.idx) { num = i; break; } } tile.ui.Selected = num == 0; tile.badge.Text = ((num >= 0) ? (num + 1).ToString() : ""); } } public void Tick() { if (!CommandoSprites.Ready) { return; } float unscaledTime = Time.unscaledTime; foreach (Tile tile in tiles) { tile.sprite.sprite = CommandoSprites.CommandoFrame(tile.idx, unscaledTime); if (!((Behaviour)tile.sprite).enabled) { ((Behaviour)tile.sprite).enabled = true; } if ((Object)(object)tile.swatch != (Object)null && ((Behaviour)tile.swatch).enabled) { ((Behaviour)tile.swatch).enabled = false; } } } } internal static class ArcadeTheming { public static string DestinationScene; } internal static class ArcadeLocal { public static NetworkUser User() { foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { if ((Object)(object)readOnlyInstances != (Object)null && ((NetworkBehaviour)readOnlyInstances).isLocalPlayer) { return readOnlyInstances; } } return null; } public static string ProfileKey() { NetworkUser val = User(); if (!((Object)(object)val == (Object)null)) { return UserLifetimeStats.ProfileKey(val); } return null; } public static uint NetId() { //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) NetworkUser val = User(); if (!((Object)(object)val == (Object)null)) { NetworkInstanceId netId = ((NetworkBehaviour)val).netId; return ((NetworkInstanceId)(ref netId)).Value; } return 0u; } public static int PreferredColorway() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) NetworkUser val = User(); if ((Object)(object)val == (Object)null) { return 0; } IReadOnlyList<int> readOnlyList = UserLifetimeStats.ArcadeColors(val); if (readOnlyList != null && readOnlyList.Count > 0) { return readOnlyList[0]; } NetworkInstanceId netId = ((NetworkBehaviour)val).netId; return CommandoSprites.ColorwayFor(((NetworkInstanceId)(ref netId)).Value); } } internal static class ArcadeRng { public static uint Step(ref uint state) { uint num = state; num ^= num << 13; num ^= num >> 17; num ^= num << 5; return state = num; } public static int Next(ref uint state, int maxExclusive) { return (int)(Step(ref state) % (uint)maxExclusive); } } internal class ArcadeContext { public uint seed; public RectTransform panel; public float width; public float height; public WormsGame.MatchConfig wormsMatch; public RaceGame.MatchConfig raceMatch; } internal interface IMiniGame { void Start(ArcadeContext ctx); void Tick(float dt); void End(); } internal static class ArcadeInput { public static bool Blocked; public static bool ActionDown; public static bool ActionHeld; public static bool RopeDown; public static bool RopeHeld; public static bool DuckHeld; public static bool ToggleDown; public static void Poll(RectTransform clickArea) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if (Blocked) { ActionDown = (ActionHeld = (RopeDown = (RopeHeld = (DuckHeld = (ToggleDown = false))))); return; } ActionDown = Input.GetKeyDown((KeyCode)32) || Input.GetKeyDown((KeyCode)119) || Input.GetKeyDown((KeyCode)273) || (Input.GetMouseButtonDown(0) && inArea(Vector2.op_Implicit(Input.mousePosition))); ActionHeld = Input.GetKey((KeyCode)32) || Input.GetKey((KeyCode)119) || Input.GetKey((KeyCode)273) || Input.GetMouseButton(0); RopeDown = Input.GetKeyDown((KeyCode)115) || Input.GetKeyDown((KeyCode)274) || Input.GetKeyDown((KeyCode)306) || (Input.GetMouseButtonDown(1) && inArea(Vector2.op_Implicit(Input.mousePosition))); RopeHeld = Input.GetKey((KeyCode)115) || Input.GetKey((KeyCode)274) || Input.GetKey((KeyCode)306) || Input.GetMouseButton(1); DuckHeld = Input.GetKey((KeyCode)115) || Input.GetKey((KeyCode)274) || Input.GetKey((KeyCode)306); ToggleDown = Input.GetKeyDown((KeyCode)103); bool inArea(Vector2 p) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)clickArea != (Object)null) { return RectTransformUtility.RectangleContainsScreenPoint(clickArea, p); } return false; } } } internal static class ArcadeHost { internal enum GameKind { Runner, Worms, Race, Terrarium } private abstract class MatchChannel { protected const float ResendSeconds = 2f; protected const float HostSilenceFoldSeconds = 8f; protected readonly bool hostLive; protected float nextResendAt; protected float lastHostMsgAt; protected abstract uint HostMatchId { get; } protected abstract uint RunningMatchId { get; } protected abstract bool JoinPending { get; } protected MatchChannel(bool hostLive) { this.hostLive = hostLive; lastHostMsgAt = Time.unscaledTime; } protected abstract void StartPendingGame(); protected abstract void SendAnnounce(); protected abstract void SendTeardown(); protected abstract void HostTickCanon(); protected abstract void Close(); public void StampHostMsg() { lastHostMsgAt = Time.unscaledTime; } public void Tick() { if (JoinPending) { if (!uiBuilt) { return; } StartPendingGame(); } if (!NetworkServer.active) { if (RunningMatchId != 0 && Time.unscaledTime - lastHostMsgAt > 8f) { Close(); FoldLocalMatch(); } } else { if (!hostLive) { return; } if (RunningMatchId != HostMatchId) { SendTeardown(); Close(); return; } HostTickCanon(); if (Time.unscaledTime >= nextResendAt) { nextResendAt = Time.unscaledTime + 2f; SendAnnounce(); } } } } private sealed class WormsChannel : MatchChannel { private readonly WormsGame.MatchConfig hostCfg; private WormsGame.MatchConfig pendingCfg; private WormsShot[] pendingShots; private readonly List<WormsShot> shotLog = new List<WormsShot>(); private WormsShot[] shotLogCache = Array.Empty<WormsShot>(); private readonly List<WormsShot> requestQueue = new List<WormsShot>(); private readonly HashSet<uint> forfeited = new HashSet<uint>(); private int timedShotCount = -1; private float turnDeadlineAt; protected override uint HostMatchId => hostCfg.matchId; protected override uint RunningMatchId { get { if (!(game is WormsGame wormsGame)) { return 0u; } return wormsGame.MatchId; } } protected override bool JoinPending => pendingCfg != null; private WormsChannel(bool hostLive, WormsGame.MatchConfig hostCfg) : base(hostLive) { this.hostCfg = hostCfg; } public static WormsChannel Host(WormsGame.MatchConfig cfg) { return new WormsChannel(hostLive: true, cfg); } public static WormsChannel Join(WormsGame.MatchConfig cfg, WormsShot[] shots) { WormsChannel wormsChannel = new WormsChannel(hostLive: false, null); if (uiBuilt) { StartGame(GameKind.Worms, cfg, null); if (game is WormsGame wormsGame) { wormsGame.CatchUp(shots); } } else { wormsChannel.pendingCfg = cfg; wormsChannel.pendingShots = shots; } return wormsChannel; } public bool OwnsMatch(uint matchId) { if (hostLive) { return hostCfg.matchId == matchId; } return false; } protected override void StartPendingGame() { WormsGame.MatchConfig matchCfg = pendingCfg; WormsShot[] array = pendingShots; pendingCfg = null; pendingShots = null; StartGame(GameKind.Worms, matchCfg, null); if (game is WormsGame wormsGame && array != null) { wormsGame.CatchUp(array); } } protected override void SendAnnounce() { if (shotLogCache.Length != shotLog.Count) { shotLogCache = shotLog.ToArray(); } NetMessageExtensions.Send((INetMessage)(object)new WormsMatchMessage(hostCfg.matchId, hostCfg.seed, hostCfg.ids, hostCfg.colorways, shotLogCache), (NetworkDestination)1); } protected override void SendTeardown() { NetMessageExtensions.Send((INetMessage)(object)new WormsMatchMessage(0u, 0u, Array.Empty<uint>(), Array.Empty<byte>(), Array.Empty<WormsShot>()), (NetworkDestination)1); } protected override void HostTickCanon() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) WormsGame wormsGame = (WormsGame)game; if (wormsGame.MatchOver) { requestQueue.Clear(); return; } while (!wormsGame.InFlight && !wormsGame.MatchOver && requestQueue.Count > 0) { WormsShot shot = requestQueue[0]; requestQueue.RemoveAt(0); HostApplyShot(shot); } if (wormsGame.MatchOver) { return; } uint currentTurnOwner = wormsGame.CurrentTurnOwner; if (currentTurnOwner != 0) { bool flag = false; foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { if ((Object)(object)readOnlyInstances != (Object)null) { NetworkInstanceId netId = ((NetworkBehaviour)readOnlyInstances).netId; if (((NetworkInstanceId)(ref netId)).Value == currentTurnOwner) { flag = true; break; } } } if (!flag && forfeited.Add(currentTurnOwner)) { HostApplyShot(new WormsShot { shooterNetId = currentTurnOwner, weapon = 254 }); } } if (wormsGame.InFlight || wormsGame.KnownShotCount != timedShotCount) { timedShotCount = wormsGame.KnownShotCount; turnDeadlineAt = Time.unscaledTime + 45f; } else if (currentTurnOwner != 0 && Time.unscaledTime >= turnDeadlineAt) { HostApplyShot(new WormsShot { shooterNetId = currentTurnOwner, weapon = byte.MaxValue }); } } protected override void Close() { wormsChannel = null; } public void HostApplyClientRequest(WormsShot shot) { //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) if (!WormsGame.ValidWeaponByte(shot.weapon)) { return; } NetworkUser val = ArcadeLocal.User(); if ((Object)(object)val != (Object)null) { uint shooterNetId = shot.shooterNetId; NetworkInstanceId netId = ((NetworkBehaviour)val).netId; if (shooterNetId == ((NetworkInstanceId)(ref netId)).Value) { return; } } HostApplyShot(shot); } public void HostApplyShot(WormsShot shot) { if (!hostLive || !(game is WormsGame wormsGame) || wormsGame.MatchId != hostCfg.matchId || wormsGame.MatchOver || (shot.weapon != byte.MaxValue && shot.weapon != 254 && !WormsGame.ValidWeaponByte(shot.weapon))) { return; } if (wormsGame.InFlight) { for (int num = requestQueue.Count - 1; num >= 0; num--) { if (requestQueue[num].shooterNetId == shot.shooterNetId && requestQueue[num].weapon != 254) { requestQueue.RemoveAt(num); } } requestQueue.Add(shot); } else if (shot.weapon == 254 || shot.shooterNetId == wormsGame.CurrentTurnOwner) { int count = shotLog.Count; shotLog.Add(shot); wormsGame.ApplyShot(shot, animate: true); NetMessageExtensions.Send((INetMessage)(object)new WormsShotMessage(hostCfg.matchId, (ushort)count, shot), (NetworkDestination)1); } } } private sealed class RaceChannel : MatchChannel { private readonly RaceGame.MatchConfig hostCfg; private RaceGame.MatchConfig pendingCfg; private float roundBumpAt; protected override uint HostMatchId => hostCfg.matchId; protected override uint RunningMatchId { get { if (!(game is RaceGame raceGame)) { return 0u; } return raceGame.MatchId; } } protected override bool JoinPending => pendingCfg != null; private RaceChannel(bool hostLive, RaceGame.MatchConfig hostCfg) : base(hostLive) { this.hostCfg = hostCfg; } public static RaceChannel Host(RaceGame.MatchConfig cfg) { return new RaceChannel(hostLive: true, cfg); } public static RaceChannel Join(RaceGame.MatchConfig cfg) { RaceChannel raceChannel = new RaceChannel(hostLive: false, null); if (uiBuilt) { StartGame(GameKind.Race, null, cfg); } else { raceChannel.pendingCfg = cfg; } return raceChannel; } protected override void StartPendingGame() { RaceGame.MatchConfig raceCfg = pendingCfg; pendingCfg = null; StartGame(GameKind.Race, null, raceCfg); } protected override void SendAnnounce() { NetMessageExtensions.Send((INetMessage)(object)new RaceMatchMessage(hostCfg.matchId, hostCfg.seed, hostCfg.round, hostCfg.ids, hostCfg.colorways, hostCfg.wins), (NetworkDestination)1); } protected override void SendTeardown() { NetMessageExtensions.Send((INetMessage)(object)new RaceMatchMessage(0u, 0u, 0, Array.Empty<uint>(), Array.Empty<byte>(), Array.Empty<byte>()), (NetworkDestination)1); } protected override void HostTickCanon() { RaceGame raceGame = (RaceGame)game; if (raceGame.TryTakeRoundWinner(out var winner)) { for (int i = 0; i < hostCfg.ids.Length; i++) { if (hostCfg.ids[i] == winner && hostCfg.wins[i] < byte.MaxValue) { hostCfg.wins[i]++; } } raceGame.ApplyMatchState(hostCfg.round, hostCfg.wins); roundBumpAt = Time.unscaledTime + 3f; nextResendAt = 0f; } if (roundBumpAt > 0f && Time.unscaledTime >= roundBumpAt) { roundBumpAt = 0f; hostCfg.round++; raceGame.ApplyMatchState(hostCfg.round, hostCfg.wins); nextResendAt = 0f; } } protected override void Close() { raceChannel = null; } } [CompilerGenerated] private static class <>O { public static UnityAction <0>__ToggleColorPanel; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Action <>9__50_0; public static UnityAction <>9__51_0; public static UnityAction <>9__51_1; public static UnityAction <>9__51_2; public static UnityAction <>9__51_3; public static UnityAction <>9__51_4; internal void <ToggleColorPanel>b__50_0() { if (colorCount != null) { colorCount.Text = $"{colorGrid.PickedCount} / 3 picked"; } } internal void <BuildUi>b__51_0() { StartOrStop(GameKind.Runner); } internal void <BuildUi>b__51_1() { StartOrStop(GameKind.Race); } internal void <BuildUi>b__51_2() { StartOrStop(GameKind.Worms); } internal void <BuildUi>b__51_3() { StartOrStop(GameKind.Terrarium); } internal void <BuildUi>b__51_4() { holdEngaged = !holdEngaged; holdBtn.Text = (holdEngaged ? "UNLOCK LOADING" : "LOCK LOADING"); } } private const float ButtonH = 30f; internal const float RunnerStripH = 150f; internal const float RunnerSoloW = 480f; private const float WormsStripW = 1100f; private const float WormsStripH = 185f; private const float RaceStripW = 1100f; private const float RaceStripH = 208f; private const float TankStripW = 700f; private const float TankStripH = 185f; private const float StripBottomLimit = -408f; internal const float CeremonyGraceSeconds = 3f; private const float ReelArrivalGrace = 1.5f; private static float lastLotteryAt = -1f; private static bool holdEngaged; private static UiKit.Btn holdBtn; private static GameKind activeKind; private static GameKind lastKind = GameKind.Runner; private static float stripH = 150f; private static float btnNoteUntil; private static UiKit.Btn btnNoteOn; private static string btnNotePrior; private static GameObject root; private static float attachedAt; private static bool uiBuilt; private static UiKit.Btn playBtn; private static UiKit.Btn raceBtn; private static UiKit.Btn wormsBtn; private static UiKit.Btn tankBtn; private static UiKit.Btn colorsBtn; private static GameObject colorPanel; private static ArcadeColorGrid colorGrid; private static UiKit.Label colorCount; private static GameObject strip; private static RectTransform stripRect; private static RectTransform stripContent; private static IMiniGame game; private static float matchStartedAt; private const float StopArmSeconds = 0.75f; private static WormsChannel wormsChannel; private static RaceChannel raceChannel; public static bool CeremonyClosed { get; private set; } public static bool HoldingLoadingScreen { get { if ((Object)(object)root != (Object)null && uiBuilt) { return holdEngaged; } return false; } } public static bool StripOpen => (Object)(object)strip != (Object)null; public static float StripReserve { get { if (!((Object)(object)strip != (Object)null)) { return 0f; } return stripH + 44f; } } public static void Attach(GameObject overlayRoot) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown CeremonyClosed = false; lastLotteryAt = -1f; uiBuilt = false; holdEngaged = false; attachedAt = Time.unscaledTime; root = new GameObject("arcade"); root.transform.SetParent(overlayRoot.transform, false); UiKit.Stretch(root.AddComponent<RectTransform>()); if (ModOptions.ArcadeEnabled.Value) { CommandoSprites.EnsureLoading(); WeaponIcons.EnsureLoading(); } } public static void Detach() { EndGame(); SpectateStrips.Clear(); TerrariumStrips.Clear(); ArcadeSpectate.Clear(); RaceSpectate.Clear(); TerrariumNet.Clear(); DropMatchChannels(); RaceSpectate.ActiveMatchId = 0u; btnNoteUntil = 0f; btnNoteOn = null; btnNotePrior = null; matchStartedAt = 0f; root = null; playBtn = null; raceBtn = null; wormsBtn = null; tankBtn = null; colorsBtn = null; colorPanel = null; colorGrid = null; colorCount = null; holdBtn = null; strip = null; stripRect = null; stripContent = null; uiBuilt = false; holdEngaged = false; CeremonyClosed = false; lastLotteryAt = -1f; } public static void Tick() { if ((Object)(object)root == (Object)null || !ModOptions.ArcadeEnabled.Value) { return; } int num; if (!CeremonyClosed) { if (!LoadingOverlay.AnyReelAwaitingShow) { num = (LoadingOverlay.AnyReelLive ? 1 : 0); if (num == 0) { goto IL_003d; } } else { num = 1; } lastLotteryAt = Time.unscaledTime; goto IL_003d; } goto IL_0098; IL_003d: float num2 = ((num != 0) ? float.MaxValue : ((!(lastLotteryAt >= 0f)) ? ((NetworkUser.readOnlyInstancesList.Count > 1) ? (attachedAt + 1.5f) : attachedAt) : lastLotteryAt)); if (Time.unscaledTime < num2) { return; } CeremonyClosed = true; CommandoSprites.EnsureLoading(); WeaponIcons.EnsureLoading(); goto IL_0098; IL_0098: if (CommandoSprites.Failed) { return; } if (!uiBuilt) { if (!CommandoSprites.Ready) { return; } BuildUi(); } PositionUi(); if (holdBtn != null) { bool flag = NetworkUser.readOnlyInstancesList.Count <= 1 || NetworkServer.active; if (holdBtn.Go.activeSelf != flag) { holdBtn.Go.SetActive(flag); } } ArcadeInput.Blocked = (Object)(object)colorPanel != (Object)null; ArcadeInput.Poll(stripContent); bool flag2 = game is WormsGame { MatchId: not 0u } || (game is RaceGame raceGame && raceGame.MatchId != 0); bool flag3 = (lastKind == GameKind.Worms || lastKind == GameKind.Race) && NetworkUser.readOnlyInstancesList.Count > 1; if (ArcadeInput.ToggleDown && !flag2 && !flag3) { StartOrStop(lastKind); } colorGrid?.Tick(); SpectateStrips.Tick(); TerrariumStrips.Tick(); if (game != null && ((Object)(object)colorPanel == (Object)null || flag2)) { game.Tick(Mathf.Min(Time.unscaledDeltaTime, 0.05f)); } TickButtonNote(); TickMatchChannels(); } private static void ToggleColorPanel() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_03db: Unknown result type (might be due to invalid IL or missing references) //IL_041b: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)colorPanel != (Object)null) { Object.Destroy((Object)(object)colorPanel); colorPanel = null; colorGrid = null; colorCount = null; return; } string text = ArcadeLocal.ProfileKey() ?? UserLifetimeStats.ProfileKey(LocalUserManager.GetFirstLocalUser()); if (text == null) { return; } colorPanel = new GameObject("arcadeColorModal"); colorPanel.transform.SetParent(root.transform, false); UiKit.Stretch(colorPanel.AddComponent<RectTransform>()); Image obj = UiKit.CreateImage("dim", colorPanel.transform, new Color(0f, 0f, 0f, 0.55f)); UiKit.Stretch(((Graphic)obj).rectTransform); ButtonClickedEvent onClick = ((Component)obj).gameObject.AddComponent<Button>().onClick; object obj2 = <>O.<0>__ToggleColorPanel; if (obj2 == null) { UnityAction val = ToggleColorPanel; <>O.<0>__ToggleColorPanel = val; obj2 = (object)val; } ((UnityEvent)onClick).AddListener((UnityAction)obj2); UiWindow uiWindow = new UiWindow("panel", colorPanel.transform, UiKit.PanelSolid, UiKit.OutlineBright); GameObject go = uiWindow.Go; RectTransform rect = uiWindow.Rect; Transform transform = go.transform; Vector2 size = new Vector2(26f, 26f); object obj3 = <>O.<0>__ToggleColorPanel; if (obj3 == null) { UnityAction val2 = ToggleColorPanel; <>O.<0>__ToggleColorPanel = val2; obj3 = (object)val2; } UiKit.Btn btn = UiKit.CreateButton("close", transform, size, 14f, "X", (UnityAction)obj3); btn.Rect.anchorMin = new Vector2(1f, 1f); btn.Rect.anchorMax = new Vector2(1f, 1f); btn.Rect.pivot = new Vector2(1f, 1f); btn.Rect.anchoredPosition = new Vector2(-6f, -6f); UiKit.Label label = UiKit.CreateLabel("header", go.transform, 17f, UiKit.HeaderTan, (TextAnchor)3); label.Rect.anchorMin = new Vector2(0f, 1f); label.Rect.anchorMax = new Vector2(1f, 1f); label.Rect.pivot = new Vector2(0.5f, 1f); label.Rect.sizeDelta = new Vector2(-28f, 36f); label.Rect.anchoredPosition = new Vector2(0f, -2f); label.Bold(); label.Text = "ARCADE COLORS"; colorCount = UiKit.CreateLabel("count", go.transform, 12f, UiKit.TextDim, (TextAnchor)5); colorCount.Rect.anchorMin = new Vector2(0f, 1f); colorCount.Rect.anchorMax = new Vector2(1f, 1f); colorCount.Rect.pivot = new Vector2(0.5f, 1f); colorCount.Rect.sizeDelta = new Vector2(-88f, 36f); colorCount.Rect.anchoredPosition = new Vector2(-30f, -2f); GameObject val3 = new GameObject("content"); val3.transform.SetParent(go.transform, false); RectTransform val4 = val3.AddComponent<RectTransform>(); val4.anchorMin = new Vector2(0.5f, 1f); val4.anchorMax = new Vector2(0.5f, 1f); val4.pivot = new Vector2(0.5f, 1f); val4.anchoredPosition = new Vector2(0f, -40f); colorGrid = new ArcadeColorGrid(); colorGrid.onChanged = delegate { if (colorCount != null) { colorCount.Text = $"{colorGrid.PickedCount} / 3 picked"; } }; float num = colorGrid.Build(val4, 408f, text); val4.sizeDelta = new Vector2(408f, num); colorCount.Text = $"{colorGrid.PickedCount} / 3 picked"; rect.sizeDelta = new Vector2(436f, 40f + num + 14f); rect.anchoredPosition = new Vector2(0f, 40f); } private static void BuildUi() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Expected O, but got Unknown //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Expected O, but got Unknown uiBuilt = true; GameObject gameObject = ((Component)root.transform.parent).gameObject; if ((Object)(object)gameObject.GetComponent<GraphicRaycaster>() == (Object)null) { gameObject.AddComponent<GraphicRaycaster>(); } if ((Object)(object)gameObject.GetComponent<CursorOpener>() == (Object)null) { gameObject.AddComponent<MPEventSystemProvider>(); gameObject.AddComponent<MPEventSystemLocator>(); gameObject.AddComponent<CursorOpener>(); } Transform transform = root.transform; Vector2 size = new Vector2(110f, 30f); object obj = <>c.<>9__51_0; if (obj == null) { UnityAction val = delegate { StartOrStop(GameKind.Runner); }; <>c.<>9__51_0 = val; obj = (object)val; } playBtn = UiKit.CreateButton("arcadeRunner", transform, size, 11f, "RUNNER", (UnityAction)obj); Transform transform2 = root.transform; Vector2 size2 = new Vector2(110f, 30f); object obj2 = <>c.<>9__51_1; if (obj2 == null) { UnityAction val2 = delegate { StartOrStop(GameKind.Race); }; <>c.<>9__51_1 = val2; obj2 = (object)val2; } raceBtn = UiKit.CreateButton("arcadeRace", transform2, size2, 11f, "RACE", (UnityAction)obj2); Transform transform3 = root.transform; Vector2 size3 = new Vector2(110f, 30f); object obj3 = <>c.<>9__51_2; if (obj3 == null) { UnityAction val3 = delegate { StartOrStop(GameKind.Worms); }; <>c.<>9__51_2 = val3; obj3 = (object)val3; } wormsBtn = UiKit.CreateButton("arcadeWorms", transform3, size3, 11f, "WORMS", (UnityAction)obj3); Transform transform4 = root.transform; Vector2 size4 = new Vector2(110f, 30f); object obj4 = <>c.<>9__51_3; if (obj4 == null) { UnityAction val4 = delegate { StartOrStop(GameKind.Terrarium); }; <>c.<>9__51_3 = val4; obj4 = (object)val4; } tankBtn = UiKit.CreateButton("arcadeTank", transform4, size4, 11f, "TANK", (UnityAction)obj4); Transform transform5 = root.transform; Vector2 size5 = new Vector2(110f, 30f); object obj5 = <>O.<0>__ToggleColorPanel; if (obj5 == null) { UnityAction val5 = ToggleColorPanel; <>O.<0>__ToggleColorPanel = val5; obj5 = (object)val5; } colorsBtn = UiKit.CreateButton("arcadeColors", transform5, size5, 11f, "COLORS", (UnityAction)obj5); Transform transform6 = root.transform; Vector2 size6 = new Vector2(150f, 26f); object obj6 = <>c.<>9__51_4; if (obj6 == null) { UnityAction val6 = delegate { holdEngaged = !holdEngaged; holdBtn.Text = (holdEngaged ? "UNLOCK LOADING" : "LOCK LOADING"); }; <>c.<>9__51_4 = val6; obj6 = (object)val6; } holdBtn = UiKit.CreateButton("arcadeLock", transform6, size6, 13f, "LOCK LOADING", (UnityAction)obj6); holdBtn.Rect.anchorMin = Vector2.zero; holdBtn.Rect.anchorMax = Vector2.zero; holdBtn.Rect.pivot = Vector2.zero; holdBtn.Rect.anchoredPosition = new Vector2(14f, 12f); holdBtn.Go.SetActive(false); } private static void PositionUi() { //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) if (!LoadingOverlay.TryGetLocalCardSlot(out var x, out var width, out var cardBottom)) { if (playBtn.Go.activeSelf) { playBtn.Go.SetActive(false); } raceBtn.Go.SetActive(false); wormsBtn.Go.SetActive(false); tankBtn.Go.SetActive(false); colorsBtn.Go.SetActive(false); if ((Object)(object)strip != (Object)null) { strip.SetActive(false); } return; } if (!playBtn.Go.activeSelf) { playBtn.Go.SetActive(true); raceBtn.Go.SetActive(true); wormsBtn.Go.SetActive(true); tankBtn.Go.SetActive(true); colorsBtn.Go.SetActive(true); if ((Object)(object)strip != (Object)null) { strip.SetActive(true); } } float num = Mathf.Min(110f, (width - 22f) / 5f); float num2 = num + 4f; float num3 = cardBottom - 22f; playBtn.Rect.sizeDelta = new Vector2(num, 30f); raceBtn.Rect.sizeDelta = new Vector2(num, 30f); wormsBtn.Rect.sizeDelta = new Vector2(num, 30f); tankBtn.Rect.sizeDelta = new Vector2(num, 30f); colorsBtn.Rect.sizeDelta = new Vector2(num, 30f); playBtn.Rect.anchoredPosition = new Vector2(x - 2f * num2, num3); raceBtn.Rect.anchoredPosition = new Vector2(x - 1f * num2, num3); wormsBtn.Rect.anchoredPosition = new Vector2(x, num3); tankBtn.Rect.anchoredPosition = new Vector2(x + 1f * num2, num3); colorsBtn.Rect.anchoredPosition = new Vector2(x + 2f * num2, num3); bool interactable = NetworkUser.readOnlyInstancesList.Count <= 1 || NetworkServer.active; wormsBtn.Interactable = interactable; raceBtn.Interactable = interactable; if ((Object)(object)stripRect != (Object)null) { float x2 = stripRect.sizeDelta.x; float num4 = (LoadingOverlay.MultiRowWall ? (LoadingOverlay.WallBottom - 44f) : (cardBottom - 44f)); num4 = Mathf.Max(num4, -408f + stripH); Rect rect = ((RectTransform)root.transform).rect; float num5 = ((Rect)(ref rect)).width * 0.5f; if (num5 < 1f) { num5 = 960f; } float num6 = Mathf.Max(num5 - 10f - x2 * 0.5f, 0f); float num7 = Mathf.Clamp(x, 0f - num6, num6); stripRect.anchoredPosition = new Vector2(num7, num4 - stripH * 0.5f); } } private static float StripWidthFor(GameKind kind, float cardW) { switch (kind) { case GameKind.Worms: return 1100f; case GameKind.Race: return 1100f; case GameKind.Terrarium: if (NetworkUser.readOnlyInstancesList.Count > 1 && !LoadingOverlay.MultiRowWall) { return cardW; } return 700f; default: if (NetworkUser.readOnlyInstancesList.Count > 1 && !LoadingOverlay.MultiRowWall) { return cardW; } return 480f; } } internal static float RunnerFieldWidthFor(float cardW) { return StripWidthFor(GameKind.Runner, (cardW <= 0f) ? 480f : cardW) - 4f; } private static void ResetGameButtons() { playBtn.Text = "RUNNER"; raceBtn.Text = "RACE"; wormsBtn.Text = "WORMS"; tankBtn.Text = "TANK"; btnNoteUntil = 0f; btnNoteOn = null; btnNotePrior = null; } private static void FlashButtonNote(UiKit.Btn btn, string note) { if (btnNoteOn != btn) { if (btnNoteOn != null && btnNotePrior != null) { btnNoteOn.Text = btnNotePrior; } btnNotePrior = btn.Text; } btn.Text = note; btnNoteOn = btn; btnNoteUntil = Time.unscaledTime + 2.5f; } private static void TickButtonNote() { if (!(btnNoteUntil <= 0f) && !(Time.unscaledTime < btnNoteUntil)) { btnNoteUntil = 0f; if (btnNoteOn != null && btnNotePrior != null) { btnNoteOn.Text = btnNotePrior; } btnNoteOn = null; btnNotePrior = null; } } private static void StartOrStop(GameKind kind) { if ((game is WormsGame { MatchId: not 0u } || game is RaceGame { MatchId: not 0u }) && !NetworkServer.active) { return; } if (kind == GameKind.Worms && NetworkUser.readOnlyInstancesList.Count > 1) { if (NetworkServer.active && (!(game is WormsGame wormsGame2) || !StopHostedMatch(wormsGame2.MatchId))) { StartWormsMultiplayer(); } return; } if (kind == GameKind.Race && NetworkUser.readOnlyInstancesList.Count > 1) { if (NetworkServer.active && (!(game is RaceGame raceGame2) || !StopHostedMatch(raceGame2.MatchId))) { StartRaceMultiplayer(); } return; } bool flag = game != null && activeKind == kind; if (game != null) { EndGame(); ResetGameButtons(); LoadingOverlay.InvalidateCards(); if (flag) { return; } } StartGame(kind, null, null); } private static void StartGame(GameKind kind, WormsGame.MatchConfig matchCfg, RaceGame.MatchConfig raceCfg) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) if (game != null) { EndGame(); } ResetGameButtons(); activeKind = kind; lastKind = kind; stripH = kind switch { GameKind.Terrarium => 185f, GameKind.Race => 208f, GameKind.Worms => 185f, _ => 150f, }; LoadingOverlay.TryGetLocalCardSlot(out var _, out var width, out var _); float num = StripWidthFor(kind, (width <= 0f) ? 480f : width); UiWindow uiWindow = new UiWindow("arcadeStrip", root.transform, new Color(0.03f, 0.035f, 0.05f, 0.97f), UiKit.Outline); strip = uiWindow.Go; stripRect = uiWindow.Rect; stripRect.sizeDelta = new Vector2(num, stripH); LoadingOverlay.InvalidateCards(); stripContent = uiWindow.AddMaskedContent(); ArcadeContext ctx = new ArcadeContext { seed = VoxelTerrainManager.StageSeed, panel = stripContent, width = num - 4f, height = stripH - 4f, wormsMatch = matchCfg, raceMatch = raceCfg }; IMiniGame miniGame2; switch (kind) { default: { IMiniGame miniGame = new RunnerGame(); miniGame2 = miniGame; break; } case GameKind.Terrarium: { IMiniGame miniGame = new TerrariumGame(); miniGame2 = miniGame; break; } case GameKind.Race: { IMiniGame miniGame = new RaceGame(); miniGame2 = miniGame; break; } case GameKind.Worms: { IMiniGame miniGame = new WormsGame(); miniGame2 = miniGame; break; } } game = miniGame2; game.Start(ctx); (kind switch { GameKind.Terrarium => tankBtn, GameKind.Race => raceBtn, GameKind.Worms => wormsBtn, _ => playBtn, }).Text = ((matchCfg != null || raceCfg != null) ? "MATCH ON" : "STOP"); } private static void EndGame() { if (game != null) { if (game is WormsGame { MatchId: not 0u } || game is RaceGame { MatchId: not 0u }) { lastKind = GameKind.Runner; } try { game.End(); } catch (Exception ex) { ScorchedVoxelsPlugin.Log.LogWarning((object)("[ScorchedVoxels] arcade game teardown: " + ex.Message)); } game = null; } if ((Object)(object)strip != (Object)null) { Object.Destroy((Object)(object)strip); strip = null; stripRect = null; stripContent = null; } } private static void FoldLocalMatch() { EndGame(); ResetGameButtons(); LoadingOverlay.InvalidateCards(); } private static void DropMatchChannels() { wormsChannel = null; raceChannel = null; } private static void TickMatchChannels() { wormsChannel?.Tick(); raceChannel?.Tick(); } private static bool StopHostedMatch(uint runningMatchId) { if (runningMatchId == 0) { return false; } if (Time.unscaledTime - matchStartedAt >= 0.75f) { EndGame(); ResetGameButtons(); LoadingOverlay.InvalidateCards(); } return true; } private static uint[] DraftModdedPlayers(string gameName, UiKit.Btn button) { //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) List<uint> list = new List<uint>(); foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { if (!((Object)(object)readOnlyInstances == (Object)null)) { NetworkInstanceId netId = ((NetworkBehaviour)readOnlyInstances).netId; uint value = ((NetworkInstanceId)(ref netId)).Value; if ((((NetworkBehaviour)readOnlyInstances).isLocalPlayer || VoxelTerrainManager.IsModdedUser(value)) && !list.Contains(value)) { list.Add(value); } if (list.Count == 8) { break; } } } if (list.Count < 2) { ScorchedVoxelsPlugin.Log.LogWarning((object)("[ScorchedVoxels] " + gameName + ": no other modded players to draft")); FlashButtonNote(button, "WAITING FOR PLAYERS"); return null; } matchStartedAt = Time.unscaledTime; return list.ToArray(); } private static uint NewMatchId() { return (uint)((Environment.TickCount * -1640531535) | 1); } private static byte[] ResolveColorways(uint[] ids) { int num = ids.Length; int[] array = new int[num]; bool[] array2 = new bool[16]; for (int i = 0; i < num; i++) { array[i] = -1; } int[] array3 = new int[num]; for (int j = 0; j < num; j++) { array3[j] = j; } Array.Sort(array3, (int a, int b) => ids[a].CompareTo(ids[b])); int[] array4; for (int num2 = 0; num2 < 3; num2++) { array4 = array3; foreach (int num4 in array4) { if (array[num4] < 0) { RosterEntry rosterEntry = LoadingRoster.Find(ids[num4]); int num5 = ((rosterEntry == null) ? (-1) : (num2 switch { 1 => rosterEntry.prefB, 0 => rosterEntry.prefA, _ => rosterEntry.prefC, })); if (num5 >= 0 && num5 < array2.Length && !array2[num5]) { array[num4] = num5; array2[num5] = true; } } } } array4 = array3; foreach (int num6 in array4) { if (array[num6] < 0) { int num7 = CommandoSprites.ColorwayFor(ids[num6]); while (array2[num7]) { num7 = (num7 + 1) % array2.Length; } array[num6] = num7; array2[num7] = true; } } byte[] array5 = new byte[num]; for (int num8 = 0; num8 < num; num8++) { array5[num8] = (byte)array[num8]; } return array5; } private static void StartWormsMultiplayer() { uint[] array = DraftModdedPlayers("worms", wormsBtn); if (array != null) { uint num = NewMatchId(); uint seed = VoxelTerrainManager.StageSeed ^ num; Random random = new Random((int)seed); for (int num2 = array.Length - 1; num2 > 0; num2--) { int num3 = random.Next(num2 + 1); ref uint reference = ref array[num2]; ref uint reference2 = ref array[num3]; uint num4 = array[num3]; uint num5 = array[num2]; reference = num4; reference2 = num5; } WormsGame.MatchConfig matchConfig = new WormsGame.MatchConfig { matchId = num, seed = seed, ids = array, colorways = ResolveColorways(array) }; wormsChannel = WormsChannel.Host(matchConfig); StartGame(GameKind.Worms, matchConfig, null); } } internal static void HostApplyWormsShot(WormsShot shot) { wormsChannel?.HostApplyShot(shot); } internal static void OnWormsShotRequest(uint matchId, WormsShot shot) { if (wormsChannel != null && wormsChannel.OwnsMatch(matchId)) { wormsChannel.HostApplyClientRequest(shot); } } internal static void OnWormsShot(uint matchId, int index, WormsShot shot) { if (game is WormsGame wormsGame && wormsGame.MatchId == matchId && index == wormsGame.KnownShotCount) { wormsGame.QueueCanonShot(shot); } } internal static void OnWormsMatchMessage(uint matchId, uint seed, uint[] ids, byte[] colorways, WormsShot[] shots) { if ((Object)(object)root == (Object)null || !ModOptions.ArcadeEnabled.Value) { return; } if (matchId == 0 || ids.Length == 0) { if (game is WormsGame { MatchId: not 0u }) { FoldLocalMatch(); } wormsChannel = null; } else if (game is WormsGame wormsGame2 && wormsGame2.MatchId == matchId) { wormsChannel?.StampHostMsg(); wormsGame2.CatchUp(shots); } else { wormsChannel = WormsChannel.Join(new WormsGame.MatchConfig { matchId = matchId, seed = seed, ids = ids, colorways = colorways }, shots); } } private static void StartRaceMultiplayer() { uint[] array = DraftModdedPlayers("race", raceBtn); if (array != null) { uint num = NewMatchId(); RaceGame.MatchConfig matchConfig = new RaceGame.MatchConfig { matchId = num, seed = (VoxelTerrainManager.StageSeed ^ num), ids = array, colorways = ResolveColorways(array), round = 0, wins = new byte[array.Length] }; raceChannel = RaceChannel.Host(matchConfig); StartGame(GameKind.Race, null, matchConfig); } } internal static void OnRaceMatchMessage(uint matchId, uint seed, byte round, uint[] ids, byte[] colorways, byte[] wins) { if ((Object)(object)root == (Object)null || !ModOptions.ArcadeEnabled.Value) { return; } if (matchId == 0 || ids.Length == 0) { if (game is RaceGame { MatchId: not 0u }) { FoldLocalMatch(); } raceChannel = null; } else if (game is RaceGame raceGame2 && raceGame2.MatchId == matchId) { raceChannel?.StampHostMsg(); raceGame2.ApplyMatchState(round, wins); } else { raceChannel = RaceChannel.Join(new RaceGame.MatchConfig { matchId = matchId, seed = seed, ids = ids, colorways = colorways, round = round, wins = wins }); } } } internal class ArcadeSnapshotMessage : INetMessage, ISerializableObject { public const int MaxObstacles = 8; private uint ownerNetId; private byte colorway; private ushort score; private byte state; private byte playerY; private byte speed; private byte[] obKind = new byte[8]; private byte[] obX = new byte[8]; private int obCount; public void Set(uint ownerNetId, byte colorway, ushort score, byte state, byte playerY, byte speed, byte[] obKind, byte[] obX, int obCount) { this.ownerNetId = ownerNetId; this.colorway = colorway; this.score = score; this.state = state; this.playerY = playerY; this.speed = speed; this.obKind = obKind; this.obX = obX; this.obCount = obCount; } public void Serialize(NetworkWriter writer) { writer.WritePackedUInt32(ownerNetId); writer.Write(colorway); writer.Write(score); writer.Write(state); writer.Write(playerY); writer.Write(speed); int num = Mathf.Min(obCount, 8); writer.Write((byte)num); for (int i = 0; i < num; i++) { writer.Write(obKind[i]); writer.Write(obX[i]); } } public void Deserialize(NetworkReader reader) { ownerNetId = reader.ReadPackedUInt32(); colorway = reader.ReadByte(); score = reader.ReadUInt16(); state = reader.ReadByte(); playerY = reader.ReadByte(); speed = reader.ReadByte(); int num = reader.ReadByte(); if (obKind.Length < 8) { obKind = new byte[8]; obX = new byte[8]; } obCount = 0; for (int i = 0; i < num; i++) { byte b = reader.ReadByte(); byte b2 = reader.ReadByte(); if (obCount < 8) { obKind[obCount] = b; obX[obCount] = b2; obCount++; } } } public void OnReceived() { if (NetworkServer.active) { if (!HostRelay.Relaying) { ArcadeSpectate.Store(ownerNetId, colorway, score, state, playerY, speed, obKind, obX, obCount); HostRelay.FanOut((INetMessage)(object)this, ownerNetId); } } else { ArcadeSpectate.Store(ownerNetId, colorway, score, state, playerY, speed, obKind, obX, obCount); } } } internal static class HostRelay { private static bool relaying; public static bool Relaying => relaying; public static void FanOut(INetMessage msg, uint ownerNetId) { if (ArcadeSpectate.IsLocalPlayer(ownerNetId)) { return; } relaying = true; try { NetMessageExtensions.Send(msg, (NetworkDestination)1); } finally { relaying = false; } } } internal struct WormsShot { public const byte WeaponPass = byte.MaxValue; public const byte WeaponForfeit = 254; public uint shooterNetId; public byte weapon; public byte angle; public byte power; public ushort tx; public ushort ty; public void Write(NetworkWriter w) { w.WritePackedUInt32(shooterNetId); w.Write(weapon); w.Write(angle); w.Write(power); w.Write(tx); w.Write(ty); } public static WormsShot Read(NetworkReader r) { return new WormsShot { shooterNetId = r.ReadPackedUInt32(), weapon = r.ReadByte(), angle = r.ReadByte(), power = r.ReadByte(), tx = r.ReadUInt16(), ty = r.ReadUInt16() }; } } internal class WormsMatchMessage : INetMessage, ISerializableObject { private uint matchId; private uint seed; private uint[] ids = Array.Empty<uint>(); private byte[] colorways = Array.Empty<byte>(); private WormsShot[] shots = Array.Empty<WormsShot>(); public WormsMatchMessage() { } public WormsMatchMessage(uint matchId, uint seed, uint[] ids, byte[] colorways, WormsShot[] shots) { this.matchId = matchId; this.seed = seed; this.ids = ids; this.colorways = colorways; this.shots = shots; } public void Serialize(NetworkWriter writer) { writer.WritePackedUInt32(matchId); writer.WritePackedUInt32(seed); writer.Write((byte)ids.Length); for (int i = 0; i < ids.Length; i++) { writer.WritePackedUInt32(ids[i]); writer.Write(colorways[i]); } writer.Write((ushort)shots.Length); WormsShot[] array = shots; foreach (WormsShot wormsShot in array) { wormsShot.Write(writer); } } public void Deserialize(NetworkReader reader) { matchId = reader.ReadPackedUInt32(); seed = reader.ReadPackedUInt32(); int num = reader.ReadByte(); ids = new uint[num]; colorways = new byte[num]; for (int i = 0; i < num; i++) { ids[i] = reader.ReadPackedUInt32(); colorways[i] = reader.ReadByte(); } int num2 = reader.ReadUInt16(); shots = new WormsShot[num2]; for (int j = 0; j < num2; j++) { shots[j] = WormsShot.Read(reader); } } public void OnReceived() { if (!NetworkServer.active) { ArcadeHost.OnWormsMatchMessage(matchId, seed, ids, colorways, shots); } } } internal class WormsShotRequestMessage : INetMessage, ISerializableObject { private uint matchId; private WormsShot shot; public WormsShotRequestMessage() { } public WormsShotRequestMessage(uint matchId, WormsShot shot) { this.matchId = matchId; this.shot = shot; } public void Serialize(NetworkWriter writer) { writer.WritePackedUInt32(matchId); shot.Write(writer); } public void Deserialize(NetworkReader reader) { matchId = reader.ReadPackedUInt32(); shot = WormsShot.Read(reader); } public void OnReceived() { if (NetworkServer.active) { ArcadeHost.OnWormsShotRequest(matchId, shot); } } } internal class WormsShotMessage : INetMessage, ISerializableObject { private uint matchId; private ushort index; private WormsShot shot; public WormsShotMessage() { } public WormsShotMessage(uint matchId, ushort index, WormsShot shot) { this.matchId = matchId; this.index = index; this.shot = shot; } public void Serialize(NetworkWriter writer) { writer.WritePackedUInt32(matchId); writer.Write(index); shot.Write(writer); } public void Deserialize(NetworkReader reader) { matchId = reader.ReadPackedUInt32(); index = reader.ReadUInt16(); shot = WormsShot.Read(reader); } public void OnReceived() { if (!NetworkServer.active) { ArcadeHost.OnWormsShot(matchId, index, shot); } } } internal class RaceMatchMessage : INetMessage, ISerializableObject { private uint matchId; private uint seed; private byte round; private uint[] ids = Array.Empty<uint>(); private byte[] colorways = Array.Empty<byte>(); private byte[] wins = Array.Empty<byte>(); public RaceMatchMessage() { } public RaceMatchMessage(uint matchId, uint seed, byte round, uint[] ids, byte[] colorways, byte[] wins) { this.matchId = matchId; this.seed = seed; this.round = round; this.ids = ids; this.colorways = colorways; this.wins = wins; } public void Serialize(NetworkWriter writer) { writer.WritePackedUInt32(matchId); writer.WritePackedUInt32(seed); writer.Write(round); writer.Write((byte)ids.Length); for (int i = 0; i < ids.Length; i++) { writer.WritePackedUInt32(ids[i]); writer.Write(colorways[i]); writer.Write(wins[i]); } } public void Deserialize(NetworkReader reader) { matchId = reader.ReadPackedUInt32(); seed = reader.ReadPackedUInt32(); round = reader.ReadByte(); int num = reader.ReadByte(); ids = new uint[num]; colorways = new byte[num]; wins = new byte[num]; for (int i = 0; i < num; i++) { ids[i] = reader.ReadPackedUInt32(); colorways[i] = reader.ReadByte(); wins[i] = reader.ReadByte(); } } public void OnReceived() { if (!NetworkServer.active) { ArcadeHost.OnRaceMatchMessage(matchId, seed, round, ids, colorways, wins); } } } internal class RaceSnapshotMessage : INetMessage, ISerializableObject { private uint ownerNetId; private uint matchId; private byte round; private byte colorway; private byte state; private ushort sQ; private byte h; private byte speedQ; private byte laps; private ushort anchorQ; public void Set(uint ownerNetId, uint matchId, byte round, byte colorway, byte state, ushort sQ, byte h, byte speedQ, byte laps, ushort anchorQ) { this.ownerNetId = ownerNetId; this.matchId = matchId; this.round = round; this.colorway = colorway; this.state = state; this.sQ = sQ; this.h = h; this.speedQ = speedQ; this.laps = laps; this.anchorQ = anchorQ; } public void Serialize(NetworkWriter writer) { writer.WritePackedUInt32(ownerNetId); writer.WritePackedUInt32(matchId); writer.Write(round); writer.Write(colorway); writer.Write(state); writer.Write(sQ); writer.Write(h); writer.Write(speedQ); writer.Write(laps); writer.Write(anchorQ); } public void Deserialize(NetworkReader reader) { ownerNetId = reader.ReadPackedUInt32(); matchId = reader.ReadPackedUInt32(); round = reader.ReadByte(); colorway = reader.ReadByte(); state = reader.ReadByte(); sQ = reader.ReadUInt16(); h = reader.ReadByte(); speedQ = reader.ReadByte(); laps = reader.ReadByte(); anchorQ = reader.ReadUInt16(); } public void OnReceived() { if (NetworkServer.active) { if (!HostRelay.Relaying) { RaceSpectate.Store(ownerNetId, matchId, round, colorway, state, sQ, h, speedQ, laps, anchorQ); HostRelay.FanOut((INetMessage)(object)this, ownerNetId); } } else { RaceSpectate.Store(ownerNetId, matchId, round, colorway, state, sQ, h, speedQ, laps, anchorQ); } } } internal static class RaceSpectate { internal class Snapshot { public byte round; public byte colorway; public bool dead; public bool roping; public bool racing; public float s; public float h; public float speedPxS; public int laps; public float anchorX; public float receivedAt; } public static readonly Dictionary<uint, Snapshot> Latest = new Dictionary<uint, Snapshot>(); public static uint ActiveMatchId; public static void Store(uint ownerNetId, uint matchId, byte round, byte colorway, byte state, ushort sQ, byte h, byte speedQ, byte laps, ushort anchorQ) { if (matchId != 0 && matchId == ActiveMatchId && !ArcadeSpectate.IsLocalPlayer(ownerNetId)) { if (!Latest.TryGetValue(ownerNetId, out var value)) { value = (Latest[ownerNetId] = new Snapshot()); } value.round = round; value.colorway = colorway; value.dead = (state & 1) != 0; value.roping = (state & 2) != 0; value.racing = (state & 4) != 0; value.s = (float)(int)sQ * 2f; value.h = (int)h; value.speedPxS = (float)(int)speedQ * 3f; value.laps = laps; value.anchorX = (float)(int)anchorQ * 2f; value.receivedAt = Time.unscaledTime; } } public static void Clear() { Latest.Clear(); } } internal static class ArcadeSpectate { internal class Snapshot { public byte colorway; public ushort score; public bool ducking; public bool gameOver; public byte playerY; public float speedPxS; public readonly List<(byte kind, byte x)> obstacles = new List<(byte, byte)>(); public float receivedAt; } public static readonly Dictionary<uint, Snapshot> Latest = new Dictionary<uint, Snapshot>(); public const float StaleSeconds = 1.2f; public static bool IsLocalPlayer(uint netId) { //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) foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList) { if ((Object)(object)readOnlyInstances != (Object)null && ((NetworkBehaviour)readOnlyInstances).isLocalPlayer) { NetworkInstanceId netId2 = ((NetworkBehaviour)readOnlyInstances).netId; if (((NetworkInstanceId)(ref netId2)).Value == netId) { return true; } } } return false; } public static void Store(uint ownerNetId, byte colorway, ushort score, byte state, byte playerY, byte speed, byte[] obKind, byte[] obX, int obCount) { if (!IsLocalPlayer(ownerNetId)) { if (!Latest.TryGetValue(ownerNetId, out var value)) { value = (Latest[ownerNetId] = new Snapshot()); } value.colorway = colorway; value.score = score; value.ducking = (state & 1) != 0; value.gameOver = (state & 2) != 0; value.playerY = playerY; value.speedPxS = (float)(int)speed * 2f; value.obstacles.Clear(); int num = Mathf.Min(obCount, 8); for (int i = 0; i < num; i++) { value.obstacles.Add((obKind[i], obX[i])); } value.receivedAt = Time.unscaledTime; } } public static void Clear() { Latest.Clear(); } } internal static class ArcadeThemes { public struct Theme { public string name; public Color32 deep; public Color32 mid; public Color32 slab; public Color32 stal; public Color32 cap; public byte dress; } public const byte DressCaps = 1; public const byte DressMotes = 2; public const byte DressStrata = 4; public const byte DressGlow = 8; public static readonly Theme[] All = new Theme[12] { new Theme { name = "PLAINS", deep = new Color32((byte)44, (byte)40, (byte)32, byte.MaxValue), mid = new Color32((byte)82, (byte)70, (byte)48, byte.MaxValue), slab = new Color32((byte)118, (byte)98, (byte)64, byte.MaxValue), stal = new Color32((byte)64, (byte)54, (byte)40, byte.MaxValue), cap = new Color32((byte)98, (byte)148, (byte)70, byte.MaxValue), dress = 1 }, new Theme { name = "ROOST", deep = new Color32((byte)34, (byte)36, (byte)46, byte.MaxValue), mid = new Color32((byte)62, (byte)66, (byte)82, byte.MaxValue), slab = new Color32((byte)94, (byte)100, (byte)118, byte.MaxValue), stal = new Color32((byte)50, (byte)54, (byte)66, byte.MaxValue), cap = new Color32((byte)172, (byte)178, (byte)190, byte.MaxValue), dress = 5 }, new Theme { name = "AQUEDUCT", deep = new Color32((byte)52, (byte)38, (byte)26, byte.MaxValue), mid = new Color32((byte)98, (byte)70, (byte)42, byte.MaxValue), slab = new Color32((byte)136, (byte)100, (byte)58, byte.MaxValue), stal = new Color32((byte)76, (byte)54, (byte)34, byte.MaxValue), cap = new Color32((byte)192, (byte)160, (byte)104, byte.MaxValue), dress = 5 }, new Theme { name = "DELTA", deep = new Color32((byte)30, (byte)38, (byte)48, byte.MaxValue), mid = new Color32((byte)58, (byte)74, (byte)90, byte.MaxValue), slab = new Color32((byte)92, (byte)112, (byte)130, byte.MaxValue), stal = new Color32((byte)46, (byte)58, (byte)70, byte.MaxValue), cap = new Color32((byte)218, (byte)228, (byte)238, byte.MaxValue), dress = 3 }, new Theme { name = "ACRES", deep = new Color32((byte)30, (byte)26, (byte)24, byte.MaxValue), mid = new Color32((byte)56, (byte)46, (byte)40, byte.MaxValue), slab = new Color32((byte)82, (byte)66, (byte)54, byte.MaxValue), stal = new Color32((byte)44, (byte)36, (byte)32, byte.MaxValue), cap = new Color32((byte)214, (byte)118, (byte)44, byte.MaxValue), dress = 8 }, new Theme { name = "GROVE", deep = new Color32((byte)40, (byte)28, (byte)30, byte.MaxValue), mid = new Color32((byte)74, (byte)48, (byte)52, byte.MaxValue), slab = new Color32((byte)106, (byte)68, (byte)70, byte.MaxValue), stal = new Color32((byte)56, (byte)38, (byte)40, byte.MaxValue), cap = new Color32((byte)170, (byte)86, (byte)96, byte.MaxValue), dress = 9 }, new Theme { name = "SIREN", deep = new Color32((byte)34, (byte)40, (byte)40, byte.MaxValue), mid = new Color32((byte)70, (byte)78, (byte)74, byte.MaxValue), slab = new Color32((byte)104, (byte)112, (byte)104, byte.MaxValue), stal = new Color32((byte)52, (byte)60, (byte)56, byte.MaxValue), cap = new Color32((byte)160, (byte)98, (byte)58, byte.MaxValue), dress = 12 }, new Theme { name = "MEADOW", deep = new Color32((byte)36, (byte)32, (byte)52, byte.MaxValue), mid = new Color32((byte)66, (byte)58, (byte)94, byte.MaxValue), slab = new Color32((byte)96, (byte)86, (byte)130, byte.MaxValue), stal = new Color32((byte)50, (byte)44, (byte)72, byte.MaxValue), cap = new Color32((byte)152, (byte)134, (byte)202, byte.MaxValue), dress = 2 }, new Theme { name = "FOREST", deep = new Color32((byte)26, (byte)34, (byte)32, byte.MaxValue), mid = new Color32((byte)50, (byte)66, (byte)58, byte.MaxValue), slab = new Color32((byte)76, (byte)96, (byte)84, byte.MaxValue), stal = new Color32((byte)38, (byte)50, (byte)44, byte.MaxValue), cap = new Color32((byte)208, (byte)220, (byte)224, byte.MaxValue), dress = 3 }, new Theme { name = "MOON", deep = new Color32((byte)40, (byte)40, (byte)44, byte.MaxValue), mid = new Color32((byte)76, (byte)76, (byte)82, byte.MaxValue), slab = new Color32((byte)110, (byte)110, (byte)118, byte.MaxValue), stal = new Color32((byte)58, (byte)58, (byte)64, byte.MaxValue), cap = new Color32((byte)202, (byte)202, (byte)212, byte.MaxValue), dress = 4 }, new Theme { name = "VOID", deep = new Color32((byte)28, (byte)22, (byte)40, byte.MaxValue), mid = new Color32((byte)54, (byte)42, (byte)76, byte.MaxValue), slab = new Color32((byte)82, (byte)62, (byte)110, byte.MaxValue), stal = new Color32((byte)42, (byte)32, (byte)58, byte.MaxValue), cap = new Color32((byte)198, (byte)90, (byte)152, byte.MaxValue), dress = 2 }, new Theme { name = "SULFUR", deep = new Color32((byte)44, (byte)40, (byte)26, byte.MaxValue), mid = new Color32((byte)82, (byte)74, (byte)42, byte.MaxValue), slab = new Color32((byte)116, (byte)104, (byte)58, byte.MaxValue), stal = new Color32((byte)62, (byte)56, (byte)32, byte.MaxValue), cap = new Color32((byte)182, (byte)192, (byte)72, byte.MaxValue), dress = 9 } }; public static Theme RollTheme(ref uint rngState, string destinationScene) { Theme result = All[ArcadeRng.Next(ref rngState, All.Length)]; int num = ForScene(destinationScene); if (num < 0) { return result; } return All[num]; } public static int ForScene(string scene) { if (string.IsNullOrEmpty(scene)) { return -1; } int num = Lookup(scene); if (num < 0 && scene.Length > 2 && scene[0] == 'i' && scene[1] == 't') { num = Lookup(scene.Substring(2)); } return num; static int Lookup(string s) { switch (s) { case "habitatfall": case "golemplains": case "golemplains2": case "lakes": case "lakesnight": case "habitat": return 0; case "blackbeach2": case "blackbeach": return 1; case "villagenight": case "goolake": case "village": return 2; case "ancientloft": case "frozenwall": return 3; case "wispgraveyard": case "artifactworld": case "lemuriantemple": return 4; case "rootjungle": case "helminthroost": case "dampcavesimple": return 5; case "shipgraveyard": return 6; case "skymeadow": return 7; case "snowyforest": case "foggyswamp": return 8; case "moon2": case "moon": return 9; case "arena": case "voidstage": case "voidraid": return 10; case "sulfurpools": case "goldshores": return 11; default: return -1; } } } public static Color32 Scale(Color32 c, float f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) return new Color32((byte)Mathf.Clamp((float)(int)c.r * f, 0f, 255f), (byte)Mathf.Clamp((float)(int)c.g * f, 0f, 255f), (byte)Mathf.Clamp((float)(int)c.b * f, 0f, 255f), byte.MaxValue); } public static uint DressHash(int x, int y) { int num = x * 374761393 + y * 668265263; int num2 = (num ^ (num >>> 13)) * 1274126177; return (uint)(num2 ^ (num2 >>> 16)); } public static bool StrataBand(int x, int y, int groupShift, int salt, bool drift, int period, int thickness) { return (y + (int)(DressHash(x >> groupShift, salt) % 5) + (drift ? (x >> 3) : 0)) % period < thickness; } public static bool AccentSeed(int x, int y, int rarity) { return DressHash(x, y) % (uint)rarity == 0; } } internal static class CommandoSprites { public enum Critter { Lemurian, Golem, Child, Drone } private class Anim { public Sprite[] frames; public float[] frameEnds; public Vector2 size; public int IndexAt(float t) { float num = frameEnds[frameEnds.Length - 1]; if (num <= 0f) { return 0; } float num2 = t % num; for (int i = 0; i < frameEnds.Length; i++) { if (num2 < frameEnds[i]) { return i; } } return frames.Length - 1; } public Sprite At(float t) { return frames[IndexAt(t)]; } } private const string Dir = "RoR2/Base/loadingbasic/"; private static readonly string[] CritterKeys = new string[4] { "RoR2/Base/loadingbasic/ssaLemurianWalk.asset", "RoR2/Base/loadingbasic/ssaGolem.asset", "RoR2/Base/loadingbasic/ssaChildWalk.asset", "RoR2/Base/loadingbasic/ssaDroneHover.asset" }; private static readonly Color32[] RampSrc = (Color32[])(object)new Color32[4] { new Color32((byte)131, (byte)69, (byte)39, byte.MaxValue), new Color32((byte)193, (byte)128, (byte)62, byte.MaxValue), new Color32((byte)223, (byte)183, (byte)98, byte.MaxValue), new Color32((byte)244, (byte)243, (byte)183, byte.MaxValue) }; private static readonly float[] RampDrift = new float[4] { 0f, 10f, 21f, 39f }; private static readonly float[] RampSat = new float[4] { 0.7f, 0.68f, 0.56f, 0.25f }; private static readonly float[] RampVal = new float[4] { 0.51f, 0.76f, 0.87f, 0.96f }; private const float BaseHue = 20f; private static readonly float[] Hues = new float[16] { 20f, 355f, 48f, 85f, 125f, 165f, 190f, 210f, 235f, 262f, 285f, 315f, 335f, float.NaN, float.NaN, float.NaN }; private const int PastelIndex = 12; private static readonly float[][] NeutralVals = new float[3][] { new float[4] { 0.62f, 0.78f, 0.9f, 0.98f }, new float[4] { 0.38f, 0.52f, 0.62f, 0.72f }, new float[4] { 0.16f, 0.24f, 0.3f, 0.38f } }; public const int ColorwayCount = 16; public static readonly string[] ColorwayNames = new string[16] { "Orange", "Red", "Yellow", "Lime", "Green", "Teal", "Cyan", "Azure", "Blue", "Indigo", "Purple", "Magenta", "Pink", "White", "Grey", "Black" }; private static bool loadStarted; private static Anim[] commando; private static bool[][] commandoMasks; private static readonly Anim[] critters = new Anim[4]; private static readonly List<Texture2D> ownedTextures = new List<Texture2D>(); private static int pendingLoads; public static bool Ready { get; private set; } public static bool Failed { get; private set; } public static Vector2 CommandoSize => commando[0].size; public static void EnsureLoading() { if (loadStarted) { return; } loadStarted = true; pendingLoads = 1 + CritterKeys.Length; LoadSsa("RoR2/Base/loadingbasic/ssaCommandoWalk.asset", delegate(SimpleSpriteAnimation anim) { try { BuildCommandoColorways(anim); } catch (Exception ex) { Failed = true; ScorchedVoxelsPlugin.Log.LogWarning((object)("[ScorchedVoxels] commando recolor failed, arcade disabled: " + ex.Message)); } }); for (int num = 0; num < CritterKeys.Length; num++) { int idx = num; LoadSsa(CritterKeys[idx], delegate(SimpleSpriteAnimation anim) { critters[idx] = FromSsa(anim); }); } } private static void LoadSsa(string key, Action<SimpleSpriteAnimation> onLoaded) { //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) try { AsyncOperationHandle<SimpleSpriteAnimation> val = Addressables.LoadAssetAsync<SimpleSpriteAnimation>((object)key); val.Completed += delegate(AsyncOperationHandle<SimpleSpriteAnimation> op) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)op.Status == 1 && (Object)(object)op.Result != (Object)null && op.Result.frames != null && op.Result.frames.Length != 0) { onLoaded(op.Result); } else { Failed = true; ScorchedVoxelsPlugin.Log.LogWarning((object)("[ScorchedVoxels] arcade sprite load failed (" + key + ") — arcade disabled")); } if (--pendingLoads == 0 && !Failed) { Ready = true; } }; } catch (Exception ex) { Failed = true; ScorchedVoxelsPlugin.Log.LogWarning((object)("[ScorchedVoxels] arcade sprite load threw (" + key + "): " + ex.Message)); } } private static Anim FromSsa(SimpleSpriteAnimation ssa) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) int num = ssa.frames.Length; Anim anim = new Anim { frames = (Sprite[])(object)new Sprite[num], frameEnds = new float[num] }; float num2 = ((ssa.frameRate > 0f) ? ssa.frameRate : 60f); for (int i = 0; i < num; i++) { anim.frames[i] = ssa.frames[i].sprite; anim.frameEnds[i] = (float)ssa.frames[i].duration / num2; } for (int j = 1; j < num; j++) { if (anim.frameEnds[j] <= anim.frameEnds[j - 1]) { anim.frameEnds[j] = anim.frameEnds[j - 1] + 1f / num2; } } Rect rect = anim.frames[0].rect; anim.size = new Vector2(((Rect)(ref rect)).width, ((Rect)(ref rect)).height); return anim; } private static void BuildCommandoColorways(SimpleSpriteAnimation ssa) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: 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_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Expected O, but got Unknown //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) Texture2D texture = ssa.frames[0].sprite.texture; RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); RenderTexture active = RenderTexture.active; Graphics.Blit((Texture)(object)texture, temporary); RenderTexture.active = temporary; Texture2D val = new Texture2D(((Texture)texture).width, ((Texture)texture).height, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), 0, 0, false); val.Apply(false, false); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); Color32[] pixels = val.GetPixels32(); Object.Destroy((Object)val); commandoMasks = new bool[ssa.frames.Length][]; for (int i = 0; i < ssa.frames.Length; i++) { Rect rect = ssa.frames[i].sprite.rect; int num = (int)((Rect)(ref rect)).x; int num2 = (int)((Rect)(ref rect)).y; int num3 = (int)((Rect)(ref rect)).width; int num4 = (int)((Rect)(ref rect)).height; bool[] array = new bool[num3 * num4]; for (int j = 0; j < num4; j++) { for (int k = 0; k < num3; k++) { array[j * num3 + k] = pixels[(num2 + j) * ((Texture)texture).width + num + k].a > 40; } } commandoMasks[i] = array; } commando = new Anim[16]; Color32[] array2 = (Color32[])(object)new Color32[pixels.Length]; Color32[] array3 = (Color32[])(object)new Color32[RampSrc.Length]; for (int l = 0; l < 16; l++) { for (int m = 0; m < RampSrc.Length; m++) { array3[m] = ColorwayColor(l, m); } for (int n = 0; n < pixels.Length; n++) { Color32 val2 = pixels[n]; if (val2.a == 0) { array2[n] = val2; continue; } int num5 = MatchRamp(val2); array2[n] = (Color32)((num5 >= 0) ? new Color32(array3[num5].r, array3[num5].g, array3[num5].b, val2.a) : val2); } Texture2D val3 = new Texture2D(((Texture)texture).width, ((Texture)texture).height, (TextureFormat)4, false) { filterMode = (FilterMode)0, wrapMode = (TextureWrapMode)1 }; val3.SetPixels32(array2); val3.Apply(false, true); ownedTextures.Add(val3); Anim anim = new Anim { frames = (Sprite[])(object)new Sprite[ssa.frames.Length], frameEnds = new float[ssa.frames.Length] }; float num6 = ((ssa.frameRate > 0f) ? ssa.frameRate : 60f); for (int num7 = 0; num7 < ssa.frames.Length; num7++) { Rect rect2 = ssa.frames[num7].sprite.rect; anim.frames[num7] = Sprite.Create(val3, rect2, new Vector2(0.5f, 0f), 100f); anim.frameEnds[num7] = (float)ssa.frames[num7].duration / num6; } for (int num8 = 1; num8 < anim.frameEnds.Length; num8++) { if (anim.frameEnds[num8] <= anim.frameEnds[num8 - 1]) { anim.frameEnds[num8] = anim.frameEnds[num8 - 1] + 1f / num6; } } Rect rect3 = anim.frames[0].rect; anim.size = new Vector2(((Rect)(ref rect3)).width, ((Rect)(ref rect3)).height); commando[l] = anim; } } private static int MatchRamp(Color32 p) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_003a: 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) for (int i = 0; i < RampSrc.Length; i++) { Color32 val = RampSrc[i]; if (Mathf.Abs(p.r - val.r) <= 8 && Mathf.Abs(p.g - val.g) <= 8 && Mathf.Abs(p.b - val.b) <= 8) { return i; } } return -1; } private static Color32 ColorwayColor(int colorway, int step) { //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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) float num = Hues[colorway]; Color val; if (float.IsNaN(num)) { val = Color.HSVToRGB(0f, 0f, NeutralVals[colorway - 13][step]); } else { float num2 = RampSat[step]; float num3 = RampVal[step]; if (colorway == 12) { num2 *= 0.55f; num3 = Mathf.Min(1f, num3 + 0.22f * (1f - num3) + 0.1f); } val = Color.HSVToRGB(Mathf.Repeat(num + RampDrift[step], 360f) / 360f, num2, num3); } return new Color32((byte)Mathf.RoundToInt(val.r * 255f), (byte)Mathf.RoundToInt(val.g * 255f), (byte)Mathf.RoundToInt(val.b * 255f), byte.MaxValue); } public static Sprite CommandoFrame(int colorway, float t) { return commando[Mod16(colorway)].At(t); } public static bool CommandoOpaque(float t, int px, int py) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) Vector2 size = commando[0].size; int num = (int)size.x; int num2 = (int)size.y; if (px < 0 || px >= num || py < 0 || py >= num2) { return false; } return commandoMasks[commando[0].IndexAt(t)][py * num + px]; } public static Color Tint(int colorway) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) Color32 val = ColorwayColor(Mod16(colorway), 1); return new Color((float)(int)val.r / 255f, (float)(int)val.g / 255f, (float)(int)val.b / 255f, 1f); } public static Sprite CritterFrame(Critter c, float t) { return critters[(int)c].At(t); } public static Vector2 CritterSize(Critter c) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return critters[(int)c].size; } private static int Mod16(int i) { return (i % 16 + 16) % 16; } public static int ColorwayFor(uint userNetId) { return (int)(userNetId % 16); } } internal static class DecorStamps { public const int Count = 25; public const int W = 40; public const int H = 44; private static int DRng(ref uint st, int max) { return ArcadeRng.Next(ref st, max); } public static int Raster(int id, byte[] cv, ref uint st) { Array.Clear(cv, 0, cv.Length); int num = 12; int num2 = 12; switch (id) { case 0: { int num23 = 4 + DRng(ref st, 4); Disc(num23, num23 - 1, num23, 1); Disc(num23 - 1, num23, num23 - 3, 2); num = 2 * num23 + 1; num2 = 2 * num23; break; } case 1: { int num12 = 3 + DRng(ref st, 3); Disc(num12, num12 - 1, num12, 1); Disc(2 * num12 + 2, num12 - 2, num12 - 1, 1); Px(num12 - 1, 2 * num12 - 2, 2); num = 3 * num12 + 2; num2 = 2 * num12; break; } case 2: { int num5 = 8 + DRng(ref st, 7); int num6 = 2 + DRng(ref st, 2); TriUp(num6, 0, num6, num5, 1); Px(num6, num5 - 1, 2); num = 2 * num6 + 1; num2 = num5; break; } case 3: { int num34 = 7 + DRng(ref st, 6); TriUp(3, 0, 3, num34, 1); TriUp(9, 0, 3, num34 - 3 + DRng(ref st, 3), 1); TriUp(14, 0, 2, num34 - 4, 1); num = 17; num2 = num34; break; } case 4: { int num28 = 16 + DRng(ref st, 9); TriUp(3, 0, 3, num28, 1); Px(3, num28 - 1, 2); Px(2, num28 - 4, 2); num = 7; num2 = num28; break; } case 5: { int num10 = 4 + DRng(ref st, 2); int num11 = 0; for (int l = 0; l < 3 + DRng(ref st, 2); l++) { if (num10 <= 1) { break; } Disc(6, num11 + num10 - 1, num10, 1); Px(6, num11 + 2 * num10 - 2, 2); num11 += 2 * num10 - 2; num10--; } num = 13; num2 = num11 + 4; break; } case 6: { int num29 = 9 + DRng(ref st, 5); for (int num30 = 0; num30 < num29; num30++) { Rect(2 + num30 / 3, num30, 4, 1, 1); } Rect(2 + (num29 - 1) / 3, num29 - 1, 4, 1, 2); num = 7 + num29 / 3; num2 = num29; break; } case 7: { for (int num22 = 0; num22 < 7 + DRng(ref st, 4); num22++) { Rect(DRng(ref st, 16), DRng(ref st, 3), 1 + DRng(ref st, 2), 1 + DRng(ref st, 2), (byte)(1 + DRng(ref st, 2))); } num = 18; num2 = 5; break; } case 8: { int num19 = 8 + DRng(ref st, 5); Rect(1, 0, 4, num19, 1); Px(2, num19 - 1, 2); Px(3, num19 / 2, 3); num = 6; num2 = num19; break; } case 9: { int num18 = 9 + DRng(ref st, 4); Rect(1, 0, 2, num18, 1); Rect(10, 0, 2, num18, 1); Rect(0, num18, 13, 2, 1); Px(1, num18 - 1, 2); Px(11, num18 - 1, 2); num = 13; num2 = num18 + 2; break; } case 10: { int num14 = 5 + DRng(ref st, 4); Rect(1, 0, 3, num14, 1); Rect(1, num14, 3, 1, 2); Disc(8, 1, 2, 1); num = 11; num2 = num14 + 1; break; } case 11: Rect(0, 0, 14 + DRng(ref st, 5), 2, 1); Rect(2, 2, 10, 2, 1); Rect(4, 4, 6, 2, 2); num = 19; num2 = 6; break; case 12: { for (int j = 0; j < 5 + DRng(ref st, 3); j++) { Rect(j * 2 + DRng(ref st, 2), 0, 1, 2 + DRng(ref st, 3), 3); } num = 14; num2 = 5; break; } case 13: { for (int num31 = 0; num31 < 2 + DRng(ref st, 2); num31++) { int num32 = num31 * 5 + 2; int num33 = 2 + DRng(ref st, 2); Rect(num32, 0, 1, num33, 2); Disc(num32, num33 + 1, 2, 3); } num = 14; num2 = 7; break; } case 14: Rect(0, 0, 12, 1, 2); TriUp(3, 1, 2, 6 + DRng(ref st, 3), 3); TriUp(7, 1, 2, 4 + DRng(ref st, 3), 3); TriUp(10, 1, 1, 5, 3); num = 13; num2 = 11; break; case 15: { int num25 = 4 + DRng(ref st, 2); for (int num26 = 0; num26 < num25; num26++) { int num27 = 6 - Mathf.Abs(num26 - num25 / 2); Rect(num26 * 3, 0, 1, num27, 2); Px(num26 * 3 + 1, num27 - 1, 2); } num = num25 * 3; num2 = 7; break; } case 16: { int num24 = 8 + DRng(ref st, 6); TriDown(3, num24 - 1, 3, num24, 1); TriDown(9, num24 - 1, 3, num24 - 3, 1); TriDown(14, num24 - 1, 2, num24 - 5, 1); num = 17; num2 = num24; break; } case 17: { int num20 = 5 + DRng(ref st, 4); for (int num21 = 0; num21 < num20; num21++) { TriDown(num21 * 3 + 1, 5, 1, 3 + DRng(ref st, 3), 2); } num = num20 * 3; num2 = 6; break; } case 18: { int num15 = 10 + DRng(ref st, 7); for (int n = 0; n < 3; n++) { int num16 = n * 4 + 1; for (int num17 = 0; num17 < num15 - n * 2; num17++) { Px(num16 + ((num17 / 3) & 1), num15 - 1 - num17, 2); } Px(num16, num15 - 1 - (num15 - n * 2) + 1, 3); } num = 11; num2 = num15; break; } case 19: { int num13 = 8 + DRng(ref st, 4); for (int m = 0; m < num13; m++) { Px(6 - m / 2, num13 - 1 - m, 2); Px(7 + m / 3, num13 - 1 - m, 2); if (m > 3) { Px(10 + m / 3, num13 - 1 - m, 2); } } num = 15; num2 = num13; break; } case 20: TriDown(3, 7, 2, 6 + DRng(ref st, 2), 3); TriDown(8, 7, 2, 4, 3); TriDown(12, 7, 1, 5, 3); Rect(0, 7, 14, 1, 2); num = 14; num2 = 8; break; case 21: { int num9 = 8 + DRng(ref st, 7); for (int k = 0; k < num9; k++) { if ((k & 1) == 0) { Rect(k, k / 2, 2, 1, 3); } } num = num9 + 2; num2 = num9 / 2 + 1; break; } case 22: { int num8 = 4 + DRng(ref st, 3); Disc(num8, num8, num8, 1); Ring(num8, num8, num8 - 2, 3); num = 2 * num8 + 1; num2 = 2 * num8 + 1; break; } case 23: { int num7 = 4 + DRng(ref st, 2); Ring(num7, num7, num7, 2); Ring(num7, num7, num7 - 2, 2); Px(num7, num7, 2); num = 2 * num7 + 1; num2 = 2 * num7 + 1; break; } default: { int num3 = 12 + DRng(ref st, 7); for (int i = 0; i < num3; i++) { int num4 = Mathf.Max(1, 3 - Mathf.Abs(i - num3 / 2) * 6 / num3); Rect(i, 2 - num4 / 2, 1, num4, 1); } num = num3; num2 = 5; break; } } return (Mathf.Min(num, 40) << 8) | Mathf.Min(num2, 44); void Disc(int cx, int cy, int r, byte s) { for (int num35 = -r; num35 <= r; num35++) { for (int num36 = -r; num36 <= r; num36++) { if (num35 * num35 + num36 * num36 <= r * r) { Px(cx + num35, cy + num36, s); } } } } void Px(int x, int y, byte s) { if (x >= 0 && y >= 0 && x < 40 && y < 44) { cv[y * 40 + x] = s; } } void Rect(int x, int y, int rw, int rh, byte s) { for (int num35 = 0; num35 < rw; num35++) { for (int num36 = 0; num36 < rh; num36++) { Px(x + num35, y + num36, s); } } } void Ring(int cx, int cy, int r, byte s) { for (int num35 = -r; num35 <= r; num35++) { for (int num36 = -r; num36 <= r; num36++) { int num37 = num35 * num35 + num36 * num36; if (num37 <= r * r && num37 > (r - 1) * (r - 1)) { Px(cx + num35, cy + num36, s); } } } } void TriDown(int cx, int topY, int halfW, int ht, byte s) { for (int num35 = 0; num35 < ht; num35++) { int num36 = Mathf.Max(halfW * (ht - num35) / ht, 0); for (int num37 = -num36; num37 <= num36; num37++) { Px(cx + num37, topY - num35, s); } } } void TriUp(int cx, int baseY, int halfW, int ht, byte s) { for (int num35 = 0; num35 < ht; num35++) { int num36 = Mathf.Max(halfW * (ht - num35) / ht, 0); for (int num37 = -num36; num37 <= num36; num37++) { Px(cx + num37, baseY + num35, s); } } } } } internal static class PetSprite { public delegate void SetPx(int x, int y, byte r, byte g, byte b); public enum Shape { Classic, Round, Tall, Squat, Pear, Dome, Brick, Wedge } public enum Pattern { Solid, Speckled, Banded, Spotted, Patched, Gradient, Mottled } public enum EyeStyle { Classic, Warm, Jade, Sky, Sparkle, Odd } public enum Accessory { None, MossTuft, Mushroom, CrystalCrown, HornNubs, Antenna, BackSpikes, Sprout, Flower, TopHat, PartyCone, SnailShell, CatEars, BunnyEars, Halo, Bow, Pebblet, Feather, Twig, Antlers, Lichen, Barnacles, CrystalStud, Candle, Fin, TailNub, Scarf } public enum Aura { None, GlowRim, SparkleField, Drips, OrbitMote } public enum Foil { None, Prismatic, LiquidGold, Starfield, Ripple, VoidSkin, ChefFire } public struct Look { public byte bodyR; public byte bodyG; public byte bodyB; public byte bellyR; public byte bellyG; public byte bellyB; public byte speckR; public byte speckG; public byte speckB; public int eyeGap; public uint salt; public bool shiny; public int shinyCoat; public Shape shape; public Pattern pattern; public EyeStyle eyes; public Accessory accessory; public Aura aura; public bool blush; public Foil foil; } public const int Stages = 5; public static readonly int[] W = new int[5] { 5, 7, 10, 14, 18 }; public static readonly int[] H = new int[5] { 4, 5, 8, 11, 12 }; private static readonly byte[,] Body = new byte[5, 3] { { 118, 120, 128 }, { 130, 118, 102 }, { 144, 120, 98 }, { 152, 112, 80 }, { 166, 98, 60 } }; private static readonly byte[,] ShinyCoat = new byte[6, 3] { { 96, 156, 118 }, { 176, 112, 130 }, { 182, 152, 76 }, { 118, 152, 176 }, { 142, 110, 172 }, { 106, 140, 94 } }; private static readonly string[] ShinyNames = new string[6] { "JADE", "ROS