diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index 6f20fe626..be8b356d9 100755 --- a/bsnes/base/base.hpp +++ b/bsnes/base/base.hpp @@ -1,7 +1,7 @@ #ifndef BASE_HPP #define BASE_HPP -const char Version[] = "086.01"; +const char Version[] = "086.02"; #include #include diff --git a/bsnes/snes/cartridge/cartridge.cpp b/bsnes/snes/cartridge/cartridge.cpp index fdfff8a0d..5187732dd 100755 --- a/bsnes/snes/cartridge/cartridge.cpp +++ b/bsnes/snes/cartridge/cartridge.cpp @@ -34,7 +34,7 @@ void Cartridge::load(Mode cartridge_mode, const char *markup) { nvram.reset(); parse_markup(markup); -//print(markup, "\n\n"); + print(markup, "\n\n"); if(ram_size > 0) { ram.map(allocate(ram_size, 0xff), ram_size); diff --git a/bsnes/snes/cartridge/markup.cpp b/bsnes/snes/cartridge/markup.cpp index aec2b2f44..f67cd1717 100755 --- a/bsnes/snes/cartridge/markup.cpp +++ b/bsnes/snes/cartridge/markup.cpp @@ -334,6 +334,7 @@ void Cartridge::parse_markup_hitachidsp(XML::Node &root) { void Cartridge::parse_markup_bsx(XML::Node &root) { if(root.exists() == false) return; if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return; + has_bsx_slot = true; for(auto &node : root["slot"]) { if(node.name != "map") continue; diff --git a/bsnes/ui/interface/gameboy/gameboy.cpp b/bsnes/ui/interface/gameboy/gameboy.cpp index 3c390903f..8ee13ae6e 100755 --- a/bsnes/ui/interface/gameboy/gameboy.cpp +++ b/bsnes/ui/interface/gameboy/gameboy.cpp @@ -16,11 +16,13 @@ bool InterfaceGameBoy::loadCartridge(GameBoy::System::Revision revision, const s interface->base = { true, filename }; } else { if(file::read(filename, data, size) == false) return false; - interface->base.name = { false, nall::basename(filename) }; + interface->base = { false, nall::basename(filename) }; } interface->unloadCartridge(); -//interface->applyPatch(interface->baseName, data, size); + interface->game = interface->base; + interface->cartridgeTitle = interface->base.title(); + interface->applyPatch(interface->base, data, size); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); diff --git a/bsnes/ui/interface/interface.cpp b/bsnes/ui/interface/interface.cpp index a72f73b79..7765ba196 100755 --- a/bsnes/ui/interface/interface.cpp +++ b/bsnes/ui/interface/interface.cpp @@ -28,6 +28,17 @@ string CartridgePath::filename(const string &folderName, const string &fileName) return { name, fileName }; } +string CartridgePath::title() const { + if(name.empty()) return ""; + if(folder) { + string title = name; + title.rtrim<1>("/"); + title = notdir(nall::basename(title)); + return title; + } + return notdir(nall::basename(name)); +} + void Interface::bindControllers() { switch(mode()) { case Mode::NES: @@ -85,10 +96,10 @@ void Interface::loadCartridge(Mode mode) { } bindControllers(); - cheatEditor->load(base.filename("cheats.xml", ".cht")); - stateManager->load(base.filename("states.bsa", ".bsa"), 0u); + cheatEditor->load(game.filename("cheats.xml", ".cht")); + stateManager->load(game.filename("states.bsa", ".bsa"), 0u); dipSwitches->load(); - utility->showMessage({ "Loaded ", notdir(baseName) }); + utility->showMessage({ "Loaded ", cartridgeTitle }); } bool Interface::loadCartridge(const string &filename) { @@ -103,8 +114,8 @@ bool Interface::loadCartridge(const string &filename) { void Interface::unloadCartridge() { if(cartridgeLoaded() == false) return; cheatDatabase->setVisible(false); - cheatEditor->save(base.filename("cheats.xml", ".cht")); - stateManager->save(base.filename("states.bsa", ".bsa"), 0u); + cheatEditor->save(game.filename("cheats.xml", ".cht")); + stateManager->save(game.filename("states.bsa", ".bsa"), 0u); setCheatCodes(); switch(mode()) { @@ -113,7 +124,7 @@ void Interface::unloadCartridge() { case Mode::GameBoy: gameBoy.unloadCartridge(); break; } - interface->baseName = ""; + cartridgeTitle = ""; utility->setMode(mode = Mode::None); } @@ -145,7 +156,7 @@ bool Interface::unserialize(serializer &s) { } bool Interface::saveState(unsigned slot) { - string filename = base.filename({ "state-", slot, ".bst" }, { "-", slot, ".bst" }); + string filename = game.filename({ "state-", slot, ".bst" }, { "-", slot, ".bst" }); serializer s = serialize(); bool result = file::write(filename, s.data(), s.size()); utility->showMessage(result == true ? string{ "Saved state ", slot } : "Failed to save state"); @@ -153,7 +164,7 @@ bool Interface::saveState(unsigned slot) { } bool Interface::loadState(unsigned slot) { - string filename = base.filename({ "state-", slot, ".bst" }, { "-", slot, ".bst" }); + string filename = game.filename({ "state-", slot, ".bst" }, { "-", slot, ".bst" }); uint8_t *data; unsigned size; if(file::read(filename, data, size) == false) { @@ -193,8 +204,8 @@ Interface::Interface() : core(nullptr) { //internal -bool Interface::applyPatch(const string &filename, uint8_t *&data, unsigned &size) { - string patchname = { nall::basename(filename), ".bps" }; +bool Interface::applyPatch(CartridgePath &filepath, uint8_t *&data, unsigned &size) { + string patchname = filepath.filename("patch.bps", ".bps"); if(file::exists(patchname) == false) return false; bpspatch bps; diff --git a/bsnes/ui/interface/interface.hpp b/bsnes/ui/interface/interface.hpp index 4ceb68ca6..3e8bbb5dd 100755 --- a/bsnes/ui/interface/interface.hpp +++ b/bsnes/ui/interface/interface.hpp @@ -13,6 +13,7 @@ struct CartridgePath { bool folder; string name; string filename(const string &folderName, const string &fileName) const; + string title() const; }; #include "nes/nes.hpp" @@ -61,14 +62,13 @@ struct Interface : property { Interface(); - bool applyPatch(const string &filename, uint8_t *&data, unsigned &size); + bool applyPatch(CartridgePath &filepath, uint8_t *&data, unsigned &size); void videoRefresh(const uint32_t *input, unsigned inputPitch, unsigned width, unsigned height); - CartridgePath base; - vector slot; - - //deprecated - string baseName; // = "/path/to/cartridge" (no extension) + CartridgePath base; //base cartridge connected to emulated system + CartridgePath slot[2]; //slot cartridges connected to base cartridge + CartridgePath game; //where to store resources (cheats.xml, states.bsa, ...) + string cartridgeTitle; //combined name of game ([base] + [slot ...]) InterfaceCore *core; InterfaceNES nes; diff --git a/bsnes/ui/interface/nes/nes.cpp b/bsnes/ui/interface/nes/nes.cpp index 6bfa0efda..1120e5931 100755 --- a/bsnes/ui/interface/nes/nes.cpp +++ b/bsnes/ui/interface/nes/nes.cpp @@ -48,7 +48,9 @@ bool InterfaceNES::loadCartridge(const string &filename) { } interface->unloadCartridge(); -//interface->applyPatch(interface->base.filename("patch.bps", ".bps"), data, size); + interface->game = interface->base; + interface->cartridgeTitle = interface->base.title(); + interface->applyPatch(interface->base, data, size); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); diff --git a/bsnes/ui/interface/snes/snes.cpp b/bsnes/ui/interface/snes/snes.cpp index b74decc50..6b5e3a69c 100755 --- a/bsnes/ui/interface/snes/snes.cpp +++ b/bsnes/ui/interface/snes/snes.cpp @@ -31,6 +31,7 @@ bool InterfaceSNES::cartridgeLoaded() { } bool InterfaceSNES::loadCartridge(const string &filename, CartridgePath &cartridge, uint8_t *&data, unsigned &size) { + data = nullptr, size = 0u; auto backup = cartridge; string suffix; if(filename.endswith("/")) { @@ -43,7 +44,7 @@ bool InterfaceSNES::loadCartridge(const string &filename, CartridgePath &cartrid cartridge = backup; return false; } -//interface->applyPatch(filename, data, size); + interface->applyPatch(cartridge, data, size); return true; } @@ -51,7 +52,10 @@ bool InterfaceSNES::loadCartridge(string basename) { uint8_t *data; unsigned size; if(loadCartridge(basename, interface->base, data, size) == false) return false; + interface->unloadCartridge(); + interface->game = interface->base; + interface->cartridgeTitle = interface->base.title(); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); @@ -73,8 +77,12 @@ bool InterfaceSNES::loadSatellaviewSlottedCartridge(string basename, string slot uint8_t *data[2]; unsigned size[2]; if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false; - loadCartridge(slotname, interface->slot(0), data[1], size[1]); + loadCartridge(slotname, interface->slot[0], data[1], size[1]); + interface->unloadCartridge(); + interface->game = !data[1] ? interface->base : interface->slot[0]; //TODO: subfolder for folders; concatenation for files + interface->cartridgeTitle = interface->base.title(); + if(data[1]) interface->cartridgeTitle.append(" + ", interface->slot[0].title()); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); @@ -98,8 +106,12 @@ bool InterfaceSNES::loadSatellaviewCartridge(string basename, string slotname) { uint8_t *data[2]; unsigned size[2]; if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false; - loadCartridge(slotname, interface->slot(0), data[1], size[1]); + loadCartridge(slotname, interface->slot[0], data[1], size[1]); + interface->unloadCartridge(); + interface->game = !data[1] ? interface->base : interface->slot[0]; + interface->cartridgeTitle = interface->base.title(); + if(data[1]) interface->cartridgeTitle = interface->slot[0].title(); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); @@ -123,9 +135,17 @@ bool InterfaceSNES::loadSufamiTurboCartridge(string basename, string slotAname, uint8_t *data[3]; unsigned size[3]; if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false; - loadCartridge(slotAname, interface->slot(0), data[1], size[1]); - loadCartridge(slotBname, interface->slot(1), data[2], size[2]); + loadCartridge(slotAname, interface->slot[0], data[1], size[1]); + loadCartridge(slotBname, interface->slot[1], data[2], size[2]); + interface->unloadCartridge(); + interface->game = !data[1] ? interface->base : interface->slot[0]; //TODO: subfolder for folders; concatenation for files + interface->cartridgeTitle = interface->base.title(); + if( data[1] && !data[2]) interface->cartridgeTitle = interface->slot[0].title(); + if(!data[1] && data[2]) interface->cartridgeTitle = interface->slot[1].title(); + if( data[1] && data[2]) interface->cartridgeTitle = { + interface->slot[0].title(), " + ", interface->slot[1].title() + }; string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); @@ -151,8 +171,12 @@ bool InterfaceSNES::loadSuperGameBoyCartridge(string basename, string slotname) uint8_t *data[2]; unsigned size[2]; if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false; - loadCartridge(slotname, interface->slot(0), data[1], size[1]); + loadCartridge(slotname, interface->slot[0], data[1], size[1]); + interface->unloadCartridge(); + interface->game = !data[1] ? interface->base : interface->slot[0]; + interface->cartridgeTitle = interface->base.title(); + if(data[1]) interface->cartridgeTitle = interface->slot[0].title(); string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); @@ -179,8 +203,6 @@ bool InterfaceSNES::loadSuperGameBoyCartridge(string basename, string slotname) void InterfaceSNES::unloadCartridge() { saveMemory(); SNES::cartridge.unload(); - interface->base.name = ""; - interface->slot.reset(); } void InterfaceSNES::power() { @@ -225,6 +247,17 @@ void InterfaceSNES::loadMemory() { delete[] data; } } + + if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) { + if(GameBoy::cartridge.ramsize) { + uint8_t *data; + unsigned size; + if(file::read(interface->slot[0].filename("program.ram", ".sav"), data, size)) { + memcpy(GameBoy::cartridge.ramdata, data, min(GameBoy::cartridge.ramsize, size)); + delete[] data; + } + } + } } void InterfaceSNES::saveMemory() { @@ -236,6 +269,14 @@ void InterfaceSNES::saveMemory() { file::write(filename, memory.data, memory.size); } + + if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) { + if(GameBoy::cartridge.ramsize) { + file::write(interface->slot[0].filename("program.ram", ".sav"), + GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize + ); + } + } } serializer InterfaceSNES::serialize() { diff --git a/bsnes/ui/utility/utility.cpp b/bsnes/ui/utility/utility.cpp index edfc3562d..2670a3a6d 100755 --- a/bsnes/ui/utility/utility.cpp +++ b/bsnes/ui/utility/utility.cpp @@ -17,13 +17,13 @@ void Utility::setMode(Interface::Mode mode) { } else if(mode == Interface::Mode::NES) { - mainWindow->setTitle(notdir(interface->baseName)); + mainWindow->setTitle(interface->cartridgeTitle); mainWindow->nesMenu.setVisible(true); dspaudio.setChannels(1); } else if(mode == Interface::Mode::SNES) { - mainWindow->setTitle(notdir(interface->baseName)); + mainWindow->setTitle(interface->cartridgeTitle); mainWindow->snesMenu.setVisible(true); dspaudio.setChannels(2); } @@ -32,7 +32,7 @@ void Utility::setMode(Interface::Mode mode) { mainWindow->gameBoyMenu.setText( GameBoy::system.cgb() == false ? "Game Boy" : "Game Boy Color" ); - mainWindow->setTitle(notdir(interface->baseName)); + mainWindow->setTitle(interface->cartridgeTitle); mainWindow->gameBoyMenu.setVisible(true); dspaudio.setChannels(2); }