public static User?GetUser()
 {
     if (Disabled || InitRunning)
     {
         return(null);
     }
     try {
         return(UserManager.GetCurrentUser());
     }
     catch (Exception e) {
         if (e is ResultException re)
         {
             if (re.Result != Result.NotFound)
             {
                 Randomizer.Log($"Result {re.Result} on GetUser, returning null", false);
             }
             if (CanTryToken)
             {
                 Randomizer.Debug("Discord user not found. Attempting to get token...");
                 new Thread(() => TryGetToken()).Start();
             }
             return(null);
         }
         Randomizer.Error("GetUser", e, false);
         return(null);
     }
 }
        public static bool CheckFlag(FlagCode flag)
        {
            switch (flag)
            {
            case FlagCode.Ore:
                if (OreFound)
                {
                    OreFound = false;
                    return(true);
                }
                return(false);

            case FlagCode.Save:
                if (PleaseSave)
                {
                    PleaseSave = false;
                    return(true);
                }
                return(false);

            case FlagCode.UnlockMap:
                if (BlackSheepWall)
                {
                    BlackSheepWall = false;
                    return(true);
                }
                return(false);

            default:
                Randomizer.Log($"Unknown Flag code {flag}");
                return(false);
            }
        }
        public static void ReadSeed()
        {
            var seedName = File.ReadAllText(Randomizer.SeedNameFile);

            if (seedName.Trim() != "")
            {
                pickupMap.Clear();
                foreach (var line in File.ReadLines(Randomizer.SeedFile))
                {
                    try {
                        var frags      = line.Split('|');
                        var uberId     = new UberId(int.Parse(frags[0]), int.Parse(frags[1]));
                        var pickupType = (PickupType)byte.Parse(frags[2]);
                        //                    Randomizer.Log($"uberId {uberId} -> {pickupType} {frags[3]}");
                        pickupMap[uberId] = BuildPickup(pickupType, frags[3]);
                    } catch (Exception e) {
                        Randomizer.Log($"Error parsing line: '{line}'\nError: {e.Message} \nStacktrace: {e.StackTrace}", false);
                    }
                }
                AHK.Print($"Seed {seedName} loaded", 300);
            }
            else
            {
                AHK.Print($"No seed loaded; Download a .wotwr file and double-click it to load one", 360);
            }
        }
示例#4
0
        public static void NewGameInit()
        {
            var memory = Randomizer.Memory;

            if (!memory.IsLoadingGame())
            {
                Randomizer.Log("New Game Init", false);
                SaveController.SetAbility(AbilityType.SpiritEdge);
                foreach (UberState s in DefaultUberStates)
                {
                    memory.WriteUberState(s);
                }
                foreach (UberState s in Kuberstates)
                {
                    memory.WriteUberState(s);
                }
                foreach (UberState s in DialogAndRumors)
                {
                    memory.WriteUberState(s);
                }

                if (SeedController.KSDoorsOpen)
                {
                    foreach (UberState s in KeystoneDoors)
                    {
                        memory.WriteUberState(s);
                    }
                }

                if (!AHK.IniFlag("ShowShortCutscenes"))
                {
                    foreach (UberState s in ShortCutscenes)
                    {
                        memory.WriteUberState(s);
                    }
                }

                if (!AHK.IniFlag("ShowLongCutscenes"))
                {
                    foreach (UberState s in LongCutscenes)
                    {
                        memory.WriteUberState(s);
                    }
                }

                if (PsuedoLocs.GAME_START.Pickup().NonEmpty)
                {
                    Randomizer.InputUnlockCallback = () => {
                        PsuedoLocs.GAME_START.Pickup().Grant();
                        InterOp.magic_function();
                        InterOp.save();
                    };
                }

                InterOp.discover_everything();
                InterOp.bind_sword();
                InterOp.save();
                NeedsNewGameInit = false;
            }
        }
