Beispiel #1
0
    def ShowConfiguration(self) -> None:
        custom_button = OptionBoxButton("- Custom Mod Name -")
        mod_buttons = [OptionBoxButton(mod.Name) for mod in GetOrderedModList()] + [custom_button]

        mod_box = OptionBox(
            Title="Select SDK Mod",
            Caption="Select the mod to enable.",
            Buttons=mod_buttons
        )

        custom_box = TextInputBox("Custom Mod Name", self.ModName)

        def OnModPick(button: OptionBoxButton) -> None:
            if button == custom_button:
                custom_box.Show()
            else:
                self.ModName = button.Name
                self.OnFinishConfiguration()

        def OnCustomSubmit(msg: str) -> None:
            if len(msg) != 0:
                self.ModName = msg
                self.OnFinishConfiguration()
            else:
                mod_box.Show(custom_button)

        mod_box.OnPress = OnModPick  # type:ignore
        mod_box.OnCancel = self.OnFinishConfiguration  # type: ignore
        custom_box.OnSubmit = OnCustomSubmit  # type: ignore

        mod_box.Show()
Beispiel #2
0
    def ShowConfiguration(self) -> None:
        mod_button = OptionBoxButton("Mod", f"Currently: '{self.ModName}'")
        input_button = OptionBoxButton("Input", f"Currently: '{self.Input}'")
        custom_button = OptionBoxButton("- Custom Mod Name -")
        mod_buttons = [
            OptionBoxButton(mod.Name) for mod in GetOrderedModList()
        ] + [custom_button]

        main_box = OptionBox(
            Title="Configure SDK Mod Input",
            Caption="Select which part you want to configure.",
            Buttons=(mod_button, input_button))

        mod_box = OptionBox(Title="Select SDK Mod",
                            Caption="Select which mod to send inputs to.",
                            Buttons=mod_buttons)

        custom_box = TextInputBox("Custom Mod Name", self.ModName)

        input_box = TrainingBox("Set Input", "Press any key to set the input.")

        def OnMainPress(button: OptionBoxButton) -> None:
            if button == mod_button:
                mod_box.Show()
            elif button == input_button:
                input_box.Show()

        def OnModPick(button: OptionBoxButton) -> None:
            if button == custom_button:
                custom_box.Show()
            else:
                self.ModName = button.Name
                mod_button.Tip = f"Currently: '{self.ModName}'"
                main_box.Show(mod_button)

        def OnCustomSubmit(msg: str) -> None:
            if len(msg) != 0:
                self.ModName = msg
                mod_button.Tip = f"Currently: '{self.ModName}'"
                main_box.Show(mod_button)
            else:
                mod_box.Show(custom_button)

        def OnInput(key: str, event: int) -> None:
            if event != 1:
                return
            self.Input = key
            input_button.Tip = f"Currently: '{self.Input}''"
            if input_box.IsShowing():
                input_box.Hide()
            main_box.Show(input_button)

        main_box.OnPress = OnMainPress  # type: ignore
        main_box.OnCancel = self.OnFinishConfiguration  # type: ignore
        mod_box.OnPress = OnModPick  # type:ignore
        mod_box.OnCancel = lambda: mod_button.Show()  # type: ignore
        custom_box.OnSubmit = OnCustomSubmit  # type: ignore
        input_box.OnInput = OnInput  # type: ignore

        main_box.Show()
Beispiel #3
0
    def ShowConfiguration(self) -> None:
        plus_one = OptionBoxButton("+1")
        plus_tenth = OptionBoxButton("+0.1")
        minus_tenth = OptionBoxButton("-0.1")
        minus_one = OptionBoxButton("-1")
        direct_edit = OptionBoxButton("Direct Edit")

        main_box = OptionBox(
            Title="Configure Delay",
            Caption=f"Current Delay: {self.Delay:.02f}s",
            Tooltip=OptionBox.CreateTooltipString(EscMessage="Back"),
            Buttons=(plus_one, plus_tenth, minus_tenth, minus_one,
                     direct_edit))
        direct_box = TextInputBox("Configure Delay", f"{self.Delay:.02f}")

        def OnMainBoxPress(button: OptionBoxButton) -> None:
            if button == direct_edit:
                direct_box.Show()
                return

            if button == plus_one:
                self.Delay += 1
            elif button == plus_tenth:
                self.Delay += 0.1
            elif button == minus_tenth:
                self.Delay = max(self.Delay - 0.1, 0)
            elif button == minus_one:
                self.Delay = max(self.Delay - 1, 0)
            direct_box.DefaultMessage = f"{self.Delay:.02f}"
            main_box.Caption = f"Current Delay: {self.Delay:.02f}s"
            main_box.Update()
            main_box.Show(button)

        main_box.OnPress = OnMainBoxPress  # type: ignore
        main_box.OnCancel = self.OnFinishConfiguration  # type: ignore

        def WriteFloatFilter(char: str, message: str, pos: int) -> bool:
            if char in "0123456789":
                return True
            if char == ".":
                return "." not in message
            return False

        def OnDirectBoxSubmit(msg: str) -> None:
            if msg != "":
                self.Delay = round(float(msg), 2)
                main_box.Caption = f"Current Delay: {self.Delay:.02f}s"
            main_box.Update()
            main_box.Show()

        direct_box.IsAllowedToWrite = WriteFloatFilter  # type: ignore
        direct_box.OnSubmit = OnDirectBoxSubmit  # type: ignore

        main_box.Show()
Beispiel #4
0
    def GenerateToken(self) -> None:
        continue_button = OptionBoxButton("Continue")
        yes_button = OptionBoxButton("Yes")
        no_button = OptionBoxButton("No")
        intro_box = OptionBox(
            Title="Generate OAuth Token",
            Caption=(
                "If you're currently streaming, switch to an intermission screen.\n\n"
                "When you contine, a file and a website will open."
                " Login with Twitch, then copy the displayed token into the file."
                " You will be asked to confirm the token in game."
            ),
            Buttons=(continue_button,)
        )
        continue_box = OptionBox(
            Title="Generate OAuth Token",
            Caption="Continue once you've pasted the token into the file.",
            Buttons=(continue_button,)
        )
        confirm_box = OptionBox(
            Title="Generate OAuth Token",
            Caption="Is this the correct token:\n\n''",
            Buttons=(yes_button, no_button)
        )

        def ReloadToken() -> None:
            self.Token = open(self.TOKEN_FILE).read().strip()

        def OnStart(button: OptionBoxButton) -> None:
            startfile(self.TOKEN_FILE)
            webbrowser.open(self.TOKEN_URL)
            continue_box.Show()

        def OnContinue(button: OptionBoxButton) -> None:
            ReloadToken()
            confirm_box.Caption = f"Is this the correct token:\n\n'{self.Token}'"
            confirm_box.Update()
            confirm_box.Show()

        def OnConfirm(button: OptionBoxButton) -> None:
            if button == no_button:
                continue_box.Show()

        intro_box.OnCancel = ReloadToken  # type: ignore
        continue_box.OnCancel = ReloadToken  # type: ignore
        confirm_box.OnCancel = ReloadToken  # type: ignore

        intro_box.OnPress = OnStart  # type: ignore
        continue_box.OnPress = OnContinue  # type: ignore
        confirm_box.OnPress = OnConfirm  # type: ignore

        intro_box.Show()
