mirror of
https://github.com/mupen64plus/mupen64plus-oldsvn.git
synced 2024-05-14 01:59:38 -04:00
merged r0982-cheats branch
This commit is contained in:
parent
b5d946aceb
commit
60d99e6776
1
Makefile
1
Makefile
|
@ -121,6 +121,7 @@ OBJ_CORE = \
|
|||
main/md5.o \
|
||||
main/plugin.o \
|
||||
main/rom.o \
|
||||
main/ini_reader.o \
|
||||
main/savestates.o \
|
||||
main/zip/ioapi.o \
|
||||
main/zip/zip.o \
|
||||
|
|
BIN
icons/16x16/tools-wizard.png
Normal file
BIN
icons/16x16/tools-wizard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 797 B |
BIN
icons/22x22/tools-wizard.png
Normal file
BIN
icons/22x22/tools-wizard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
icons/32x32/tools-wizard.png
Normal file
BIN
icons/32x32/tools-wizard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
|
@ -25,6 +25,7 @@ preferences-system.png
|
|||
16x16/audio-card.png
|
||||
16x16/document-save-as.png
|
||||
16x16/application-exit.png
|
||||
16x16/tools-wizard.png
|
||||
22x22/document-open.png
|
||||
22x22/document-save.png
|
||||
22x22/media-playback-pause.png
|
||||
|
@ -38,6 +39,7 @@ preferences-system.png
|
|||
22x22/document-save-as.png
|
||||
22x22/document-properties.png
|
||||
22x22/view-refresh.png
|
||||
22x22/tools-wizard.png
|
||||
32x32/audio-card.png
|
||||
32x32/dialog-error.png
|
||||
32x32/dialog-question.png
|
||||
|
@ -58,6 +60,7 @@ preferences-system.png
|
|||
32x32/document-save-as.png
|
||||
32x32/document-properties.png
|
||||
32x32/view-refresh.png
|
||||
32x32/tools-wizard.png
|
||||
|
||||
are Copyright: The Oxygen Icon Theme
|
||||
| Copyright (C) 2007 David Vignoni <david@icon-king.com>
|
||||
|
@ -187,3 +190,4 @@ are Copyright: The Mupen64plus Team
|
|||
| along with this program; if not, write to the
|
||||
| Free Software Foundation, Inc.,
|
||||
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ $INSTALL -d -v "${SHAREDIR}"
|
|||
$INSTALL -d -v "${SHAREDIR}/config"
|
||||
$INSTALL -m 0644 config/* "${SHAREDIR}/config"
|
||||
$INSTALL -m 0644 mupen64plus.ini "${SHAREDIR}/"
|
||||
$INSTALL -m 0644 mupen64plus.cht "${SHAREDIR}/"
|
||||
$INSTALL -d -v "${SHAREDIR}/doc"
|
||||
$INSTALL -m 0644 doc/* "${SHAREDIR}/doc"
|
||||
$INSTALL -d -v "${SHAREDIR}/fonts"
|
||||
|
@ -103,4 +104,3 @@ then
|
|||
fi
|
||||
|
||||
printf "Done.\n"
|
||||
|
||||
|
|
347
main/cheat.c
347
main/cheat.c
|
@ -32,13 +32,19 @@
|
|||
#include "rom.h"
|
||||
#include "util.h" // list utilities
|
||||
#include "config.h"
|
||||
#include "ini_reader.h"
|
||||
|
||||
// this seems stupid
|
||||
#define CHEAT_CODE_MAGIC_VALUE 0xcafe // use this to know that old_value is uninitialized
|
||||
|
||||
#define DATABASE_FILENAME "mupen64plus.cht"
|
||||
#define CHEAT_FILENAME "cheats.cfg"
|
||||
static ini_file *cheat_file = NULL;
|
||||
static ini_section *current_rom_section = NULL;
|
||||
static list_t current_rom_cheats = NULL;
|
||||
|
||||
// public globals
|
||||
// for local cheats stored in cheats.cfg
|
||||
list_t g_Cheats = NULL; // list of all supported cheats
|
||||
|
||||
// static globals
|
||||
static rom_cheats_t *g_Current = NULL; // current loaded rom
|
||||
|
||||
// private functions
|
||||
|
@ -47,9 +53,9 @@ static unsigned short read_address_16bit(unsigned int address)
|
|||
return *(unsigned short *)((rdramb + ((address & 0xFFFFFF)^S16)));
|
||||
}
|
||||
|
||||
static unsigned short read_address_8bit(unsigned int address)
|
||||
static unsigned char read_address_8bit(unsigned int address)
|
||||
{
|
||||
return *(unsigned short *)((rdramb + ((address & 0xFFFFFF)^S8)));
|
||||
return *(unsigned char *)((rdramb + ((address & 0xFFFFFF)^S8)));
|
||||
}
|
||||
|
||||
static void update_address_16bit(unsigned int address, unsigned short new_value)
|
||||
|
@ -78,7 +84,7 @@ static int address_equal_to_16bit(unsigned int address, unsigned short value)
|
|||
|
||||
// individual application - returns 0 if we are supposed to skip the next cheat
|
||||
// (only really used on conditional codes)
|
||||
static int execute_cheat(unsigned int address, unsigned short value, unsigned short *old_value)
|
||||
static int execute_cheat(unsigned int address, unsigned short value, int *old_value)
|
||||
{
|
||||
switch (address & 0xFF000000)
|
||||
{
|
||||
|
@ -88,47 +94,39 @@ static int execute_cheat(unsigned int address, unsigned short value, unsigned sh
|
|||
case 0xA8000000:
|
||||
case 0xF0000000:
|
||||
// if pointer to old value is valid and uninitialized, write current value to it
|
||||
if(old_value && *old_value == CHEAT_CODE_MAGIC_VALUE)
|
||||
*old_value = read_address_8bit(address);
|
||||
if(old_value && (*old_value == CHEAT_CODE_MAGIC_VALUE))
|
||||
*old_value = (int) read_address_8bit(address);
|
||||
update_address_8bit(address,value);
|
||||
return 1;
|
||||
break;
|
||||
case 0x81000000:
|
||||
case 0x89000000:
|
||||
case 0xA1000000:
|
||||
case 0xA9000000:
|
||||
case 0xF1000000:
|
||||
// if pointer to old value is valid and uninitialized, write current value to it
|
||||
if(old_value && *old_value == CHEAT_CODE_MAGIC_VALUE)
|
||||
*old_value = read_address_16bit(address);
|
||||
if(old_value && (*old_value == CHEAT_CODE_MAGIC_VALUE))
|
||||
*old_value = (int) read_address_16bit(address);
|
||||
update_address_16bit(address,value);
|
||||
return 1;
|
||||
break;
|
||||
case 0xD0000000:
|
||||
case 0xD8000000:
|
||||
return address_equal_to_8bit(address,value);
|
||||
break;
|
||||
case 0xD1000000:
|
||||
case 0xD9000000:
|
||||
return address_equal_to_16bit(address,value);
|
||||
break;
|
||||
case 0xD2000000:
|
||||
case 0xDB000000:
|
||||
return !(address_equal_to_8bit(address,value));
|
||||
break;
|
||||
case 0xD3000000:
|
||||
case 0xDA000000:
|
||||
return !(address_equal_to_16bit(address,value));
|
||||
break;
|
||||
case 0xEE000000:
|
||||
// most likely, this doesnt do anything.
|
||||
execute_cheat(0xF1000318, 0x0040, NULL);
|
||||
execute_cheat(0xF100031A, 0x0000, NULL);
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,16 +139,15 @@ static int gs_button_pressed(void)
|
|||
// public functions
|
||||
void cheat_apply_cheats(int entry)
|
||||
{
|
||||
list_node_t *node1, *node2;
|
||||
cheat_t *cheat;
|
||||
list_t node1 = NULL;
|
||||
list_t node2 = NULL;
|
||||
cheat_code_t *code;
|
||||
|
||||
// if no cheats for current rom, return
|
||||
if(!g_Current) return;
|
||||
|
||||
list_foreach(g_Current->cheats, node1)
|
||||
{
|
||||
cheat = (cheat_t *)node1->data;
|
||||
|
||||
if (current_rom_cheats == NULL)
|
||||
return;
|
||||
|
||||
list_foreach(current_rom_cheats, node1) {
|
||||
cheat_t* cheat = (cheat_t*) node1->data;
|
||||
if(cheat->always_enabled || cheat->enabled)
|
||||
{
|
||||
cheat->was_enabled = 1;
|
||||
|
@ -259,7 +256,20 @@ void cheat_apply_cheats(int entry)
|
|||
}
|
||||
|
||||
/** cheat_read_config
|
||||
* Read config file and populate list of supported cheats. Format of cheat file is:
|
||||
* First read and parse the DATABASE (PJ64),
|
||||
* then read and parse the CHEAT file.
|
||||
*/
|
||||
void cheat_read_config(void)
|
||||
{
|
||||
|
||||
/**
|
||||
* Read and parse the DATABASE (PJ64),
|
||||
*/
|
||||
char buf[PATH_MAX];
|
||||
snprintf(buf, PATH_MAX, "%s%s", get_installpath(), DATABASE_FILENAME);
|
||||
cheat_file = ini_file_parse(buf);
|
||||
|
||||
/** Read config file and populate list of supported cheats. Format of cheat file is:
|
||||
*
|
||||
* {Some Game's CRC}
|
||||
* name=Some Game
|
||||
|
@ -281,8 +291,6 @@ void cheat_apply_cheats(int entry)
|
|||
* name=Another Game
|
||||
* ...
|
||||
*/
|
||||
void cheat_read_config(void)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
FILE *f = NULL;
|
||||
char line[2048];
|
||||
|
@ -342,7 +350,7 @@ void cheat_read_config(void)
|
|||
|
||||
// else, line must be a cheat code
|
||||
cheatcode = cheat_new_cheat_code(cheat);
|
||||
sscanf(line, "%x %hx", &cheatcode->address, &cheatcode->value);
|
||||
sscanf(line, "%x %x", &cheatcode->address, &cheatcode->value);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
@ -389,7 +397,7 @@ void cheat_write_config(void)
|
|||
{
|
||||
cheatcode = (cheat_code_t *)node3->data;
|
||||
|
||||
fprintf(f, "%.8x %.4hx\n", cheatcode->address, cheatcode->value);
|
||||
fprintf(f, "%.8x %.4x\n", cheatcode->address, cheatcode->value);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
|
@ -398,42 +406,15 @@ void cheat_write_config(void)
|
|||
fclose(f);
|
||||
}
|
||||
|
||||
/** cheat_delete_all
|
||||
* Delete all cheat-related structures
|
||||
*/
|
||||
void cheat_delete_all(void)
|
||||
{
|
||||
list_node_t *node1, *node2, *node3;
|
||||
rom_cheats_t *romcheat = NULL;
|
||||
cheat_t *cheat = NULL;
|
||||
cheat_code_t *cheatcode = NULL;
|
||||
ini_file_free(&cheat_file);
|
||||
}
|
||||
|
||||
list_foreach(g_Cheats, node1)
|
||||
{
|
||||
romcheat = (rom_cheats_t *)node1->data;
|
||||
|
||||
if(romcheat->rom_name)
|
||||
free(romcheat->rom_name);
|
||||
|
||||
list_foreach(romcheat->cheats, node2)
|
||||
{
|
||||
cheat = (cheat_t *)node2->data;
|
||||
|
||||
if(cheat->name)
|
||||
free(cheat->name);
|
||||
list_foreach(cheat->cheat_codes, node3)
|
||||
{
|
||||
cheatcode = (cheat_code_t *)node3->data;
|
||||
free(cheatcode);
|
||||
}
|
||||
list_delete(&cheat->cheat_codes);
|
||||
free(cheat);
|
||||
}
|
||||
list_delete(&romcheat->cheats);
|
||||
free(romcheat);
|
||||
}
|
||||
list_delete(&g_Cheats);
|
||||
g_Current = NULL;
|
||||
void cheat_unload_current_rom(void)
|
||||
{
|
||||
current_rom_section = NULL;
|
||||
current_rom_cheats = NULL;
|
||||
}
|
||||
|
||||
/** cheat_load_current_rom
|
||||
|
@ -441,52 +422,234 @@ void cheat_delete_all(void)
|
|||
*/
|
||||
void cheat_load_current_rom(void)
|
||||
{
|
||||
list_node_t *node, *node2;
|
||||
rom_cheats_t *rom_cheat = NULL;
|
||||
/* The title is always 22 chars long. Add one for the \0 */
|
||||
char buf[23];
|
||||
list_node_t *node = NULL;
|
||||
ini_section *section = NULL;
|
||||
|
||||
if (ROM_HEADER && cheat_file)
|
||||
{
|
||||
snprintf(buf, 23, "%X-%X-C:%X",
|
||||
g_MemHasBeenBSwapped ? sl(ROM_HEADER->CRC1) : ROM_HEADER->CRC1,
|
||||
g_MemHasBeenBSwapped ? sl(ROM_HEADER->CRC2) : ROM_HEADER->CRC2,
|
||||
(ROM_HEADER->Country_code)&0xff);
|
||||
list_foreach(cheat_file->sections, node)
|
||||
{
|
||||
section = node->data;
|
||||
if (strcasecmp(buf, section->title) == 0)
|
||||
{
|
||||
puts("FOUND CHEAT ENTRY");
|
||||
current_rom_section = section;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static cheat_t *find_or_create_cheat(list_t *list, int number)
|
||||
{
|
||||
list_t node = NULL;
|
||||
cheat_t *cheat = NULL;
|
||||
cheat_code_t *cheatcode = NULL;
|
||||
int found = 0;
|
||||
|
||||
list_foreach(*list, node) {
|
||||
cheat = node->data;
|
||||
if (cheat->number == number) {
|
||||
found = 1;
|
||||
break;
|
||||
} else if (cheat->number == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
cheat = malloc(sizeof(cheat_t));
|
||||
cheat->name = NULL;
|
||||
cheat->comment = NULL;
|
||||
cheat->number = number;
|
||||
cheat->cheat_codes = NULL;
|
||||
cheat->options = NULL;
|
||||
cheat->enabled = 0;
|
||||
cheat->was_enabled = 0;
|
||||
cheat->always_enabled = 0;
|
||||
list_append(list, cheat);
|
||||
}
|
||||
|
||||
return cheat;
|
||||
}
|
||||
|
||||
list_t cheats_for_current_rom()
|
||||
{
|
||||
list_t node = NULL;
|
||||
list_t node2 = NULL;
|
||||
list_t list = NULL;
|
||||
list_t temp = NULL;
|
||||
ini_entry *entry = NULL;
|
||||
cheat_t *cheat = NULL;
|
||||
rom_cheats_t *romcheat = NULL;
|
||||
int n = 0, len = 0;
|
||||
int value = 0;
|
||||
unsigned int address = 0;
|
||||
char buf[PATH_MAX];
|
||||
cheat_option_t *option;
|
||||
cheat_code_t *code;
|
||||
|
||||
if (!current_rom_section)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_foreach(current_rom_section->entries, node)
|
||||
{
|
||||
entry = node->data;
|
||||
len = strlen(entry->key);
|
||||
if (strcmp("_O", entry->key + len - 2) == 0) // Option for a cheat
|
||||
{
|
||||
if (sscanf(entry->key, "Cheat%d_O", &n) == 1)
|
||||
{
|
||||
cheat = find_or_create_cheat(&list, n);
|
||||
temp = tokenize_string(entry->value, ",");
|
||||
node2 = NULL;
|
||||
list_foreach(temp, node2)
|
||||
{
|
||||
memset(buf, '\0', PATH_MAX);
|
||||
if (sscanf(node2->data, "$%x %[a-zA-Z0-9 ']", &value, buf) == 2)
|
||||
{
|
||||
option = malloc(sizeof(cheat_option_t));
|
||||
option->code = value;
|
||||
option->description = malloc(strlen(buf) + 1);
|
||||
strcpy(option->description, buf);
|
||||
list_append(&cheat->options, option);
|
||||
}
|
||||
free(node2->data);
|
||||
}
|
||||
list_delete(&temp);
|
||||
}
|
||||
}
|
||||
else if (strcmp("_N", entry->key + len - 2) == 0) // Comment for a cheat
|
||||
{
|
||||
if (sscanf(entry->key, "Cheat%d_N", &n) == 1)
|
||||
{
|
||||
cheat = find_or_create_cheat(&list, n);
|
||||
cheat->comment = malloc(strlen(entry->value) + 1);
|
||||
strcpy(cheat->comment, entry->value);
|
||||
}
|
||||
}
|
||||
else if (sscanf(entry->key, "Cheat%d", &n) == 1)
|
||||
{
|
||||
cheat = find_or_create_cheat(&list, n);
|
||||
temp = tokenize_string(entry->value, ",");
|
||||
cheat->name = list_first_data(temp);
|
||||
list_node_delete(&temp, list_first_node(temp));
|
||||
node2 = NULL;
|
||||
list_foreach(temp, node2)
|
||||
{
|
||||
//TODO: This will not handle the case where all digits in code field
|
||||
// is '?'. Should be handled separately.
|
||||
if (sscanf(node2->data, "%x %x", &address, &value) == 2)
|
||||
{
|
||||
code = malloc(sizeof(cheat_code_t));
|
||||
code->address = address;
|
||||
|
||||
// If there i a '?' in the data, mark it with code->option = 1
|
||||
if (strchr(node2->data, '?'))
|
||||
code->option = 1;
|
||||
else
|
||||
code->option = 0;
|
||||
|
||||
code->value = value;
|
||||
code->old_value = CHEAT_CODE_MAGIC_VALUE;
|
||||
list_append(&cheat->cheat_codes, code);
|
||||
}
|
||||
free(node2->data);
|
||||
}
|
||||
list_delete(&temp);
|
||||
|
||||
/* Remove quotation marks from around name */
|
||||
strcpy(cheat->name, cheat->name + 1);
|
||||
cheat->name[strlen(cheat->name) - 1] = '\0';
|
||||
}
|
||||
|
||||
cheat = NULL;
|
||||
}
|
||||
|
||||
// Adding cheats from cheats.cfg to the 'current_rom_cheats' list.
|
||||
rom_cheats_t *rom_cheat = NULL;
|
||||
code = NULL;
|
||||
node = NULL;
|
||||
node2 = NULL;
|
||||
cheat = NULL;
|
||||
unsigned int crc1, crc2;
|
||||
|
||||
g_Current = NULL;
|
||||
crc1 = g_MemHasBeenBSwapped ? sl(ROM_HEADER->CRC1) : ROM_HEADER->CRC1;
|
||||
crc2 = g_MemHasBeenBSwapped ? sl(ROM_HEADER->CRC2) : ROM_HEADER->CRC2;
|
||||
|
||||
if(!ROM_HEADER) return;
|
||||
|
||||
if(g_MemHasBeenBSwapped)
|
||||
{
|
||||
crc1 = sl(ROM_HEADER->CRC1);
|
||||
crc2 = sl(ROM_HEADER->CRC2);
|
||||
}
|
||||
else
|
||||
{
|
||||
crc1 = ROM_HEADER->CRC1;
|
||||
crc2 = ROM_HEADER->CRC2;
|
||||
}
|
||||
|
||||
list_foreach(g_Cheats, node)
|
||||
{
|
||||
list_foreach(g_Cheats, node) {
|
||||
rom_cheat = (rom_cheats_t *)node->data;
|
||||
|
||||
if(crc1 == rom_cheat->crc1 &&
|
||||
crc2 == rom_cheat->crc2)
|
||||
{
|
||||
crc2 == rom_cheat->crc2) {
|
||||
g_Current = rom_cheat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if rom was found, clear any old saved values from cheat codes
|
||||
if(g_Current)
|
||||
{
|
||||
list_foreach(g_Current->cheats, node)
|
||||
{
|
||||
if(g_Current) {
|
||||
list_foreach(g_Current->cheats, node) {
|
||||
cheat = (cheat_t *)node->data;
|
||||
cheat_t* newcheat;
|
||||
newcheat = find_or_create_cheat(&list, -1);
|
||||
memcpy(newcheat,cheat,sizeof(cheat_t));
|
||||
newcheat->cheat_codes = NULL;
|
||||
newcheat->options = NULL;
|
||||
|
||||
list_foreach(cheat->cheat_codes, node2)
|
||||
if (cheat->cheat_codes)
|
||||
{
|
||||
cheatcode = (cheat_code_t *)node2->data;
|
||||
cheatcode->old_value = CHEAT_CODE_MAGIC_VALUE;
|
||||
list_foreach(cheat->cheat_codes, node2) {
|
||||
code = (cheat_code_t *)node2->data;
|
||||
cheat_code_t* newcode;
|
||||
newcode = malloc(sizeof(cheat_code_t));
|
||||
memcpy(newcode,code,sizeof(cheat_code_t));
|
||||
newcode->old_value = CHEAT_CODE_MAGIC_VALUE;
|
||||
list_append(&newcheat->cheat_codes, newcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current_rom_cheats = list;
|
||||
return list;
|
||||
}
|
||||
|
||||
void cheats_free(list_t *cheats)
|
||||
{
|
||||
cheat_t *cheat = NULL;
|
||||
cheat_option_t *option = NULL;
|
||||
list_t node1, node2;
|
||||
node1 = node2 = NULL;
|
||||
|
||||
list_foreach(*cheats, node1) {
|
||||
cheat = node1->data;
|
||||
|
||||
free(cheat->name);
|
||||
free(cheat->comment);
|
||||
|
||||
list_foreach(cheat->cheat_codes, node2) {
|
||||
free(node2->data);
|
||||
}
|
||||
list_delete(&cheat->cheat_codes);
|
||||
|
||||
list_foreach(cheat->options, node2) {
|
||||
option = node2->data;
|
||||
free(option->description);
|
||||
free(option);
|
||||
}
|
||||
list_delete(&cheat->options);
|
||||
}
|
||||
|
||||
list_delete(cheats);
|
||||
}
|
||||
|
||||
/** cheat_new_rom
|
||||
|
|
52
main/cheat.h
52
main/cheat.h
|
@ -19,6 +19,9 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef CHEAT_H
|
||||
#define CHEAT_H
|
||||
|
||||
#include "util.h" // list_t
|
||||
|
||||
#define ENTRY_BOOT 0
|
||||
|
@ -26,37 +29,47 @@
|
|||
|
||||
extern list_t g_Cheats;
|
||||
|
||||
void cheat_apply_cheats(int entry);
|
||||
void cheat_read_config(void);
|
||||
void cheat_write_config(void);
|
||||
void cheat_delete_all(void);
|
||||
void cheat_load_current_rom(void);
|
||||
void cheat_unload_current_rom(void);
|
||||
|
||||
// represents all cheats for a given rom
|
||||
typedef struct {
|
||||
typedef struct rom_cheats {
|
||||
char *rom_name;
|
||||
unsigned int crc1;
|
||||
unsigned int crc2;
|
||||
list_t cheats; // list of cheat_t's
|
||||
} rom_cheats_t;
|
||||
|
||||
// represents a cheat for a game
|
||||
typedef struct {
|
||||
char *name;
|
||||
int enabled; // cheat enabled until mupen64plus is closed
|
||||
int always_enabled; // always enabled (written to config)
|
||||
int was_enabled; // cheat was previously enabled, but has now been disabled
|
||||
list_t cheat_codes; // list of cheat_code_t's
|
||||
} cheat_t;
|
||||
typedef struct cheat_option {
|
||||
int code; /* e.g. 0xFF */
|
||||
char *description; /* e.g. Music Off */
|
||||
} cheat_option_t;
|
||||
|
||||
// represents a cheatcode associated with a cheat
|
||||
typedef struct {
|
||||
typedef struct cheat_code {
|
||||
unsigned int address;
|
||||
unsigned short value;
|
||||
unsigned short old_value; // value before cheat was applied
|
||||
int value;
|
||||
int old_value;
|
||||
int option; // If this is an option mark it with 0x1, else 0x0
|
||||
} cheat_code_t;
|
||||
|
||||
#define CHEAT_CODE_MAGIC_VALUE 0xcafe // use this to know that old_value is uninitialized
|
||||
typedef struct cheat {
|
||||
char *name;
|
||||
char *comment;
|
||||
int number;
|
||||
int enabled;
|
||||
int always_enabled;
|
||||
int was_enabled;
|
||||
list_t cheat_codes;
|
||||
list_t options;
|
||||
} cheat_t;
|
||||
|
||||
void cheat_apply_cheats(int entry);
|
||||
void cheat_read_config(void);
|
||||
void cheat_write_config(void);
|
||||
void cheat_delete_all(void);
|
||||
void cheat_load_current_rom(void);
|
||||
list_t cheats_for_current_rom(); // use cheats_free to free returned list
|
||||
|
||||
void cheats_free(list_t *cheats); // list_t becomes invalid after this!
|
||||
|
||||
rom_cheats_t *cheat_new_rom(void);
|
||||
cheat_t *cheat_new_cheat(rom_cheats_t *);
|
||||
|
@ -65,3 +78,4 @@ void cheat_delete_rom(rom_cheats_t *);
|
|||
void cheat_delete_cheat(rom_cheats_t *, cheat_t *);
|
||||
void cheat_delete_cheat_code(cheat_t *, cheat_code_t *);
|
||||
|
||||
#endif // #define CHEAT_H
|
||||
|
|
154
main/gui_qt4/cheatcheatdialog.cpp
Normal file
154
main/gui_qt4/cheatcheatdialog.cpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - cheatcheatdialog.cpp *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 olejl *
|
||||
* *
|
||||
* This program 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 Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <QtGui>
|
||||
|
||||
#include "cheatcheatdialog.h"
|
||||
#include "cheatdialog.h" //Q_DECLARE_METATYPE(core::cheat_code_t*)
|
||||
|
||||
CheatCheatDialog::CheatCheatDialog(core::cheat_t *cheat, QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
// Use this as our internal pointer to the cheat we are working on.
|
||||
// To make it accessable for other than only constructor
|
||||
_cheat = cheat;
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(onaccepted()));
|
||||
connect(pushAdd, SIGNAL(clicked()), this, SLOT(onadd()));
|
||||
connect(pushRemove, SIGNAL(clicked()), this, SLOT(onremove()));
|
||||
|
||||
core::list_t node = 0;
|
||||
|
||||
tableModel = new QStandardItemModel();
|
||||
tableView->verticalHeader()->hide();
|
||||
tableView->setModel(tableModel);
|
||||
tableView->resizeColumnsToContents();
|
||||
tableView->horizontalHeader()->setStretchLastSection(true);
|
||||
QStandardItem *header0 = new QStandardItem(QString("Address"));
|
||||
QStandardItem *header1 = new QStandardItem(QString("Value"));
|
||||
tableModel->setHorizontalHeaderItem(0, header0);
|
||||
tableModel->setHorizontalHeaderItem(1, header1);
|
||||
|
||||
if (_cheat->name) {
|
||||
lineEditName->setText(tr("%1").arg(_cheat->name));
|
||||
}
|
||||
if (_cheat->comment) {
|
||||
textEditComment->setText(tr("%1").arg(_cheat->comment));
|
||||
}
|
||||
if (_cheat->always_enabled) {
|
||||
radioAlwayEnabled->setChecked(true);
|
||||
}
|
||||
list_foreach(_cheat->cheat_codes, node) {
|
||||
core::cheat_code_t *code = static_cast<core::cheat_code_t*>(node->data);
|
||||
addCheatCodeToTable(code);
|
||||
}
|
||||
tableView->resizeColumnsToContents();
|
||||
tableView->horizontalHeader()->setStretchLastSection(true);
|
||||
|
||||
// Put this here to avoid signal while initializing tableView
|
||||
connect(tableModel, SIGNAL(itemChanged(QStandardItem *)), this, SLOT(codeItemChanged(QStandardItem *)));
|
||||
}
|
||||
|
||||
CheatCheatDialog::~CheatCheatDialog()
|
||||
{
|
||||
// TODO: destructor
|
||||
}
|
||||
|
||||
void CheatCheatDialog::onaccepted()
|
||||
{
|
||||
QByteArray arr = lineEditName->text().toLatin1();
|
||||
int size = arr.size() + 1;
|
||||
_cheat->name = (char*) malloc(size);
|
||||
if (_cheat->name==NULL) { return; } // TODO: proper error handling?
|
||||
memset(_cheat->name, '\0', size);
|
||||
strcpy(_cheat->name, arr.data());
|
||||
|
||||
arr = textEditComment->toPlainText().toLatin1();
|
||||
size = arr.size() + 1;
|
||||
_cheat->comment = (char*) malloc(size);
|
||||
if (_cheat->comment==NULL) { return; } // TODO: proper error handling?
|
||||
memset(_cheat->comment, '\0', size);
|
||||
strcpy(_cheat->comment, arr.data());
|
||||
|
||||
if (radioAlwayEnabled->isChecked()) {
|
||||
_cheat->always_enabled = 1;
|
||||
}
|
||||
if (radioEnabled->isChecked()) {
|
||||
_cheat->enabled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void CheatCheatDialog::onadd()
|
||||
{
|
||||
core::cheat_code_t* code = cheat_new_cheat_code(_cheat);
|
||||
addCheatCodeToTable(code);
|
||||
}
|
||||
|
||||
void CheatCheatDialog::onremove()
|
||||
{
|
||||
const QModelIndex& index = tableView->selectionModel()->currentIndex();
|
||||
QStandardItem* item = 0;
|
||||
core::cheat_code_t* code;
|
||||
|
||||
if (index.isValid()) {
|
||||
item = tableModel->itemFromIndex(index);
|
||||
code = item->data(CheatDialog::CheatCodeRole).value<core::cheat_code_t*>();
|
||||
tableModel->removeRow(index.row());
|
||||
core::cheat_delete_cheat_code(_cheat, code);
|
||||
}
|
||||
}
|
||||
|
||||
void CheatCheatDialog::codeItemChanged(QStandardItem* item)
|
||||
{
|
||||
bool ok;
|
||||
core::cheat_code_t* code = NULL;
|
||||
|
||||
QModelIndex index = tableModel->indexFromItem(item);
|
||||
code = item->data(CheatDialog::CheatCodeRole).value<core::cheat_code_t*>();
|
||||
|
||||
if (code) {
|
||||
if (index.column() == 0) { // address
|
||||
code->address = code->address, item->text().toUInt(&ok, 16);
|
||||
item->setText(tr("%1").arg(code->address, 8, 16, QChar('0')).toUpper());
|
||||
} else { // value
|
||||
code->value = item->text().toUInt(&ok, 16);;
|
||||
item->setText(tr("%1").arg(code->value, 4, 16, QChar('0')).toUpper());
|
||||
}
|
||||
tableView->resizeColumnsToContents();
|
||||
tableView->horizontalHeader()->setStretchLastSection(true);
|
||||
}
|
||||
}
|
||||
|
||||
void CheatCheatDialog::addCheatCodeToTable(core::cheat_code_t *code) {
|
||||
QList<QStandardItem *> row;
|
||||
QStandardItem *address = new QStandardItem(QString("%1").arg(code->address, 8, 16, QChar('0')).toUpper());
|
||||
QStandardItem *value = new QStandardItem(QString("%1").arg(code->value, 4, 16, QChar('0')).toUpper());
|
||||
|
||||
// Store the cheat in both rows. siplifies the 'codeItemChanged'
|
||||
address->setData(QVariant::fromValue(code), CheatDialog::CheatCodeRole);
|
||||
value->setData(QVariant::fromValue(code), CheatDialog::CheatCodeRole);
|
||||
row.append(address);
|
||||
row.append(value);
|
||||
|
||||
tableModel->appendRow(row);
|
||||
tableView->setRowHeight(tableModel->rowCount() - 1,15);
|
||||
}
|
||||
|
54
main/gui_qt4/cheatcheatdialog.h
Normal file
54
main/gui_qt4/cheatcheatdialog.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - cheatcheatdialog.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 olejl *
|
||||
* *
|
||||
* This program 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 Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef CHEATCHEATDIALOG_H
|
||||
#define CHEATCHEATDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QStandardItemModel>
|
||||
#include "ui_cheatcheatdialog.h"
|
||||
|
||||
namespace core {
|
||||
extern "C" {
|
||||
#include "../cheat.h"
|
||||
}
|
||||
}
|
||||
|
||||
class CheatCheatDialog : public QDialog, private Ui_CheatCheatDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CheatCheatDialog(core::cheat_t *, QWidget* parent = 0);
|
||||
virtual ~CheatCheatDialog();
|
||||
|
||||
private slots:
|
||||
void onaccepted();
|
||||
void onadd();
|
||||
void onremove();
|
||||
void codeItemChanged(QStandardItem *item);
|
||||
|
||||
private:
|
||||
void addCheatCodeToTable(core::cheat_code_t *code);
|
||||
core::cheat_t *_cheat;
|
||||
QStandardItemModel *tableModel;
|
||||
};
|
||||
|
||||
#endif // CHEATCHEATDIALOG_H
|
173
main/gui_qt4/cheatcheatdialog.ui
Normal file
173
main/gui_qt4/cheatcheatdialog.ui
Normal file
|
@ -0,0 +1,173 @@
|
|||
<ui version="4.0" >
|
||||
<class>CheatCheatDialog</class>
|
||||
<widget class="QDialog" name="CheatCheatDialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>276</width>
|
||||
<height>439</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Cheat</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2" >
|
||||
<item row="0" column="0" >
|
||||
<layout class="QGridLayout" name="gridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="labelName" >
|
||||
<property name="text" >
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLineEdit" name="lineEditName" >
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>23</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2" >
|
||||
<widget class="QRadioButton" name="radioDisabled" >
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>23</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Disabled</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2" >
|
||||
<widget class="QRadioButton" name="radioEnabled" >
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>23</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Enabled (Session)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2" >
|
||||
<widget class="QRadioButton" name="radioAlwayEnabled" >
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>23</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Enabled (Always)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0" colspan="3" >
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>29</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0" colspan="2" >
|
||||
<widget class="QTextEdit" name="textEditComment" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0" >
|
||||
<widget class="QLabel" name="labelComment" >
|
||||
<property name="text" >
|
||||
<string>Comment:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item rowspan="3" row="9" column="1" >
|
||||
<widget class="QTableView" name="tableView" >
|
||||
<property name="showGrid" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0" >
|
||||
<widget class="QPushButton" name="pushAdd" >
|
||||
<property name="text" >
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" >
|
||||
<widget class="QPushButton" name="pushRemove" >
|
||||
<property name="text" >
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>CheatCheatDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>CheatCheatDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
330
main/gui_qt4/cheatdialog.cpp
Normal file
330
main/gui_qt4/cheatdialog.cpp
Normal file
|
@ -0,0 +1,330 @@
|
|||
/**
|
||||
* Mupen64 - cheatdialog.h
|
||||
* Copyright (C) 2008 slougi
|
||||
*
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/
|
||||
* or modify it under the terms of the GNU General Public Li-
|
||||
* cence as published by the Free Software Foundation; either
|
||||
* version 2 of the Licence, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be use-
|
||||
* ful, but WITHOUT ANY WARRANTY; without even the implied war-
|
||||
* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* Licence along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
||||
* USA.
|
||||
**/
|
||||
|
||||
#include <QtGui>
|
||||
|
||||
#include "globals.h"
|
||||
#include "cheatdialog.h"
|
||||
#include "cheatromdialog.h"
|
||||
#include "cheatcheatdialog.h"
|
||||
|
||||
CheatDialog::CheatDialog(QWidget* parent) : QDialog(parent)
|
||||
, m_cheats(0), m_model(new QStandardItemModel(this))
|
||||
{
|
||||
setupUi(this);
|
||||
setWindowIcon(icon("tools-wizard.png"));
|
||||
|
||||
connect(m_model, SIGNAL(itemChanged(QStandardItem *)), this, SLOT(cheatItemChanged(QStandardItem *)));
|
||||
connect(pushNew, SIGNAL(clicked()), this, SLOT(onnew()));
|
||||
connect(pushEdit, SIGNAL(clicked()), this, SLOT(onedit()));
|
||||
connect(pushDelete, SIGNAL(clicked()), this, SLOT(ondelete()));
|
||||
connect(treeView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(treeViewClicked(const QModelIndex&)));
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(onaccepted()));
|
||||
|
||||
// If a rom is loaded, prevent editing of cheats (causes a SIGSEGV)
|
||||
if (core::ROM_HEADER) {
|
||||
pushNew->setEnabled(false);
|
||||
pushEdit->setEnabled(false);
|
||||
pushDelete->setEnabled(false);
|
||||
} else {
|
||||
pushNew->setEnabled(true);
|
||||
pushEdit->setEnabled(true);
|
||||
pushDelete->setEnabled(true);
|
||||
}
|
||||
|
||||
core::list_t node1 = 0;
|
||||
core::list_t node2 = 0;
|
||||
|
||||
QMap<QString, QStandardItem*> itemMap;
|
||||
|
||||
m_cheats = core::cheats_for_current_rom();
|
||||
if (m_cheats) {
|
||||
setWindowTitle(tr("%1 - Cheats").arg(core::ROM_SETTINGS.goodname));
|
||||
list_foreach(m_cheats, node1) {
|
||||
core::cheat_t* cheat = static_cast<core::cheat_t*>(node1->data);
|
||||
QStandardItem* entry = 0;
|
||||
if (QString(cheat->name).contains("\\")) {
|
||||
QStringList parts = QString(cheat->name).split("\\");
|
||||
QStandardItem* parent = 0;
|
||||
int name_index = parts.size()-1;
|
||||
QString itemMapIndex = "";
|
||||
|
||||
for (int lvl = 0;lvl < name_index;lvl++) {
|
||||
itemMapIndex = QString(itemMapIndex + parts.at(lvl));
|
||||
if (itemMap.contains(itemMapIndex)) {
|
||||
parent = itemMap.value(itemMapIndex);
|
||||
} else {
|
||||
entry = new QStandardItem(parts.at(lvl));
|
||||
if (lvl == 0) {
|
||||
m_model->appendRow(entry);
|
||||
} else {
|
||||
parent->appendRow(entry);
|
||||
}
|
||||
parent = entry;
|
||||
itemMap[itemMapIndex] = parent;
|
||||
}
|
||||
}
|
||||
|
||||
// The last string in the list should be the cheat name.
|
||||
entry = createItemForCheat(parts.at(name_index), cheat);
|
||||
parent->appendRow(entry);
|
||||
} else {
|
||||
entry = createItemForCheat(cheat->name, cheat);
|
||||
m_model->appendRow(entry);
|
||||
}
|
||||
if (entry && cheat->options) {
|
||||
list_foreach(cheat->options, node2) {
|
||||
core::cheat_option_t* option = 0;
|
||||
QStandardItem* optionItem = 0;
|
||||
|
||||
option = static_cast<core::cheat_option_t*>(node2->data);
|
||||
optionItem = new QStandardItem(tr("%1 (Option)").arg(option->description));
|
||||
optionItem->setEditable(false);
|
||||
optionItem->setCheckable(true);
|
||||
optionItem->setData(QVariant::fromValue(option->code), CheatOptionRole);
|
||||
entry->appendRow(optionItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adding cheats from cheats.cfg.
|
||||
// Only add if emulator is not running. If emulator is running they will be
|
||||
// added to the 'cheat_load_current_rom'. Only for editing!
|
||||
if (!core::ROM_HEADER) {
|
||||
personal = new QStandardItem(tr("Personal Cheats"));
|
||||
m_model->appendRow(personal);
|
||||
|
||||
// populate model
|
||||
core::list_node_t* romnode;
|
||||
core::list_node_t* cheatnode;
|
||||
core::rom_cheats_t* romcheat;
|
||||
core::cheat_t* cheat;
|
||||
|
||||
list_foreach(core::g_Cheats, romnode) {
|
||||
QStandardItem* newrom = 0;
|
||||
|
||||
romcheat = (core::rom_cheats_t *)romnode->data;
|
||||
newrom = new QStandardItem(romcheat->rom_name);
|
||||
newrom->setData(QVariant::fromValue(romcheat), RomRole);
|
||||
personal->appendRow(newrom);
|
||||
|
||||
list_foreach(romcheat->cheats, cheatnode)
|
||||
{
|
||||
cheat = (core::cheat_t *)cheatnode->data;
|
||||
|
||||
QStandardItem * newitem;
|
||||
newitem = createItemForCheat(cheat->name, cheat);
|
||||
newitem->setData(QVariant::fromValue(cheat), CheatRole);
|
||||
newrom->appendRow(newitem);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_model->sort(0);
|
||||
treeView->setModel(m_model);
|
||||
}
|
||||
|
||||
CheatDialog::~CheatDialog()
|
||||
{
|
||||
cheats_free(&m_cheats);
|
||||
}
|
||||
|
||||
QStandardItem* CheatDialog::createItemForCheat(QString name,
|
||||
core::cheat_t* cheat)
|
||||
{
|
||||
QStandardItem* item = new QStandardItem(name);
|
||||
if (!cheat->options) {
|
||||
item->setCheckable(true);
|
||||
}
|
||||
item->setEditable(false);
|
||||
item->setData(QVariant::fromValue(cheat), CheatRole);
|
||||
item->setToolTip(QString(cheat->comment));
|
||||
return item;
|
||||
}
|
||||
|
||||
void CheatDialog::cheatItemChanged(QStandardItem* item)
|
||||
{
|
||||
core::cheat_t* cheat = 0;
|
||||
core::cheat_code_t* cheatcode = 0;
|
||||
core::list_t node = 0;
|
||||
QVariant codeVariant = item->data(CheatOptionRole);
|
||||
int code = codeVariant.isValid() ? codeVariant.value<int>() : -1;
|
||||
|
||||
if (code >= 0) {
|
||||
cheat = item->parent()->data(CheatRole).value<core::cheat_t*>();
|
||||
} else {
|
||||
cheat = item->data(CheatRole).value<core::cheat_t*>();
|
||||
}
|
||||
|
||||
Q_ASSERT(item->checkState() != Qt::PartiallyChecked);
|
||||
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
if (code >= 0) {
|
||||
// Only one option can be selected at a time.
|
||||
// Deselect all other options
|
||||
QStandardItem* parent = item->parent();
|
||||
for (int i = 0; i < parent->rowCount(); i++) {
|
||||
if (parent->child(i) != item) {
|
||||
parent->child(i)->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cheat) {
|
||||
cheat->enabled = 1;
|
||||
if (code>=0) {
|
||||
list_foreach(cheat->cheat_codes, node) {
|
||||
cheatcode = (core::cheat_code_t *)node->data;
|
||||
// If this is an option to set, search for a code which is supposed
|
||||
// to be patched with the new codes
|
||||
if (cheatcode->option) {
|
||||
cheatcode->value = code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (item->checkState() == Qt::Unchecked) {
|
||||
if (cheat) {
|
||||
cheat->enabled = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheatDialog::onnew()
|
||||
{
|
||||
QStandardItem* item = 0;
|
||||
QStandardItem* newitem = 0;
|
||||
core::cheat_t* cheat = NULL;
|
||||
core::rom_cheats_t* romcheat = NULL;
|
||||
|
||||
const QModelIndex& index = treeView->selectionModel()->currentIndex();
|
||||
if (index.isValid()) {
|
||||
item = m_model->itemFromIndex(index);
|
||||
romcheat = item->data(RomRole).value<core::rom_cheats_t*>();
|
||||
}
|
||||
|
||||
// If a rom is selected, make new cheat
|
||||
if (romcheat) {
|
||||
cheat = core::cheat_new_cheat(romcheat);
|
||||
CheatCheatDialog* d = new CheatCheatDialog(cheat,this);
|
||||
if (d->exec()) {
|
||||
newitem = createItemForCheat(cheat->name, cheat);
|
||||
newitem->setData(QVariant::fromValue(cheat), CheatRole);
|
||||
item->appendRow(newitem);
|
||||
}
|
||||
else {
|
||||
// delete newly created cheat if the user click cancel
|
||||
cheat_delete_cheat(romcheat, cheat);
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
// otherwise add a new rom
|
||||
else {
|
||||
romcheat = core::cheat_new_rom();
|
||||
romcheat->rom_name = NULL;
|
||||
CheatRomDialog* d = new CheatRomDialog(romcheat,this);
|
||||
if (d->exec()) {
|
||||
// add new rom to tree model
|
||||
QStandardItem* newrom = 0;
|
||||
newrom = new QStandardItem(romcheat->rom_name);
|
||||
newrom->setData(QVariant::fromValue(romcheat), RomRole);
|
||||
personal->appendRow(newrom);
|
||||
}
|
||||
else {
|
||||
cheat_delete_rom(romcheat);
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
}
|
||||
|
||||
void CheatDialog::onedit()
|
||||
{
|
||||
core::cheat_t* cheat = NULL;
|
||||
core::rom_cheats_t* romcheat = NULL;
|
||||
QStandardItem* item;
|
||||
|
||||
const QModelIndex& index = treeView->selectionModel()->currentIndex();
|
||||
if (index.isValid()) {
|
||||
item = m_model->itemFromIndex(index);
|
||||
romcheat = item->data(RomRole).value<core::rom_cheats_t*>();
|
||||
cheat = item->data(CheatRole).value<core::cheat_t*>();
|
||||
if (romcheat) {
|
||||
CheatRomDialog* d = new CheatRomDialog(romcheat,this);
|
||||
if (d->exec()) {
|
||||
// Reset the rom name in case it was changed
|
||||
item->setText(tr("%1").arg(romcheat->rom_name));
|
||||
}
|
||||
} else if (cheat) {
|
||||
CheatCheatDialog* d = new CheatCheatDialog(cheat,this);
|
||||
if (d->exec()) {
|
||||
// Reset the cheat name in case it was changed
|
||||
item->setText(tr("%1").arg(cheat->name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheatDialog::ondelete()
|
||||
{
|
||||
core::rom_cheats_t* romcheat = NULL;
|
||||
core::cheat_t* cheat = NULL;
|
||||
QStandardItem* romitem = 0;
|
||||
QStandardItem* cheatitem = 0;
|
||||
const QModelIndex& index = treeView->selectionModel()->currentIndex();
|
||||
const QModelIndex& parent = index.parent();
|
||||
|
||||
if (parent.isValid()) {
|
||||
if (index.isValid()) {
|
||||
romitem = m_model->itemFromIndex(index);
|
||||
romcheat = romitem->data(RomRole).value<core::rom_cheats_t*>();
|
||||
if (romcheat) {
|
||||
core::cheat_delete_rom(romcheat);
|
||||
m_model->removeRow(index.row(), parent);
|
||||
} else {
|
||||
romitem = m_model->itemFromIndex(parent);
|
||||
cheatitem = m_model->itemFromIndex(index);
|
||||
romcheat = romitem->data(RomRole).value<core::rom_cheats_t*>();
|
||||
cheat = cheatitem->data(CheatRole).value<core::cheat_t*>();
|
||||
if (romcheat && cheat) {
|
||||
core::cheat_delete_cheat(romcheat, cheat);
|
||||
m_model->removeRow(index.row(), parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheatDialog::treeViewClicked(const QModelIndex& index)
|
||||
{
|
||||
core::cheat_t* cheat;
|
||||
|
||||
cheat = m_model->itemFromIndex(index)->data(CheatRole).value<core::cheat_t*>();
|
||||
if (cheat) {
|
||||
textDescription->setPlainText(QString(cheat->comment));
|
||||
}
|
||||
}
|
||||
|
||||
void CheatDialog::onaccepted()
|
||||
{
|
||||
core::cheat_write_config();
|
||||
}
|
||||
|
64
main/gui_qt4/cheatdialog.h
Normal file
64
main/gui_qt4/cheatdialog.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* Mupen64 - cheatdialog.h
|
||||
* Copyright (C) 2008 slougi
|
||||
*
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/
|
||||
* or modify it under the terms of the GNU General Public Li-
|
||||
* cence as published by the Free Software Foundation; either
|
||||
* version 2 of the Licence, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be use-
|
||||
* ful, but WITHOUT ANY WARRANTY; without even the implied war-
|
||||
* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* Licence along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
||||
* USA.
|
||||
**/
|
||||
|
||||
#ifndef CHEATDIALOG_H
|
||||
#define CHEATDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "ui_cheatdialog.h"
|
||||
|
||||
class QStandardItem;
|
||||
class QStandardItemModel;
|
||||
namespace core {
|
||||
extern "C" {
|
||||
#include "../cheat.h"
|
||||
#include "../rom.h"
|
||||
}
|
||||
}
|
||||
Q_DECLARE_METATYPE(core::cheat_t*)
|
||||
Q_DECLARE_METATYPE(core::cheat_code_t*)
|
||||
Q_DECLARE_METATYPE(core::rom_cheats_t*)
|
||||
|
||||
class CheatDialog : public QDialog, private Ui_CheatDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CheatDialog(QWidget* parent = 0);
|
||||
virtual ~CheatDialog();
|
||||
enum { CheatRole = Qt::UserRole + 1, CheatOptionRole, RomRole, CheatCodeRole };
|
||||
|
||||
private slots:
|
||||
void cheatItemChanged(QStandardItem *item);
|
||||
void onnew();
|
||||
void onedit();
|
||||
void ondelete();
|
||||
void treeViewClicked(const QModelIndex& index);
|
||||
void onaccepted();
|
||||
|
||||
private:
|
||||
core::list_t m_cheats;
|
||||
QStandardItemModel* m_model;
|
||||
QStandardItem* createItemForCheat(QString name, core::cheat_t* cheat);
|
||||
QStandardItem* personal;
|
||||
};
|
||||
|
||||
#endif // CHEATDIALOG_H
|
120
main/gui_qt4/cheatdialog.ui
Normal file
120
main/gui_qt4/cheatdialog.ui
Normal file
|
@ -0,0 +1,120 @@
|
|||
<ui version="4.0" >
|
||||
<class>CheatDialog</class>
|
||||
<widget class="QDialog" name="CheatDialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>611</width>
|
||||
<height>634</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Cheats</string>
|
||||
</property>
|
||||
<property name="sizeGripEnabled" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3" >
|
||||
<item row="0" column="0" >
|
||||
<layout class="QGridLayout" name="gridLayout_2" >
|
||||
<item row="2" column="3" >
|
||||
<widget class="QPushButton" name="pushDelete" >
|
||||
<property name="text" >
|
||||
<string>&Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4" >
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="5" >
|
||||
<widget class="QTextEdit" name="textDescription" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>70</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="5" >
|
||||
<widget class="QTreeView" name="treeView" >
|
||||
<property name="animated" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="headerHidden" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QPushButton" name="pushNew" >
|
||||
<property name="text" >
|
||||
<string>&New</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" >
|
||||
<widget class="QPushButton" name="pushEdit" >
|
||||
<property name="text" >
|
||||
<string>&Edit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>CheatDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>CheatDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
60
main/gui_qt4/cheatromdialog.cpp
Normal file
60
main/gui_qt4/cheatromdialog.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - cheatromdialog.cpp *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 olejl *
|
||||
* *
|
||||
* This program 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 Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <QtGui>
|
||||
|
||||
#include "cheatromdialog.h"
|
||||
|
||||
CheatRomDialog::CheatRomDialog(core::rom_cheats_t *rom, QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
// Use this as our internal pointer to the cheat we are working on.
|
||||
// To make it accessable for other than only constructor
|
||||
_rom = rom;
|
||||
if (_rom->rom_name) {
|
||||
lineEditName->setText(QString(_rom->rom_name));
|
||||
lineEditCRC1->setText(QString("%1").arg(_rom->crc1, 8, 16, QChar('0')).toUpper());
|
||||
lineEditCRC2->setText(QString("%1").arg(_rom->crc2, 8, 16, QChar('0')).toUpper());
|
||||
}
|
||||
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(onaccepted()));
|
||||
}
|
||||
|
||||
CheatRomDialog::~CheatRomDialog()
|
||||
{
|
||||
// TODO: destructor
|
||||
}
|
||||
|
||||
void CheatRomDialog::onaccepted()
|
||||
{
|
||||
bool *ok = NULL;
|
||||
int size;
|
||||
|
||||
QByteArray arr = lineEditName->text().toLatin1();
|
||||
size = arr.size() + 1;
|
||||
_rom->rom_name = (char*) malloc(size);
|
||||
if (_rom->rom_name==NULL) return; // TODO: proper error handling?
|
||||
memset(_rom->rom_name, '\0', size);
|
||||
strcpy(_rom->rom_name, arr.data());
|
||||
_rom->crc1 = QString(lineEditCRC1->text()).toUInt(ok,16);
|
||||
_rom->crc2 = QString(lineEditCRC2->text()).toUInt(ok,16);
|
||||
}
|
||||
|
49
main/gui_qt4/cheatromdialog.h
Normal file
49
main/gui_qt4/cheatromdialog.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - cheatromdialog.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 olejl *
|
||||
* *
|
||||
* This program 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 Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef CHEATROMDIALOG_H
|
||||
#define CHEATROMDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "ui_cheatromdialog.h"
|
||||
|
||||
namespace core {
|
||||
extern "C" {
|
||||
#include "../cheat.h"
|
||||
}
|
||||
}
|
||||
|
||||
class CheatRomDialog : public QDialog, private Ui_CheatRomDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CheatRomDialog(core::rom_cheats_t *, QWidget* parent = 0);
|
||||
virtual ~CheatRomDialog();
|
||||
|
||||
private slots:
|
||||
void onaccepted();
|
||||
|
||||
private:
|
||||
core::rom_cheats_t *_rom;
|
||||
|
||||
};
|
||||
|
||||
#endif // CHEATROMDIALOG_H
|
90
main/gui_qt4/cheatromdialog.ui
Normal file
90
main/gui_qt4/cheatromdialog.ui
Normal file
|
@ -0,0 +1,90 @@
|
|||
<ui version="4.0" >
|
||||
<class>CheatRomDialog</class>
|
||||
<widget class="QDialog" name="CheatRomDialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>302</width>
|
||||
<height>107</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>New Rom</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2" >
|
||||
<item row="0" column="0" >
|
||||
<layout class="QGridLayout" name="gridLayout" >
|
||||
<item row="0" column="1" colspan="2" >
|
||||
<widget class="QLineEdit" name="lineEditName" />
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="lineEditCRC1" />
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QLineEdit" name="lineEditCRC2" />
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3" >
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="labelCRC" >
|
||||
<property name="text" >
|
||||
<string>Rom CRC:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="labelName" >
|
||||
<property name="text" >
|
||||
<string>Rom Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>CheatRomDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>CheatRomDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -40,6 +40,9 @@ HEADERS += globals.h \
|
|||
rommodel.h \
|
||||
settingsdialog.h \
|
||||
starlabel.h \
|
||||
cheatdialog.h \
|
||||
cheatromdialog.h \
|
||||
cheatcheatdialog.h \
|
||||
../config.h \
|
||||
../main.h \
|
||||
../version.h \
|
||||
|
@ -62,7 +65,10 @@ FORMS += mainwidget.ui \
|
|||
mainwindow.ui \
|
||||
romdirectorieslistwidget.ui \
|
||||
rominfodialog.ui \
|
||||
settingsdialog.ui
|
||||
settingsdialog.ui \
|
||||
cheatdialog.ui \
|
||||
cheatcheatdialog.ui \
|
||||
cheatromdialog.ui
|
||||
SOURCES += globals.cpp \
|
||||
main.cpp \
|
||||
mainwidget.cpp \
|
||||
|
@ -73,4 +79,8 @@ SOURCES += globals.cpp \
|
|||
rommodel.cpp \
|
||||
settingsdialog.cpp \
|
||||
starlabel.cpp \
|
||||
cheatdialog.cpp \
|
||||
cheatcheatdialog.cpp \
|
||||
cheatromdialog.cpp \
|
||||
translate.cpp
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "globals.h"
|
||||
#include "rommodel.h"
|
||||
#include "settingsdialog.h"
|
||||
#include "cheatdialog.h"
|
||||
|
||||
#include <SDL_video.h>
|
||||
|
||||
|
@ -348,6 +349,12 @@ void MainWindow::emulationStop()
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::showCheatDialog()
|
||||
{
|
||||
CheatDialog* d = new CheatDialog(this);
|
||||
d->show();
|
||||
}
|
||||
|
||||
void MainWindow::fullScreenToggle()
|
||||
{
|
||||
if (core::g_EmulatorRunning) {
|
||||
|
@ -518,6 +525,11 @@ void MainWindow::setupActions()
|
|||
this, SLOT(emulationPauseContinue()));
|
||||
actionStop->setIcon(icon("media-playback-stop.png"));
|
||||
connect(actionStop, SIGNAL(triggered()), this, SLOT(emulationStop()));
|
||||
|
||||
actionCheats->setIcon(icon("tools-wizard.png"));
|
||||
connect(actionCheats, SIGNAL(triggered()),
|
||||
this, SLOT(showCheatDialog()));
|
||||
|
||||
actionSaveState->setIcon(icon("document-save.png"));
|
||||
connect(actionSaveState, SIGNAL(triggered()),
|
||||
this, SLOT(saveStateSave()));
|
||||
|
|
|
@ -124,6 +124,7 @@ class MainWindow : public QMainWindow, public Ui_MainWindow
|
|||
void emulationStart();
|
||||
void emulationPauseContinue();
|
||||
void emulationStop();
|
||||
void showCheatDialog();
|
||||
void saveStateSave();
|
||||
void saveStateSaveAs();
|
||||
void saveStateProject64SaveAs();
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
<addaction name="actionLoadState" />
|
||||
<addaction name="actionLoadStateFrom" />
|
||||
<addaction name="separator" />
|
||||
<addaction name="actionCheats" />
|
||||
<addaction name="separator" />
|
||||
<addaction name="actionCurrentSaveStateSlot" />
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_Settings" >
|
||||
|
@ -258,6 +260,11 @@
|
|||
<string>Save P&roject64 State as...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCheats" >
|
||||
<property name="text" >
|
||||
<string>Ch&eats</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
193
main/ini_reader.c
Normal file
193
main/ini_reader.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - ini_reader.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2008 slougi *
|
||||
* *
|
||||
* This program 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 Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ini_reader.h"
|
||||
|
||||
#define BUF_MAX 4096
|
||||
|
||||
static int iscomment(char *line);
|
||||
static ini_entry *parse_entry(char *line);
|
||||
static ini_section *parse_section(char *line);
|
||||
static void dump_entries(ini_section *s, list_t entries);
|
||||
static void dump_sections(ini_file* ini, list_t sections);
|
||||
|
||||
static ini_entry *parse_entry(char *line)
|
||||
{
|
||||
int i;
|
||||
char *equals_sign = NULL;
|
||||
ini_entry *entry = NULL;
|
||||
|
||||
char key[BUF_MAX];
|
||||
char value[BUF_MAX];
|
||||
|
||||
memset(key, '\0', BUF_MAX);
|
||||
memset(value, '\0', BUF_MAX);
|
||||
|
||||
if ((equals_sign = strstr(line, "=")) != NULL)
|
||||
{
|
||||
entry = malloc(sizeof(ini_entry));
|
||||
for (i = 0; line != equals_sign; i++, line++)
|
||||
{
|
||||
key[i] = *line;
|
||||
}
|
||||
line = equals_sign + 1;
|
||||
strncpy(value, line, BUF_MAX);
|
||||
|
||||
trim(key);
|
||||
entry->key = malloc(strlen(key) + 1);
|
||||
strcpy(entry->key, key);
|
||||
|
||||
trim(value);
|
||||
entry->value = malloc(strlen(value) + 1);
|
||||
strcpy(entry->value, value);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static ini_section *parse_section(char *line)
|
||||
{
|
||||
int i = 0;
|
||||
char buf[BUF_MAX];
|
||||
char *opening_bracket = NULL;
|
||||
char *closing_bracket = NULL;
|
||||
ini_section *section = NULL;
|
||||
|
||||
memset(buf, '\0', BUF_MAX);
|
||||
|
||||
if ((opening_bracket = strstr(line, "[")) == line)
|
||||
{
|
||||
if ((closing_bracket = strstr(line, "]")) != NULL)
|
||||
{
|
||||
while (++opening_bracket != closing_bracket)
|
||||
{
|
||||
buf[i++] = *opening_bracket;
|
||||
}
|
||||
section = malloc(sizeof(ini_section));
|
||||
section->title = malloc(strlen(buf) + 1);
|
||||
strcpy(section->title, buf);
|
||||
section->entries = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
static int iscomment(char *line)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (strstr(line, "//") == line)
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
else if (strstr(line, "#") == line)
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ini_file* ini_file_parse(const char* filename)
|
||||
{
|
||||
int i = 0;
|
||||
ini_file *res = NULL;
|
||||
list_t sections = NULL;
|
||||
ini_entry* entry = NULL;
|
||||
ini_section* section = NULL;
|
||||
FILE *fp = fopen(filename, "r");
|
||||
char buf[BUF_MAX];
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (fgets(buf, BUF_MAX, fp)) {
|
||||
i++;
|
||||
|
||||
trim(buf);
|
||||
if (strlen(buf) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((section = parse_section(buf)))
|
||||
{
|
||||
list_append(§ions, section);
|
||||
}
|
||||
else if ((entry = parse_entry(buf)))
|
||||
{
|
||||
section = list_last_data(sections);
|
||||
if (section) {
|
||||
list_append(§ion->entries, entry);
|
||||
}
|
||||
}
|
||||
else if (iscomment(buf))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Couldn't parse line %d in file %s: %s", i, filename, buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!list_empty(sections))
|
||||
{
|
||||
res = malloc(sizeof(ini_file));
|
||||
res->filename = malloc(strlen(filename) + 1);
|
||||
strcpy(res->filename, filename);
|
||||
res->sections = sections;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return res;
|
||||
}
|
||||
|
||||
void ini_file_free(ini_file **ini)
|
||||
{
|
||||
list_t p1, p2;
|
||||
ini_section* section;
|
||||
ini_entry* entry;
|
||||
|
||||
free((*ini)->filename);
|
||||
|
||||
list_foreach((*ini)->sections, p1)
|
||||
{
|
||||
section = p1->data;
|
||||
free(section->title);
|
||||
list_foreach(section->entries, p2)
|
||||
{
|
||||
entry = p2->data;
|
||||
free(entry->key);
|
||||
free(entry->value);
|
||||
}
|
||||
}
|
||||
free(*ini);
|
||||
*ini = 0;
|
||||
}
|
||||
|
45
main/ini_reader.h
Normal file
45
main/ini_reader.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - ini_reader.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2008 slougi *
|
||||
* *
|
||||
* This program 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 Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef INI_READER_H
|
||||
#define INI_READER_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
typedef struct _ini_entry {
|
||||
char *key;
|
||||
char *value;
|
||||
} ini_entry;
|
||||
|
||||
typedef struct _ini_section {
|
||||
char *title;
|
||||
list_t entries;
|
||||
} ini_section;
|
||||
|
||||
typedef struct _ini_file {
|
||||
char *filename;
|
||||
list_t sections;
|
||||
} ini_file;
|
||||
|
||||
ini_file* ini_file_parse(const char* filename);
|
||||
void ini_file_free(ini_file** ini);
|
||||
|
||||
#endif // INI_READER_H
|
|
@ -929,6 +929,7 @@ static int emulationThread( void *_arg )
|
|||
osd_exit();
|
||||
}
|
||||
|
||||
cheat_unload_current_rom();
|
||||
romClosed_RSP();
|
||||
romClosed_input();
|
||||
romClosed_audio();
|
||||
|
@ -1554,7 +1555,13 @@ int main(int argc, char *argv[])
|
|||
|
||||
// cleanup and exit
|
||||
config_write();
|
||||
cheat_write_config();
|
||||
|
||||
/** Disabling as it seems to be causing some problems
|
||||
* Maybe some of the "objects are already deleted?
|
||||
* Is it required? Cheats should be saved when clicking OK in
|
||||
* The cheats dialog.
|
||||
**/
|
||||
// cheat_write_config();
|
||||
cheat_delete_all();
|
||||
#ifndef NO_GUI
|
||||
g_romcache.rcstask = RCS_SHUTDOWN;
|
||||
|
|
22
main/util.c
22
main/util.c
|
@ -735,5 +735,27 @@ char* dirfrompath(const char* string)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
list_t tokenize_string(const char *string, const char* delim)
|
||||
{
|
||||
list_t list = NULL;
|
||||
char *token = NULL, *wrk = NULL;
|
||||
char buf[4096]; // some of those strings are really long
|
||||
strncpy(buf, string, 4096);
|
||||
|
||||
token = strtok(buf, delim);
|
||||
if (token)
|
||||
{
|
||||
wrk = malloc(strlen(token) + 1);
|
||||
strcpy(wrk, token);
|
||||
list_append(&list, wrk);
|
||||
}
|
||||
|
||||
while ((token = strtok(NULL, delim)))
|
||||
{
|
||||
wrk = malloc(strlen(token) + 1);
|
||||
strcpy(wrk, token);
|
||||
list_append(&list, wrk);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
|
10
main/util.h
10
main/util.h
|
@ -28,10 +28,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** string utilities **/
|
||||
char *trim(char *str);
|
||||
char *strnstrip(char* string, int size);
|
||||
char *event_to_str(const SDL_Event *event);
|
||||
int event_active(const char *event_str);
|
||||
int key_pressed(SDLKey k);
|
||||
|
||||
|
@ -79,6 +75,12 @@ void playersstring(unsigned char players, char *string);
|
|||
#define list_foreach(list, curr_node) \
|
||||
for((curr_node) = (list); (curr_node) != NULL; (curr_node) = (curr_node)->next)
|
||||
|
||||
/** string utilities **/
|
||||
char *trim(char *str);
|
||||
char *strnstrip(char* string, int size);
|
||||
char *event_to_str(const SDL_Event *event);
|
||||
list_t tokenize_string(const char *string, const char* delim);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
15366
mupen64plus.cht
Normal file
15366
mupen64plus.cht
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue