/* RetroArch - A frontend for libretro. * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2017 - Daniel De Matteis * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- * ation, either version 3 of the License, or (at your option) any later version. * * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with RetroArch. * If not, see . */ #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "../config.h" #endif #ifdef HAVE_CHEEVOS #include "../cheevos/cheevos.h" #endif #include "cheat_manager.h" #include "../msg_hash.h" #include "../retroarch.h" #include "../dynamic.h" #include "../core.h" #include "../verbosity.h" struct item_cheat { char *desc; bool state; char *code; }; struct cheat_manager { struct item_cheat *cheats; unsigned ptr; unsigned size; unsigned buf_size; }; static cheat_manager_t *cheat_manager_state; unsigned cheat_manager_get_buf_size(void) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return 0; return handle->buf_size; } unsigned cheat_manager_get_size(void) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return 0; return handle->size; } void cheat_manager_apply_cheats(void) { #ifdef HAVE_CHEEVOS bool data_bool = false; #endif unsigned i, idx = 0; cheat_manager_t *handle = cheat_manager_state; if (!handle) return; core_reset_cheat(); for (i = 0; i < handle->size; i++) { if (handle->cheats[i].state) { retro_ctx_cheat_info_t cheat_info; cheat_info.index = idx++; cheat_info.enabled = true; cheat_info.code = handle->cheats[i].code; if (!string_is_empty(cheat_info.code)) core_set_cheat(&cheat_info); } } runloop_msg_queue_push(msg_hash_to_str(MSG_APPLYING_CHEAT), 1, 180, true); RARCH_LOG("%s\n", msg_hash_to_str(MSG_APPLYING_CHEAT)); #ifdef HAVE_CHEEVOS data_bool = idx != 0; cheevos_apply_cheats(&data_bool); #endif } void cheat_manager_set_code(unsigned i, const char *str) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return; if (!string_is_empty(str)) handle->cheats[i].code = strdup(str); handle->cheats[i].state = true; } /** * cheat_manager_save: * @path : Path to cheats file (relative path). * * Saves cheats to file on disk. * * Returns: true (1) if successful, otherwise false (0). **/ bool cheat_manager_save(const char *path, const char *cheat_database) { bool ret; unsigned i; char buf[PATH_MAX_LENGTH]; char cheats_file[PATH_MAX_LENGTH]; config_file_t *conf = NULL; cheat_manager_t *handle = cheat_manager_state; buf[0] = cheats_file[0] = '\0'; fill_pathname_join(buf, cheat_database, path, sizeof(buf)); fill_pathname_noext(cheats_file, buf, ".cht", sizeof(cheats_file)); conf = config_file_new(cheats_file); if (!conf) conf = config_file_new(NULL); if (!conf) return false; if (!handle) { config_file_free(conf); return false; } config_set_int(conf, "cheats", handle->size); for (i = 0; i < handle->size; i++) { char key[64]; char desc_key[256]; char code_key[256]; char enable_key[256]; key[0] = desc_key[0] = code_key[0] = enable_key[0] = '\0'; snprintf(key, sizeof(key), "cheat%u", i); snprintf(desc_key, sizeof(desc_key), "cheat%u_desc", i); snprintf(code_key, sizeof(code_key), "cheat%u_code", i); snprintf(enable_key, sizeof(enable_key), "cheat%u_enable", i); if (handle->cheats[i].desc) config_set_string(conf, desc_key, handle->cheats[i].desc); else config_set_string(conf, desc_key, handle->cheats[i].code); config_set_string(conf, code_key, handle->cheats[i].code); config_set_bool(conf, enable_key, handle->cheats[i].state); } ret = config_file_write(conf, cheats_file); config_file_free(conf); return ret; } static cheat_manager_t *cheat_manager_new(unsigned size) { unsigned i; cheat_manager_t *handle = (cheat_manager_t*) calloc(1, sizeof(struct cheat_manager)); if (!handle) return NULL; handle->buf_size = size; handle->size = size; handle->cheats = (struct item_cheat*) calloc(handle->buf_size, sizeof(struct item_cheat)); if (!handle->cheats) { handle->buf_size = 0; handle->size = 0; handle->cheats = NULL; return handle; } for (i = 0; i < handle->size; i++) { handle->cheats[i].desc = NULL; handle->cheats[i].code = NULL; handle->cheats[i].state = false; } return handle; } bool cheat_manager_load(const char *path) { unsigned cheats = 0, i; cheat_manager_t *cheat; config_file_t *conf = config_file_new(path); if (!conf) return false; config_get_uint(conf, "cheats", &cheats); if (cheats == 0) goto error; cheat = cheat_manager_new(cheats); if (!cheat) goto error; for (i = 0; i < cheats; i++) { char key[64]; char desc_key[256]; char code_key[256]; char enable_key[256]; char *tmp = NULL; bool tmp_bool = false; key[0] = desc_key[0] = code_key[0] = enable_key[0] = '\0'; snprintf(key, sizeof(key), "cheat%u", i); snprintf(desc_key, sizeof(desc_key), "cheat%u_desc", i); snprintf(code_key, sizeof(code_key), "cheat%u_code", i); snprintf(enable_key, sizeof(enable_key), "cheat%u_enable", i); if (config_get_string(conf, desc_key, &tmp) && !string_is_empty(tmp)) cheat->cheats[i].desc = strdup(tmp); if (config_get_string(conf, code_key, &tmp) && !string_is_empty(tmp)) cheat->cheats[i].code = strdup(tmp); if (config_get_bool(conf, enable_key, &tmp_bool)) cheat->cheats[i].state = tmp_bool; if (tmp) free(tmp); } config_file_free(conf); cheat_manager_state = cheat; return true; error: config_file_free(conf); return false; } bool cheat_manager_realloc(unsigned new_size) { unsigned i; cheat_manager_t *handle = cheat_manager_state; if (!handle) return false; if (!handle->cheats) handle->cheats = (struct item_cheat*) calloc(new_size, sizeof(struct item_cheat)); else handle->cheats = (struct item_cheat*) realloc(handle->cheats, new_size * sizeof(struct item_cheat)); if (!handle->cheats) { handle->buf_size = handle->size = 0; handle->cheats = NULL; return false; } handle->buf_size = new_size; handle->size = new_size; for (i = 0; i < handle->size; i++) { handle->cheats[i].desc = NULL; handle->cheats[i].code = NULL; handle->cheats[i].state = false; } return true; } void cheat_manager_free(void) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return; if (handle->cheats) { unsigned i; for (i = 0; i < handle->size; i++) { free(handle->cheats[i].desc); free(handle->cheats[i].code); } free(handle->cheats); } free(handle); } void cheat_manager_update(cheat_manager_t *handle, unsigned handle_idx) { char msg[256]; if (!handle) return; snprintf(msg, sizeof(msg), "Cheat: #%u [%s]: %s", handle_idx, handle->cheats[handle_idx].state ? "ON" : "OFF", (handle->cheats[handle_idx].desc) ? (handle->cheats[handle_idx].desc) : (handle->cheats[handle_idx].code) ); runloop_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s\n", msg); } void cheat_manager_toggle_index(unsigned i) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return; handle->cheats[i].state = !handle->cheats[i].state; cheat_manager_update(handle, i); } void cheat_manager_toggle(void) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return; handle->cheats[handle->ptr].state ^= true; cheat_manager_apply_cheats(); cheat_manager_update(handle, handle->ptr); } void cheat_manager_index_next(void) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return; handle->ptr = (handle->ptr + 1) % handle->size; cheat_manager_update(handle, handle->ptr); } void cheat_manager_index_prev(void) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return; if (handle->ptr == 0) handle->ptr = handle->size - 1; else handle->ptr--; cheat_manager_update(handle, handle->ptr); } const char *cheat_manager_get_code(unsigned i) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return NULL; return handle->cheats[i].code; } const char *cheat_manager_get_desc(unsigned i) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return NULL; return handle->cheats[i].desc; } bool cheat_manager_get_code_state(unsigned i) { cheat_manager_t *handle = cheat_manager_state; if (!handle) return false; return handle->cheats[i].state; } void cheat_manager_state_free(void) { cheat_manager_free(); cheat_manager_state = NULL; } bool cheat_manager_alloc_if_empty(void) { cheat_manager_t *handle = cheat_manager_state; if (!handle) { cheat_manager_t *tmp = cheat_manager_new(0); if (!tmp) return false; cheat_manager_state = tmp; } return true; }