示例#5
0
 public static void OnSave(int slot, int backupSlot = -1)
 {
     if (Randomizer.Memory.PlayerStats.Health == 0)
     {
         DidWeJustDie = true;
         return; // the game saves right when you die, but we don't want to save progress when that happens.
     }
     if (slot == -1)
     {
         Randomizer.Log("Error: tried to save to empty slot");
         return;
     }
     if (slot != CurrentSlot)
     {
         // this is a slot swap and not a save
         CurrentSlot = slot;
         Data        = new SaveData(slot);
         Data.Load(backupSlot);
         if (Randomizer.InputUnlockCallback != null)
         {
             AHK.Print("Warning: Callback overwritten on slot change!", 240);
             Randomizer.InputUnlockCallback = null;
         }
         return;
     }
     Data.Save(backupSlot);
 }
 public static void TryGetToken()
 {
     if (Disabled || InitRunning)
     {
         return;
     }
     CanTryToken = false;
     ApplicationManager.GetOAuth2Token((Result result, ref OAuth2Token token) => {
         try {
             if (result == Result.Ok) // You may now use this token against Discord's HTTP API
             {
                 Token = token;
                 Randomizer.Log($"Token for the user: {token.AccessToken}. Expires in {token.Expires}. Session ID: {WebSocketClient.SessionId}", false);
             }
             else
             {
                 Randomizer.Log($"Got: {result}, token is ${token.AccessToken}", false);
                 Token = token;
             }
         }
         catch (Exception e) {
             if (e is ResultException re)
             {
                 Randomizer.Debug($"Got result {re.Result} when grabbing token");
             }
             else
             {
                 Randomizer.Error("appManager", e);
             }
         }
     });
 }
示例#7
0
 public static void NewGame(int slot)
 {
     Randomizer.Log($"NewGame {slot}");
     Randomizer.PerformNewGameInit = true;
     CurrentSlot = slot;
     Data        = new SaveData(slot);
     Data.Save();
 }
