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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@ struct ID {
System, System,
WonderSwan, WonderSwan,
WonderSwanColor, WonderSwanColor,
PocketChallengeV2,
}; };
struct Port { enum : uint { struct Port { enum : uint {
@ -64,6 +65,17 @@ struct WonderSwanColorInterface : Interface {
auto load(uint id) -> bool override; 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 { struct Settings {
bool blurEmulation = true; bool blurEmulation = true;
bool colorEmulation = 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 { 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 { auto InternalRAM::read(uint16 addr, uint size) -> uint32 {

View File

@ -1,5 +1,5 @@
struct System : IO { 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 loaded() const -> bool { return _loaded; }
auto model() const -> Model { return _model; } 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::WonderSwan() -> bool { return system.model() == System::Model::WonderSwan; }
auto Model::WonderSwanColor() -> bool { return system.model() == System::Model::WonderSwanColor; } auto Model::WonderSwanColor() -> bool { return system.model() == System::Model::WonderSwanColor; }
auto Model::SwanCrystal() -> bool { return system.model() == System::Model::SwanCrystal; } 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 { struct Model {
inline static auto WonderSwan() -> bool; //SW-001 (ASWAN) inline static auto WonderSwan() -> bool; //SW-001 (ASWAN)
inline static auto WonderSwanColor() -> bool; //WSC-001 (SPHINX) inline static auto WonderSwanColor() -> bool; //WSC-001 (SPHINX)
inline static auto SwanCrystal() -> bool; //SCT-001 (SPHINX2) inline static auto SwanCrystal() -> bool; //SCT-001 (SPHINX2)
inline static auto PocketChallengeV2() -> bool; //(ASWAN)
}; };
#include <ws/memory/memory.hpp> #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::GameGear = BML::unserialize(string::read(locate("Database/Game Gear.bml")));
Database::WonderSwan = BML::unserialize(string::read(locate("Database/WonderSwan.bml"))); Database::WonderSwan = BML::unserialize(string::read(locate("Database/WonderSwan.bml")));
Database::WonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.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::BSMemory = BML::unserialize(string::read(locate("Database/BS Memory.bml")));
Database::SufamiTurbo = BML::unserialize(string::read(locate("Database/Sufami Turbo.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 == ".gg") return gameGearManifest(location);
if(type == ".ws") return wonderSwanManifest(location); if(type == ".ws") return wonderSwanManifest(location);
if(type == ".wsc") return wonderSwanColorManifest(location); if(type == ".wsc") return wonderSwanColorManifest(location);
if(type == ".pc2") return pocketChallengeV2Manifest(location);
if(type == ".bs") return bsMemoryManifest(location); if(type == ".bs") return bsMemoryManifest(location);
if(type == ".st") return sufamiTurboManifest(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 == ".gg") return gameGearImport(buffer, location);
if(type == ".ws") return wonderSwanImport(buffer, location); if(type == ".ws") return wonderSwanImport(buffer, location);
if(type == ".wsc") return wonderSwanColorImport(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 == ".bs") return bsMemoryImport(buffer, location);
if(type == ".st") return sufamiTurboImport(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 wonderSwanColorManifest(vector<uint8_t>& buffer, string location) -> string;
auto wonderSwanColorImport(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 //bs-memory.cpp
auto bsMemoryManifest(string location) -> string; auto bsMemoryManifest(string location) -> string;
auto bsMemoryManifest(vector<uint8_t>& buffer, string location) -> string; auto bsMemoryManifest(vector<uint8_t>& buffer, string location) -> string;
@ -124,6 +129,7 @@ namespace Database {
Markup::Node GameGear; Markup::Node GameGear;
Markup::Node WonderSwan; Markup::Node WonderSwan;
Markup::Node WonderSwanColor; Markup::Node WonderSwanColor;
Markup::Node PocketChallengeV2;
Markup::Node BSMemory; Markup::Node BSMemory;
Markup::Node SufamiTurbo; 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/game-gear.cpp"
#include "core/wonderswan.cpp" #include "core/wonderswan.cpp"
#include "core/wonderswan-color.cpp" #include "core/wonderswan-color.cpp"
#include "core/pocket-challenge-v2.cpp"
#include "core/bs-memory.cpp" #include "core/bs-memory.cpp"
#include "core/sufami-turbo.cpp" #include "core/sufami-turbo.cpp"
@ -92,6 +93,7 @@ auto nall::main(string_vector args) -> void {
"*.gg:" "*.gg:"
"*.ws:" "*.ws:"
"*.wsc:" "*.wsc:"
"*.pc2:"
"*.bs:" "*.bs:"
"*.st:" "*.st:"
"*.zip" "*.zip"

View File

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