diff --git a/CHANGES b/CHANGES index 7d0ced346..54b89d79b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,7 @@ 0.10.0: (Future) Features: - Tool for converting scanned pictures of e-Reader cards to raw dotcode data + - Cheat code support in homebrew ports Misc: - Qt: Rearrange menus some diff --git a/src/feature/CMakeLists.txt b/src/feature/CMakeLists.txt index e92064d2b..f07dae66c 100644 --- a/src/feature/CMakeLists.txt +++ b/src/feature/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCE_FILES video-logger.c) set(GUI_FILES + gui/cheats.c gui/gui-config.c gui/gui-runner.c gui/remap.c) diff --git a/src/feature/gui/cheats.c b/src/feature/gui/cheats.c new file mode 100644 index 000000000..d69d3ddc3 --- /dev/null +++ b/src/feature/gui/cheats.c @@ -0,0 +1,158 @@ +/* Copyright (c) 2013-2021 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "gui-config.h" + +#include +#include +#include "feature/gui/gui-runner.h" +#include + +enum mGUICheatAction { + CHEAT_ADD_LINE = 1, + CHEAT_RENAME, + CHEAT_DELETE, +}; + +static const char* const offOn[] = { "Off", "On" }; + +static void mGUIShowCheatSet(struct mGUIRunner* runner, struct mCheatDevice* device, struct mCheatSet* set) { + char cheatName[64]; + snprintf(cheatName, sizeof(cheatName), "Edit cheat: %s", set->name); + struct GUIMenu menu = { + .title = cheatName, + .index = 0, + .background = &runner->background.d + }; + GUIMenuItemListInit(&menu.items, 0); + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Enable", + .state = set->enabled, + .validStates = offOn, + .nStates = 2 + }; + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Add line", + .data = (void*) CHEAT_ADD_LINE, + }; + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Rename", + .data = (void*) CHEAT_RENAME, + }; + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Delete", + .data = (void*) CHEAT_DELETE, + }; + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Back", + .data = 0, + }; + + while (true) { + struct GUIKeyboardParams keyboard; + GUIKeyboardParamsInit(&keyboard); + struct GUIMenuItem* item; + enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &menu, &item); + set->enabled = GUIMenuItemListGetPointer(&menu.items, 0)->state; + if (reason != GUI_MENU_EXIT_ACCEPT || !item->data) { + break; + } + + enum mGUICheatAction action = (enum mGUICheatAction) item->data; + switch (action) { + case CHEAT_ADD_LINE: + strlcpy(keyboard.title, "Add line", sizeof(keyboard.title)); + keyboard.maxLen = 12; + if (runner->params.getText(&keyboard) == GUI_KEYBOARD_DONE) { + mCheatAddLine(set, keyboard.result, 0); + } + break; + case CHEAT_RENAME: + strlcpy(keyboard.title, "Rename cheat", sizeof(keyboard.title)); + strlcpy(keyboard.result, set->name, sizeof(keyboard.result)); + keyboard.maxLen = 50; + if (runner->params.getText(&keyboard) == GUI_KEYBOARD_DONE) { + mCheatSetRename(set, keyboard.result); + snprintf(cheatName, sizeof(cheatName), "Edit cheat: %s", set->name); + } + break; + case CHEAT_DELETE: + mCheatRemoveSet(device, set); + break; + } + + if (action == CHEAT_DELETE) { + break; + } + } + GUIMenuItemListDeinit(&menu.items); +} + +void mGUIShowCheats(struct mGUIRunner* runner) { + struct mCheatDevice* device = runner->core->cheatDevice(runner->core); + if (!device) { + return; + } + struct GUIMenu menu = { + .title = "Cheats", + .index = 0, + .background = &runner->background.d + }; + GUIMenuItemListInit(&menu.items, 0); + + while (true) { + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct mCheatSet* set = *mCheatSetsGetPointer(&device->cheats, i); + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = set->name, + .data = set, + .state = set->enabled, + .validStates = offOn, + .nStates = 2 + }; + } + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Add new cheat set", + .data = 0, + }; + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Back", + .data = (void*) -1, + }; + + struct GUIMenuItem* item; + enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &menu, &item); + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct mCheatSet* set = *mCheatSetsGetPointer(&device->cheats, i); + struct GUIMenuItem* item = GUIMenuItemListGetPointer(&menu.items, i); + set->enabled = item->state; + } + + if (reason != GUI_MENU_EXIT_ACCEPT || item->data == (void*) -1) { + break; + } + struct mCheatSet* set = NULL; + if (!item->data) { + struct GUIKeyboardParams keyboard; + GUIKeyboardParamsInit(&keyboard); + keyboard.maxLen = 50; + strlcpy(keyboard.title, "Cheat name", sizeof(keyboard.title)); + strlcpy(keyboard.result, "New cheat", sizeof(keyboard.result)); + if (runner->params.getText(&keyboard) == GUI_KEYBOARD_DONE) { + set = device->createSet(device, keyboard.result); + mCheatAddSet(device, set); + } + } else { + set = item->data; + } + if (set) { + mGUIShowCheatSet(runner, device, set); + } + GUIMenuItemListClear(&menu.items); + } + GUIMenuItemListDeinit(&menu.items); + mCheatAutosave(device); +} diff --git a/src/feature/gui/cheats.h b/src/feature/gui/cheats.h new file mode 100644 index 000000000..33374e253 --- /dev/null +++ b/src/feature/gui/cheats.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2013-2021 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_CHEATS_H +#define GUI_CHEATS_H + +#include + +CXX_GUARD_START + +struct mGUIRunner; +void mGUIShowCheats(struct mGUIRunner* runner); + +CXX_GUARD_END + +#endif diff --git a/src/feature/gui/gui-runner.c b/src/feature/gui/gui-runner.c index 302e21b28..b27fe49dc 100644 --- a/src/feature/gui/gui-runner.c +++ b/src/feature/gui/gui-runner.c @@ -8,6 +8,7 @@ #include #include #include "feature/gui/gui-config.h" +#include "feature/gui/cheats.h" #include #include #include @@ -35,6 +36,7 @@ enum { RUNNER_SCREENSHOT, RUNNER_CONFIG, RUNNER_RESET, + RUNNER_CHEATS, RUNNER_COMMAND_MASK = 0xFFFF }; @@ -333,7 +335,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { }; GUIMenuItemListInit(&pauseMenu.items, 0); GUIMenuItemListInit(&stateSaveMenu.items, 9); - GUIMenuItemListInit(&stateLoadMenu.items, 9); + GUIMenuItemListInit(&stateLoadMenu.items, 10); *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Unpause", .data = (void*) RUNNER_CONTINUE }; *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .submenu = &stateSaveMenu }; *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .submenu = &stateLoadMenu }; @@ -360,6 +362,9 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(9)) }; *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Take screenshot", .data = (void*) RUNNER_SCREENSHOT }; + if (runner->params.getText) { + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Cheats", .data = (void*) RUNNER_CHEATS }; + } *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Configure", .data = (void*) RUNNER_CONFIG }; *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Reset game", .data = (void*) RUNNER_RESET }; *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT }; @@ -616,6 +621,9 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { case RUNNER_CONFIG: mGUIShowConfig(runner, runner->configExtra, runner->nConfigExtra); break; + case RUNNER_CHEATS: + mGUIShowCheats(runner); + break; case RUNNER_CONTINUE: break; }