示例#8
0
        public static void Update()
        {
            if (NeedsNewGameInit)
            {
                NewGameInit();
            }
            bool SkipListners = SkipListenersNextUpdate;

            SkipListenersNextUpdate = false;

            var memory = Randomizer.Memory;
            Dictionary <long, UberState> uberStates = memory.GetUberStates();

            foreach (KeyValuePair <long, UberState> pair in uberStates)
            {
                try {
                    UberState state = pair.Value;
                    UberId    key   = state.GetUberId();

                    if (UberStates.TryGetValue(key, out UberState oldState))
                    {
                        UberValue value    = state.Value;
                        UberValue oldValue = oldState.Value;
                        if (value.Int != oldValue.Int)
                        {
                            var oldValFmt = oldState.FmtVal(); // get this now because we overwrite the value by reference
                            if (ShouldRevert(state))
                            {
                                Randomizer.Log($"Reverting state change of {state.Name} from {oldValFmt} to {state.FmtVal()}", false);
                                memory.WriteUberState(oldState);
                                continue;
                            }
                            HandleSpecial(state);
                            UberStates[key].Value = state.Value;
                            if (!SkipListners)
                            {
                                var  pos   = Randomizer.Memory.Position();
                                bool found = false;
                                if (value.Int > 0)
                                {
                                    found = SeedController.OnUberState(state);
                                }
                                if ((value.Int == 0 || !found) && !(state.GroupName == "statsUberStateGroup" || state.GroupName == "achievementsGroup"))
                                {
                                    Randomizer.Log($"State change: {state.Name} {state.ID} {state.GroupName} {state.GroupID} {state.Type} {state.FmtVal()} (was {oldValFmt}, pos ({Math.Round(pos.X)},{Math.Round(pos.Y)}) )", false);
                                }
                            }
                        }
                    }
                    else
                    {
                        UberStates[key] = state.Clone();
                    }
                } catch (Exception e) {
                    Randomizer.Error($"USC.Update {pair}", e);
                }
            }
        }
        public static void Tick()
        {
            var signal = Engine.ExecFunction("Tick");

            if (signal != null && signal != "none")
            {
                Engine.SetVar("signal", "none");
                switch (signal)
                {
                case "reload":
                    if (FramesTillUnlockReload == 0)
                    {
                        SeedController.ReadSeed();
                        FramesTillUnlockReload = 60;
                    }
                    break;

                case "dev":
                    Randomizer.Dev = !Randomizer.Dev;
                    Randomizer.Log($"Dev: {Randomizer.Dev}");
                    break;

                case "exitapp":
                    Environment.Exit(Environment.ExitCode);
                    break;

                default:
                    Randomizer.Log($"Recieved unknown signal {signal}");
                    break;
                }
            }
            FramesTillUnlockReload = Math.Max(0, FramesTillUnlockReload - 1);
            if (FramesTillNextSend > 0)
            {
                FramesTillNextSend--;
            }
            else
            {
                if (MessageQueue.Count > 0)
                {
                    Current            = MessageQueue.Dequeue();
                    FramesTillNextSend = Current.Frames();
                    Engine.ExecFunction("PickupMessage", Current.Text(), (Current.Frames() * 50 / 3).ToString());
                    if (IniFlag("LogOnPrint"))
                    {
                        Randomizer.Log($"Sending {Current.Text()} for {Current.Frames()} ({MessageQueue.Count} remaining in queue)", false);
                    }
                }
                else
                {
                    Current = null;
                }
            }
        }
        public static Sellable TwillenShard(ShardType shard)
        {
            UberId fakeId = new UberId((int)FakeUberGroups.TWILLEN_SHARD, (int)shard);

            if (pickupMap.TryGetValue(fakeId, out Pickup p) && p is Sellable)
            {
                return(p as Sellable);
            }
            Randomizer.Log($"Couldn't find a valid Sellable for {shard}...");
            return(new Resource(ResourceType.Energy));
        }
 public static void DiscordInitComplete()
 {
     if (Disabled)
     {
         return;
     }
     User        = UserManager.GetCurrentUser();
     InitRunning = false;
     Randomizer.Log($"have user UID: {User.Id}", false);
     Randomizer.Client.Connect();
 }
        public static Sellable OpherWeapon(AbilityType ability)
        {
            UberId fakeId = new UberId((int)FakeUberGroups.OPHER_WEAPON, (int)ability);

            if (pickupMap.TryGetValue(fakeId, out Pickup p) && p is Sellable)
            {
                return(p as Sellable);
            }
            Randomizer.Log($"Couldn't find a valid Sellable for {ability}...");
            return(new Resource(ResourceType.Energy));
        }
        public static void TwillenBuyShard(ShardType slot)
        {
            Sellable item = SeedController.TwillenShard(slot);

            if (SaveController.Data.TwillenSold.Contains(slot))
            {
                Randomizer.Log($"TBS: not enough money or slot already sold ");
                return;
            }
            SaveController.Data.TwillenSold.Add(slot);
            item.Grant();
            return;
        }
        public static void OpherBuyWeapon(AbilityType slot)
        {
            Sellable item = SeedController.OpherWeapon(slot);

            if (SaveController.Data.OpherSold.Contains(slot))
            {
                Randomizer.Log($"OBW: not enough money or slot already sold ");
                return;
            }
            SaveController.Data.OpherSold.Add(slot);
            item.Grant();
            return;
        }
        public static void OnBuyOpherWeapon(AbilityType slot)
        {
            Pickup item = SeedController.OpherWeapon(slot);

            if (SaveController.Data.OpherSold.Contains(slot))
            {
                Randomizer.Log($"OBW: not enough money or slot already sold");
                return;
            }
            SaveController.Data.OpherSold.Add(slot);
            Randomizer.Log($"sold {item} from {slot} for ${SeedController.OpherWeapon(slot).CostWithMod(GetCostMod(slot))}", false);
            item.Grant();
            return;
        }
        public static void OnTree(AbilityType ability)
        {
            UberId fakeId = new UberId((int)FakeUberGroups.TREE, (int)ability);

            if (pickupMap.TryGetValue(fakeId, out Pickup p))
            {
                AHK.Print(p.ToString());
                p.Grant();
                Randomizer.PleaseSave = true;
            }
            else
            {
                Randomizer.Log($"Tree {ability} not found in seed. Get a seed from seedpack 10 or later.");
            }
        }
示例#17
0
        public static void Update(bool NewGameInit = false)
        {
            var memory = Randomizer.Memory;
            Dictionary <long, UberState> uberStates = memory.GetUberStates();

            foreach (KeyValuePair <long, UberState> pair in uberStates)
            {
                long      key   = pair.Key;
                UberState state = pair.Value;
                if (state.GroupName == "statsUberStateGroup" || (state.GroupName == "achievementsGroup" && state.Name == "spiritLightGainedCounter"))
                {
                    continue;
                }
                if (UberStates.TryGetValue(key, out UberState oldState))
                {
                    UberValue value    = state.Value;
                    UberValue oldValue = oldState.Value;
                    if (value.Int != oldValue.Int)
                    {
                        var pos = Randomizer.Memory.Position();
                        if (Ready)
                        {
                            if (value.Int > 0)
                            {
                                SeedController.OnUberState(state);
                                if (!Randomizer.PleaseSave)
                                {
                                    Randomizer.Log($"Potential pickup: {state.GroupName}.{state.Name} ({state.GroupID}, {state.ID}) at ({Math.Round(pos.X)},{Math.Round(pos.Y)}) {value.Int}", false);
                                }
                            }
                            else
                            {
                                Randomizer.Log($"State change {state.GroupName}.{state.Name} ({state.GroupID}, {state.ID}) at ({Math.Round(pos.X)},{Math.Round(pos.Y)}): {oldValue.Int}->{value.Int}", false);
                            }
                        }
                        UberStates[key].Value = state.Value;
                    }
                }
                else
                {
                    UberStates[key] = state.Clone();
                }
            }
            if (!NewGameInit)
            {
                Ready = true;
            }
        }
