2015-04-21 11:51:57 +00:00
|
|
|
CheatEditor::CheatEditor(TabFrame* parent) : TabFrameItem(parent) {
|
|
|
|
setIcon(Icon::Edit::Replace);
|
|
|
|
setText("Cheat Editor");
|
|
|
|
|
|
|
|
layout.setMargin(5);
|
|
|
|
cheatList.append(ListViewColumn().setText("Slot").setForegroundColor({0, 128, 0}).setHorizontalAlignment(1.0));
|
2015-04-21 11:58:59 +00:00
|
|
|
cheatList.append(ListViewColumn().setText("Code(s)"));
|
2015-04-21 11:51:57 +00:00
|
|
|
cheatList.append(ListViewColumn().setText("Description").setWidth(~0));
|
|
|
|
for(auto slot : range(Slots)) cheatList.append(ListViewItem().setText(0, 1 + slot));
|
|
|
|
cheatList.setCheckable();
|
|
|
|
cheatList.setHeaderVisible();
|
2015-04-21 11:58:59 +00:00
|
|
|
cheatList.onChange([&] { doChangeSelected(); });
|
|
|
|
cheatList.onToggle([&](sListViewItem item) {
|
|
|
|
cheats[item->offset()].enabled = item->checked();
|
|
|
|
synchronizeCodes();
|
|
|
|
});
|
2015-04-21 11:51:57 +00:00
|
|
|
codeLabel.setText("Code(s):");
|
|
|
|
codeValue.onChange([&] { doModify(); });
|
|
|
|
descriptionLabel.setText("Description:");
|
|
|
|
descriptionValue.onChange([&] { doModify(); });
|
|
|
|
findCodesButton.setText("Find Codes ...").onActivate([&] { cheatDatabase->findCodes(); });
|
|
|
|
resetButton.setText("Reset").onActivate([&] { doReset(); });
|
|
|
|
eraseButton.setText("Erase").onActivate([&] { doErase(); });
|
|
|
|
}
|
|
|
|
|
2015-04-21 11:58:59 +00:00
|
|
|
auto CheatEditor::doChangeSelected() -> void {
|
2015-04-21 11:51:57 +00:00
|
|
|
if(auto item = cheatList.selected()) {
|
2015-04-21 11:58:59 +00:00
|
|
|
auto& cheat = cheats[item->offset()];
|
|
|
|
codeValue.setEnabled(true).setText(cheat.code);
|
|
|
|
descriptionValue.setEnabled(true).setText(cheat.description);
|
2015-04-21 11:51:57 +00:00
|
|
|
eraseButton.setEnabled(true);
|
|
|
|
} else {
|
|
|
|
codeValue.setEnabled(false).setText("");
|
|
|
|
descriptionValue.setEnabled(false).setText("");
|
|
|
|
eraseButton.setEnabled(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto CheatEditor::doModify() -> void {
|
|
|
|
if(auto item = cheatList.selected()) {
|
2015-04-21 11:58:59 +00:00
|
|
|
auto& cheat = cheats[item->offset()];
|
|
|
|
cheat.code = codeValue.text();
|
|
|
|
cheat.description = descriptionValue.text();
|
2015-04-21 11:51:57 +00:00
|
|
|
doRefresh();
|
|
|
|
synchronizeCodes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto CheatEditor::doRefresh() -> void {
|
|
|
|
for(auto slot : range(Slots)) {
|
2015-04-21 11:58:59 +00:00
|
|
|
auto& cheat = cheats[slot];
|
|
|
|
if(cheat.code || cheat.description) {
|
|
|
|
lstring codes = cheat.code.split("+");
|
2015-04-21 11:51:57 +00:00
|
|
|
if(codes.size() > 1) codes[0].append("+...");
|
2015-04-21 11:58:59 +00:00
|
|
|
cheatList.item(slot)->setChecked(cheat.enabled).setText(1, codes[0]).setText(2, cheat.description);
|
2015-04-21 11:51:57 +00:00
|
|
|
} else {
|
2015-04-21 11:58:59 +00:00
|
|
|
cheatList.item(slot)->setChecked(false).setText(1, "").setText(2, "(empty)");
|
2015-04-21 11:51:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cheatList.resizeColumns();
|
|
|
|
}
|
|
|
|
|
2015-04-21 11:58:59 +00:00
|
|
|
auto CheatEditor::doReset(bool force) -> void {
|
|
|
|
if(force || MessageDialog().setParent(*toolsManager).setText("Permanently erase all slots?").question() == 0) {
|
2015-04-21 11:51:57 +00:00
|
|
|
for(auto& cheat : cheats) {
|
2015-04-21 11:58:59 +00:00
|
|
|
cheat.enabled = false;
|
2015-04-21 11:51:57 +00:00
|
|
|
cheat.code = "";
|
|
|
|
cheat.description = "";
|
|
|
|
}
|
|
|
|
cheatList.setSelected(false);
|
2015-04-21 11:58:59 +00:00
|
|
|
doChangeSelected();
|
2015-04-21 11:51:57 +00:00
|
|
|
doRefresh();
|
|
|
|
synchronizeCodes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto CheatEditor::doErase() -> void {
|
|
|
|
if(auto item = cheatList.selected()) {
|
2015-04-21 11:58:59 +00:00
|
|
|
auto& cheat = cheats[item->offset()];
|
|
|
|
cheat.enabled = false;
|
|
|
|
cheat.code = "";
|
|
|
|
cheat.description = "";
|
2015-04-21 11:51:57 +00:00
|
|
|
codeValue.setText("");
|
|
|
|
descriptionValue.setText("");
|
|
|
|
doRefresh();
|
|
|
|
synchronizeCodes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto CheatEditor::synchronizeCodes() -> void {
|
|
|
|
if(!emulator) return;
|
|
|
|
|
|
|
|
lstring codes;
|
2015-04-21 11:58:59 +00:00
|
|
|
for(auto& cheat : cheats) {
|
|
|
|
if(!cheat.enabled || !cheat.code) continue;
|
|
|
|
codes.append(cheat.code);
|
2015-04-21 11:51:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
emulator->cheatSet(codes);
|
|
|
|
}
|
|
|
|
|
|
|
|
//returns true if code was added
|
|
|
|
//returns false if there are no more free slots for additional codes
|
2015-04-21 11:58:59 +00:00
|
|
|
auto CheatEditor::addCode(const string& code, const string& description, bool enabled) -> bool {
|
2015-04-21 11:51:57 +00:00
|
|
|
for(auto& cheat : cheats) {
|
|
|
|
if(cheat.code || cheat.description) continue;
|
2015-04-21 11:58:59 +00:00
|
|
|
cheat.enabled = enabled;
|
2015-04-21 11:51:57 +00:00
|
|
|
cheat.code = code;
|
|
|
|
cheat.description = description;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2015-04-21 11:58:59 +00:00
|
|
|
|
|
|
|
auto CheatEditor::loadCheats() -> void {
|
|
|
|
doReset(true);
|
|
|
|
auto contents = string::read({program->folderPaths[0], "cheats.bml"});
|
Update to v094r17 release.
byuu says:
This updates higan to use the new Markup::Node changes. This is a really
big change, and one slight typo anywhere could break certain classes of
games from playing.
I don't have ananke hooked up again yet, so I don't have the ability to
test this much. If anyone with some v094 game folders wouldn't mind
testing, I'd help out a great deal.
I'm most concerned about testing one of each SNES special chip game.
Most notably, systems like the SA-1, HitachiDSP and NEC-DSP were using
the fancier lookups, eg node["rom[0]/name"], which I had to convert to
a rather ugly node["rom"].at(0)["name"], which I'm fairly confident
won't work. I'm going to blame that on the fumes from the shelves I just
stained >.> Might work with node.find("rom[0]/name")(0) though ...? But
so ugly ... ugh.
That aside, this WIP adds the accuracy-PPU inlining, so the accuracy
profile should run around 7.5% faster than before.
2015-05-02 13:05:46 +00:00
|
|
|
auto document = BML::unserialize(contents);
|
|
|
|
for(auto cheat : document["cartridge"].find("cheat")) {
|
|
|
|
if(!addCode(cheat["code"].text(), cheat["description"].text(), (bool)cheat["enabled"])) break;
|
2015-04-21 11:58:59 +00:00
|
|
|
}
|
|
|
|
doRefresh();
|
|
|
|
synchronizeCodes();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto CheatEditor::saveCheats() -> void {
|
|
|
|
if(!emulator) return;
|
|
|
|
string document = {"cartridge sha256:", emulator->sha256(), "\n"};
|
|
|
|
unsigned count = 0;
|
|
|
|
for(auto& cheat : cheats) {
|
|
|
|
if(!cheat.code && !cheat.description) continue;
|
|
|
|
document.append(" cheat", cheat.enabled ? " enabled" : "", "\n");
|
|
|
|
document.append(" description:", cheat.description, "\n");
|
|
|
|
document.append(" code:", cheat.code, "\n");
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
if(count) {
|
|
|
|
file::write({program->folderPaths[0], "cheats.bml"}, document);
|
|
|
|
} else {
|
|
|
|
file::remove({program->folderPaths[0], "cheats.bml"});
|
|
|
|
}
|
|
|
|
doReset(true);
|
|
|
|
}
|