mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
540d960e30
commit
8617711ea2
|
@ -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/";
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
system name:Pocket Challenge V2
|
||||||
|
eeprom name=internal.ram size=128
|
|
@ -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());
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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}};
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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"
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue