Update to v106r44 release.

byuu says:

Changelog:

  - hiro/Windows: use `WS_CLIPSIBLINGS` on Label to prevent resize
    drawing issues
  - bsnes: correct viewport resizing
  - bsnes: speed up window resizing a little bit
  - bsnes: fix the cheat editor list enable checkbox
  - bsnes: fix the state manager filename display in game ROM mode
  - bsnes: fix the state manager save/rename/remove functionality in
    game ROM mode
  - bsnes: correct path searching for IPS and BPS patches in game ROM
    mode
  - bsnes: patch BS-X town cartridge to disable play limits
  - bsnes: do not load (program,data,expansion).(rom,flash) from disk in
    game pak mode
      - this is required to support soft-patching and ROM hacks
  - bsnes: added speed mode selection (50%, 75%, 100%, 150%, 200%);
    maintains proper pitch
  - bsnes: added icons to the menubar
      - this is particularly useful to tell game ROMs from game paks in
        the load recent game menu
  - bsnes: added emblem at bottom left of status bar to indicate if a
    game is verified or not
      - verified means it is in the icarus verified game dump database
      - the verified diamond is orange; the unverified diamond is blue
  - bsnes: added an option (which defaults to off) to warn when loading
    unverified games
      - working around a bug in GTK, I have to use the uglier
        MessageWindow instead of MessageDialog
  - bsnes: added (non-functional) link to <https://doc.byuu.org/bsnes/>
    to the help menu
  - bsnes: added GUI setting to toggle memory auto-save feature
  - bsnes: added GUI setting to toggle capturing a backup save state
    when closing the emulator
  - bsnes: made auto-saving states on exit an option
  - bsnes: added an option to auto-load the auto-saved state on load
      - basically, the two combined implements auto-resume
  - bsnes: when firmware is missing, offer to take the user to the
    online help documentation
  - bsnes: added fast PPU option to disable the sprite limit
      - increase from 32 items/line + 34 tiles/line to 128 items/line +
        128 tiles/line
      - technically, 1024 tiles/line are possible with 128 sprites at
        64-width
      - but this is just a waste of cache locality and worst-case
        performance; it'll never happen

Errata:

  - hiro/Windows: fallthrough on Canvas `WM_ERASEBKGND` to prevent
    startup flicker
This commit is contained in:
Tim Allen 2018-06-28 16:28:27 +10:00
parent b14c6bf155
commit ec960c5172
30 changed files with 559 additions and 319 deletions

View File

