mirror of https://github.com/bsnes-emu/bsnes.git
Update to v076r01 release.
byuu says: Changelog: - fixed linear mirroring issue in memory map (fixes dash in Mega Man X) - home path for Windows is now %APPDATA%/bsnes (not %APPDATA%/.bsnes) - home path for OS X and Linux is now ~/.config/bsnes (not ~/.bsnes) - bsnes-geometry.cfg is now geometry.cfg; and it stores width,height - I do not yet restore width, height; because the GTK+ and Qt APIs treat window resize as implying setMinimumSize - added bsnes/ui/path; which I have some significant plans for - fixed a bug in realpath (specified path is not always a folder, so we should not always append / as with userpath) - bsnes.cfg, geometry.cfg and cheats.xml may now optionally exist in the same folder as the binary itself - ruby only imports the nall namespace after including system headers (should fix OS X 'decimal' issue) - nall::fp now uses atof (fixes nall::fp("0.05")) - I split the CheatDatabase to a separate cheat-database.cpp file; it was pretty ugly packed into cheat-editor.cpp - Makefile now has "options := " line; where you can add "debugger" if you like, and in the future maybe more options - also works via command-line: make options=debugger
This commit is contained in:
parent
64072325c4
commit
bc5fd8c53c
|
@ -1,9 +1,12 @@
|
||||||
include nall/Makefile
|
include nall/Makefile
|
||||||
snes := snes
|
snes := snes
|
||||||
gameboy := gameboy
|
gameboy := gameboy
|
||||||
profile := accuracy
|
profile := compatibility
|
||||||
ui := ui
|
ui := ui
|
||||||
|
|
||||||
|
# debugger
|
||||||
|
options :=
|
||||||
|
|
||||||
# compiler
|
# compiler
|
||||||
c := $(compiler) -std=gnu99
|
c := $(compiler) -std=gnu99
|
||||||
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
||||||
|
@ -18,9 +21,11 @@ objects := libco
|
||||||
# profile-guided optimization
|
# profile-guided optimization
|
||||||
# flags += -fprofile-use
|
# flags += -fprofile-use
|
||||||
|
|
||||||
|
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
|
||||||
|
|
||||||
# platform
|
# platform
|
||||||
ifeq ($(platform),x)
|
ifeq ($(platform),x)
|
||||||
link += -s -ldl -lX11 -lXext
|
link += -ldl -lX11 -lXext
|
||||||
else ifeq ($(platform),osx)
|
else ifeq ($(platform),osx)
|
||||||
else ifeq ($(platform),win)
|
else ifeq ($(platform),win)
|
||||||
link += -mwindows
|
link += -mwindows
|
||||||
|
|
|
@ -117,38 +117,7 @@ uintmax_t binary(const char *str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
double fp(const char *str) {
|
double fp(const char *str) {
|
||||||
if(!str) return 0.0;
|
return atof(str);
|
||||||
bool negate = false;
|
|
||||||
|
|
||||||
//check for negation
|
|
||||||
if(*str == '-') {
|
|
||||||
negate = true;
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
|
|
||||||
intmax_t result_integral = 0;
|
|
||||||
while(*str) {
|
|
||||||
uint8_t x = *str++;
|
|
||||||
if(x >= '0' && x <= '9') x -= '0';
|
|
||||||
else if(x == '.' || x == ',') break; //break loop and read fractional part
|
|
||||||
else return (double)result_integral; //invalid value, assume no fractional part
|
|
||||||
result_integral = result_integral * 10 + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
intmax_t result_fractional = 0;
|
|
||||||
while(*str) {
|
|
||||||
uint8_t x = *str++;
|
|
||||||
if(x >= '0' && x <= '9') x -= '0';
|
|
||||||
else break; //stop at first invalid character
|
|
||||||
result_fractional = result_fractional * 10 + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
//calculate fractional portion
|
|
||||||
double result = (double)result_fractional;
|
|
||||||
while((uintmax_t)result > 0) result /= 10.0;
|
|
||||||
result += (double)result_integral;
|
|
||||||
|
|
||||||
return !negate ? result : -result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ string realpath(const char *name) {
|
||||||
if(::realpath(name, path)) {
|
if(::realpath(name, path)) {
|
||||||
string result(path);
|
string result(path);
|
||||||
result.transform("\\", "/");
|
result.transform("\\", "/");
|
||||||
if(result.endswith("/") == false) result.append("/");
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include <ruby/ruby.hpp>
|
#include <ruby/ruby.hpp>
|
||||||
using namespace nall;
|
|
||||||
|
|
||||||
#undef mkdir
|
#undef mkdir
|
||||||
#undef usleep
|
#undef usleep
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
ruby
|
ruby
|
||||||
version: 0.06 (2009-05-22)
|
version: 0.06a (2011-02-27)
|
||||||
license: public domain
|
license: public domain
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace nall;
|
||||||
|
|
||||||
/* Video */
|
/* Video */
|
||||||
|
|
||||||
#define DeclareVideo(Name) \
|
#define DeclareVideo(Name) \
|
||||||
|
|
|
@ -44,12 +44,8 @@ void Bus::map(
|
||||||
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
|
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
|
||||||
for(unsigned addr = addr_lo; addr <= addr_hi; addr++) {
|
for(unsigned addr = addr_lo; addr <= addr_hi; addr++) {
|
||||||
unsigned destaddr = (bank << 16) | addr;
|
unsigned destaddr = (bank << 16) | addr;
|
||||||
if(mode == MapMode::Linear) {
|
if(mode == MapMode::Linear) destaddr = mirror(base + offset++, length);
|
||||||
destaddr = mirror(base + offset, length);
|
if(mode == MapMode::Shadow) destaddr = mirror(base + destaddr, length);
|
||||||
offset = (offset + 1) % length;
|
|
||||||
} else if(mode == MapMode::Shadow) {
|
|
||||||
destaddr = mirror(base + destaddr, length);
|
|
||||||
}
|
|
||||||
lookup[(bank << 16) | addr] = id;
|
lookup[(bank << 16) | addr] = id;
|
||||||
target[(bank << 16) | addr] = destaddr;
|
target[(bank << 16) | addr] = destaddr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bsnes";
|
static const char Name[] = "bsnes";
|
||||||
static const char Version[] = "076";
|
static const char Version[] = "076.01";
|
||||||
static const unsigned SerializerVersion = 18;
|
static const unsigned SerializerVersion = 18;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//#define DEBUGGER
|
|
||||||
|
|
||||||
#include <libco/libco.h>
|
#include <libco/libco.h>
|
||||||
|
|
||||||
#include <nall/algorithm.hpp>
|
#include <nall/algorithm.hpp>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
include $(snes)/Makefile
|
include $(snes)/Makefile
|
||||||
include $(gameboy)/Makefile
|
include $(gameboy)/Makefile
|
||||||
|
|
||||||
ui_objects := ui-main ui-general ui-settings ui-tools ui-input ui-utility ui-cartridge ui-debugger
|
ui_objects := ui-main ui-general ui-settings ui-tools ui-input ui-utility ui-path ui-cartridge ui-debugger
|
||||||
ui_objects += ruby phoenix
|
ui_objects += ruby phoenix
|
||||||
ui_objects += $(if $(call streq,$(platform),win),resource)
|
ui_objects += $(if $(call streq,$(platform),win),resource)
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwild
|
||||||
obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/settings/*)
|
obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/settings/*)
|
||||||
obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/input/*)
|
obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/input/*)
|
||||||
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/utility/*)
|
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/utility/*)
|
||||||
|
obj/ui-path.o: $(ui)/path/path.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/path/*)
|
||||||
obj/ui-cartridge.o: $(ui)/cartridge/cartridge.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/cartridge/*)
|
obj/ui-cartridge.o: $(ui)/cartridge/cartridge.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/cartridge/*)
|
||||||
obj/ui-debugger.o: $(ui)/debugger/debugger.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/debugger/*)
|
obj/ui-debugger.o: $(ui)/debugger/debugger.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/debugger/*)
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ struct TopLevelWindow : Window {
|
||||||
#include "tools/tools.hpp"
|
#include "tools/tools.hpp"
|
||||||
#include "input/input.hpp"
|
#include "input/input.hpp"
|
||||||
#include "utility/utility.hpp"
|
#include "utility/utility.hpp"
|
||||||
|
#include "path/path.hpp"
|
||||||
#include "cartridge/cartridge.hpp"
|
#include "cartridge/cartridge.hpp"
|
||||||
|
|
||||||
#if defined(DEBUGGER)
|
#if defined(DEBUGGER)
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
Configuration config;
|
Configuration config;
|
||||||
|
|
||||||
void Configuration::load() {
|
void Configuration::load() {
|
||||||
configuration::load(string(path.user, "bsnes.cfg"));
|
configuration::load(::path.home("bsnes.cfg"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Configuration::save() {
|
void Configuration::save() {
|
||||||
mkdir(path.user, 0755);
|
configuration::save(::path.home("bsnes.cfg"));
|
||||||
configuration::save(string(path.user, "bsnes.cfg"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Configuration::create() {
|
void Configuration::create() {
|
||||||
|
|
|
@ -10,8 +10,8 @@ void Application::main(int argc, char **argv) {
|
||||||
config.create();
|
config.create();
|
||||||
inputMapper.create();
|
inputMapper.create();
|
||||||
|
|
||||||
config.path.base = realpath(argv[0]);
|
config.path.base = dir(realpath(argv[0]));
|
||||||
config.path.user = { userpath(), ".bsnes/" };
|
config.path.user = userpath();
|
||||||
|
|
||||||
config.load();
|
config.load();
|
||||||
config.save();
|
config.save();
|
||||||
|
@ -57,6 +57,7 @@ void Application::main(int argc, char **argv) {
|
||||||
inputSettings.create();
|
inputSettings.create();
|
||||||
advancedSettings.create();
|
advancedSettings.create();
|
||||||
cheatEditor.create();
|
cheatEditor.create();
|
||||||
|
cheatDatabase.create();
|
||||||
stateManager.create();
|
stateManager.create();
|
||||||
#if defined(DEBUGGER)
|
#if defined(DEBUGGER)
|
||||||
debugger.create();
|
debugger.create();
|
||||||
|
@ -158,19 +159,23 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::loadGeometry() {
|
void Application::loadGeometry() {
|
||||||
geometryConfig.load(string(config.path.user, "bsnes-geometry.cfg"));
|
geometryConfig.load(path.home("geometry.cfg"));
|
||||||
foreach(window, windows) {
|
foreach(window, windows) {
|
||||||
lstring position;
|
lstring position;
|
||||||
position.split(",", window->position);
|
position.split(",", window->position);
|
||||||
Geometry geom = window->geometry();
|
Geometry geom = window->geometry();
|
||||||
window->setGeometry({ (signed)integer(position[0]), (signed)integer(position[1]), geom.width, geom.height });
|
window->setGeometry({
|
||||||
|
(signed)integer(position[0]), (signed)integer(position[1]),
|
||||||
|
geom.width, geom.height
|
||||||
|
//(unsigned)decimal(position[2]), (unsigned)decimal(position[3])
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::saveGeometry() {
|
void Application::saveGeometry() {
|
||||||
foreach(window, windows) {
|
foreach(window, windows) {
|
||||||
Geometry geom = window->geometry();
|
Geometry geom = window->geometry();
|
||||||
window->position = { geom.x, ",", geom.y };
|
window->position = { geom.x, ",", geom.y, ",", geom.width, ",", geom.height };
|
||||||
}
|
}
|
||||||
geometryConfig.save(string(config.path.user, "bsnes-geometry.cfg"));
|
geometryConfig.save(path.home("geometry.cfg"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include "../base.hpp"
|
||||||
|
Path path;
|
||||||
|
|
||||||
|
string Path::home(const string &filename) {
|
||||||
|
string path = { config.path.base, filename };
|
||||||
|
if(file::exists(path)) return path;
|
||||||
|
|
||||||
|
path = config.path.user;
|
||||||
|
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
|
||||||
|
path.append(".config/");
|
||||||
|
mkdir(path, 0755);
|
||||||
|
path.append("bsnes/");
|
||||||
|
mkdir(path, 0755);
|
||||||
|
#else
|
||||||
|
path.append("bsnes/");
|
||||||
|
mkdir(path, 0755);
|
||||||
|
#endif
|
||||||
|
path.append(filename);
|
||||||
|
return path;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
struct Path {
|
||||||
|
string home(const string &filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Path path;
|
|
@ -0,0 +1,93 @@
|
||||||
|
CheatDatabase cheatDatabase;
|
||||||
|
|
||||||
|
void CheatDatabase::create() {
|
||||||
|
application.addWindow(this, "CheatDatabase", "192,192");
|
||||||
|
|
||||||
|
listView.setCheckable(true);
|
||||||
|
selectAllButton.setText("Select All");
|
||||||
|
unselectAllButton.setText("Unselect All");
|
||||||
|
okButton.setText("Ok");
|
||||||
|
|
||||||
|
layout.setMargin(5);
|
||||||
|
layout.append(listView, 0, 0, 5);
|
||||||
|
controlLayout.append(selectAllButton, 100, 0, 5);
|
||||||
|
controlLayout.append(unselectAllButton, 100, 0);
|
||||||
|
controlLayout.append(spacerWidget, 0, 0);
|
||||||
|
controlLayout.append(okButton, 80, 0);
|
||||||
|
layout.append(controlLayout, 0, Style::ButtonHeight);
|
||||||
|
setGeometry({ 0, 0, 600, layout.minimumHeight() + 350 });
|
||||||
|
append(layout);
|
||||||
|
|
||||||
|
selectAllButton.onTick = [this]() {
|
||||||
|
foreach(item, this->listData, n) this->listView.setChecked(n, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
unselectAllButton.onTick = [this]() {
|
||||||
|
foreach(item, this->listData, n) this->listView.setChecked(n, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
okButton.onTick = { &CheatDatabase::addCodes, this };
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheatDatabase::findCodes() {
|
||||||
|
string data;
|
||||||
|
data.readfile(path.home("cheats.xml"));
|
||||||
|
if(auto position = strpos(data, SNES::cartridge.sha256())) {
|
||||||
|
auto startPosition = strpos((const char*)data + position(), ">");
|
||||||
|
auto endPosition = strpos((const char*)data + position(), "</cartridge>");
|
||||||
|
string xmlData = {
|
||||||
|
"<cartridge>\n",
|
||||||
|
substr((const char*)data + position() + 1, startPosition(), endPosition() - startPosition() - 1),
|
||||||
|
"</cartridge>\n"
|
||||||
|
};
|
||||||
|
|
||||||
|
setTitle("");
|
||||||
|
listView.reset();
|
||||||
|
listData.reset();
|
||||||
|
|
||||||
|
xml_element document = xml_parse(xmlData);
|
||||||
|
foreach(root, document.element) {
|
||||||
|
if(root.name == "cartridge") foreach(node, root.element) {
|
||||||
|
if(node.name == "name") setTitle(node.parse());
|
||||||
|
else if(node.name == "cheat") {
|
||||||
|
string description, code;
|
||||||
|
foreach(element, node.element) {
|
||||||
|
if(element.name == "description") description = element.parse();
|
||||||
|
else if(element.name == "code") code.append(string(element.parse(), "+"));
|
||||||
|
}
|
||||||
|
code.rtrim<1>("+");
|
||||||
|
code.append("\t");
|
||||||
|
code.append(description);
|
||||||
|
listView.append(description);
|
||||||
|
listData.append(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setVisible(true);
|
||||||
|
} else {
|
||||||
|
MessageWindow::information(cheatEditor, "Sorry, no cheat codes found for this cartridge.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheatDatabase::addCodes() {
|
||||||
|
foreach(code, listData, n) {
|
||||||
|
if(listView.checked(n)) {
|
||||||
|
if(auto position = cheatEditor.findUnusedSlot()) {
|
||||||
|
lstring part;
|
||||||
|
part.split("\t", code);
|
||||||
|
SNES::cheat[position()].enabled = false;
|
||||||
|
SNES::cheat[position()] = part[0];
|
||||||
|
cheatEditor.cheatList.setChecked(position(), false);
|
||||||
|
cheatEditor.cheatText[position()][CheatEditor::CheatCode] = part[0];
|
||||||
|
cheatEditor.cheatText[position()][CheatEditor::CheatDesc] = part[1];
|
||||||
|
} else {
|
||||||
|
MessageWindow::warning(*this, "Ran out of empty slots for cheat codes.\nNot all cheat codes were added.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setVisible(false);
|
||||||
|
cheatEditor.refresh();
|
||||||
|
cheatEditor.synchronize();
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
struct CheatDatabase : TopLevelWindow {
|
||||||
|
VerticalLayout layout;
|
||||||
|
ListView listView;
|
||||||
|
HorizontalLayout controlLayout;
|
||||||
|
Button selectAllButton;
|
||||||
|
Button unselectAllButton;
|
||||||
|
Widget spacerWidget;
|
||||||
|
Button okButton;
|
||||||
|
lstring listData;
|
||||||
|
|
||||||
|
void create();
|
||||||
|
void findCodes();
|
||||||
|
void addCodes();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern CheatDatabase cheatDatabase;
|
|
@ -100,7 +100,7 @@ void CheatEditor::create() {
|
||||||
descLayout.append(descEdit, 0, 0);
|
descLayout.append(descEdit, 0, 0);
|
||||||
layout.append(descLayout, 0, Style::LineEditHeight, 5);
|
layout.append(descLayout, 0, Style::LineEditHeight, 5);
|
||||||
controlLayout.append(findButton, 100, 0);
|
controlLayout.append(findButton, 100, 0);
|
||||||
controlLayout.append(spacer, 0, 0);
|
controlLayout.append(spacerWidget, 0, 0);
|
||||||
controlLayout.append(clearAllButton, 80, 0, 5);
|
controlLayout.append(clearAllButton, 80, 0, 5);
|
||||||
controlLayout.append(clearButton, 80, 0);
|
controlLayout.append(clearButton, 80, 0);
|
||||||
layout.append(controlLayout, 0, Style::ButtonHeight);
|
layout.append(controlLayout, 0, Style::ButtonHeight);
|
||||||
|
@ -113,46 +113,13 @@ void CheatEditor::create() {
|
||||||
cheatList.onChange = { &CheatEditor::synchronize, this };
|
cheatList.onChange = { &CheatEditor::synchronize, this };
|
||||||
cheatList.onTick = { &CheatEditor::toggle, this };
|
cheatList.onTick = { &CheatEditor::toggle, this };
|
||||||
codeEdit.onChange = descEdit.onChange = { &CheatEditor::bind, this };
|
codeEdit.onChange = descEdit.onChange = { &CheatEditor::bind, this };
|
||||||
findButton.onTick = { &CheatEditor::findCodes, this };
|
findButton.onTick = { &CheatDatabase::findCodes, &cheatDatabase };
|
||||||
clearAllButton.onTick = { &CheatEditor::clearAll, this };
|
clearAllButton.onTick = { &CheatEditor::clearAll, this };
|
||||||
clearButton.onTick = { &CheatEditor::clear, this };
|
clearButton.onTick = { &CheatEditor::clear, this };
|
||||||
|
|
||||||
onClose = []() {
|
onClose = []() {
|
||||||
cheatEditor.databaseWindow.setVisible(false);
|
cheatDatabase.setVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
//databaseWindow
|
|
||||||
application.addWindow(&databaseWindow, "CheatDatabase", "192,192");
|
|
||||||
|
|
||||||
databaseList.setCheckable(true);
|
|
||||||
databaseSelectAll.setText("Select All");
|
|
||||||
databaseUnselectAll.setText("Unselect All");
|
|
||||||
databaseOk.setText("Ok");
|
|
||||||
|
|
||||||
databaseLayout.setMargin(5);
|
|
||||||
databaseLayout.append(databaseList, 0, 0, 5);
|
|
||||||
databaseControlLayout.append(databaseSelectAll, 100, 0, 5);
|
|
||||||
databaseControlLayout.append(databaseUnselectAll, 100, 0);
|
|
||||||
databaseControlLayout.append(databaseSpacer, 0, 0);
|
|
||||||
databaseControlLayout.append(databaseOk, 80, 0);
|
|
||||||
databaseLayout.append(databaseControlLayout, 0, Style::ButtonHeight);
|
|
||||||
|
|
||||||
databaseWindow.setGeometry({ 0, 0, 600, layout.minimumHeight() + 250 });
|
|
||||||
databaseWindow.append(databaseLayout);
|
|
||||||
|
|
||||||
databaseSelectAll.onTick = []() {
|
|
||||||
for(unsigned i = 0; i < cheatEditor.databaseCode.size(); i++) {
|
|
||||||
cheatEditor.databaseList.setChecked(i, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
databaseUnselectAll.onTick = []() {
|
|
||||||
for(unsigned i = 0; i < cheatEditor.databaseCode.size(); i++) {
|
|
||||||
cheatEditor.databaseList.setChecked(i, false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
databaseOk.onTick = { &CheatEditor::addDatabaseCodes, this };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEditor::synchronize() {
|
void CheatEditor::synchronize() {
|
||||||
|
@ -201,48 +168,6 @@ void CheatEditor::bind() {
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEditor::findCodes() {
|
|
||||||
string data;
|
|
||||||
data.readfile(string(config.path.user, "cheats.xml"));
|
|
||||||
if(data == "") data.readfile(string(config.path.base, "cheats.xml"));
|
|
||||||
if(auto position = strpos(data, SNES::cartridge.sha256())) {
|
|
||||||
auto startPosition = strpos((const char*)data + position(), ">");
|
|
||||||
auto endPosition = strpos((const char*)data + position(), "</cartridge>");
|
|
||||||
string xmlData = {
|
|
||||||
"<cartridge>\n",
|
|
||||||
substr((const char*)data + position() + 1, startPosition(), endPosition() - startPosition() - 1),
|
|
||||||
"</cartridge>\n"
|
|
||||||
};
|
|
||||||
|
|
||||||
databaseWindow.setTitle("");
|
|
||||||
databaseList.reset();
|
|
||||||
databaseCode.reset();
|
|
||||||
|
|
||||||
xml_element document = xml_parse(xmlData);
|
|
||||||
foreach(root, document.element) {
|
|
||||||
if(root.name == "cartridge") foreach(node, root.element) {
|
|
||||||
if(node.name == "name") databaseWindow.setTitle(node.parse());
|
|
||||||
else if(node.name == "cheat") {
|
|
||||||
string description, code;
|
|
||||||
foreach(element, node.element) {
|
|
||||||
if(element.name == "description") description = element.parse();
|
|
||||||
else if(element.name == "code") code.append(string(element.parse(), "+"));
|
|
||||||
}
|
|
||||||
code.rtrim<1>("+");
|
|
||||||
code.append("\t");
|
|
||||||
code.append(description);
|
|
||||||
databaseList.append(description);
|
|
||||||
databaseCode.append(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
databaseWindow.setVisible(true);
|
|
||||||
} else {
|
|
||||||
MessageWindow::information(cheatEditor, "Sorry, no cheat codes found for this cartridge.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
optional<unsigned> CheatEditor::findUnusedSlot() {
|
optional<unsigned> CheatEditor::findUnusedSlot() {
|
||||||
for(unsigned i = 0; i < 128; i++) {
|
for(unsigned i = 0; i < 128; i++) {
|
||||||
if(cheatText[i][CheatCode] == "" && cheatText[i][CheatDesc] == "") return { true, i };
|
if(cheatText[i][CheatCode] == "" && cheatText[i][CheatDesc] == "") return { true, i };
|
||||||
|
@ -250,28 +175,6 @@ optional<unsigned> CheatEditor::findUnusedSlot() {
|
||||||
return { false, 0 };
|
return { false, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEditor::addDatabaseCodes() {
|
|
||||||
for(unsigned n = 0; n < databaseCode.size(); n++) {
|
|
||||||
if(databaseList.checked(n)) {
|
|
||||||
if(auto position = findUnusedSlot()) {
|
|
||||||
lstring part;
|
|
||||||
part.split("\t", databaseCode[n]);
|
|
||||||
SNES::cheat[position()].enabled = false;
|
|
||||||
SNES::cheat[position()] = part[0];
|
|
||||||
cheatList.setChecked(position(), false);
|
|
||||||
cheatText[position()][CheatCode] = part[0];
|
|
||||||
cheatText[position()][CheatDesc] = part[1];
|
|
||||||
} else {
|
|
||||||
MessageWindow::warning(databaseWindow, "Ran out of empty slots for cheat codes.\nNot all cheat codes were added.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
databaseWindow.setVisible(false);
|
|
||||||
refresh();
|
|
||||||
synchronize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheatEditor::clearAll() {
|
void CheatEditor::clearAll() {
|
||||||
if(MessageWindow::question(cheatEditor, "Permanently erase all entered cheat codes?", MessageWindow::Buttons::YesNo) == MessageWindow::Response::Yes) {
|
if(MessageWindow::question(cheatEditor, "Permanently erase all entered cheat codes?", MessageWindow::Buttons::YesNo) == MessageWindow::Response::Yes) {
|
||||||
for(unsigned i = 0; i < 128; i++) {
|
for(unsigned i = 0; i < 128; i++) {
|
||||||
|
|
|
@ -8,21 +8,11 @@ struct CheatEditor : TopLevelWindow {
|
||||||
Label descLabel;
|
Label descLabel;
|
||||||
LineEdit descEdit;
|
LineEdit descEdit;
|
||||||
HorizontalLayout controlLayout;
|
HorizontalLayout controlLayout;
|
||||||
Label spacer;
|
Widget spacerWidget;
|
||||||
Button findButton;
|
Button findButton;
|
||||||
Button clearAllButton;
|
Button clearAllButton;
|
||||||
Button clearButton;
|
Button clearButton;
|
||||||
|
|
||||||
TopLevelWindow databaseWindow;
|
|
||||||
VerticalLayout databaseLayout;
|
|
||||||
ListView databaseList;
|
|
||||||
HorizontalLayout databaseControlLayout;
|
|
||||||
Button databaseSelectAll;
|
|
||||||
Button databaseUnselectAll;
|
|
||||||
Label databaseSpacer;
|
|
||||||
Button databaseOk;
|
|
||||||
lstring databaseCode;
|
|
||||||
|
|
||||||
void load(string filename);
|
void load(string filename);
|
||||||
void save(string filename);
|
void save(string filename);
|
||||||
void create();
|
void create();
|
||||||
|
@ -34,11 +24,11 @@ private:
|
||||||
void refresh();
|
void refresh();
|
||||||
void toggle(unsigned row);
|
void toggle(unsigned row);
|
||||||
void bind();
|
void bind();
|
||||||
void findCodes();
|
|
||||||
optional<unsigned> findUnusedSlot();
|
optional<unsigned> findUnusedSlot();
|
||||||
void addDatabaseCodes();
|
|
||||||
void clearAll();
|
void clearAll();
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
friend class CheatDatabase;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CheatEditor cheatEditor;
|
extern CheatEditor cheatEditor;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
#include "../base.hpp"
|
#include "../base.hpp"
|
||||||
#include "cheat-editor.cpp"
|
#include "cheat-editor.cpp"
|
||||||
|
#include "cheat-database.cpp"
|
||||||
#include "state-manager.cpp"
|
#include "state-manager.cpp"
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
#include "cheat-editor.hpp"
|
#include "cheat-editor.hpp"
|
||||||
|
#include "cheat-database.hpp"
|
||||||
#include "state-manager.hpp"
|
#include "state-manager.hpp"
|
||||||
|
|
Loading…
Reference in New Issue