Beispiel #5
0
    def Configure(self) -> None:
        toggleEnabledButton = OptionBoxButton("Toggle Enabled")
        editTriggerButton = OptionBoxButton(
            "Edit Trigger",
            "Edits what redemption title triggers this effect. Not case sensitive, but must match exactly otherwise."
        )
        extraConfigurationButton = OptionBoxButton(
            "Extra Options", "Adjust extra, effect specific options.")

        def GetCaptionStr(trig: CrowdControl._Trigger) -> str:
            caption = ""
            if trig.IsEnabled:
                caption = f"Enabled: '{trig.Trigger}'"
            else:
                caption = "Disabled"
            caption += "\n" + trig.Effect.Description
            return caption

        class _EffectButton(OptionBoxButton):
            TrigObj: CrowdControl._Trigger

            def __init__(self, trig: CrowdControl._Trigger) -> None:
                self.TrigObj = trig

            @property
            def Name(self) -> str:  # type: ignore
                return f"{self.TrigObj.Effect.Name}   -   {GetCaptionStr(self.TrigObj)}"

        effectButtons = [_EffectButton(trig) for trig in self.Triggers]
        currentButton = effectButtons[0]

        selectBox = OptionBox(Title="Configure Effects",
                              Caption="Select the effect to configure.",
                              Buttons=effectButtons,
                              Tooltip=OptionBox.CreateTooltipString() +
                              "     " + "[R] Reset All")
        editBox = OptionBox(Title="Configure <effect>",
                            Caption="Enabled\n<description>",
                            Buttons=(toggleEnabledButton, editTriggerButton,
                                     extraConfigurationButton))
        renameBox = TextInputBox(Title="Configure <effect>")

        def UpdateEditBox() -> None:
            editBox.Title = f"Configure {currentButton.TrigObj.Effect.Name}"
            if currentButton.TrigObj.IsEnabled:
                editBox.Caption = f"Enabled: '{currentButton.TrigObj.Trigger}'"
            else:
                editBox.Caption = "Disabled"
            editBox.Caption += "\n" + currentButton.TrigObj.Effect.Description

            if currentButton.TrigObj.Effect.HasConfigMenu:
                editBox.Buttons = [
                    toggleEnabledButton, editTriggerButton,
                    extraConfigurationButton
                ]
            else:
                editBox.Buttons = [toggleEnabledButton, editTriggerButton]

            editBox.Update()

        def OnSelect(button: _EffectButton) -> None:
            nonlocal currentButton
            currentButton = button
            UpdateEditBox()
            editBox.Show()

        def OnEdit(button: OptionBoxButton) -> None:
            if button == toggleEnabledButton:
                currentButton.TrigObj.IsEnabled = not currentButton.TrigObj.IsEnabled
                for option in currentButton.TrigObj.Effect.Options:
                    option.IsHidden = not currentButton.TrigObj.IsEnabled
                UpdateEditBox()
                editBox.Show()
            elif button == editTriggerButton:
                renameBox.Title = editBox.Title
                renameBox.DefaultMessage = currentButton.TrigObj.Trigger
                renameBox.Show()
            elif button == extraConfigurationButton:
                currentButton.TrigObj.Effect.FinishConfiguration = editBox.Show  # type: ignore
                currentButton.TrigObj.Effect.ShowConfiguration()

        def OnRename(msg: str) -> None:
            if len(msg) > 0:
                currentButton.TrigObj.Trigger = msg
            UpdateEditBox()
            editBox.Show()

        oldSelectInput = selectBox.OnInput

        def OnSelectInput(key: str, event: int) -> None:
            if key == "R" and event == 1:
                for trig in self.Triggers:
                    trig.IsEnabled = True
                    trig.Trigger = trig.Effect.Name
                    for option in trig.Effect.Options:
                        option.IsHidden = False
                UpdateEditBox()
                selectBox.Hide()
                selectBox.Show()
            else:
                oldSelectInput(key, event)

        selectBox.OnPress = OnSelect  # type: ignore
        selectBox.OnCancel = self.SaveTriggers  # type: ignore
        selectBox.OnInput = OnSelectInput  # type:ignore
        editBox.OnPress = OnEdit  # type: ignore
        editBox.OnCancel = lambda: selectBox.ShowButton(currentButton
                                                        )  # type: ignore
        renameBox.OnSubmit = OnRename  # type: ignore
        selectBox.Show()
