Update to v106r17 release.

byuu says:

Changelog:

  - tomoko: the library menu is now called the systems menu (even in
    code)
  - tomoko: added icons to menus (disambiguates systems menu entries)
  - icarus: added missing .ws, .wsc extensions to scan dialog search
    list
  - higan: added Benesse - Pocket Challenge V2 emulation¹

¹: the Benesse - Pocket Challenge V2 is a WonderSwan (ASWAN) SoC
inside a custom designed shell. Games made for the WonderSwan (mostly)
run on the Pocket Challenge V2 and vice versa. The big difference is
that the Benesse has a different number of input buttons, that are also
named differently. Of course, right now, I don't know what the buttons
are named or where they're mapped on the 16-input keypad matrix I/O
port. It's also possible that the internal EEPROM doesn't exist, it
definitely has a unique (and also undumped) IPLROM, and other things.
The ROMs have their own .pc2 file extension. So it's getting its own
system entry.

What I'm going to do for v107 and above is utilize the new systems
configuration to mark the Benesse as hidden by default from the main
menu. I don't think anyone in the world will actually care or want to
play this, but there was really no reason not to add it.
This commit is contained in:
Tim Allen 2018-04-25 19:34:43 +10:00
parent 540d960e30
commit 8617711ea2
22 changed files with 211 additions and 75 deletions

View File

@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "106.16";
static const string Version = "106.17";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org/";

View File

@ -0,0 +1,2 @@
system name:Pocket Challenge V2
eeprom name=internal.ram size=128

View File

@ -6,7 +6,7 @@ unique_pointer<Presentation> presentation;
Presentation::Presentation() {
presentation = this;
libraryMenu.setText("Systems");
systemsMenu.setText("Systems");
systemMenu.setVisible(false);
resetSystem.setText("Soft Reset").onActivate([&] { program->softReset(); });
@ -67,10 +67,10 @@ Presentation::Presentation() {
statusBar.setVisible(showStatusBar.checked());
if(visible()) resizeViewport();
});
showSystemSettings.setText("Systems ...").onActivate([&] { settingsManager->show(0); });
showVideoSettings.setText("Video ...").onActivate([&] { settingsManager->show(1); });
showAudioSettings.setText("Audio ...").onActivate([&] { settingsManager->show(2); });
showInputSettings.setText("Input ...").onActivate([&] {
showSystemSettings.setIcon(Icon::Device::Storage).setText("Systems ...").onActivate([&] { settingsManager->show(0); });
showVideoSettings.setIcon(Icon::Device::Display).setText("Video ...").onActivate([&] { settingsManager->show(1); });
showAudioSettings.setIcon(Icon::Device::Speaker).setText("Audio ...").onActivate([&] { settingsManager->show(2); });
showInputSettings.setIcon(Icon::Device::Joypad).setText("Input ...").onActivate([&] {
if(emulator) {
//default input panel to current core's input settings
for(auto item : settingsManager->input.emulatorList.items()) {
@ -83,8 +83,8 @@ Presentation::Presentation() {
}
settingsManager->show(3);
});
showHotkeySettings.setText("Hotkeys ...").onActivate([&] { settingsManager->show(4); });
showAdvancedSettings.setText("Advanced ...").onActivate([&] { settingsManager->show(5); });
showHotkeySettings.setIcon(Icon::Device::Keyboard).setText("Hotkeys ...").onActivate([&] { settingsManager->show(4); });
showAdvancedSettings.setIcon(Icon::Action::Settings).setText("Advanced ...").onActivate([&] { settingsManager->show(5); });
toolsMenu.setText("Tools").setVisible(false);
saveQuickStateMenu.setText("Save Quick State");
@ -100,19 +100,19 @@ Presentation::Presentation() {
loadSlot4.setText("Slot 4").onActivate([&] { program->loadState(4); });
loadSlot5.setText("Slot 5").onActivate([&] { program->loadState(5); });
pauseEmulation.setText("Pause Emulation").onToggle([&] { program->togglePause(); });
cheatEditor.setText("Cheat Editor ...").onActivate([&] { toolsManager->show(0); });
stateManager.setText("State Manager ...").onActivate([&] { toolsManager->show(1); });
manifestViewer.setText("Manifest Viewer ...").onActivate([&] { toolsManager->show(2); });
gameNotes.setText("Game Notes ...").onActivate([&] { toolsManager->show(3); });
cheatEditor.setIcon(Icon::Edit::Replace).setText("Cheat Editor ...").onActivate([&] { toolsManager->show(0); });
stateManager.setIcon(Icon::Application::FileManager).setText("State Manager ...").onActivate([&] { toolsManager->show(1); });
manifestViewer.setIcon(Icon::Emblem::Text).setText("Manifest Viewer ...").onActivate([&] { toolsManager->show(2); });
gameNotes.setIcon(Icon::Emblem::Text).setText("Game Notes ...").onActivate([&] { toolsManager->show(3); });
helpMenu.setText("Help");
documentation.setText("Documentation ...").onActivate([&] {
documentation.setIcon(Icon::Application::Browser).setText("Documentation ...").onActivate([&] {
invoke("https://doc.byuu.org/higan/");
});
credits.setText("Credits ...").onActivate([&] {
credits.setIcon(Icon::Application::Browser).setText("Credits ...").onActivate([&] {
invoke("https://doc.byuu.org/higan/credits/");
});
about.setText("About ...").onActivate([&] {
about.setIcon(Icon::Prompt::Question).setText("About ...").onActivate([&] {
aboutWindow->setVisible().setFocused();
});
@ -304,32 +304,34 @@ auto Presentation::toggleFullScreen() -> void {
}
auto Presentation::loadSystems() -> void {
libraryMenu.reset();
systemsMenu.reset();
for(auto system : settings.find("Systems/System")) {
if(!system["Show"].boolean()) continue;
if(!system["Visible"].boolean()) continue;
MenuItem item;
string boot = system["Boot"].text();
item.setText({system["Name"].text(), " ..."}).onActivate([=] {
bool booted = false;
string name = system.text();
string filename = system["Load"].text();
string load = Location::base(filename).trimRight("/", 1L);
string alias = system["Alias"].text();
item
.setIcon(load ? Icon::Emblem::Folder : Icon::Device::Storage)
.setText({alias ? alias : load ? load : name, " ..."}).onActivate([=] {
for(auto& emulator : program->emulators) {
if(boot == emulator->information.name) {
if(name == emulator->information.name) {
if(filename) program->mediumQueue.append(filename);
program->loadMedium(*emulator, emulator->media(0));
booted = true;
break;
}
}
if(!booted && directory::exists(boot)) {
program->mediumQueue.append(boot);
program->loadMedium();
}
});
libraryMenu.append(item);
systemsMenu.append(item);
}
//add icarus menu option -- but only if icarus binary is present
if(execute("icarus", "--name").output.strip() == "icarus") {
if(libraryMenu.actionCount()) libraryMenu.append(MenuSeparator());
libraryMenu.append(MenuItem().setText("Load ROM File ...").onActivate([&] {
if(systemsMenu.actionCount()) systemsMenu.append(MenuSeparator());
systemsMenu.append(MenuItem()
.setIcon(Icon::Emblem::File)
.setText("Load ROM File ...").onActivate([&] {
audio->clear();
if(auto location = execute("icarus", "--import")) {
program->mediumQueue.append(location.output.strip());

View File

@ -18,7 +18,7 @@ struct Presentation : Window {
auto loadShaders() -> void;
MenuBar menuBar{this};
Menu libraryMenu{&menuBar};
Menu systemsMenu{&menuBar};
Menu systemMenu{&menuBar};
Menu inputPort1{&systemMenu};
Menu inputPort2{&systemMenu};
@ -74,6 +74,7 @@ struct Presentation : Window {
Menu helpMenu{&menuBar};
MenuItem documentation{&helpMenu};
MenuItem credits{&helpMenu};
MenuSeparator helpMenuSeparator{&helpMenu};
MenuItem about{&helpMenu};
FixedLayout layout{this};

View File

@ -29,6 +29,7 @@ Program::Program(string_vector args) {
emulators.append(new MasterSystem::GameGearInterface);
emulators.append(new WonderSwan::WonderSwanInterface);
emulators.append(new WonderSwan::WonderSwanColorInterface);
emulators.append(new WonderSwan::PocketChallengeV2Interface);
new Presentation;
presentation->setVisible();

View File

@ -4,13 +4,16 @@ struct SystemProperties : Window {
auto modify(Markup::Node) -> void;
VerticalLayout layout{this};
HorizontalLayout nameLayout{&layout, Size{~0, 0}};
Label nameLabel{&nameLayout, Size{40, 0}};
LineEdit nameEdit{&nameLayout, Size{~0, 0}};
HorizontalLayout bootLayout{&layout, Size{~0, 0}};
Label bootLabel{&bootLayout, Size{40, 0}};
ComboEdit bootEdit{&bootLayout, Size{~0, 0}};
Button bootBrowse{&bootLayout, Size{80, 0}};
HorizontalLayout systemLayout{&layout, Size{~0, 0}};
Label systemLabel{&systemLayout, Size{50, 0}};
ComboButton systemOption{&systemLayout, Size{~0, 0}};
HorizontalLayout loadLayout{&layout, Size{~0, 0}};
Label loadLabel{&loadLayout, Size{50, 0}};
LineEdit loadEdit{&loadLayout, Size{~0, 0}};
Button loadBrowse{&loadLayout, Size{80, 0}};
HorizontalLayout aliasLayout{&layout, Size{~0, 0}};
Label aliasLabel{&aliasLayout, Size{50, 0}};
LineEdit aliasEdit{&aliasLayout, Size{~0, 0}};
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
Widget spacer{&controlLayout, Size{~0, 0}};
Button acceptButton{&controlLayout, Size{80, 0}};

View File

@ -2,13 +2,13 @@ SystemProperties::SystemProperties() {
systemProperties = this;
layout.setMargin(5);
nameLabel.setText("Name:");
bootLabel.setText("Boot:");
bootEdit.setEditable(false);
systemLabel.setAlignment(1.0).setText("System:");
for(auto& emulator : program->emulators) {
bootEdit.append(ComboEditItem().setText(emulator->information.name));
systemOption.append(ComboButtonItem().setText(emulator->information.name));
}
bootBrowse.setText("Browse ...").onActivate([&] {
loadLabel.setAlignment(1.0).setText("Load:");
loadEdit.setEditable(false);
loadBrowse.setText("Browse ...").onActivate([&] {
string filters = "Games|";
for(auto& emulator : program->emulators) {
for(auto& media : emulator->media) {
@ -21,9 +21,10 @@ SystemProperties::SystemProperties() {
.setPath(settings["Library/Location"].text())
.setFilters(filters)
.openFolder()) {
bootEdit.setText(location);
loadEdit.setText(location);
}
});
aliasLabel.setAlignment(1.0).setText("Alias:");
acceptButton.onActivate([&] {
setVisible(false);
settingsManager->systems.accept();
@ -39,20 +40,25 @@ SystemProperties::SystemProperties() {
auto SystemProperties::append() -> void {
setCentered(*settingsManager);
nameEdit.setText("");
bootEdit.setText("");
systemOption.item(0).setSelected();
loadEdit.setText("");
aliasEdit.setText("");
acceptButton.setText("Append");
setFocused();
setVisible();
nameEdit.setFocused();
systemOption.setFocused();
}
auto SystemProperties::modify(Markup::Node system) -> void {
setCentered(*settingsManager);
nameEdit.setText(system["Name"].text());
bootEdit.setText(system["Boot"].text());
systemOption.item(0).setSelected();
for(auto item : systemOption.items()) {
if(item.text() == system.text()) item.setSelected();
}
loadEdit.setText(system["Load"].text());
aliasEdit.setText(system["Alias"].text());
acceptButton.setText("Modify");
setFocused();
setVisible();
nameEdit.setFocused();
systemOption.setFocused();
}

View File

@ -34,17 +34,20 @@ auto SystemSettings::reload() -> void {
systemList.reset();
systemList.append(TableViewHeader().setVisible()
.append(TableViewColumn())
.append(TableViewColumn().setText("Name"))
.append(TableViewColumn().setText("Boot").setExpandable())
.append(TableViewColumn().setText("System").setExpandable())
);
for(auto system : settings.find("Systems/System")) {
string boot = Location::base(system["Boot"].text());
string name = system.text();
string load = Location::base(system["Load"].text()).trimRight("/", 1L);
string alias = system["Alias"].text();
systemList.append(TableViewItem()
.append(TableViewCell().setCheckable().setChecked(system["Show"].boolean()))
.append(TableViewCell().setText(system["Name"].text()))
.append(TableViewCell()
.setIcon(boot.endsWith("/") ? Icon::Emblem::Folder : Icon::Device::Storage)
.setText(string{boot}.trimRight("/", 1L))
.setCheckable()
.setChecked(system["Visible"].boolean())
)
.append(TableViewCell()
.setIcon(load ? Icon::Emblem::Folder : Icon::Device::Storage)
.setText(alias ? alias : load ? load : name)
)
);
}
@ -55,7 +58,7 @@ auto SystemSettings::reload() -> void {
auto SystemSettings::toggle(TableViewCell cell) -> void {
if(auto item = cell->parentTableViewItem()) {
if(auto system = settings.find("Systems/System")[item->offset()]) {
system("Show").setValue(item->cell(0).checked());
system("Visible").setValue(item->cell(0).checked());
presentation->loadSystems();
}
}
@ -93,8 +96,8 @@ auto SystemSettings::remove() -> void {
if(auto item = systemList.selected()) {
if(auto system = settings.find("Systems/System")[item.offset()]) {
if(MessageDialog().setParent(*settingsManager).setText({
"Are you sure you want to delete this system?\n\n"
"Name: ", system["Name"].text()
"Are you sure you want to delete this system?\n\n",
item.cell(1).text()
}).question() == "Yes") {
settings["Systems"].remove(system);
reload();
@ -105,16 +108,17 @@ auto SystemSettings::remove() -> void {
auto SystemSettings::accept() -> void {
if(systemProperties->acceptButton.text() == "Append") {
Markup::Node system{"System"};
system.append({"Name", systemProperties->nameEdit.text()});
system.append({"Boot", systemProperties->bootEdit.text()});
system.append({"Show", "true"});
Markup::Node system{"System", systemProperties->systemOption.selected().text()};
system.append({"Load", systemProperties->loadEdit.text()});
system.append({"Alias", systemProperties->aliasEdit.text()});
system.append({"Visible", "true"});
settings["Systems"].append(system);
} else if(systemProperties->acceptButton.text() == "Modify") {
if(auto item = systemList.selected()) {
if(auto system = settings.find("Systems/System")[item.offset()]) {
system("Name").setValue(systemProperties->nameEdit.text());
system("Boot").setValue(systemProperties->bootEdit.text());
system.setValue(systemProperties->systemOption.selected().text());
system("Load").setValue(systemProperties->loadEdit.text());
system("Alias").setValue(systemProperties->aliasEdit.text());
}
}
}

View File

@ -56,6 +56,12 @@ auto Cartridge::load() -> bool {
} else return false;
}
if(Model::PocketChallengeV2()) {
if(auto loaded = platform->load(ID::PocketChallengeV2, "Pocket Challenge V2", "pc2")) {
information.pathID = loaded.pathID();
} else return false;
}
if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) {
information.manifest = fp->reads();
} else return false;

View File

@ -51,7 +51,7 @@ auto CPU::power() -> void {
bus.map(this, 0x00a0);
bus.map(this, 0x00b0, 0x00b6);
if(!Model::WonderSwan()) {
if(Model::WonderSwanColor() || Model::SwanCrystal()) {
bus.map(this, 0x0040, 0x0049);
bus.map(this, 0x0062);
}

View File

@ -48,10 +48,10 @@ auto CPU::portRead(uint16 addr) -> uint8 {
//HW_FLAGS
if(addr == 0x00a0) {
bool color = !Model::WonderSwan();
bool color = Model::WonderSwanColor() || Model::SwanCrystal();
return (
1 << 0 //0 = BIOS mapped; 1 = cartridge mapped
| color << 1 //0 = WonderSwan; 1 = WonderSwan Color or SwanCrystal
| color << 1 //0 = WonderSwan or Pocket Challenge V2; 1 = WonderSwan Color or SwanCrystal
| 1 << 2 //0 = 8-bit bus width; 1 = 16-bit bus width
| 1 << 7 //1 = built-in self-test passed
);
@ -59,7 +59,7 @@ auto CPU::portRead(uint16 addr) -> uint8 {
//INT_BASE
if(addr == 0x00b0) return (
r.interruptBase | (Model::WonderSwan() ? 3 : 0)
r.interruptBase | (Model::WonderSwan() || Model::PocketChallengeV2() ? 3 : 0)
);
//SER_DATA
@ -122,7 +122,7 @@ auto CPU::portWrite(uint16 addr, uint8 data) -> void {
//INT_BASE
if(addr == 0x00b0) {
r.interruptBase = Model::WonderSwan() ? data & ~7 : data & ~1;
r.interruptBase = Model::WonderSwan() || Model::PocketChallengeV2() ? data & ~7 : data & ~1;
}
//SER_DATA

View File

@ -5,6 +5,7 @@ namespace WonderSwan {
Settings settings;
#include "wonderswan.cpp"
#include "wonderswan-color.cpp"
#include "pocket-challenge-v2.cpp"
Interface::Interface() {
Port hardwarePort{ID::Port::Hardware, "Hardware"};

View File

@ -5,6 +5,7 @@ struct ID {
System,
WonderSwan,
WonderSwanColor,
PocketChallengeV2,
};
struct Port { enum : uint {
@ -64,6 +65,17 @@ struct WonderSwanColorInterface : Interface {
auto load(uint id) -> bool override;
};
struct PocketChallengeV2Interface : Interface {
using Emulator::Interface::load;
PocketChallengeV2Interface();
auto videoColors() -> uint32 override;
auto videoColor(uint32 color) -> uint64 override;
auto load(uint id) -> bool override;
};
struct Settings {
bool blurEmulation = true;
bool colorEmulation = true;

View File

@ -0,0 +1,40 @@
PocketChallengeV2Interface::PocketChallengeV2Interface() {
information.manufacturer = "Benesse";
information.name = "Pocket Challenge V2";
information.overscan = false;
media.append({ID::PocketChallengeV2, "Pocket Challenge V2", "pc2"});
}
//todo: this should be generating grayscale colors
//instead, the PPU is selecting grayscale colors from the color palette
auto PocketChallengeV2Interface::videoColors() -> uint32 {
return 1 << 12;
}
auto PocketChallengeV2Interface::videoColor(uint32 color) -> uint64 {
uint b = color.bits(0, 3);
uint g = color.bits(4, 7);
uint r = color.bits(8,11);
uint64_t R = image::normalize(r, 4, 16);
uint64_t G = image::normalize(g, 4, 16);
uint64_t B = image::normalize(b, 4, 16);
if(settings.colorEmulation) {
R = (r * 26 + g * 4 + b * 2);
G = ( g * 24 + b * 8);
B = (r * 6 + g * 4 + b * 22);
R = image::normalize(min(480, R), 9, 16);
G = image::normalize(min(480, G), 9, 16);
B = image::normalize(min(480, B), 9, 16);
}
return R << 32 | G << 16 | B << 0;
}
auto PocketChallengeV2Interface::load(uint id) -> bool {
if(id == ID::PocketChallengeV2) return system.load(this, System::Model::PocketChallengeV2);
return false;
}

View File

@ -10,7 +10,7 @@ auto InternalRAM::power() -> void {
}
auto InternalRAM::serialize(serializer& s) -> void {
s.array(memory, Model::WonderSwan() ? 0x4000 : 0x10000);
s.array(memory, Model::WonderSwan() || Model::PocketChallengeV2() ? 0x4000 : 0x10000);
}
auto InternalRAM::read(uint16 addr, uint size) -> uint32 {

View File

@ -1,5 +1,5 @@
struct System : IO {
enum class Model : uint { WonderSwan, WonderSwanColor, SwanCrystal };
enum class Model : uint { WonderSwan, WonderSwanColor, SwanCrystal, PocketChallengeV2 };
auto loaded() const -> bool { return _loaded; }
auto model() const -> Model { return _model; }
@ -67,3 +67,4 @@ extern System system;
auto Model::WonderSwan() -> bool { return system.model() == System::Model::WonderSwan; }
auto Model::WonderSwanColor() -> bool { return system.model() == System::Model::WonderSwanColor; }
auto Model::SwanCrystal() -> bool { return system.model() == System::Model::SwanCrystal; }
auto Model::PocketChallengeV2() -> bool { return system.model() == System::Model::PocketChallengeV2; }

View File

@ -32,9 +32,10 @@ namespace WonderSwan {
};
struct Model {
inline static auto WonderSwan() -> bool; //SW-001 (ASWAN)
inline static auto WonderSwanColor() -> bool; //WSC-001 (SPHINX)
inline static auto SwanCrystal() -> bool; //SCT-001 (SPHINX2)
inline static auto WonderSwan() -> bool; //SW-001 (ASWAN)
inline static auto WonderSwanColor() -> bool; //WSC-001 (SPHINX)
inline static auto SwanCrystal() -> bool; //SCT-001 (SPHINX2)
inline static auto PocketChallengeV2() -> bool; //(ASWAN)
};
#include <ws/memory/memory.hpp>

View File

@ -11,6 +11,7 @@ Icarus::Icarus() {
Database::GameGear = BML::unserialize(string::read(locate("Database/Game Gear.bml")));
Database::WonderSwan = BML::unserialize(string::read(locate("Database/WonderSwan.bml")));
Database::WonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.bml")));
Database::PocketChallengeV2 = BML::unserialize(string::read(locate("Database/Pocket Challenge V2.bml")));
Database::BSMemory = BML::unserialize(string::read(locate("Database/BS Memory.bml")));
Database::SufamiTurbo = BML::unserialize(string::read(locate("Database/Sufami Turbo.bml")));
}
@ -50,6 +51,7 @@ auto Icarus::manifest(string location) -> string {
if(type == ".gg") return gameGearManifest(location);
if(type == ".ws") return wonderSwanManifest(location);
if(type == ".wsc") return wonderSwanColorManifest(location);
if(type == ".pc2") return pocketChallengeV2Manifest(location);
if(type == ".bs") return bsMemoryManifest(location);
if(type == ".st") return sufamiTurboManifest(location);
@ -93,6 +95,7 @@ auto Icarus::import(string location) -> string {
if(type == ".gg") return gameGearImport(buffer, location);
if(type == ".ws") return wonderSwanImport(buffer, location);
if(type == ".wsc") return wonderSwanColorImport(buffer, location);
if(type == ".pc2") return pocketChallengeV2Import(buffer, location);
if(type == ".bs") return bsMemoryImport(buffer, location);
if(type == ".st") return sufamiTurboImport(buffer, location);

View File

@ -96,6 +96,11 @@ struct Icarus {
auto wonderSwanColorManifest(vector<uint8_t>& buffer, string location) -> string;
auto wonderSwanColorImport(vector<uint8_t>& buffer, string location) -> string;
//pocket-challenge-v2.cpp
auto pocketChallengeV2Manifest(string location) -> string;
auto pocketChallengeV2Manifest(vector<uint8_t>& buffer, string location) -> string;
auto pocketChallengeV2Import(vector<uint8_t>& buffer, string location) -> string;
//bs-memory.cpp
auto bsMemoryManifest(string location) -> string;
auto bsMemoryManifest(vector<uint8_t>& buffer, string location) -> string;
@ -124,6 +129,7 @@ namespace Database {
Markup::Node GameGear;
Markup::Node WonderSwan;
Markup::Node WonderSwanColor;
Markup::Node PocketChallengeV2;
Markup::Node BSMemory;
Markup::Node SufamiTurbo;
};

View File

@ -0,0 +1,39 @@
auto Icarus::pocketChallengeV2Manifest(string location) -> string {
vector<uint8_t> buffer;
concatenate(buffer, {location, "program.rom"});
return pocketChallengeV2Manifest(buffer, location);
}
auto Icarus::pocketChallengeV2Manifest(vector<uint8_t>& buffer, string location) -> string {
if(settings["icarus/UseDatabase"].boolean()) {
auto digest = Hash::SHA256(buffer).digest();
for(auto game : Database::PocketChallengeV2.find("game")) {
if(game["sha256"].text() == digest) return BML::serialize(game);
}
}
if(settings["icarus/UseHeuristics"].boolean()) {
Heuristics::WonderSwan game{buffer, location};
if(auto manifest = game.manifest()) return manifest;
}
return {};
}
auto Icarus::pocketChallengeV2Import(vector<uint8_t>& buffer, string location) -> string {
auto name = Location::prefix(location);
auto source = Location::path(location);
string target{settings["Library/Location"].text(), "Pocket Challenge V2/", name, ".pc2/"};
auto manifest = pocketChallengeV2Manifest(buffer, location);
if(!manifest) return failure("failed to parse ROM image");
if(!create(target)) return failure("library path unwritable");
if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) {
copy({source, name, ".sav"}, {target, "save.ram"});
}
if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest);
write({target, "program.rom"}, buffer);
return success(target);
}

View File

@ -44,6 +44,7 @@ Settings settings;
#include "core/game-gear.cpp"
#include "core/wonderswan.cpp"
#include "core/wonderswan-color.cpp"
#include "core/pocket-challenge-v2.cpp"
#include "core/bs-memory.cpp"
#include "core/sufami-turbo.cpp"
@ -92,6 +93,7 @@ auto nall::main(string_vector args) -> void {
"*.gg:"
"*.ws:"
"*.wsc:"
"*.pc2:"
"*.bs:"
"*.st:"
"*.zip"

View File

@ -110,6 +110,9 @@ auto ScanDialog::gamePakType(const string& type) -> bool {
|| type == ".gbc"
|| type == ".gba"
|| type == ".gg"
|| type == ".ws"
|| type == ".wsc"
|| type == ".pc2"
|| type == ".bs"
|| type == ".st";
}
@ -126,6 +129,9 @@ auto ScanDialog::gameRomType(const string& type) -> bool {
|| type == ".gbc"
|| type == ".gba"
|| type == ".gg"
|| type == ".ws"
|| type == ".wsc"
|| type == ".pc2"
|| type == ".bs"
|| type == ".st";
}