示例#18
0
 public static void OnSave(int slot)
 {
     if (slot == -1)
     {
         Randomizer.Log("Error: tried to load from empty slot");
         return;
     }
     if (slot != CurrentSlot)
     {
         // this is a slot swap and not a save
         CurrentSlot = slot;
         Data        = new SaveData(slot);
         Data.Load();
         return;
     }
     Data.Save();
 }
        public static ulong ShopStringRepl(IntPtr str)
        {
            var strr    = MemoryReader.ReadString(Randomizer.Memory.Program, str);
            var shopStr = GetShopNameReplacement(strr);

            if (shopStr != strr)
            {
                return((ulong)getIl2cppStringPointer(shopStr));
            }
            else if (!Strings.Contains(strr))
            {
                if (Randomizer.Dev)
                {
                    Randomizer.Log("New String: " + strr, false);
                }
                Strings.Add(strr);
            }
            return(0);
        }
 public static void Initialize()
 {
     Disabled = AHK.IniFlag("DisableNetcode");
     if (Disabled)
     {
         Randomizer.Log("Netcode disabled, skipping discord init", false, "DEBUG");
         return;
     }
     if (InitRunning)
     {
         Randomizer.Log("Init running already, skipping", false, "DEBUG");
         return;
     }
     InitRunning = true;
     new Thread(() => {
         try {
             if (discord == null)
             {
                 discord = new Discord.Discord(CLIENT_ID, (UInt64)CreateFlags.Default);
             }
             if (UserManager == null)
             {
                 UserManager = discord.GetUserManager();
             }
             if (ApplicationManager == null)
             {
                 ApplicationManager = discord.GetApplicationManager();
             }
             Initialized = true;
             if (GetUser() != null)
             {
                 Randomizer.Log("User already known, skipping rest of discord init", false, "DEBUG");
                 Randomizer.Client.Connect();
                 return;
             }
             discord.SetLogHook(LogLevel.Debug, (level, message) => Randomizer.Log($"discord: {message}", level.CompareTo(LogLevel.Info) > 0, level.ToString()));
             UserManager.OnCurrentUserUpdate += DiscordInitComplete;
         } catch (Exception e) {
             Randomizer.Error("DiscInitThread", e);
         }
         InitRunning = false;
     }).Start();
 }
 public static void Update()
 {
     if (InterOp.get_game_state() == GameState.Game)
     {
         DontTrackYet = false;
     }
     if (IgnoreUpdateFrames > 0)
     {
         IgnoreUpdateFrames--;
         return;
     }
     try {
         if (Last == null || Last.ore != InterOp.get_ore() || Last.spiritLight != InterOp.get_experience())
         {
             Write();
         }
     } catch (Exception e) {
         Randomizer.Error("Track.Update", e);
         Randomizer.Log($"Last: {Last}", false);
     }
 }
示例#22
0
        public static void Tick()
        {
            var signal = Engine.ExecFunction("Tick");

            if (signal != null && signal != "none")
            {
                Engine.SetVar("signal", "none");
                HandleSignal(signal);
            }
            FramesTillUnlockReload = Math.Max(0, FramesTillUnlockReload - 1);
            if (FramesTillNextSend > 0)
            {
                FramesTillNextSend--;
            }
            else
            {
                if (CanPrint)
                {
                    Current            = MessageQueue.Peek();
                    FramesTillNextSend = Current.Frames;
                    try {
                        if (Current.Clear)
                        {
                            InterOp.clear_visible_hints();
                        }
                        InterOp.display_hint(Current.Text, Current.Frames / 60f, Current.Pos, Current.Mute);
                        if (IniFlag("LogOnPrint"))
                        {
                            Randomizer.Log($"Sending {Current.Text} for {Current.Frames} ({MessageQueue.Count} remaining in queue)", false);
                        }
                        MessageQueue.Dequeue();
                    } catch (Exception e) { Randomizer.Error("AHK.sendMsg", e, false); }
                }
                else
                {
                    Current = null;
                }
            }
        }