Beispiel #6
0
class PresetManager:
    Option: Options.Hidden
    PresetList: List[Preset]
    CheatList: List[ABCCheat]

    _NewPreset: ClassVar[OptionBoxButton] = OptionBoxButton(
        "Create New Preset")
    _OpenPresetFile: ClassVar[OptionBoxButton] = OptionBoxButton(
        "Open Settings File",
        ("Useful for reordering or sharing presets."
         " The game will have to be restarted for changes to apply."))
    _EditPreset: ClassVar[OptionBoxButton] = OptionBoxButton("Configure")
    _RenamePreset: ClassVar[OptionBoxButton] = OptionBoxButton("Rename")
    _DeletePreset: ClassVar[OptionBoxButton] = OptionBoxButton("Delete")
    _Yes: ClassVar[OptionBoxButton] = OptionBoxButton("Yes")
    _No: ClassVar[OptionBoxButton] = OptionBoxButton("No")

    _ConfigureBox: OptionBox
    _ButtonPresetMap: Dict[str, Preset]

    _CurrentPreset: Optional[Preset]
    _PresetActionBox: OptionBox
    _ConfirmDeleteBox: OptionBox

    _RenameBox: TextInputBox

    def __init__(self, Option: Options.Hidden, CheatList: List[ABCCheat]):
        self.Option = Option
        self.CheatList = CheatList

        # Move legacy presets into the option
        legacy_path = os.path.join(os.path.dirname(__file__), "Presets.json")
        try:
            loaded_data = []
            with open(legacy_path) as file:
                loaded_data = json.load(file)
            os.remove(legacy_path)
            self.Option.CurrentValue = loaded_data
        except (FileNotFoundError, json.JSONDecodeError):
            pass

        self.LoadPresets()

        self._ConfigureBox = OptionBox(
            Title="Configure Presets",
            Caption="Select the preset you want to configure",
            Tooltip=OptionBox.CreateTooltipString(EscMessage="Exit"),
            Buttons=(
                self._NewPreset,
                self._OpenPresetFile,
            ),
        )
        self._ConfigureBox.OnPress = self._SelectSpecificPreset  # type: ignore
        self._UpdateConfigureBox()

        self._CurrentPreset = None

        # These two dialog boxes are mostly the constant, we'll just update their title as needed
        self._PresetActionBox = OptionBox(
            Title="Selected 'PRESET NAME'",
            Caption="Select the action to perform on this preset",
            Tooltip=OptionBox.CreateTooltipString(EscMessage="Back"),
            Buttons=(self._EditPreset, self._RenamePreset, self._DeletePreset),
        )
        self._PresetActionBox.OnPress = self._SelectPresetAction  # type: ignore
        self._PresetActionBox.OnCancel = self.StartConfiguring  # type: ignore

        self._ConfirmDeleteBox = OptionBox(
            Title="Delete 'PRESET NAME'",
            Caption="Are you sure you want to delete this preset?",
            Tooltip=OptionBox.CreateTooltipString(EscMessage="Back"),
            Buttons=(self._No, self._Yes),
        )
        self._ConfirmDeleteBox.OnPress = self._OnConfirmDelete  # type: ignore
        self._ConfirmDeleteBox.OnCancel = lambda: self._OnConfirmDelete(
            None)  # type: ignore

        self._RenameBox = TextInputBox("Rename 'PRESET NAME'")
        self._RenameBox.OnSubmit = self._OnPresetRename  # type: ignore

    def LoadPresets(self) -> None:
        self.PresetList = []
        for idx, current_dict in enumerate(self.Option.CurrentValue):
            name: str = f"Preset {idx}"
            settings: Dict[str, str] = {}

            if "Name" in current_dict:
                name = html.escape(str(current_dict["Name"]))

            if "Settings" in current_dict and isinstance(
                    current_dict["Settings"], dict):
                settings = current_dict["Settings"]
                # Sanity-check the data
                for cheat in self.CheatList:
                    if cheat.Name in settings:
                        value = settings[cheat.Name]
                        # We don't really care what this value is for regular cheats, but better to
                        #  keep it consistent
                        if not isinstance(cheat, ABCCycleableCheat):
                            value = "Run"
                        settings[cheat.Name] = value

            current_preset = Preset(name, settings, self.CheatList)
            current_preset.OnFinishConfiguring = self._OnFinishConfiguringPreset  # type: ignore
            self.PresetList.append(current_preset)

        # If there are no valid presets then still add the first one
        if len(self.PresetList) == 0:
            new_preset = Preset("Preset 1", {}, self.CheatList)
            new_preset.OnFinishConfiguring = self._OnFinishConfiguringPreset  # type: ignore
            self.PresetList.append(new_preset)

    def SavePresets(self) -> None:
        data = []
        for preset in self.PresetList:
            data.append({
                "Name": html.unescape(preset.Name),
                "Settings": preset.GetSettings()
            })

        self.Option.CurrentValue = data
        self.SaveOptions()

    def StartConfiguring(self) -> None:
        self._UpdateConfigureBox()
        self._ConfigureBox.Show()

    # The next four functions should be overwritten by the main mod
    def AddKeybind(self, Name: str) -> None:
        raise NotImplementedError

    def RenameKeybind(self, OldName: str, NewName: str) -> None:
        raise NotImplementedError

    def RemoveKeybind(self, Name: str) -> None:
        raise NotImplementedError

    def SaveOptions(self) -> None:
        raise NotImplementedError

    def _OnFinishConfiguringPreset(self) -> None:
        self.SavePresets()
        self.StartConfiguring()

    def _UpdateConfigureBox(self) -> None:
        button_list = []
        self._ButtonPresetMap = {}
        for preset in self.PresetList:
            button = OptionBoxButton(html.unescape(preset.Name))
            button_list.append(button)
            self._ButtonPresetMap[button.Name] = preset

        button_list += [
            self._NewPreset,
            self._OpenPresetFile,
        ]

        self._ConfigureBox.Buttons = button_list
        self._ConfigureBox.Update()

    def _SelectSpecificPreset(self, button: OptionBoxButton) -> None:
        if button == self._NewPreset:
            # Get a new default name that's at least the size of the list + 1, or the largest
            #  existing default name + 1
            # This makes renaming or deleting cheats still add a somewhat logical name
            max_val = len(self.PresetList)
            for preset in self.PresetList:
                val: int
                try:
                    val = int(preset.Name.split(" ")[-1])
                except ValueError:
                    continue
                if val > max_val:
                    max_val = val
            name = f"Preset {max_val + 1}"

            new_preset = Preset(name, {}, self.CheatList)
            new_preset.OnFinishConfiguring = self._OnFinishConfiguringPreset  # type: ignore
            self.PresetList.append(new_preset)

            self.AddKeybind(name)

            self.SavePresets()
        elif button == self._OpenPresetFile:
            settings_path = os.path.join(os.path.dirname(__file__),
                                         "settings.json")
            os.startfile(settings_path)

        if button.Name in self._ButtonPresetMap:
            self._CurrentPreset = self._ButtonPresetMap[button.Name]
            self._PresetActionBox.Title = f"Selected '{self._CurrentPreset.Name}'"
            self._PresetActionBox.Update()
            self._PresetActionBox.Show()
            return

        self.StartConfiguring()

    def _SelectPresetAction(self, button: OptionBoxButton) -> None:
        if self._CurrentPreset is None:
            raise RuntimeError("Current Preset is None")
        if button == self._EditPreset:
            self._CurrentPreset.StartConfiguring()
            self._CurrentPreset = None
        elif button == self._RenamePreset:
            self._RenameBox.Title = f"Rename '{self._CurrentPreset.Name}'"
            self._RenameBox.DefaultMessage = self._CurrentPreset.Name
            self._RenameBox.Show()
        elif button == self._DeletePreset:
            self._ConfirmDeleteBox.Title = f"Delete '{self._CurrentPreset.Name}'"
            self._ConfirmDeleteBox.Update()
            self._ConfirmDeleteBox.Show()

    def _OnPresetRename(self, msg: str) -> None:
        if self._CurrentPreset is None:
            raise RuntimeError("Current Preset is None")

        if len(msg) > 0:
            self.RenameKeybind(self._CurrentPreset.Name, msg)

            self._ButtonPresetMap[msg] = self._ButtonPresetMap[
                self._CurrentPreset.Name]
            del self._ButtonPresetMap[self._CurrentPreset.Name]

            self._CurrentPreset.UpdateName(msg)
            self.SavePresets()
            self._UpdateConfigureBox()

        self._PresetActionBox.Title = f"Selected '{self._CurrentPreset.Name}'"
        self._PresetActionBox.Update()
        self._PresetActionBox.Show(self._RenamePreset)

    def _OnConfirmDelete(self, button: Optional[OptionBoxButton]) -> None:
        if self._CurrentPreset is None:
            raise RuntimeError("Current Preset is None")
        if button == self._Yes:
            self.PresetList.remove(self._CurrentPreset)
            self.RemoveKeybind(self._CurrentPreset.Name)
            self._CurrentPreset = None
            self.SavePresets()
            self.StartConfiguring()
        else:
            self._PresetActionBox.Show()
