diff --git a/cheats.cpp b/cheats.cpp index 26ed2d18d..49df7b071 100644 --- a/cheats.cpp +++ b/cheats.cpp @@ -459,6 +459,28 @@ void cheats_toggle() } } +const char *cheats_get_name(int idx) +{ + if (idx < 0 || idx >= cheats_available()) return NULL; + return cheats[idx].name; +} + +bool cheats_get_enabled(int idx) +{ + if (idx < 0 || idx >= cheats_available()) return false; + return cheats[idx].enabled; +} + +int cheats_get_selected() +{ + return iSelectedEntry; +} + +void cheats_set_selected(int idx) +{ + if (idx >= 0 && idx < cheats_available()) iSelectedEntry = idx; +} + int cheats_loaded() { return loaded; diff --git a/cheats.h b/cheats.h index 040457731..32f6b892f 100644 --- a/cheats.h +++ b/cheats.h @@ -1,6 +1,9 @@ #ifndef CHEATS_H #define CHEATS_H +#include +#include + void cheats_init(const char *rom_path, uint32_t romcrc); int cheats_available(); void cheats_scan(int mode); @@ -9,6 +12,11 @@ void cheats_print(); void cheats_toggle(); int cheats_loaded(); +const char *cheats_get_name(int idx); +bool cheats_get_enabled(int idx); +int cheats_get_selected(); +void cheats_set_selected(int idx); + void cheats_init_arcade(int unit_size, int max_active); void cheats_add_arcade(const char *name, const char *cheatData, int cheatSize); void cheats_finalize_arcade(); diff --git a/input.cpp b/input.cpp index 18a43cbb1..1f380e391 100644 --- a/input.cpp +++ b/input.cpp @@ -36,6 +36,7 @@ #include "frame_timer.h" #include "scaler.h" #include "file_io.h" +#include "support/zaparoo/cheat_cmd.h" #include "support/zaparoo/alt_launcher.h" #define NUMDEV 30 @@ -6238,6 +6239,7 @@ int input_test(int getchar) printf("MiSTer_cmd: %s\n", cmd); if (!strncmp(cmd, "fb_cmd", 6)) video_cmd(cmd); else if (!strncmp(cmd, "video_mode ", 11)) video_mode_cmd(cmd + 11); + else if (!strncmp(cmd, "cheat ", 6)) zaparoo_cheat_cmd(cmd + 6); else if (!strncmp(cmd, "load_core ", 10)) { if(isXmlName(cmd)) xml_load(cmd + 10); diff --git a/support/zaparoo/cheat_cmd.cpp b/support/zaparoo/cheat_cmd.cpp new file mode 100644 index 000000000..39f2f9e78 --- /dev/null +++ b/support/zaparoo/cheat_cmd.cpp @@ -0,0 +1,140 @@ +#include "cheat_cmd.h" + +#include +#include +#include +#include +#include + +#include "cheats.h" + +enum +{ + CHEAT_CMD_OK = 0, + CHEAT_CMD_NO_CHEATS = -1, + CHEAT_CMD_NOT_FOUND = -2, + CHEAT_CMD_LOAD_FAILED = -3 +}; + +static const char *skip_space(const char *s) +{ + while (*s && isspace((unsigned char)*s)) s++; + return s; +} + +static bool parse_token(const char **cmd, char *token, size_t token_size) +{ + const char *s = skip_space(*cmd); + size_t len = 0; + + while (s[len] && !isspace((unsigned char)s[len])) len++; + if (!len || len >= token_size) return false; + + memcpy(token, s, len); + token[len] = 0; + *cmd = s + len; + return true; +} + +static const char *cheat_cmd_status(int status) +{ + switch (status) + { + case CHEAT_CMD_OK: return "ok"; + case CHEAT_CMD_NO_CHEATS: return "no cheats loaded"; + case CHEAT_CMD_NOT_FOUND: return "not found"; + case CHEAT_CMD_LOAD_FAILED: return "load failed"; + default: return "error"; + } +} + +static int find_cheat_by_name(const char *name) +{ + if (!name || !*name) return -1; + + for (int i = 0; i < cheats_available(); i++) + { + const char *cheat_name = cheats_get_name(i); + if (cheat_name && !strcmp(cheat_name, name)) return i; + } + + return -1; +} + +static int toggle_index(int idx) +{ + if (!cheats_available()) return CHEAT_CMD_NO_CHEATS; + if (idx < 0 || idx >= cheats_available()) return CHEAT_CMD_NOT_FOUND; + + bool was_enabled = cheats_get_enabled(idx); + int old_entry = cheats_get_selected(); + cheats_set_selected(idx); + cheats_toggle(); + cheats_set_selected(old_entry); + + return (cheats_get_enabled(idx) != was_enabled) ? CHEAT_CMD_OK : CHEAT_CMD_LOAD_FAILED; +} + +static int set_index_enabled(int idx, bool enabled) +{ + if (!cheats_available()) return CHEAT_CMD_NO_CHEATS; + if (idx < 0 || idx >= cheats_available()) return CHEAT_CMD_NOT_FOUND; + if (cheats_get_enabled(idx) == enabled) return CHEAT_CMD_OK; + + return toggle_index(idx); +} + +static int clear_enabled() +{ + if (!cheats_available()) return CHEAT_CMD_NO_CHEATS; + + int status = CHEAT_CMD_OK; + for (int i = 0; i < cheats_available(); i++) + { + if (cheats_get_enabled(i)) + { + int res = toggle_index(i); + if (res != CHEAT_CMD_OK) status = res; + } + } + + return status; +} + +void zaparoo_cheat_cmd(const char *cmd) +{ + char action[16]; + + if (!parse_token(&cmd, action, sizeof(action))) + { + printf("MiSTer_cmd cheat: missing command\n"); + return; + } + + if (!strcmp(action, "clear")) + { + int status = clear_enabled(); + printf("MiSTer_cmd cheat clear: %s\n", cheat_cmd_status(status)); + return; + } + + const char *name = skip_space(cmd); + if (!*name) + { + printf("MiSTer_cmd cheat %s: missing name\n", action); + return; + } + + int idx = find_cheat_by_name(name); + int status; + if (!strcmp(action, "on")) status = set_index_enabled(idx, true); + else if (!strcmp(action, "off")) status = set_index_enabled(idx, false); + else if (!strcmp(action, "toggle")) status = toggle_index(idx); + else + { + printf("MiSTer_cmd cheat: unknown command '%s'\n", action); + return; + } + + printf("MiSTer_cmd cheat %s '%s': %s\n", action, name, cheat_cmd_status(status)); +} diff --git a/support/zaparoo/cheat_cmd.h b/support/zaparoo/cheat_cmd.h new file mode 100644 index 000000000..6979614d3 --- /dev/null +++ b/support/zaparoo/cheat_cmd.h @@ -0,0 +1,3 @@ +#pragma once + +void zaparoo_cheat_cmd(const char *cmd); diff --git a/support/zaparoo/main_capabilities.cpp b/support/zaparoo/main_capabilities.cpp new file mode 100644 index 000000000..a75d1edba --- /dev/null +++ b/support/zaparoo/main_capabilities.cpp @@ -0,0 +1,5 @@ +extern "C" __attribute__((used)) +const char zaparoo_main_capabilities[] = + "ZAPAROO_MAIN_CAPABILITIES:" + "{\"schema\":1,\"id\":\"zaparoo-main\",\"version\":\"" VDATE "\"," + "\"capabilities\":{\"cheat_cmd\":1}}";