示例#23
0
        public static void Tick()
        {
            var signal = Engine.ExecFunction("Tick");

            if (signal != null && signal != "none")
            {
                Engine.SetVar("signal", "none");
                switch (signal)
                {
                case "reload":
                    if (FramesTillUnlockReload == 0)
                    {
                        FramesTillNextSend = 0;
                        SeedController.ReadSeed();
                        Randomizer.Memory.OnInit();
                        if (Randomizer.Memory.GameState == Memory.GameState.Game)
                        {
                            PsuedoLocs.RELOAD_SEED.Pickup().Grant();
                        }
                        FramesTillUnlockReload = 60;
                    }
                    break;

                case "lastPickup":
                    FramesTillNextSend = 1; // the only reason this isn't = 0 is that spamming this could get really annoying
                    MessageQueue.Enqueue(Last);
                    break;

                case "hintMessage":
                    HintsController.ShowHintMessage();
                    break;

                case "dev":
                    Randomizer.Dev = !Randomizer.Dev;
                    Randomizer.Log($"Dev: {Randomizer.Dev}");
                    break;

                case "exitapp":
                    Environment.Exit(Environment.ExitCode);
                    break;

                case "toggleDebug":
                    Randomizer.Memory.Debug = !Randomizer.Memory.Debug;
                    Print($"Debug {(Randomizer.Memory.Debug ? "enabled" : "disabled")}", toMessageLog: false);
                    break;

                case "toggleCursorLock":
                    Print($"Cursor Lock {(InterOp.toggle_cursorlock() ? "enabled" : "disabled")}", toMessageLog: false);
                    break;

                case "test1":
                    PsuedoLocs.BINDING_ONE.Pickup().Grant();
                    break;

                case "test2":
                    PsuedoLocs.BINDING_TWO.Pickup().Grant();
                    break;

                case "test3":
                    PsuedoLocs.BINDING_THREE.Pickup().Grant();
                    break;

                case "test4":
                    Print("magic", 180, false);
                    InterOp.magic_function();
                    break;

                case "test5":
                    tpCheatToggle = !tpCheatToggle;
                    Print($"TPCheat {(tpCheatToggle ? "enabled" : "disabled")}");
                    break;

                default:
                    Randomizer.Log($"Recieved unknown signal {signal}");
                    break;
                }
            }
            FramesTillUnlockReload = Math.Max(0, FramesTillUnlockReload - 1);
            if (FramesTillNextSend > 0)
            {
                FramesTillNextSend--;
            }
            else
            {
                if (CanPrint)
                {
                    Current            = MessageQueue.Peek();
                    FramesTillNextSend = Current.Frames;
                    try {
                        InterOp.clear_visible_hints();
                        InterOp.display_hint(InterOp.Util.getIl2cppStringPointer(Current.Text), Current.Frames / 60f);
                        if (IniFlag("LogOnPrint"))
                        {
                            Randomizer.Log($"Sending {Current.Text} for {Current.Frames} ({MessageQueue.Count} remaining in queue)", false);
                        }
                        MessageQueue.Dequeue();
                    } catch (Exception e) { Randomizer.Error("AHK.sendMsg", e, false); }
                }
                else
                {
                    Current = null;
                }
            }
        }
        public static void NewGameInit()
        {
            if (!InterOp.is_loading_game())
            {
                InterOp.clear_quest_messages();
                Randomizer.Log($"New Game Init - {SeedController.SeedName}", false);
                ShopController.SetCostsAfterInit();

                foreach (UberState s in DefaultUberStates)
                {
                    s.Write();
                }
                foreach (UberState s in Kuberstates)
                {
                    s.Write();
                }
                foreach (UberState s in DialogAndRumors)
                {
                    s.Write();
                }

                if (SeedController.KSDoorsOpen)
                {
                    foreach (UberState s in KeystoneDoors)
                    {
                        s.Write();
                    }
                }

                if (!AHK.IniFlag("ShowShortCutscenes"))
                {
                    foreach (UberState s in ShortCutscenes)
                    {
                        s.Write();
                    }
                }

                if (!AHK.IniFlag("ShowLongCutscenes"))
                {
                    foreach (UberState s in LongCutscenes)
                    {
                        s.Write();
                    }
                }

                InterOp.discover_everything();
                if (SeedController.Settings.LegacySeedgen && !SeedController.Flags.Contains(Flag.NOSWORD))
                {
                    SaveController.SetAbility(AbilityType.SpiritEdge);
                    var slotRaw = AHK.IniString("Misc", "SpawnSlot");
                    var slot    = 0;
                    if (slotRaw != string.Empty)
                    {
                        slot = slotRaw.ParseToInt("Spawn Slot Ini") - 1;
                        if (slot > 2 || slot < 0)
                        {
                            AHK.Print($"Ignoring invalid slot specifier {slotRaw}", toMessageLog: false);
                            slot = 0;
                        }
                    }
                    InterOp.bind(slot, 1002);
                }
                if (PsuedoLocs.GAME_START.Pickup().NonEmpty)
                {
                    Randomizer.InputUnlockCallback = () => {
                        MapController.UpdateReachable(2000);
                        PsuedoLocs.GAME_START.OnCollect();
                        InterOp.save();
                    };
                }
                else
                {
                    MapController.UpdateReachable();
                }
                InterOp.set_shard_slots(3);
                InterOp.save();

                NeedsNewGameInit = false;
            }
        }