Beispiel #7
0
class Preset:
    Name: str
    IsBeingConfigured: bool
    CheatList: List[ABCCheat]

    _NewSettings: Dict[str, str]
    _OldSettings: Dict[str, str]

    _SelectedCheat: Optional[ABCCheat]
    _ConfigureBox: OptionBox
    _SaveBox: OptionBox
    _CheatConfigureBoxes: Dict[str, OptionBox]

    _SaveButton: ClassVar[OptionBoxButton] = OptionBoxButton("Save")
    _DiscardButton: ClassVar[OptionBoxButton] = OptionBoxButton("Discard")
    _DontRunButton: ClassVar[OptionBoxButton] = OptionBoxButton("Ignore")
    _RunButton: ClassVar[OptionBoxButton] = OptionBoxButton("Run")
    _IgnoreButton: ClassVar[OptionBoxButton] = OptionBoxButton(
        "Ignore", "Do not change this cheat's state.")

    def __init__(self, Name: str, Settings: Dict[str, str],
                 CheatList: List[ABCCheat]) -> None:
        self.Name = Name
        self.IsBeingConfigured = False
        self.CheatList = CheatList

        self._NewSettings = Settings
        self._OldSettings = dict(Settings)
        self._SelectedCheat = None

        self._SaveBox = OptionBox(
            Title=f"Save '{self.Name}'",
            Caption="Do you want to save your changes?",
            Tooltip=OptionBox.CreateTooltipString(EscMessage="Back"),
            Buttons=(
                self._SaveButton,
                self._DiscardButton,
            ),
        )
        self._SaveBox.OnPress = self._FinishConfiguring  # type: ignore
        self._SaveBox.OnCancel = lambda: self._ConfigureBox.Show(
        )  # type: ignore

        self._CheatConfigureBoxes = {}
        cheat_buttons: List[OptionBoxButton] = []
        for cheat in self.CheatList:
            tip: str
            box: OptionBox
            if not isinstance(cheat, ABCCycleableCheat):
                tip = "Currently: Ignore"
                if cheat.Name in self._NewSettings:
                    tip = "Currently: Run"

                box = OptionBox(
                    Title=f"Configure '{cheat.Name}'",
                    Caption=
                    ("Select if this cheat should be run or ignored when you press this preset's"
                     " keybind."),
                    Tooltip=OptionBox.CreateTooltipString(EscMessage="Back"),
                    Buttons=(
                        self._RunButton,
                        self._DontRunButton,
                    ),
                )
            else:
                tip = "Currently: Ignore"
                if cheat.Name in self._NewSettings:
                    tip = f"Currently: {self._NewSettings[cheat.Name]}"

                cheat_options: List[OptionBoxButton] = []
                for option in cheat.AllValues:
                    cheat_options.append(OptionBoxButton(option))
                cheat_options.append(self._IgnoreButton)

                box = OptionBox(
                    Title=f"Configure '{cheat.Name}'",
                    Caption=
                    ("Select the value that this cheat should be set to when you press this"
                     " preset's keybind."),
                    Tooltip=OptionBox.CreateTooltipString(EscMessage="Back"),
                    Buttons=cheat_options,
                )

            box.OnPress = self._ChangeCheatValue  # type: ignore
            box.OnCancel = lambda: self._ConfigureBox.Show()  # type: ignore

            button = OptionBoxButton(cheat.Name, tip)
            self._CheatConfigureBoxes[cheat.Name] = box
            cheat_buttons.append(button)

        self._ConfigureBox = OptionBox(
            Title=f"Configure '{self.Name}'",
            Caption="Choose a specific cheat to configure.",
            Tooltip=OptionBox.CreateTooltipString(EscMessage="Back"),
            Buttons=cheat_buttons,
        )
        self._ConfigureBox.OnPress = self._SelectSpecificCheat  # type: ignore
        self._ConfigureBox.OnCancel = lambda: self._SaveBox.Show(
        )  # type: ignore

    def UpdateName(self, Name: str) -> None:
        self.Name = Name
        self._SaveBox.Title = f"Save '{self.Name}'"
        self._SaveBox.Update()
        self._ConfigureBox.Title = f"Configure '{self.Name}'"
        self._ConfigureBox.Update()

    # Callback that should be overwritten
    def OnFinishConfiguring(self) -> None:
        raise NotImplementedError

    def GetSettings(self) -> Dict[str, str]:
        if self.IsBeingConfigured:
            return dict(self._OldSettings)

        return dict(self._NewSettings)

    def ApplySettings(self) -> None:
        settings = self.GetSettings()
        message = ""
        for cheat in self.CheatList:
            if cheat.Name in settings:
                if isinstance(cheat, ABCCycleableCheat):
                    cheat.CurrentValue = settings[cheat.Name]
                    cheat.OnCycle()
                    message += f"{cheat.Name}: {cheat.CurrentValue}\n"
                else:
                    cheat.OnPress()
                    message += f"Executed '{cheat.Name}'\n"

        ShowHUDMessage(self.Name, message[:-1], 5)

    def StartConfiguring(self) -> None:
        if self.IsBeingConfigured:
            raise RuntimeError(
                "Tried to re-configure a preset that is currently being configured"
            )
        self.IsBeingConfigured = True

        for idx, button in enumerate(self._ConfigureBox.Buttons):
            new_tip = "Currently: Ignore"
            if button.Name in self._NewSettings:
                new_tip = f"Currently: {self._NewSettings[button.Name]}"
            button.Tip = new_tip

        self._ConfigureBox.Show()

    def _FinishConfiguring(self, button: OptionBoxButton) -> None:
        if button == self._SaveButton:
            self._OldSettings = dict(self._NewSettings)
        elif button == self._DiscardButton:
            self._NewSettings = dict(self._OldSettings)

        self.IsBeingConfigured = False
        self.OnFinishConfiguring()

    def _SelectSpecificCheat(self, button: OptionBoxButton) -> None:
        for cheat in self.CheatList:
            if cheat.Name == button.Name:
                self._SelectedCheat = cheat
                break
        else:
            raise RuntimeError(
                "Could not find cheat associated with the button just pressed")
        self._CheatConfigureBoxes[button.Name].Show()

    def _ChangeCheatValue(self, button: OptionBoxButton) -> None:
        if self._SelectedCheat is None:
            raise RuntimeError("Selected cheat is None")

        current_cheat_button: OptionBoxButton
        for cheat_button in self._ConfigureBox.Buttons:
            if cheat_button.Name == self._SelectedCheat.Name:
                current_cheat_button = cheat_button
                break
        else:
            raise RuntimeError(
                "Could not find the button associated with the cheat just edited"
            )

        new_tip = f"Currently: {button.Name}"

        if button == self._IgnoreButton or button == self._DontRunButton:
            if self._SelectedCheat.Name in self._NewSettings:
                del self._NewSettings[self._SelectedCheat.Name]
            new_tip = "Currently: Ignore"
        else:
            self._NewSettings[self._SelectedCheat.Name] = button.Name

        current_cheat_button.Tip = new_tip

        self._SelectedCheat = None
        self._ConfigureBox.Update()
        self._ConfigureBox.Show()