@ -13,13 +13,13 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "106.43"; static const string Version = "106.44";
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/";
//incremented only when serialization format changes //incremented only when serialization format changes
static const string SerializerVersion = "104"; static const string SerializerVersion = "106.44";
namespace Constants { namespace Constants {
namespace Colorburst { namespace Colorburst {

View File

@ -48,6 +48,7 @@ auto Cartridge::loadCartridge(Markup::Node node) -> void {
} }
if(auto node = board["memory(type=ROM,content=Program)"]) loadROM(node); if(auto node = board["memory(type=ROM,content=Program)"]) loadROM(node);
if(auto node = board["memory(type=ROM,content=Expansion)"]) loadROM(node); //todo: handle this better
if(auto node = board["memory(type=RAM,content=Save)"]) loadRAM(node); if(auto node = board["memory(type=RAM,content=Save)"]) loadRAM(node);
if(auto node = board["processor(identifier=ICD)"]) loadICD(node); if(auto node = board["processor(identifier=ICD)"]) loadICD(node);
if(auto node = board["processor(identifier=MCC)"]) loadMCC(node); if(auto node = board["processor(identifier=MCC)"]) loadMCC(node);

View File

@ -234,6 +234,7 @@ auto Interface::cheatSet(const string_vector& list) -> void {
auto Interface::cap(const string& name) -> bool { auto Interface::cap(const string& name) -> bool {
if(name == "Fast PPU") return true; if(name == "Fast PPU") return true;
if(name == "Fast PPU/No Sprite Limit") return true;
if(name == "Fast DSP") return true; if(name == "Fast DSP") return true;
if(name == "Mode") return true; if(name == "Mode") return true;
if(name == "Blur Emulation") return true; if(name == "Blur Emulation") return true;
@ -250,6 +251,7 @@ auto Interface::get(const string& name) -> any {
: "" : ""
}; };
if(name == "Fast PPU") return settings.fastPPU; if(name == "Fast PPU") return settings.fastPPU;
if(name == "Fast PPU/No Sprite Limit") return settings.fastPPUNoSpriteLimit;
if(name == "Fast DSP") return settings.fastDSP; if(name == "Fast DSP") return settings.fastDSP;
if(name == "Blur Emulation") return settings.blurEmulation; if(name == "Blur Emulation") return settings.blurEmulation;
if(name == "Color Emulation") return settings.colorEmulation; if(name == "Color Emulation") return settings.colorEmulation;
@ -262,6 +264,10 @@ auto Interface::set(const string& name, const any& value) -> bool {
settings.fastPPU = value.get<bool>(); settings.fastPPU = value.get<bool>();
return true; return true;
} }
if(name == "Fast PPU/No Sprite Limit" && value.is<bool>()) {
settings.fastPPUNoSpriteLimit = value.get<bool>();
return true;
}
if(name == "Fast DSP" && value.is<bool>()) { if(name == "Fast DSP" && value.is<bool>()) {
settings.fastDSP = value.get<bool>(); settings.fastDSP = value.get<bool>();
return true; return true;
@ -275,7 +281,10 @@ auto Interface::set(const string& name, const any& value) -> bool {
Emulator::video.setPalette(); Emulator::video.setPalette();
return true; return true;
} }
if(name == "Scanline Emulation" && value.is<bool>()) return settings.scanlineEmulation = value.get<bool>(), true; if(name == "Scanline Emulation" && value.is<bool>()) {
settings.scanlineEmulation = value.get<bool>();
return true;
}
return false; return false;
} }

View File

@ -68,6 +68,7 @@ struct Interface : Emulator::Interface {
struct Settings { struct Settings {
bool fastPPU = false; bool fastPPU = false;
bool fastPPUNoSpriteLimit = false;
bool fastDSP = false; bool fastDSP = false;
bool blurEmulation = true; bool blurEmulation = true;

View File

@ -8,8 +8,8 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void {
uint itemCount = 0; uint itemCount = 0;
uint tileCount = 0; uint tileCount = 0;
for(auto& item : items) item.valid = false; for(auto n : range(ppu.ItemLimit)) items[n].valid = false;
for(auto& tile : tiles) tile.valid = false; for(auto n : range(ppu.TileLimit)) tiles[n].valid = false;
for(auto n : range(128)) { for(auto n : range(128)) {
ObjectItem item{true, self.first + n}; ObjectItem item{true, self.first + n};
@ -33,12 +33,12 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void {
if((y >= object.y && y < object.y + height) if((y >= object.y && y < object.y + height)
|| (object.y + height >= 256 && y < (object.y + height & 255)) || (object.y + height >= 256 && y < (object.y + height & 255))
) { ) {
if(itemCount++ >= 32) break; if(itemCount++ >= ppu.ItemLimit) break;
items[itemCount - 1] = item; items[itemCount - 1] = item;
} }
} }
for(int n = 31; n >= 0; n--) { for(int n : rrange(ppu.ItemLimit)) {
const auto& item = items[n]; const auto& item = items[n];
if(!item.valid) continue; if(!item.valid) continue;
@ -85,18 +85,18 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void {
uint address = tiledataAddress + ((characterY + (characterX + mirrorX & 15)) << 4); uint address = tiledataAddress + ((characterY + (characterX + mirrorX & 15)) << 4);
tile.number = address >> 4; tile.number = address >> 4;
if(tileCount++ >= 34) break; if(tileCount++ >= ppu.TileLimit) break;
tiles[tileCount - 1] = tile; tiles[tileCount - 1] = tile;
} }
} }
ppu.io.obj.rangeOver |= itemCount > 32; ppu.io.obj.rangeOver |= itemCount > ppu.ItemLimit;
ppu.io.obj.timeOver |= tileCount > 34; ppu.io.obj.timeOver |= tileCount > ppu.TileLimit;
uint8 palette[256]; uint8 palette[256];
uint8 priority[256]; uint8 priority[256];
for(uint n : range(34)) { for(uint n : range(ppu.TileLimit)) {
const auto& tile = tiles[n]; const auto& tile = tiles[n];
if(!tile.valid) continue; if(!tile.valid) continue;

View File

@ -124,6 +124,9 @@ auto PPU::power(bool reset) -> void {
io = {}; io = {};
updateVideoMode(); updateVideoMode();
ItemLimit = !settings.fastPPUNoSpriteLimit ? 32 : 128;
TileLimit = !settings.fastPPUNoSpriteLimit ? 34 : 128;
Line::start = 0; Line::start = 0;
Line::count = 0; Line::count = 0;
} }

View File

@ -259,6 +259,8 @@ public:
//[unserialized] //[unserialized]
uint32* output; uint32* output;
array<uint8*[3]> tilecache; //bitplane -> bitmap tiledata array<uint8*[3]> tilecache; //bitplane -> bitmap tiledata
uint ItemLimit;
uint TileLimit;
struct Line { struct Line {
//line.cpp //line.cpp
@ -276,7 +278,6 @@ public:
//mode7.cpp //mode7.cpp
auto renderMode7(PPU::IO::Background&, uint source) -> void; auto renderMode7(PPU::IO::Background&, uint source) -> void;
auto renderMode7Hires(PPU::IO::Background&, uint source) -> void;
//object.cpp //object.cpp
auto renderObject(PPU::IO::Object&) -> void; auto renderObject(PPU::IO::Object&) -> void;
@ -291,8 +292,8 @@ public:
IO io; IO io;
array<uint15[256]> cgram; array<uint15[256]> cgram;
array<ObjectItem[32]> items; array<ObjectItem[128]> items; //32 on real hardware
array<ObjectTile[34]> tiles; array<ObjectTile[128]> tiles; //34 on real hardware; 1024 max (128 * 64-width tiles)
array<Pixel[256]> above; array<Pixel[256]> above;
array<Pixel[256]> below; array<Pixel[256]> below;

View File

@ -7,20 +7,20 @@ Presentation::Presentation() {
presentation = this; presentation = this;
systemMenu.setText("System"); systemMenu.setText("System");
loadGame.setText("Load Game ...").onActivate([&] { loadGame.setIcon(Icon::Action::Open).setText("Load Game ...").onActivate([&] {
program->load(); program->load();
}); });
loadRecentGame.setText("Load Recent Game"); loadRecentGame.setIcon(Icon::Action::Open).setText("Load Recent Game");
updateRecentGames(); updateRecentGames();
resetSystem.setText("Reset System").setEnabled(false).onActivate([&] { resetSystem.setIcon(Icon::Action::Refresh).setText("Reset System").setEnabled(false).onActivate([&] {
program->reset(); program->reset();
}); });
unloadGame.setText("Unload Game").setEnabled(false).onActivate([&] { unloadGame.setIcon(Icon::Action::Remove).setText("Unload Game").setEnabled(false).onActivate([&] {
program->unload(); program->unload();
}); });
controllerPort1.setText("Controller Port 1"); controllerPort1.setIcon(Icon::Device::Joypad).setText("Controller Port 1");
controllerPort2.setText("Controller Port 2"); controllerPort2.setIcon(Icon::Device::Joypad).setText("Controller Port 2");
expansionPort.setText("Expansion Port"); expansionPort.setIcon(Icon::Device::Storage).setText("Expansion Port");
for(auto& port : emulator->ports) { for(auto& port : emulator->ports) {
Menu* menu = nullptr; Menu* menu = nullptr;
if(port.name == "Controller Port 1") menu = &controllerPort1; if(port.name == "Controller Port 1") menu = &controllerPort1;
@ -53,22 +53,31 @@ Presentation::Presentation() {
devices.objects<MenuRadioItem>()(0).doActivate(); devices.objects<MenuRadioItem>()(0).doActivate();
} }
} }
quit.setText("Quit").onActivate([&] { program->quit(); }); quit.setIcon(Icon::Action::Quit).setText("Quit").onActivate([&] { program->quit(); });
settingsMenu.setText("Settings"); settingsMenu.setText("Settings");
viewMenu.setText("View"); scaleMenu.setIcon(Icon::Emblem::Image).setText("View");
smallView.setText("Small").onActivate([&] { smallestScale.setText("Smallest (240p)").onActivate([&] {
settings["View/Size"].setValue("Smallest");
resizeWindow();
});
smallScale.setText("Small (480p)").onActivate([&] {
settings["View/Size"].setValue("Small"); settings["View/Size"].setValue("Small");
resizeWindow(); resizeWindow();
}); });
mediumView.setText("Medium").onActivate([&] { mediumScale.setText("Medium (720p)").onActivate([&] {
settings["View/Size"].setValue("Medium"); settings["View/Size"].setValue("Medium");
resizeWindow(); resizeWindow();
}); });
largeView.setText("Large").onActivate([&] { largeScale.setText("Large (960p)").onActivate([&] {
settings["View/Size"].setValue("Large"); settings["View/Size"].setValue("Large");
resizeWindow(); resizeWindow();
}); });
largestScale.setText("Largest (1200p)").onActivate([&] {
settings["View/Size"].setValue("Largest");
resizeWindow();
});
outputMenu.setIcon(Icon::Emblem::Image).setText("Output");
aspectCorrection.setText("Aspect Correction").setChecked(settings["View/AspectCorrection"].boolean()).onToggle([&] { aspectCorrection.setText("Aspect Correction").setChecked(settings["View/AspectCorrection"].boolean()).onToggle([&] {
settings["View/AspectCorrection"].setValue(aspectCorrection.checked()); settings["View/AspectCorrection"].setValue(aspectCorrection.checked());
resizeWindow(); resizeWindow();
@ -85,7 +94,7 @@ Presentation::Presentation() {
settings["View/BlurEmulation"].setValue(blurEmulation.checked()); settings["View/BlurEmulation"].setValue(blurEmulation.checked());
emulator->set("Blur Emulation", blurEmulation.checked()); emulator->set("Blur Emulation", blurEmulation.checked());
}).doToggle(); }).doToggle();
shaderMenu.setText("Shader"); shaderMenu.setIcon(Icon::Emblem::Image).setText("Shader");
updateShaders(); updateShaders();
synchronizeVideo.setText("Synchronize Video").setChecked(settings["Video/Blocking"].boolean()).onToggle([&] { synchronizeVideo.setText("Synchronize Video").setChecked(settings["Video/Blocking"].boolean()).onToggle([&] {
settings["Video/Blocking"].setValue(synchronizeVideo.checked()); settings["Video/Blocking"].setValue(synchronizeVideo.checked());
@ -108,38 +117,47 @@ Presentation::Presentation() {
} }
if(visible()) resizeWindow(); if(visible()) resizeWindow();
}); });
videoSettings.setText("Video ...").onActivate([&] { settingsWindow->show(0); }); videoSettings.setIcon(Icon::Device::Display).setText("Video ...").onActivate([&] { settingsWindow->show(0); });
audioSettings.setText("Audio ...").onActivate([&] { settingsWindow->show(1); }); audioSettings.setIcon(Icon::Device::Speaker).setText("Audio ...").onActivate([&] { settingsWindow->show(1); });
inputSettings.setText("Input ...").onActivate([&] { settingsWindow->show(2); }); inputSettings.setIcon(Icon::Device::Joypad).setText("Input ...").onActivate([&] { settingsWindow->show(2); });
hotkeySettings.setText("Hotkeys ...").onActivate([&] { settingsWindow->show(3); }); hotkeySettings.setIcon(Icon::Device::Keyboard).setText("Hotkeys ...").onActivate([&] { settingsWindow->show(3); });
pathSettings.setText("Paths ...").onActivate([&] { settingsWindow->show(4); }); pathSettings.setIcon(Icon::Emblem::Folder).setText("Paths ...").onActivate([&] { settingsWindow->show(4); });
advancedSettings.setText("Advanced ...").onActivate([&] { settingsWindow->show(5); }); advancedSettings.setIcon(Icon::Action::Settings).setText("Advanced ...").onActivate([&] { settingsWindow->show(5); });
toolsMenu.setText("Tools").setVisible(false); toolsMenu.setText("Tools").setVisible(false);
saveState.setText("Save State"); saveState.setIcon(Icon::Action::Save).setText("Save State");
for(uint index : range(QuickStates)) { for(uint index : range(QuickStates)) {
saveState.append(MenuItem().setText({"Slot ", 1 + index}).onActivate([=] { saveState.append(MenuItem().setText({"Slot ", 1 + index}).onActivate([=] {
program->saveState({"quick/slot ", 1 + index}); program->saveState({"quick/slot ", 1 + index});
})); }));
} }
loadState.setText("Load State"); loadState.setIcon(Icon::Media::Play).setText("Load State");
for(uint index : range(QuickStates)) { for(uint index : range(QuickStates)) {
loadState.append(MenuItem().setText({"Slot ", 1 + index}).onActivate([=] { loadState.append(MenuItem().setText({"Slot ", 1 + index}).onActivate([=] {
program->loadState({"quick/slot ", 1 + index}); program->loadState({"quick/slot ", 1 + index});
})); }));
} }
loadState.append(MenuSeparator()); loadState.append(MenuSeparator());
loadState.append(MenuItem().setText("Recovery").onActivate([&] { loadState.append(MenuItem().setIcon(Icon::Edit::Undo).setText("Undo Last Save").onActivate([&] {
program->loadState("quick/recovery"); program->loadState("quick/recovery");
})); }));
speedMenu.setIcon(Icon::Device::Clock).setText("Speed");
speedSlowest.setText("Slowest (50%)").setProperty("multiplier", "2.0").onActivate([&] { program->updateAudioFrequency(); });
speedSlow.setText("Slow (75%)").setProperty("multiplier", "1.333").onActivate([&] { program->updateAudioFrequency(); });
speedNormal.setText("Normal (100%)").setProperty("multiplier", "1.0").onActivate([&] { program->updateAudioFrequency(); });
speedFast.setText("Fast (150%)").setProperty("multiplier", "0.667").onActivate([&] { program->updateAudioFrequency(); });
speedFastest.setText("Fastest (200%)").setProperty("multiplier", "0.5").onActivate([&] { program->updateAudioFrequency(); });
pauseEmulation.setText("Pause Emulation").onToggle([&] { pauseEmulation.setText("Pause Emulation").onToggle([&] {
if(pauseEmulation.checked()) audio->clear(); if(pauseEmulation.checked()) audio->clear();
}); });
cheatEditor.setText("Cheat Editor ...").onActivate([&] { toolsWindow->show(0); }); cheatEditor.setIcon(Icon::Edit::Replace).setText("Cheat Editor ...").onActivate([&] { toolsWindow->show(0); });
stateManager.setText("State Manager ...").onActivate([&] { toolsWindow->show(1); }); stateManager.setIcon(Icon::Application::FileManager).setText("State Manager ...").onActivate([&] { toolsWindow->show(1); });
helpMenu.setText("Help"); helpMenu.setText("Help");
about.setText("About ...").onActivate([&] { documentation.setIcon(Icon::Application::Browser).setText("Documentation ...").onActivate([&] {
invoke("https://doc.byuu.org/bsnes/");
});
about.setIcon(Icon::Prompt::Question).setText("About ...").onActivate([&] {
aboutWindow->setCentered(*this).setVisible().setFocused(); aboutWindow->setCentered(*this).setVisible().setFocused();
}); });
@ -153,15 +171,27 @@ Presentation::Presentation() {
layout.remove(statusLayout); layout.remove(statusLayout);
} }
statusLeft.setFont(Font().setBold()); auto font = Font().setBold();
statusLeft.setAlignment(0.0); auto back = Color{ 32, 32, 32};
statusLeft.setBackgroundColor({ 32, 32, 32}); auto fore = Color{255, 255, 255};
statusLeft.setForegroundColor({255, 255, 255});
statusRight.setFont(Font().setBold()); updateStatusIcon();
spacerIcon.setBackgroundColor(back).setForegroundColor(fore);
spacerLeft.setBackgroundColor(back).setForegroundColor(fore);
statusLeft.setFont(font);
statusLeft.setAlignment(0.0);
statusLeft.setBackgroundColor(back);
statusLeft.setForegroundColor(fore);
statusRight.setFont(font);
statusRight.setAlignment(1.0); statusRight.setAlignment(1.0);
statusRight.setBackgroundColor({ 32, 32, 32}); statusRight.setBackgroundColor(back);
statusRight.setForegroundColor({255, 255, 255}); statusRight.setForegroundColor(fore);
spacerRight.setBackgroundColor(back).setForegroundColor(fore);
program->updateStatus(); program->updateStatus();
@ -200,6 +230,19 @@ Presentation::Presentation() {
#endif #endif
} }
auto Presentation::updateStatusIcon() -> void {
image icon;
icon.allocate(16, StatusHeight);
icon.fill(0xff202020);
if(emulator->loaded()) {
image emblem{program->verified() ? Icon::Emblem::Program : Icon::Emblem::Binary};
icon.impose(image::blend::sourceAlpha, 0, (StatusHeight - 16) / 2, emblem, 0, 0, 16, 16);
}
statusIcon.setIcon(icon);
}
auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void { auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void {
return; return;
@ -225,8 +268,8 @@ auto Presentation::clearViewport() -> void {
uint32_t* output; uint32_t* output;
uint length; uint length;
uint width = viewport.geometry().width(); uint width = 16;
uint height = viewport.geometry().height(); uint height = 16;
if(video->lock(output, length, width, height)) { if(video->lock(output, length, width, height)) {
for(uint y : range(height)) { for(uint y : range(height)) {
auto line = output + y * (length >> 2); auto line = output + y * (length >> 2);
@ -262,8 +305,9 @@ auto Presentation::resizeViewport() -> void {
viewportHeight = height * multiplier; viewportHeight = height * multiplier;
} }
uint paddingWidth = (windowWidth - viewportWidth) / 2; //center viewport within viewportLayout by use of viewportLayout padding
uint paddingHeight = (windowHeight - viewportHeight) / 2; uint paddingWidth = windowWidth - viewportWidth;
uint paddingHeight = windowHeight - viewportHeight;
viewportLayout.setPadding({ viewportLayout.setPadding({
paddingWidth / 2, paddingHeight / 2, paddingWidth / 2, paddingHeight / 2,
paddingWidth - paddingWidth / 2, paddingHeight - paddingHeight / 2 paddingWidth - paddingWidth / 2, paddingHeight - paddingHeight / 2
@ -278,9 +322,11 @@ auto Presentation::resizeWindow() -> void {
uint statusHeight = settings["UserInterface/ShowStatusBar"].boolean() ? StatusHeight : 0; uint statusHeight = settings["UserInterface/ShowStatusBar"].boolean() ? StatusHeight : 0;
uint multiplier = 2; uint multiplier = 2;
if(settings["View/Size"].text() == "Small" ) multiplier = 2; if(settings["View/Size"].text() == "Smallest") multiplier = 1;
if(settings["View/Size"].text() == "Medium") multiplier = 3; if(settings["View/Size"].text() == "Small" ) multiplier = 2;
if(settings["View/Size"].text() == "Large" ) multiplier = 4; if(settings["View/Size"].text() == "Medium" ) multiplier = 3;
if(settings["View/Size"].text() == "Large" ) multiplier = 4;
if(settings["View/Size"].text() == "Largest" ) multiplier = 5;
setSize({width * multiplier, height * multiplier + statusHeight}); setSize({width * multiplier, height * multiplier + statusHeight});
resizeViewport(); resizeViewport();
@ -322,17 +368,20 @@ auto Presentation::updateRecentGames() -> void {
displayName.append(Location::prefix(part), " + "); displayName.append(Location::prefix(part), " + ");
} }
displayName.trimRight(" + ", 1L); displayName.trimRight(" + ", 1L);
item.setText(displayName).onActivate([=] { item.setIcon(games(0).endsWith("/") ? Icon::Action::Open : Icon::Emblem::File);
item.setText(displayName);
item.onActivate([=] {
program->gameQueue = games; program->gameQueue = games;
program->load(); program->load();
}); });
} else { } else {
item.setText("<empty>").setEnabled(false); item.setText("<empty>");
item.setEnabled(false);
} }
loadRecentGame.append(item); loadRecentGame.append(item);
} }
loadRecentGame.append(MenuSeparator()); loadRecentGame.append(MenuSeparator());
loadRecentGame.append(MenuItem().setText("Clear List").onActivate([&] { loadRecentGame.append(MenuItem().setIcon(Icon::Edit::Clear).setText("Clear List").onActivate([&] {
for(auto index : range(RecentGames)) { for(auto index : range(RecentGames)) {
settings({"Game/Recent/", 1 + index}).setValue(""); settings({"Game/Recent/", 1 + index}).setValue("");
} }

View File

@ -10,9 +10,10 @@ struct AboutWindow : Window {
struct Presentation : Window { struct Presentation : Window {
enum : uint { RecentGames = 9, QuickStates = 9 }; enum : uint { RecentGames = 9, QuickStates = 9 };
enum : uint { StatusHeight = 25 }; enum : uint { StatusHeight = 24 };
Presentation(); Presentation();
auto updateStatusIcon() -> void;
auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void; auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void;
auto clearViewport() -> void; auto clearViewport() -> void;
auto resizeViewport() -> void; auto resizeViewport() -> void;
@ -37,15 +38,17 @@ struct Presentation : Window {
MenuSeparator quitSeparator{&systemMenu}; MenuSeparator quitSeparator{&systemMenu};
MenuItem quit{&systemMenu}; MenuItem quit{&systemMenu};
Menu settingsMenu{&menuBar}; Menu settingsMenu{&menuBar};
Menu viewMenu{&settingsMenu}; Menu scaleMenu{&settingsMenu};
MenuItem smallView{&viewMenu}; MenuItem smallestScale{&scaleMenu};
MenuItem mediumView{&viewMenu}; MenuItem smallScale{&scaleMenu};
MenuItem largeView{&viewMenu}; MenuItem mediumScale{&scaleMenu};
MenuSeparator viewSeparator{&viewMenu}; MenuItem largeScale{&scaleMenu};
MenuCheckItem aspectCorrection{&viewMenu}; MenuItem largestScale{&scaleMenu};
MenuCheckItem overscanCropping{&viewMenu}; Menu outputMenu{&settingsMenu};
MenuCheckItem integralScaling{&viewMenu}; MenuCheckItem aspectCorrection{&outputMenu};
MenuCheckItem blurEmulation{&viewMenu}; MenuCheckItem overscanCropping{&outputMenu};
MenuCheckItem integralScaling{&outputMenu};
MenuCheckItem blurEmulation{&outputMenu};
Menu shaderMenu{&settingsMenu}; Menu shaderMenu{&settingsMenu};
MenuSeparator settingsSeparatorA{&settingsMenu}; MenuSeparator settingsSeparatorA{&settingsMenu};
MenuCheckItem synchronizeVideo{&settingsMenu}; MenuCheckItem synchronizeVideo{&settingsMenu};
@ -62,19 +65,33 @@ struct Presentation : Window {
Menu toolsMenu{&menuBar}; Menu toolsMenu{&menuBar};
Menu saveState{&toolsMenu}; Menu saveState{&toolsMenu};
Menu loadState{&toolsMenu}; Menu loadState{&toolsMenu};
MenuSeparator toolsSeparatorA{&toolsMenu};
Menu speedMenu{&toolsMenu};
MenuRadioItem speedSlowest{&speedMenu};
MenuRadioItem speedSlow{&speedMenu};
MenuRadioItem speedNormal{&speedMenu};
MenuRadioItem speedFast{&speedMenu};
MenuRadioItem speedFastest{&speedMenu};
Group speedGroup{&speedSlowest, &speedSlow, &speedNormal, &speedFast, &speedFastest};
MenuCheckItem pauseEmulation{&toolsMenu}; MenuCheckItem pauseEmulation{&toolsMenu};
MenuSeparator toolsSeparator{&toolsMenu}; MenuSeparator toolsSeparatorB{&toolsMenu};
MenuItem cheatEditor{&toolsMenu}; MenuItem cheatEditor{&toolsMenu};
MenuItem stateManager{&toolsMenu}; MenuItem stateManager{&toolsMenu};
Menu helpMenu{&menuBar}; Menu helpMenu{&menuBar};
MenuItem documentation{&helpMenu};
MenuSeparator helpSeparator{&helpMenu};
MenuItem about{&helpMenu}; MenuItem about{&helpMenu};
VerticalLayout layout{this}; VerticalLayout layout{this};
HorizontalLayout viewportLayout{&layout, Size{~0, ~0}, 0}; HorizontalLayout viewportLayout{&layout, Size{~0, ~0}, 0};
Viewport viewport{&viewportLayout, Size{~0, ~0}, 0}; Viewport viewport{&viewportLayout, Size{~0, ~0}, 0};
HorizontalLayout statusLayout{&layout, Size{~0, StatusHeight}, 0}; HorizontalLayout statusLayout{&layout, Size{~0, StatusHeight}, 0};
Label spacerIcon{&statusLayout, Size{8, ~0}, 0};
Canvas statusIcon{&statusLayout, Size{16, ~0}, 0};
Label spacerLeft{&statusLayout, Size{4, ~0}, 0};
Label statusLeft{&statusLayout, Size{~0, ~0}, 0}; Label statusLeft{&statusLayout, Size{~0, ~0}, 0};
Label statusRight{&statusLayout, Size{80, ~0}, 0}; Label statusRight{&statusLayout, Size{80, ~0}, 0};
Label spacerRight{&statusLayout, Size{8, ~0}, 0};
}; };
extern unique_pointer<AboutWindow> aboutWindow; extern unique_pointer<AboutWindow> aboutWindow;

View File

@ -48,7 +48,11 @@ auto Program::updateAudioFrequency() -> void {
settings["Audio/Frequency"].setValue(audio->availableFrequencies()(0)); settings["Audio/Frequency"].setValue(audio->availableFrequencies()(0));
} }
audio->setFrequency(settings["Audio/Frequency"].real()); audio->setFrequency(settings["Audio/Frequency"].real());
Emulator::audio.setFrequency(settings["Audio/Frequency"].real() + settings["Audio/Skew"].integer()); double frequency = settings["Audio/Frequency"].real() + settings["Audio/Skew"].integer();
for(auto item : presentation->speedGroup.objects<MenuRadioItem>()) {
if(item.checked()) frequency *= item.property("multiplier").real();
}
Emulator::audio.setFrequency(frequency);
settingsWindow->audio.updateFrequency(); settingsWindow->audio.updateFrequency();
} }

View File

@ -152,8 +152,8 @@ auto Program::openRomBSMemory(string name, vfs::file::mode mode) -> vfs::shared:
return vfs::memory::file::open(bsMemory.program.data(), bsMemory.program.size()); return vfs::memory::file::open(bsMemory.program.data(), bsMemory.program.size());
} }
if(name == "program.flash" && mode == vfs::file::mode::read) { if(name == "program.flash") {
//write mode is not supported for ROM mode //writes are not flushed to disk in bsnes
return vfs::memory::file::open(bsMemory.program.data(), bsMemory.program.size()); return vfs::memory::file::open(bsMemory.program.data(), bsMemory.program.size());
} }

View File

@ -7,17 +7,31 @@ auto Program::load() -> void {
Emulator::audio.reset(2, audio->frequency()); Emulator::audio.reset(2, audio->frequency());
if(emulator->load(media.id)) { if(emulator->load(media.id)) {
gameQueue = {}; gameQueue = {};
if(!verified() && settingsWindow->advanced.warnOnUnverifiedGames.checked()) {
//todo: MessageDialog crashes with GTK+; unsure the reason why this happens
//once MessageDialog functions, add an "Always" option
if(MessageWindow(
"Warning: this game image is unverified. Running it *may* be a security risk.\n\n"
"Do you wish to run the game anyway?"
).setParent(*presentation).question() == MessageWindow::Response::No) {
emulator->unload();
return showMessage("Game loading cancelled");
}
}
updateInputDevices(); updateInputDevices();
applyHacks(); hackCompatibility();
emulator->power(); emulator->power();
updateVideoPalette(); if(settingsWindow->advanced.autoLoadStateOnLoad.checked()) {
updateAudioEffects(); program->loadState("quick/recovery");
}
showMessage(!appliedPatch() ? "Game loaded" : "Game loaded and patch applied"); showMessage(!appliedPatch() ? "Game loaded" : "Game loaded and patch applied");
presentation->setTitle(emulator->title()); presentation->setTitle(emulator->title());
presentation->resetSystem.setEnabled(true); presentation->resetSystem.setEnabled(true);
presentation->unloadGame.setEnabled(true); presentation->unloadGame.setEnabled(true);
presentation->toolsMenu.setVisible(true); presentation->toolsMenu.setVisible(true);
presentation->speedNormal.setChecked();
presentation->pauseEmulation.setChecked(false); presentation->pauseEmulation.setChecked(false);
presentation->updateStatusIcon();
presentation->resizeViewport(); presentation->resizeViewport();
toolsWindow->cheatEditor.loadCheats(); toolsWindow->cheatEditor.loadCheats();
toolsWindow->stateManager.loadStates(); toolsWindow->stateManager.loadStates();
@ -28,6 +42,10 @@ auto Program::load() -> void {
if(auto location = sufamiTurboA.location) locations.append("|", location); if(auto location = sufamiTurboA.location) locations.append("|", location);
if(auto location = sufamiTurboB.location) locations.append("|", location); if(auto location = sufamiTurboB.location) locations.append("|", location);
presentation->addRecentGame(locations); presentation->addRecentGame(locations);
updateVideoPalette();
updateAudioEffects();
updateAudioFrequency();
} }
break; break;
@ -81,11 +99,13 @@ auto Program::loadSuperFamicom(string location) -> void {
if(auto document = BML::unserialize(string::read(locate("database/Super Famicom.bml")))) { if(auto document = BML::unserialize(string::read(locate("database/Super Famicom.bml")))) {
if(auto game = document[{"game(sha256=", sha256, ")"}]) { if(auto game = document[{"game(sha256=", sha256, ")"}]) {
manifest = BML::serialize(game); manifest = BML::serialize(game);
superFamicom.verified = true;
} }
} }
superFamicom.label = heuristics.label(); superFamicom.label = heuristics.label();
superFamicom.manifest = manifest ? manifest : heuristics.manifest(); superFamicom.manifest = manifest ? manifest : heuristics.manifest();
applyHackOverclockSuperFX(); hackPatchMemory(rom);
hackOverclockSuperFX();
superFamicom.document = BML::unserialize(superFamicom.manifest); superFamicom.document = BML::unserialize(superFamicom.manifest);
superFamicom.location = location; superFamicom.location = location;
@ -130,11 +150,13 @@ auto Program::loadGameBoy(string location) -> void {
if(auto document = BML::unserialize(string::read(locate("database/Game Boy.bml")))) { if(auto document = BML::unserialize(string::read(locate("database/Game Boy.bml")))) {
if(auto game = document[{"game(sha256=", sha256, ")"}]) { if(auto game = document[{"game(sha256=", sha256, ")"}]) {
manifest = BML::serialize(game); manifest = BML::serialize(game);
gameBoy.verified = true;
} }
} }
if(auto document = BML::unserialize(string::read(locate("database/Game Boy Color.bml")))) { if(auto document = BML::unserialize(string::read(locate("database/Game Boy Color.bml")))) {
if(auto game = document[{"game(sha256=", sha256, ")"}]) { if(auto game = document[{"game(sha256=", sha256, ")"}]) {
manifest = BML::serialize(game); manifest = BML::serialize(game);
gameBoy.verified = true;
} }
} }
gameBoy.manifest = manifest ? manifest : heuristics.manifest(); gameBoy.manifest = manifest ? manifest : heuristics.manifest();
@ -163,6 +185,7 @@ auto Program::loadBSMemory(string location) -> void {
if(auto document = BML::unserialize(string::read(locate("database/BS Memory.bml")))) { if(auto document = BML::unserialize(string::read(locate("database/BS Memory.bml")))) {
if(auto game = document[{"game(sha256=", sha256, ")"}]) { if(auto game = document[{"game(sha256=", sha256, ")"}]) {
manifest = BML::serialize(game); manifest = BML::serialize(game);
bsMemory.verified = true;
} }
} }
bsMemory.manifest = manifest ? manifest : heuristics.manifest(); bsMemory.manifest = manifest ? manifest : heuristics.manifest();
@ -190,6 +213,7 @@ auto Program::loadSufamiTurboA(string location) -> void {
if(auto document = BML::unserialize(string::read(locate("database/Sufami Turbo.bml")))) { if(auto document = BML::unserialize(string::read(locate("database/Sufami Turbo.bml")))) {
if(auto game = document[{"game(sha256=", sha256, ")"}]) { if(auto game = document[{"game(sha256=", sha256, ")"}]) {
manifest = BML::serialize(game); manifest = BML::serialize(game);
sufamiTurboA.verified = true;
} }
} }
sufamiTurboA.manifest = manifest ? manifest : heuristics.manifest(); sufamiTurboA.manifest = manifest ? manifest : heuristics.manifest();
@ -217,6 +241,7 @@ auto Program::loadSufamiTurboB(string location) -> void {
if(auto document = BML::unserialize(string::read(locate("database/Sufami Turbo.bml")))) { if(auto document = BML::unserialize(string::read(locate("database/Sufami Turbo.bml")))) {
if(auto game = document[{"game(sha256=", sha256, ")"}]) { if(auto game = document[{"game(sha256=", sha256, ")"}]) {
manifest = BML::serialize(game); manifest = BML::serialize(game);
sufamiTurboB.verified = true;
} }
} }
sufamiTurboB.manifest = manifest ? manifest : heuristics.manifest(); sufamiTurboB.manifest = manifest ? manifest : heuristics.manifest();
@ -233,7 +258,7 @@ auto Program::save() -> void {
auto Program::reset() -> void { auto Program::reset() -> void {
if(!emulator->loaded()) return; if(!emulator->loaded()) return;
applyHacks(); hackCompatibility();
emulator->reset(); emulator->reset();
showMessage("Game reset"); showMessage("Game reset");
} }
@ -242,7 +267,9 @@ auto Program::unload() -> void {
if(!emulator->loaded()) return; if(!emulator->loaded()) return;
toolsWindow->cheatEditor.saveCheats(); toolsWindow->cheatEditor.saveCheats();
toolsWindow->setVisible(false); toolsWindow->setVisible(false);
saveRecoveryState(); if(settingsWindow->advanced.autoSaveStateOnUnload.checked()) {
saveRecoveryState();
}
emulator->unload(); emulator->unload();
showMessage("Game unloaded"); showMessage("Game unloaded");
superFamicom = {}; superFamicom = {};
@ -254,5 +281,17 @@ auto Program::unload() -> void {
presentation->resetSystem.setEnabled(false); presentation->resetSystem.setEnabled(false);
presentation->unloadGame.setEnabled(false); presentation->unloadGame.setEnabled(false);
presentation->toolsMenu.setVisible(false); presentation->toolsMenu.setVisible(false);
presentation->updateStatusIcon();
presentation->clearViewport(); presentation->clearViewport();
} }
//a game is considered verified if the game plus its slot(s) are found in the games database
auto Program::verified() const -> bool {
if(!emulator->loaded()) return false;
if(superFamicom && !superFamicom.verified) return false;
if(gameBoy && !gameBoy.verified) return false;
if(bsMemory && !bsMemory.verified) return false;
if(sufamiTurboA && !sufamiTurboA.verified) return false;
if(sufamiTurboB && !sufamiTurboB.verified) return false;
return true;
}

View File

@ -1,5 +1,6 @@
auto Program::applyHacks() -> void { auto Program::hackCompatibility() -> void {
bool fastPPU = settingsWindow->advanced.fastPPUOption.checked(); bool fastPPU = settingsWindow->advanced.fastPPUOption.checked();
bool fastPPUNoSpriteLimit = settingsWindow->advanced.noSpriteLimit.checked();
bool fastDSP = settingsWindow->advanced.fastDSPOption.checked(); bool fastDSP = settingsWindow->advanced.fastDSPOption.checked();
auto label = superFamicom.label; auto label = superFamicom.label;
@ -8,13 +9,30 @@ auto Program::applyHacks() -> void {
if(label == "RENDERING RANGER R2") fastDSP = false; if(label == "RENDERING RANGER R2") fastDSP = false;
emulator->set("Fast PPU", fastPPU); emulator->set("Fast PPU", fastPPU);
emulator->set("Fast PPU/No Sprite Limit", fastPPUNoSpriteLimit);
emulator->set("Fast DSP", fastDSP); emulator->set("Fast DSP", fastDSP);
} }
auto Program::applyHackOverclockSuperFX() -> void { auto Program::hackPatchMemory(vector<uint8_t>& data) -> void {
auto label = superFamicom.label;
if(label == "Satellaview BS-X" && data.size() >= 0x100000) {
//BS-X: Sore wa Namae o Nusumareta Machi no Monogatari (JPN) (1.1)
//disable limited play check for BS Memory flash cartridges
//benefit: allow locked out BS Memory flash games to play without manual header patching
//detriment: BS Memory ROM cartridges will cause the game to hang in the load menu
if(data[0x4a9b] == 0x10) data[0x4a9b] = 0x80;
if(data[0x4d6d] == 0x10) data[0x4d6d] = 0x80;
if(data[0x4ded] == 0x10) data[0x4ded] = 0x80;
if(data[0x4e9a] == 0x10) data[0x4e9a] = 0x80;
}
}
auto Program::hackOverclockSuperFX() -> void {
//todo: implement a better way of detecting SuperFX games //todo: implement a better way of detecting SuperFX games
//todo: apply multiplier changes on reset, not just on game load? //todo: apply multiplier changes on reset, not just on game load?
double multiplier = settingsWindow->advanced.superFXValue.text().natural() / 100.0; double multiplier = settingsWindow->advanced.superFXValue.text().natural() / 100.0;
if(multiplier == 1.0) return;
auto label = superFamicom.label; auto label = superFamicom.label;
if(label == "NIDAN MORITASHOGI2") return; //ST018 uses same clock speed as SuperFX if(label == "NIDAN MORITASHOGI2") return; //ST018 uses same clock speed as SuperFX

View File

@ -5,6 +5,7 @@
#include <icarus/heuristics/bs-memory.cpp> #include <icarus/heuristics/bs-memory.cpp>
#include <icarus/heuristics/sufami-turbo.cpp> #include <icarus/heuristics/sufami-turbo.cpp>
//ROM data is held in memory to support compressed archives, soft-patching, and game hacks
auto Program::open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file { auto Program::open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file {
vfs::shared::file result; vfs::shared::file result;
@ -25,6 +26,12 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
if(id == 1) { //Super Famicom if(id == 1) { //Super Famicom
if(name == "manifest.bml" && mode == vfs::file::mode::read) { if(name == "manifest.bml" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(superFamicom.manifest.data<uint8_t>(), superFamicom.manifest.size()); result = vfs::memory::file::open(superFamicom.manifest.data<uint8_t>(), superFamicom.manifest.size());
} else if(name == "program.rom" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(superFamicom.program.data(), superFamicom.program.size());
} else if(name == "data.rom" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(superFamicom.data.data(), superFamicom.data.size());
} else if(name == "expansion.rom" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(superFamicom.expansion.data(), superFamicom.expansion.size());
} else if(superFamicom.location.endsWith("/")) { } else if(superFamicom.location.endsWith("/")) {
result = openPakSuperFamicom(name, mode); result = openPakSuperFamicom(name, mode);
} else { } else {
@ -35,6 +42,8 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
if(id == 2) { //Game Boy if(id == 2) { //Game Boy
if(name == "manifest.bml" && mode == vfs::file::mode::read) { if(name == "manifest.bml" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(gameBoy.manifest.data<uint8_t>(), gameBoy.manifest.size()); result = vfs::memory::file::open(gameBoy.manifest.data<uint8_t>(), gameBoy.manifest.size());
} else if(name == "program.rom" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(gameBoy.program.data(), gameBoy.program.size());
} else if(gameBoy.location.endsWith("/")) { } else if(gameBoy.location.endsWith("/")) {
result = openPakGameBoy(name, mode); result = openPakGameBoy(name, mode);
} else { } else {
@ -45,6 +54,11 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
if(id == 3) { //BS Memory if(id == 3) { //BS Memory
if(name == "manifest.bml" && mode == vfs::file::mode::read) { if(name == "manifest.bml" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(bsMemory.manifest.data<uint8_t>(), bsMemory.manifest.size()); result = vfs::memory::file::open(bsMemory.manifest.data<uint8_t>(), bsMemory.manifest.size());
} else if(name == "program.rom" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(bsMemory.program.data(), bsMemory.program.size());
} else if(name == "program.flash") {
//writes are not flushed to disk in bsnes
result = vfs::memory::file::open(bsMemory.program.data(), bsMemory.program.size());
} else if(bsMemory.location.endsWith("/")) { } else if(bsMemory.location.endsWith("/")) {
result = openPakBSMemory(name, mode); result = openPakBSMemory(name, mode);
} else { } else {
@ -55,6 +69,8 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
if(id == 4) { //Sufami Turbo - Slot A if(id == 4) { //Sufami Turbo - Slot A
if(name == "manifest.bml" && mode == vfs::file::mode::read) { if(name == "manifest.bml" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(sufamiTurboA.manifest.data<uint8_t>(), sufamiTurboA.manifest.size()); result = vfs::memory::file::open(sufamiTurboA.manifest.data<uint8_t>(), sufamiTurboA.manifest.size());
} else if(name == "program.rom" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(sufamiTurboA.program.data(), sufamiTurboA.program.size());
} else if(sufamiTurboA.location.endsWith("/")) { } else if(sufamiTurboA.location.endsWith("/")) {
result = openPakSufamiTurboA(name, mode); result = openPakSufamiTurboA(name, mode);
} else { } else {
@ -65,6 +81,8 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
if(id == 5) { //Sufami Turbo - Slot B if(id == 5) { //Sufami Turbo - Slot B
if(name == "manifest.bml" && mode == vfs::file::mode::read) { if(name == "manifest.bml" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(sufamiTurboB.manifest.data<uint8_t>(), sufamiTurboB.manifest.size()); result = vfs::memory::file::open(sufamiTurboB.manifest.data<uint8_t>(), sufamiTurboB.manifest.size());
} else if(name == "program.rom" && mode == vfs::file::mode::read) {
result = vfs::memory::file::open(sufamiTurboB.program.data(), sufamiTurboB.program.size());
} else if(sufamiTurboB.location.endsWith("/")) { } else if(sufamiTurboB.location.endsWith("/")) {
result = openPakSufamiTurboB(name, mode); result = openPakSufamiTurboB(name, mode);
} else { } else {
@ -73,7 +91,12 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
} }
if(!result && required) { if(!result && required) {
MessageDialog({"Error: missing required data: ", name}).setParent(*presentation).error(); if(MessageDialog({
"Error: missing required data: ", name, "\n\n",
"Would you like to view the online documentation for more information?"
}).setParent(*presentation).error({"Yes", "No"}) == "Yes") {
presentation->documentation.doActivate();
}
} }
return result; return result;

View File

@ -23,9 +23,9 @@ auto Program::applyPatchIPS(vector<uint8_t>& data, string location) -> bool {
} }
} }
} }
if(!patch) patch = file::read(locate(path("Patches", location, ".ips"))); if(!patch) patch = file::read(path("Patches", location, ".ips"));
} else { } else {
patch = file::read(locate(path("Patches", location, ".ips"))); patch = file::read(path("Patches", location, ".ips"));
} }
if(!patch) return false; if(!patch) return false;
@ -101,9 +101,9 @@ auto Program::applyPatchBPS(vector<uint8_t>& input, string location) -> bool {
} }
} }
} }
if(!patch) patch = file::read(locate(path("Patches", location, ".bps"))); if(!patch) patch = file::read(path("Patches", location, ".bps"));
} else { } else {
patch = file::read(locate(path("Patches", location, ".bps"))); patch = file::read(path("Patches", location, ".bps"));
} }
if(!patch) return false; if(!patch) return false;

View File

@ -60,6 +60,8 @@ Program::Program(string_vector arguments) {
} }
auto Program::main() -> void { auto Program::main() -> void {
if(Application::modal()) return;
updateStatus(); updateStatus();
video->poll(); video->poll();
inputManager->poll(); inputManager->poll();
@ -75,7 +77,7 @@ auto Program::main() -> void {
} }
emulator->run(); emulator->run();
if(settings["Emulator/AutoSaveMemory/Enable"].boolean()) { if(settingsWindow->advanced.autoSaveMemory.checked()) {
auto currentTime = chrono::timestamp(); auto currentTime = chrono::timestamp();
if(currentTime - autoSaveTime >= settings["Emulator/AutoSaveMemory/Interval"].natural()) { if(currentTime - autoSaveTime >= settings["Emulator/AutoSaveMemory/Interval"].natural()) {
autoSaveTime = currentTime; autoSaveTime = currentTime;

View File

@ -23,6 +23,7 @@ struct Program : Emulator::Platform {
auto save() -> void; auto save() -> void;
auto reset() -> void; auto reset() -> void;
auto unload() -> void; auto unload() -> void;
auto verified() const -> bool;
//game-pak.cpp //game-pak.cpp
auto openPakSuperFamicom(string name, vfs::file::mode mode) -> vfs::shared::file; auto openPakSuperFamicom(string name, vfs::file::mode mode) -> vfs::shared::file;
@ -83,44 +84,39 @@ struct Program : Emulator::Platform {
auto applyPatchBPS(vector<uint8_t>& data, string location) -> bool; auto applyPatchBPS(vector<uint8_t>& data, string location) -> bool;
//hacks.cpp //hacks.cpp
auto applyHacks() -> void; auto hackCompatibility() -> void;
auto applyHackOverclockSuperFX() -> void; auto hackPatchMemory(vector<uint8_t>& data) -> void;
auto hackOverclockSuperFX() -> void;
public: public:
struct SuperFamicom { struct Game {
string label; explicit operator bool() const { return (bool)location; }
string location; string location;
string manifest; string manifest;
Markup::Node document; Markup::Node document;
boolean patched;
boolean verified;
};
struct SuperFamicom : Game {
string label;
vector<uint8_t> program; vector<uint8_t> program;
vector<uint8_t> data; vector<uint8_t> data;
vector<uint8_t> expansion; vector<uint8_t> expansion;
vector<uint8_t> firmware; vector<uint8_t> firmware;
boolean patched;
} superFamicom; } superFamicom;
struct GameBoy { struct GameBoy : Game {
string location;
string manifest;
Markup::Node document;
vector<uint8_t> program; vector<uint8_t> program;
boolean patched;
} gameBoy; } gameBoy;
struct BSMemory { struct BSMemory : Game {
string location;
string manifest;
Markup::Node document;
vector<uint8_t> program; vector<uint8_t> program;
boolean patched;
} bsMemory; } bsMemory;
struct SufamiTurbo { struct SufamiTurbo : Game {
string location;
string manifest;
Markup::Node document;
vector<uint8_t> program; vector<uint8_t> program;
boolean patched;
} sufamiTurboA, sufamiTurboB; } sufamiTurboA, sufamiTurboB;
string_vector gameQueue; string_vector gameQueue;

View File

@ -8,7 +8,7 @@ auto Program::managedStates() -> string_vector {
if(input.open(statePath())) { if(input.open(statePath())) {
string_vector filenames; string_vector filenames;
for(auto& file : input.file) { for(auto& file : input.file) {
if(file.name.match("managed/*.bst")) filenames.append(file.name); if(file.name.match("managed/*.bst")) filenames.append(file.name.trimLeft("managed/", 1L));
} }
filenames.isort(); filenames.isort();
return filenames; return filenames;
@ -75,6 +75,7 @@ auto Program::saveState(string filename) -> bool {
states.append({file.name, input.extract(file)}); states.append({file.name, input.extract(file)});
} }
} }
input.close();
Encode::ZIP output{statePath()}; Encode::ZIP output{statePath()};
for(auto& state : states) { for(auto& state : states) {
@ -114,6 +115,7 @@ auto Program::removeState(string filename) -> bool {
states.append({file.name, input.extract(file)}); states.append({file.name, input.extract(file)});
} }
} }
input.close();
if(states) { if(states) {
Encode::ZIP output{statePath()}; Encode::ZIP output{statePath()};
@ -151,6 +153,7 @@ auto Program::renameState(string from, string to) -> bool {
states.append({file.name, input.extract(file)}); states.append({file.name, input.extract(file)});
} }
} }
input.close();
Encode::ZIP output{statePath()}; Encode::ZIP output{statePath()};
for(auto& state : states) { for(auto& state : states) {

View File

@ -12,7 +12,6 @@ auto Program::updateStatus() -> void {
if(chrono::timestamp() - statusTime <= 2) { if(chrono::timestamp() - statusTime <= 2) {
message = statusMessage; message = statusMessage;
} }
message.prepend(" ");
if(message != presentation->statusLeft.text()) { if(message != presentation->statusLeft.text()) {
presentation->statusLeft.setText(message); presentation->statusLeft.setText(message);
} }
@ -27,7 +26,6 @@ auto Program::updateStatus() -> void {
} else { } else {
frameRate = statusFrameRate; frameRate = statusFrameRate;
} }
frameRate.append(" ");
if(frameRate != presentation->statusRight.text()) { if(frameRate != presentation->statusRight.text()) {
presentation->statusRight.setText(frameRate); presentation->statusRight.setText(frameRate);
} }

View File

@ -863,8 +863,8 @@ const nall::vector<uint8_t> Manifest = { //size: 334
115,112,10,32,32,32,32,114,97,109,32,110,97,109,101,61,97,112,117,46,114,97,109,32,115,105,122,101,61,48,120,49, 115,112,10,32,32,32,32,114,97,109,32,110,97,109,101,61,97,112,117,46,114,97,109,32,115,105,122,101,61,48,120,49,
48,48,48,48,32,118,111,108,97,116,105,108,101,10, 48,48,48,48,32,118,111,108,97,116,105,108,101,10,
}; };
const nall::vector<uint8_t> Boards = { //size: 29603 const nall::vector<uint8_t> Boards = { //size: 30186
100,97,116,97,98,97,115,101,10,32,32,114,101,118,105,115,105,111,110,58,32,50,48,49,56,45,48,54,45,48,49,10, 100,97,116,97,98,97,115,101,10,32,32,114,101,118,105,115,105,111,110,58,32,50,48,49,56,45,48,54,45,50,53,10,
10,47,47,66,111,97,114,100,115,32,40,80,114,111,100,117,99,116,105,111,110,41,10,10,100,97,116,97,98,97,115,101, 10,47,47,66,111,97,114,100,115,32,40,80,114,111,100,117,99,116,105,111,110,41,10,10,100,97,116,97,98,97,115,101,
10,32,32,114,101,118,105,115,105,111,110,58,32,50,48,49,56,45,48,53,45,49,54,10,10,98,111,97,114,100,58,32, 10,32,32,114,101,118,105,115,105,111,110,58,32,50,48,49,56,45,48,53,45,49,54,10,10,98,111,97,114,100,58,32,
66,65,78,68,65,73,45,80,84,45,57,50,51,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32, 66,65,78,68,65,73,45,80,84,45,57,50,51,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
@ -1437,7 +1437,7 @@ const nall::vector<uint8_t> Boards = { //size: 29603
32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32, 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,
32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45, 32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,
102,102,102,102,10,10,47,47,66,111,97,114,100,115,32,40,71,101,110,101,114,105,99,41,10,10,100,97,116,97,98,97, 102,102,102,102,10,10,47,47,66,111,97,114,100,115,32,40,71,101,110,101,114,105,99,41,10,10,100,97,116,97,98,97,
115,101,10,32,32,114,101,118,105,115,105,111,110,58,32,50,48,49,56,45,48,54,45,48,49,10,10,98,111,97,114,100, 115,101,10,32,32,114,101,118,105,115,105,111,110,58,32,50,48,49,56,45,48,54,45,50,53,10,10,98,111,97,114,100,
58,32,65,82,77,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79, 58,32,65,82,77,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115, 77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56, 115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,
@ -1585,211 +1585,229 @@ const nall::vector<uint8_t> Boards = { //size: 29603
97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,32,32,109,97,112,32, 97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,57,54,48,53,48,10,32,32,32,32,32,32,109,97,112,32,
97,100,100,114,101,115,115,61,54,56,45,54,102,44,101,56,45,101,102,58,48,48,48,48,45,55,102,102,102,32,109,97, 97,100,100,114,101,115,115,61,54,56,45,54,102,44,101,56,45,101,102,58,48,48,48,48,45,55,102,102,102,32,109,97,
115,107,61,48,120,56,48,48,48,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58, 115,107,61,48,120,56,48,48,48,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,
32,71,66,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116, 32,69,88,83,80,67,55,49,49,48,45,82,65,77,45,69,80,83,79,78,82,84,67,10,32,32,109,101,109,111,114,121,
101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,55, 32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,69,120,112,97,110,115,105,111,110,10,32,32,32,32,
100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32, 109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,52,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,114,
32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,55, 111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,80,67,55,49,49,48,10,32,32,32,32,109,
102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110, 97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,51,102,
116,105,102,105,101,114,61,73,67,68,32,114,101,118,105,115,105,111,110,61,50,10,32,32,32,32,109,97,112,32,97,100, 10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,53,48,44,53,56,58,48,48,48,48,45,102,102,102,102,
100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,54,55,102,102,44,55,48,48,48, 10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,
45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110, 44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,48,48,10,32,
116,61,66,111,111,116,32,97,114,99,104,105,116,101,99,116,117,114,101,61,76,82,51,53,57,48,50,10,32,32,32,32, 32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,
111,115,99,105,108,108,97,116,111,114,10,32,32,32,32,115,108,111,116,32,116,121,112,101,61,71,97,109,101,66,111,121, 32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,
10,10,98,111,97,114,100,58,32,71,83,85,45,82,65,77,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99, 61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,101,109,111,114,
104,105,116,101,99,116,117,114,101,61,71,83,85,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48, 121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,10,32,32,32,32,109,101,109,111,
45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,52,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116, 114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,
121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,97, 97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,
112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32, 32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,114,116,99,32,109,97,110,117,102,97,99,116,117,114,101,114,61,
109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48, 69,112,115,111,110,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,
45,53,102,44,99,48,45,100,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116, 102,58,52,56,52,48,45,52,56,52,50,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,84,67,32,
121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97, 99,111,110,116,101,110,116,61,84,105,109,101,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,110,10,
100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,115,105,122, 10,98,111,97,114,100,58,32,71,66,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,49, 79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
44,102,48,45,102,49,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,72,73,82,79,77,10,32, 115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,
32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109, 56,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,
10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48, 58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,
48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45, 111,114,32,105,100,101,110,116,105,102,105,101,114,61,73,67,68,32,114,101,118,105,115,105,111,110,61,50,10,32,32,32,
102,102,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,72,73,82,79,77,45,82,65,77,10,32, 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,54,55,
32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109, 102,102,44,55,48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,
10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48, 32,99,111,110,116,101,110,116,61,66,111,111,116,32,97,114,99,104,105,116,101,99,116,117,114,101,61,76,82,51,53,57,
48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45, 48,50,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,32,32,32,32,115,108,111,116,32,116,121,112,101,61,
102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99, 71,97,109,101,66,111,121,10,10,98,111,97,114,100,58,32,71,83,85,45,82,65,77,10,32,32,112,114,111,99,101,115,
111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51, 115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,71,83,85,10,32,32,32,32,109,97,112,32,97,100,100,
102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98, 114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,52,102,102,10,32,32,32,32,109,
111,97,114,100,58,32,72,73,84,65,67,72,73,45,76,79,82,79,77,10,32,32,112,114,111,99,101,115,115,111,114,32, 101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,
97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,32,32,109,97,112,32,97, 32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,
100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,99,48,48,45,54,102,102,102,44,55,99,48, 48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,
48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101, 114,101,115,115,61,52,48,45,53,102,44,99,48,45,100,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,
110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45, 101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,
51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32, 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,
32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10, 102,102,102,32,115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,55,58,48,48,48,48,45,55,102,102, 115,61,55,48,45,55,49,44,102,48,45,102,49,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,
102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97, 72,73,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,
116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,32,32,109,101, 80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,
109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105, 45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,
116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114, 45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,10,98,111,97,114,100,58,32,72,73,82,79,
101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,54,98,102,102,44,55,48,48,48,45,55, 77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,
98,102,102,32,109,97,115,107,61,48,120,102,48,48,48,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10, 80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,
98,111,97,114,100,58,32,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99, 45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,
111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48, 45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,
48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48, 101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
10,10,98,111,97,114,100,58,32,76,79,82,79,77,45,82,65,77,35,65,10,32,32,109,101,109,111,114,121,32,116,121, 115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,
101,48,48,48,10,10,98,111,97,114,100,58,32,72,73,84,65,67,72,73,45,76,79,82,79,77,10,32,32,112,114,111,
99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,
32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,99,48,48,45,54,
102,102,102,44,55,99,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,
77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,
101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,
120,56,48,48,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,
116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,55,58,48,
48,48,48,45,55,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,
10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,
97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,72,71,53,49,66,83,49,54,57,10,32,32,32,32,32,32,109,
97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,54,98,102,102,
44,55,48,48,48,45,55,98,102,102,32,109,97,115,107,61,48,120,102,48,48,48,10,32,32,32,32,111,115,99,105,108,
108,97,116,111,114,10,10,98,111,97,114,100,58,32,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,
101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,
100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,
61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,76,79,82,79,77,45,82,65,77,35,65,10,32,32,109,101,
109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,
32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,
102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,
77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,
48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,
10,10,98,111,97,114,100,58,32,76,79,82,79,77,45,82,65,77,35,66,10,32,32,109,101,109,111,114,121,32,116,121,
112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97, 112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,
100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115, 100,100,114,101,115,115,61,48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,
107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101, 107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,
110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48, 110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,
45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100, 45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,
58,32,76,79,82,79,77,45,82,65,77,35,66,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32, 58,32,78,69,67,45,72,73,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,
99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61, 110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,
48,48,45,55,100,44,56,48,45,102,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48, 45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,
48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101, 101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,114,111,99,
10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,
48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,10,98,111,97,114,100,58,32,78,69,67,45,72,
73,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,
114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,
98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,
55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,114,111,99,101,115,115,111,114,32,97,
114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,112,32,97,100,100,114,
101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,
120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,
32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,
114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,
121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,
101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,
32,78,69,67,45,72,73,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,
32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,
61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,109,97,112,32,97,
100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,109,
101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,
109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,48,48,48,45,55,102,102,
102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,
101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,
48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,102,102,102,10,
32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,
114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,
111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,
101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,
55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,78,69,67,45,
76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,
80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,
45,57,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,
101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109, 101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,
97,112,32,97,100,100,114,101,115,115,61,51,48,45,51,102,44,98,48,45,98,102,58,56,48,48,48,45,102,102,102,102, 97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,45,55,102,102,102,
32,109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77, 32,109,97,115,107,61,48,120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80, 99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,
68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110, 55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32, 61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,
109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99, 101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,
104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114, 105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,
10,10,98,111,97,114,100,58,32,78,69,67,45,76,79,82,79,77,45,82,65,77,35,65,10,32,32,109,101,109,111,114, 10,98,111,97,114,100,58,32,78,69,67,45,72,73,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,
121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109, 121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,
97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,56,48,48,48,45,102,102,102,102, 97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,
32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99, 32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,55,100,44,99,48,45,102,102,58,48,48,48,48,45,102,
111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55, 102,102,102,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,
100,44,102,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114, 118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,54,
99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,112,32,97,100,100,114,101, 48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,
115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120, 32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,112,32,97,100,
51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116, 100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,
61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32, 61,48,120,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,
32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97, 110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,
114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116, 32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,
121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114, 32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,
101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,100,58, 32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,
32,78,69,67,45,76,79,82,79,77,45,82,65,77,35,66,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82, 117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111,97,114,
79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101, 100,58,32,78,69,67,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,
115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120, 111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,
56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83, 48,45,49,102,44,56,48,45,57,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,
97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58, 10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,
48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111, 53,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,51,48,45,51,102,44,98,48,45,98,102,58,56,48,
114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,112,32,97, 48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,
100,100,114,101,115,115,61,54,48,45,54,102,44,101,48,45,101,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115, 121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,
107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110, 116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,
116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50, 32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,
53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97, 50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,
116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111, 97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,
114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101, 105,108,108,97,116,111,114,10,10,98,111,97,114,100,58,32,78,69,67,45,76,79,82,79,77,45,82,65,77,35,65,10,
99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,10,98,111, 32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,
97,114,100,58,32,79,66,67,49,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,109,111,114,121,32,116,121,112, 109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48,45,57,102,58,56,48,
101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100, 48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,
100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107, 101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,
61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,79, 115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,112,114,111,99,101,
66,67,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58, 115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,97,
54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,97,112,32,97,100, 112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,
100,114,101,115,115,61,55,48,45,55,49,44,102,48,45,102,49,58,54,48,48,48,45,55,102,102,102,44,101,48,48,48, 109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,
45,102,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112, 99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,
101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,10,98,111,97,114,100,58,32,83,65,49,45,82, 55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
65,77,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,87,54,53,67, 61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,109,
56,49,54,83,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102, 101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,97,114,99,104,
58,50,50,48,48,45,50,51,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100, 105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,116,111,114,10,
114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61, 10,98,111,97,114,100,58,32,78,69,67,45,76,79,82,79,77,45,82,65,77,35,66,10,32,32,109,101,109,111,114,121,
48,120,52,48,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102, 32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,
58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77, 112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,
32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101, 109,97,115,107,61,48,120,56,48,48,48,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,
61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114, 110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,
101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,115,105,122,101,61,48, 44,102,48,45,102,102,58,48,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,
120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,52,102,58,48,48, 114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,
48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116, 32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,48,45,54,102,44,101,48,45,101,102,58,48,48,48,48,45,55,
101,110,116,61,73,110,116,101,114,110,97,108,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48, 102,102,102,32,109,97,115,107,61,48,120,51,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,
48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,55,102,102,32,115,105,122,101,61,48,120,56,48,48,10, 82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,32,97,114,99,104,105,116,101,99,116,117,114,101,
10,98,111,97,114,100,58,32,83,68,68,49,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102, 61,117,80,68,55,55,50,53,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,
105,101,114,61,83,68,68,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56, 116,101,110,116,61,68,97,116,97,32,97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,
48,45,98,102,58,52,56,48,48,45,52,56,48,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112, 32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,68,97,116,97,32,
32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,10,32, 97,114,99,104,105,116,101,99,116,117,114,101,61,117,80,68,55,55,50,53,10,32,32,32,32,111,115,99,105,108,108,97,
32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102, 116,111,114,10,10,98,111,97,114,100,58,32,79,66,67,49,45,76,79,82,79,77,45,82,65,77,10,32,32,109,101,109,
10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80, 111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,
114,111,103,114,97,109,10,10,98,111,97,114,100,58,32,83,68,68,49,45,82,65,77,10,32,32,109,101,109,111,114,121, 32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,
32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,109,97,112,32,97, 102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,
100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115, 105,102,105,101,114,61,79,66,67,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,
107,61,48,120,101,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,51,58,48, 44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,
48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,111,99,101,115,115,111,114, 32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,49,44,102,48,45,102,49,58,54,48,48,48,45,55,102,
32,105,100,101,110,116,105,102,105,101,114,61,83,68,68,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115, 102,102,44,101,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,101,109,
61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,48,102,10,32,32,32,32,109,99,117,10,32, 111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,10,98,111,97,114,100,
32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48, 58,32,83,65,49,45,82,65,77,10,32,32,112,114,111,99,101,115,115,111,114,32,97,114,99,104,105,116,101,99,116,117,
48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48, 114,101,61,87,54,53,67,56,49,54,83,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,
48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99, 102,44,56,48,45,98,102,58,50,50,48,48,45,50,51,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,
111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,10,98,111,97,114,100,58,32,83,80,67,55,49,49,48,45,82, 109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,
65,77,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,80,67,55,49,49, 102,32,109,97,115,107,61,48,120,52,48,56,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,
48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56, 115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,
48,48,45,52,56,51,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,53,48,44,53,56,58,48,48, 121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,101,109,111,
48,48,45,102,102,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115, 114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,
115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56, 97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,
48,48,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48, 32,115,105,122,101,61,48,120,50,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,
48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,32,32,32,32,32,109,101,109,111, 48,45,52,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,
114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32, 65,77,32,99,111,110,116,101,110,116,61,73,110,116,101,114,110,97,108,10,32,32,32,32,32,32,109,97,112,32,97,100,
32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,10,32, 100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,51,48,48,48,45,51,55,102,102,32,115,105,122,101,
32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10, 61,48,120,56,48,48,10,10,98,111,97,114,100,58,32,83,68,68,49,10,32,32,112,114,111,99,101,115,115,111,114,32,
32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48, 105,100,101,110,116,105,102,105,101,114,61,83,68,68,49,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,100,58,32,83,80,67,55, 48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,48,102,10,32,32,32,32,109,99,117,10,32,32,
49,49,48,45,82,65,77,45,69,80,83,79,78,82,84,67,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,
110,116,105,102,105,101,114,61,83,80,67,55,49,49,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,51,102,10,32,32,32,32,109,97,112,32,97,100,
100,114,101,115,115,61,53,48,44,53,56,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,99,117,10,32,32,
32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48, 32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,
45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100, 45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,
100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,99,48,48, 48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,
48,48,48,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110, 110,116,101,110,116,61,80,114,111,103,114,97,109,10,10,98,111,97,114,100,58,32,83,68,68,49,45,82,65,77,10,32,
116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32, 32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,
99,111,110,116,101,110,116,61,68,97,116,97,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77, 32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,
32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61, 102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48, 55,48,45,55,51,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,112,114,
48,10,32,32,114,116,99,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,110,10,32,32,32,32,109, 111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,68,68,49,10,32,32,32,32,109,97,112,32,
97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,52,48,45,52,56,52,50, 97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,48,102,10,32,32,
10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,84,67,32,99,111,110,116,101,110,116,61,84,105,109, 32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,
101,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,110,10,10,98,111,97,114,100,58,32,83,84,45, 45,98,102,58,56,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,
76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61, 99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,
80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,49,102,44,56,48, 101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,10,98,111,97,114,100,58,32,83,80,
45,57,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,115,108,111,116, 67,55,49,49,48,45,82,65,77,10,32,32,112,114,111,99,101,115,115,111,114,32,105,100,101,110,116,105,102,105,101,114,
32,116,121,112,101,61,83,117,102,97,109,105,84,117,114,98,111,10,32,32,32,32,114,111,109,10,32,32,32,32,32,32, 61,83,80,67,55,49,49,48,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,
109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,56,48,48,48,45,102,102,102, 48,45,98,102,58,52,56,48,48,45,52,56,51,102,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,53,
102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,114,97,109,10,32,32,32,32,32,32,109,97,112,32, 48,44,53,56,58,48,48,48,48,45,102,102,102,102,10,32,32,32,32,109,99,117,10,32,32,32,32,32,32,109,97,112,
97,100,100,114,101,115,115,61,54,48,45,54,102,44,101,48,45,101,102,58,48,48,48,48,45,102,102,102,102,10,32,32, 32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,56,48,48,48,45,102,102,102,102,32,109,
115,108,111,116,32,116,121,112,101,61,83,117,102,97,109,105,84,117,114,98,111,10,32,32,32,32,114,111,109,10,32,32, 97,115,107,61,48,120,56,48,48,48,48,48,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,99,
32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,53,102,44,99,48,45,100,102,58,48,48,48,48, 48,45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,99,48,48,48,48,48,10,32,32,32,
45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,114,97,109,10,32,32,32,32,32,32, 32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,80,114,111,103,114,
109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,48,48,48,45,102,102,102, 97,109,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,111,110,116,101,110,116,
102,10,10, 61,68,97,116,97,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,65,77,32,99,111,110,116,101,110,
116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,
48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,107,61,48,120,101,48,48,48,10,10,98,111,97,114,
100,58,32,83,80,67,55,49,49,48,45,82,65,77,45,69,80,83,79,78,82,84,67,10,32,32,112,114,111,99,101,115,
115,111,114,32,105,100,101,110,116,105,102,105,101,114,61,83,80,67,55,49,49,48,10,32,32,32,32,109,97,112,32,97,
100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,48,48,45,52,56,51,102,10,32,32,32,
32,109,97,112,32,97,100,100,114,101,115,115,61,53,48,44,53,56,58,48,48,48,48,45,102,102,102,102,10,32,32,32,
32,109,99,117,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,
98,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,48,48,10,32,32,32,32,32,
32,109,97,112,32,97,100,100,114,101,115,115,61,99,48,45,102,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,
107,61,48,120,99,48,48,48,48,48,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,
32,99,111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,32,32,109,101,109,111,114,121,32,116,121,
112,101,61,82,79,77,32,99,111,110,116,101,110,116,61,68,97,116,97,10,32,32,32,32,109,101,109,111,114,121,32,116,
121,112,101,61,82,65,77,32,99,111,110,116,101,110,116,61,83,97,118,101,10,32,32,32,32,32,32,109,97,112,32,97,
100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,54,48,48,48,45,55,102,102,102,32,109,97,115,
107,61,48,120,101,48,48,48,10,32,32,114,116,99,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,
110,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,48,45,51,102,44,56,48,45,98,102,58,52,56,
52,48,45,52,56,52,50,10,32,32,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,84,67,32,99,111,110,116,
101,110,116,61,84,105,109,101,32,109,97,110,117,102,97,99,116,117,114,101,114,61,69,112,115,111,110,10,10,98,111,97,
114,100,58,32,83,84,45,76,79,82,79,77,10,32,32,109,101,109,111,114,121,32,116,121,112,101,61,82,79,77,32,99,
111,110,116,101,110,116,61,80,114,111,103,114,97,109,10,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,48,
48,45,49,102,44,56,48,45,57,102,58,56,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,
10,32,32,115,108,111,116,32,116,121,112,101,61,83,117,102,97,109,105,84,117,114,98,111,10,32,32,32,32,114,111,109,
10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,50,48,45,51,102,44,97,48,45,98,102,58,56,
48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,114,97,109,10,32,32,32,
32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,54,48,45,54,102,44,101,48,45,101,102,58,48,48,48,48,45,
102,102,102,102,10,32,32,115,108,111,116,32,116,121,112,101,61,83,117,102,97,109,105,84,117,114,98,111,10,32,32,32,
32,114,111,109,10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,52,48,45,53,102,44,99,48,45,
100,102,58,48,48,48,48,45,102,102,102,102,32,109,97,115,107,61,48,120,56,48,48,48,10,32,32,32,32,114,97,109,
10,32,32,32,32,32,32,109,97,112,32,97,100,100,114,101,115,115,61,55,48,45,55,100,44,102,48,45,102,102,58,48,
48,48,48,45,102,102,102,102,10,10,
}; };
const nall::vector<uint8_t> IPLROM = { //size: 64 const nall::vector<uint8_t> IPLROM = { //size: 64
205,239,189,232,0,198,29,208,252,143,170,244,143,187,245,120,204,244,208,251,47,25,235,244,208,252,126,244,208,11,228,245, 205,239,189,232,0,198,29,208,252,143,170,244,143,187,245,120,204,244,208,251,47,25,235,244,208,252,126,244,208,11,228,245,

View File

@ -62,9 +62,36 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
} }
}); });
optionsLabel.setText("Options").setFont(Font().setBold());
warnOnUnverifiedGames.setText("Warn when loading games that have not been verified").setChecked(settings["Emulator/WarnOnUnverifiedGames"].boolean()).onToggle([&] {
settings["Emulator/WarnOnUnverifiedGames"].setValue(warnOnUnverifiedGames.checked());
});
autoSaveMemory.setText("Auto-save memory periodically").setChecked(settings["Emulator/AutoSaveMemory/Enable"].boolean()).onToggle([&] {
settings["Emulator/AutoSaveMemory/Enable"].setValue(autoSaveMemory.checked());
});
autoSaveStateOnUnload.setText("Auto-save undo state when unloading games").setChecked(settings["Emulator/AutoSaveStateOnUnload"].boolean()).onToggle([&] {
settings["Emulator/AutoSaveStateOnUnload"].setValue(autoSaveStateOnUnload.checked());
if(!autoSaveStateOnUnload.checked()) {
autoLoadStateOnLoad.setEnabled(false).setChecked(false).doToggle();
} else {
autoLoadStateOnLoad.setEnabled(true);
}
}).doToggle();
autoLoadStateOnLoad.setText("Auto-resume on load").setChecked(settings["Emulator/AutoLoadStateOnLoad"].boolean()).onToggle([&] {
settings["Emulator/AutoLoadStateOnLoad"].setValue(autoLoadStateOnLoad.checked());
});
hacksLabel.setText("Emulator Hacks").setFont(Font().setBold()); hacksLabel.setText("Emulator Hacks").setFont(Font().setBold());
fastPPUOption.setText("Fast PPU").setChecked(settings["Emulator/Hack/FastPPU"].boolean()).onToggle([&] { fastPPUOption.setText("Fast PPU").setChecked(settings["Emulator/Hack/FastPPU"].boolean()).onToggle([&] {
settings["Emulator/Hack/FastPPU"].setValue(fastPPUOption.checked()); settings["Emulator/Hack/FastPPU"].setValue(fastPPUOption.checked());
if(!fastPPUOption.checked()) {
noSpriteLimit.setEnabled(false).setChecked(false).doToggle();
} else {
noSpriteLimit.setEnabled(true);
}
}).doToggle();
noSpriteLimit.setText("No sprite limit").setChecked(settings["Emulator/Hack/FastPPU/NoSpriteLimit"].boolean()).onToggle([&] {
settings["Emulator/Hack/FastPPU/NoSpriteLimit"].setValue(noSpriteLimit.checked());
}); });
fastDSPOption.setText("Fast DSP").setChecked(settings["Emulator/Hack/FastDSP"].boolean()).onToggle([&] { fastDSPOption.setText("Fast DSP").setChecked(settings["Emulator/Hack/FastDSP"].boolean()).onToggle([&] {
settings["Emulator/Hack/FastDSP"].setValue(fastDSPOption.checked()); settings["Emulator/Hack/FastDSP"].setValue(fastDSPOption.checked());

View File

@ -54,6 +54,8 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
settings["Audio/Reverb"].setValue(reverb.checked()); settings["Audio/Reverb"].setValue(reverb.checked());
program->updateAudioEffects(); program->updateAudioEffects();
}); });
//todo: does not work properly with Super Game Boy
reverb.setVisible(false);
} }
auto AudioSettings::updateDevice() -> void { auto AudioSettings::updateDevice() -> void {

View File

@ -59,11 +59,15 @@ Settings::Settings() {
set("UserInterface/ShowStatusBar", true); set("UserInterface/ShowStatusBar", true);
set("Emulator/Hack/FastPPU", true); set("Emulator/WarnOnUnverifiedGames", false);
set("Emulator/Hack/FastDSP", true);
set("Emulator/Hack/FastSuperFX", "100%");
set("Emulator/AutoSaveMemory/Enable", true); set("Emulator/AutoSaveMemory/Enable", true);
set("Emulator/AutoSaveMemory/Interval", 30); set("Emulator/AutoSaveMemory/Interval", 30);
set("Emulator/AutoSaveStateOnUnload", false);
set("Emulator/AutoLoadStateOnLoad", false);
set("Emulator/Hack/FastPPU", true);
set("Emulator/Hack/FastPPU/NoSpriteLimit", false);
set("Emulator/Hack/FastDSP", true);
set("Emulator/Hack/FastSuperFX", "100%");
set("Crashed", false); set("Crashed", false);
} }

View File

@ -165,8 +165,16 @@ public:
ComboButton audioDriverOption{&driverLayout, Size{~0, 0}}; ComboButton audioDriverOption{&driverLayout, Size{~0, 0}};
Label inputDriverLabel{&driverLayout, Size{0, 0}}; Label inputDriverLabel{&driverLayout, Size{0, 0}};
ComboButton inputDriverOption{&driverLayout, Size{~0, 0}}; ComboButton inputDriverOption{&driverLayout, Size{~0, 0}};
Label optionsLabel{&layout, Size{~0, 0}, 2};
CheckLabel warnOnUnverifiedGames{&layout, Size{~0, 0}};
CheckLabel autoSaveMemory{&layout, Size{~0, 0}};
HorizontalLayout autoStateLayout{&layout, Size{~0, 0}};
CheckLabel autoSaveStateOnUnload{&autoStateLayout, Size{0, 0}};
CheckLabel autoLoadStateOnLoad{&autoStateLayout, Size{0, 0}};
Label hacksLabel{&layout, Size{~0, 0}, 2}; Label hacksLabel{&layout, Size{~0, 0}, 2};
CheckLabel fastPPUOption{&layout, Size{~0, 0}}; HorizontalLayout fastPPULayout{&layout, Size{~0, 0}};
CheckLabel fastPPUOption{&fastPPULayout, Size{0, 0}};
CheckLabel noSpriteLimit{&fastPPULayout, Size{0, 0}};
CheckLabel fastDSPOption{&layout, Size{~0, 0}}; CheckLabel fastDSPOption{&layout, Size{~0, 0}};
HorizontalLayout superFXLayout{&layout, Size{~0, 0}}; HorizontalLayout superFXLayout{&layout, Size{~0, 0}};
Label superFXLabel{&superFXLayout, Size{0, 0}}; Label superFXLabel{&superFXLayout, Size{0, 0}};

View File

@ -116,8 +116,11 @@ CheatEditor::CheatEditor(TabFrame* parent) : TabFrameItem(parent) {
editButton.setEnabled(batched.size() == 1); editButton.setEnabled(batched.size() == 1);
removeButton.setEnabled(batched.size() >= 1); removeButton.setEnabled(batched.size() >= 1);
}); });
cheatList.onToggle([&](TableViewCell) { cheatList.onToggle([&](TableViewCell cell) {
synchronizeCodes(); if(auto item = cell->parentTableViewItem()) {
cheats[item->offset()].enable = cell.checked();
synchronizeCodes();
}
}); });
findCheatsButton.setText("Find Cheats ...").onActivate([&] { findCheatsButton.setText("Find Cheats ...").onActivate([&] {
cheatDatabase->findCheats(); cheatDatabase->findCheats();

View File

@ -206,6 +206,8 @@ auto Presentation::updateEmulator() -> void {
} }
auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void { auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void {
return;
int ox = width - 128; int ox = width - 128;
int oy = height - 128; int oy = height - 128;
if(ox >= 0 && oy >= 0) { if(ox >= 0 && oy >= 0) {
@ -228,8 +230,8 @@ auto Presentation::clearViewport() -> void {
uint32_t* output; uint32_t* output;
uint length = 0; uint length = 0;
uint width = viewport.geometry().width(); uint width = 16;
uint height = viewport.geometry().height(); uint height = 16;
if(video->lock(output, length, width, height)) { if(video->lock(output, length, width, height)) {
for(uint y : range(height)) { for(uint y : range(height)) {
auto line = output + y * (length >> 2); auto line = output + y * (length >> 2);

View File

@ -10,6 +10,10 @@ auto Application::font() -> Font {
return state.font; return state.font;
} }
auto Application::modal() -> bool {
return state.modal > 0;
}
auto Application::name() -> string { auto Application::name() -> string {
return state.name; return state.name;
} }

View File

@ -374,6 +374,7 @@ struct Application {
static auto doMain() -> void; static auto doMain() -> void;
static auto font() -> Font; static auto font() -> Font;
static auto modal() -> bool;
static auto name() -> string; static auto name() -> string;
static auto onMain(const function<void ()>& callback = {}) -> void; static auto onMain(const function<void ()>& callback = {}) -> void;
static auto run() -> void; static auto run() -> void;
@ -408,6 +409,7 @@ struct Application {
//private: //private:
struct State { struct State {
Font font; Font font;
int modal = 0;
string name; string name;
function<void ()> onMain; function<void ()> onMain;
bool quit = false; bool quit = false;

View File

@ -248,6 +248,12 @@ auto mWindow::setGeometry(Geometry geometry) -> type& {
auto mWindow::setModal(bool modal) -> type& { auto mWindow::setModal(bool modal) -> type& {
state.modal = modal; state.modal = modal;
signal(setModal, modal); signal(setModal, modal);
if(modal) {
Application::state.modal++;
} else {
Application::state.modal--;
assert(Application::state.modal >= 0);
}
return *this; return *this;
} }

View File

@ -4,7 +4,7 @@ namespace hiro {
auto pLabel::construct() -> void { auto pLabel::construct() -> void {
hwnd = CreateWindow(L"hiroLabel", L"", hwnd = CreateWindow(L"hiroLabel", L"",
WS_CHILD, WS_CHILD | WS_CLIPSIBLINGS,
0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference);
pWidget::_setState(); pWidget::_setState();