示例#25
0
        public static void HandleSignal(string signal)
        {
            switch (signal)
            {
            case "reload":
                if (FramesTillUnlockReload == 0)
                {
                    iniFlagCache.Clear();
                    FramesTillNextSend = 0;
                    Randomizer.Client.Connect();
                    SeedController.ReadSeed();
                    if (InterOp.get_game_state() == GameState.Game)
                    {
                        PsuedoLocs.RELOAD_SEED.OnCollect();
                    }
                    FramesTillUnlockReload = 120;
                }
                break;

            case "lastPickup":
                FramesTillNextSend = 1; // the only reason this isn't = 0 is that spamming this could get really annoying
                MessageQueue.Enqueue(Last);
                break;

            case "progressAndHints":
                HintsController.ProgressWithHints();
                break;

            case "dev":
                Randomizer.Dev = !Randomizer.Dev;
                Randomizer.Log($"Dev: {Randomizer.Dev}");
                break;

            case "exitapp":
                Environment.Exit(Environment.ExitCode);
                break;

            case "toggleDebug":
                InterOp.set_debug_controls(!InterOp.get_debug_controls());
                Print($"Debug {(InterOp.get_debug_controls() ? "enabled" : "disabled")}", toMessageLog: false);
                break;

            case "toggleCursorLock":
                Print($"Cursor Lock {(InterOp.toggle_cursorlock() ? "enabled" : "disabled")}", toMessageLog: false);
                break;

            case "binding1":
                PsuedoLocs.BINDING_ONE.OnCollect();
                break;

            case "binding2":
                PsuedoLocs.BINDING_TWO.OnCollect();
                break;

            case "binding3":
                PsuedoLocs.BINDING_THREE.OnCollect();
                break;

            case "binding4":
                PsuedoLocs.BINDING_FOUR.OnCollect();
                break;

            case "binding5":
                PsuedoLocs.BINDING_FIVE.OnCollect();
                break;

            case "unlockSpoiers":
                if (SeedController.Settings.RaceMode)
                {
                    return;                             // no cheat
                }
                UberSet.Bool(GameComplete, true);
                Print("spoiler unlocked", toMessageLog: false);
                break;

            case "tpCheat":
                if (SeedController.Settings.RaceMode)
                {
                    return;                             // no cheat
                }
                tpCheatToggle = !tpCheatToggle;
                Print($"TPCheat {(tpCheatToggle ? "enabled" : "disabled")}", toMessageLog: false);
                break;

            case "warpCredits":
                if (UberGet.Bool(GameComplete))
                {
                    InterOp.start_credits();
                }
                else
                {
                    Print($"Credit warp not unlocked!", toMessageLog: false);
                }
                break;

            case "printCoords":
                var pos = InterOp.get_position();
                Print($"{pos.X}, {pos.Y}", toMessageLog: false);
                break;

            case "nameSpoilerToggle":
                MapController.NameLabels = !MapController.NameLabels;
                Print($"Loc name labels {(MapController.NameLabels ? "enabled" : "disabled")}", toMessageLog: false);
                break;

            case "logicprovidertoggle":
                MapController.RustLogic = !MapController.RustLogic;
                Print($"Logic Provider: {(MapController.RustLogic ? "Rust" : "Java")}", toMessageLog: false);
                MapController.UpdateReachable();
                break;

            default:
                Randomizer.Log($"Recieved unknown signal {signal}");
                break;
            }
        }
        public static void ResolveUberStateChange(UberState state, UberValue old)
        {
            try {
                UberId key = state.GetUberId();
                if (!UberStates.TryGetValue(key, out UberState oldState))
                {
                    oldState       = state.Clone();
                    oldState.Value = old;
                    UberStates.Add(key, oldState);
                }

                UberValue value = state.Value;
                if (value.Int == old.Int)
                {
                    return;
                }

                var oldValFmt = old.FmtVal(state.Type); // get this now because we overwrite the value by reference
                if (ShouldRevert(state))
                {
                    Randomizer.Log($"Reverting state change of {state.Name} from {oldValFmt} to {state.FmtVal()}", false);
                    oldState.Write();
                    return;
                }

                HandleSpecial(state);
                UberStates[key].Value = state.Value;
                var  pos   = InterOp.get_position();
                bool found = false;
                if (value.Int > 0)
                {
                    var id = state.GetUberId();
                    if (SkipUberStateMapCount.GetOrElse(key, 0) > 0)
                    {
                        var p = id.toCond().Pickup().Concat(id.toCond(state.ValueAsInt()).Pickup());
                        if (p.NonEmpty)
                        {
                            SkipUberStateMapCount[key] -= 1;
                            Randomizer.Log($"Suppressed granting {p} from {id}={state.ValueAsInt()}. Will suppress {SkipUberStateMapCount[key]} more times", false, "DEBUG");
                            return;
                        }
                    }
                    found = SeedController.OnUberState(state);
                }

                if (SyncedUberStates.Contains(key))
                {
                    Randomizer.Client.SendUpdate(key, state.ValueAsFloat());
                }

                BonusItemController.OnUberState(state);
                var zone = ZoneType.Void;
                if (InterOp.get_game_state() == GameState.Game)
                {
                    zone = InterOp.get_player_area().toZone();
                }
                if (!NeedsNewGameInit && (value.Int == 0 || !found) && !(state.GroupName == "statsUberStateGroup" || state.GroupName == "achievementsGroup" || state.GroupID == 8 || state.GroupID == 10))
                {
                    Randomizer.Debug($"State change: {state.GroupName}.{state.Name} ({state.GroupID}|{state.ID}) {state.Type} {oldValFmt}->{state.FmtVal()} at ({Math.Round(pos.X)}, {Math.Round(pos.Y)}) in {zone}");
                }
                //Randomizer.Debug($"{state.GroupName}.{state.Name}, {state.GroupID}, {state.ID}, {state.Type}, {oldValFmt}, {state.FmtVal()}, {zone}, {Math.Round(pos.X)},{Math.Round(pos.Y)}");
            }
            catch (Exception e) {
                Randomizer.Error($"USC.Update {state}", e);
            }
        }
        public static void Tick()
        {
            var signal = Engine.ExecFunction("Tick");

            if (signal != null && signal != "none")
            {
                Engine.SetVar("signal", "none");
                switch (signal)
                {
                case "reload":
                    if (FramesTillUnlockReload == 0)
                    {
                        iniFlagCache.Clear();
                        FramesTillNextSend = 0;
                        Randomizer.Client.Connect();
                        SeedController.ReadSeed();
                        if (InterOp.get_game_state() == GameState.Game)
                        {
                            PsuedoLocs.RELOAD_SEED.OnCollect();
                        }
                        FramesTillUnlockReload = 120;
                    }
                    break;

                case "lastPickup":
                    FramesTillNextSend = 1; // the only reason this isn't = 0 is that spamming this could get really annoying
                    MessageQueue.Enqueue(Last);
                    break;

                case "hintMessage":
                    HintsController.ProgressWithHints();
                    break;

                case "dev":
                    Randomizer.Dev = !Randomizer.Dev;
                    Randomizer.Log($"Dev: {Randomizer.Dev}");
                    break;

                case "exitapp":
                    Environment.Exit(Environment.ExitCode);
                    break;

                case "toggleDebug":
                    InterOp.set_debug_controls(!InterOp.get_debug_controls());
                    Print($"Debug {(InterOp.get_debug_controls() ? "enabled" : "disabled")}", toMessageLog: false);
                    break;

                case "toggleCursorLock":
                    Print($"Cursor Lock {(InterOp.toggle_cursorlock() ? "enabled" : "disabled")}", toMessageLog: false);
                    break;

                case "test1":
                    PsuedoLocs.BINDING_ONE.OnCollect();
                    break;

                case "test2":
                    PsuedoLocs.BINDING_TWO.OnCollect();
                    break;

                case "test3":
                    PsuedoLocs.BINDING_THREE.OnCollect();
                    break;

                case "test4":
                    if (SeedController.HasInternalSpoilers)
                    {
                        UberSet.Bool(34543, 11226, true);
                        Print("spoiler unlocked", toMessageLog: false);
                    }
                    break;

                case "test5":
                    tpCheatToggle = !tpCheatToggle;
                    Print($"TPCheat {(tpCheatToggle ? "enabled" : "disabled")}", toMessageLog: false);
                    break;

                case "printcoords":
                    var pos = InterOp.get_position();
                    Print($"{pos.X}, {pos.Y}", toMessageLog: false);
                    break;

                case "namespoilertoggle":
                    MapController.NameLabels = !MapController.NameLabels;
                    Print($"Loc name labels {(MapController.NameLabels ? "enabled" : "disabled")}", toMessageLog: false);
                    break;

                default:
                    Randomizer.Log($"Recieved unknown signal {signal}");
                    break;
                }
            }
            FramesTillUnlockReload = Math.Max(0, FramesTillUnlockReload - 1);
            if (FramesTillNextSend > 0)
            {
                FramesTillNextSend--;
            }
            else
            {
                if (CanPrint)
                {
                    Current            = MessageQueue.Peek();
                    FramesTillNextSend = Current.Frames;
                    try {
                        InterOp.clear_visible_hints();
                        InterOp.display_hint(Current.Text, Current.Frames / 60f, Current.Pos);
                        if (IniFlag("LogOnPrint"))
                        {
                            Randomizer.Log($"Sending {Current.Text} for {Current.Frames} ({MessageQueue.Count} remaining in queue)", false);
                        }
                        MessageQueue.Dequeue();
                    } catch (Exception e) { Randomizer.Error("AHK.sendMsg", e, false); }
                }
                else
                {
                    Current = null;
                }
            }
        }
        public static void OnKill(string name, DamageType dt)
        {
            name = name.Replace("(Clone)", "");
            var et = EnemyFromName(name);

            if (et == EnemyType.Unknown && Randomizer.Dev)
            {
                Randomizer.Log($"Unknown Enemy {name}");
            }
            UberInc.Int(10, 10); // enemies killed
            switch (et)
            {
            case EnemyType.Miner:
            case EnemyType.ShieldMiner:
                UberInc.Int(10, 40);
                break;

            case EnemyType.Skeeto:
            case EnemyType.SmallSkeeto:
            case EnemyType.Bee:
                UberInc.Int(10, 41);
                break;

            case EnemyType.Tentacle:
                UberInc.Int(10, 42);
                break;

            case EnemyType.DropSlime:
            case EnemyType.ShellSlime:
            case EnemyType.Slime:
            case EnemyType.SpikeSlime:
                UberInc.Int(10, 43);
                break;

            case EnemyType.Fish:
            case EnemyType.Waterworm:
                UberInc.Int(10, 44);
                break;

            case EnemyType.Balloon:
            case EnemyType.Baneling:
                UberInc.Int(10, 45);
                break;

            case EnemyType.Scourge: // is both a flier and explosive
                UberInc.Int(10, 41);
                UberInc.Int(10, 45);
                break;

            case EnemyType.BombSlime: // is both a slime and explosive
                UberInc.Int(10, 43);
                UberInc.Int(10, 45);
                break;

            default:
                break;
            }
            switch (dt)
            {
            case DamageType.Sword:
                UberInc.Int(10, 11);
                break;

            case DamageType.Hammer:
                UberInc.Int(10, 12);
                break;

            case DamageType.Bow:
                UberInc.Int(10, 13);
                break;

            case DamageType.SpiritSpear:
                UberInc.Int(10, 14);
                break;

            case DamageType.SpiritSentry:
                UberInc.Int(10, 15);
                break;

            case DamageType.Blaze:
                UberInc.Int(10, 16);
                break;

            case DamageType.Grenade:
                UberInc.Int(10, 17);
                break;

            case DamageType.Heat:
                UberInc.Int(10, 18);
                break;

            case DamageType.Chakram:
                UberInc.Int(10, 19);
                break;

            case DamageType.ChargeJump:
                UberInc.Int(10, 20);
                break;

            case DamageType.Glow:
                UberInc.Int(10, 21);
                break;

            case DamageType.Projectile:
                UberInc.Int(10, 22);
                break;

            case DamageType.Water:
                UberInc.Int(10, 23);
                break;

            default:
                break;
            }
        }