diff --git a/gambatte_qt/src/gambattemenuhandler.cpp b/gambatte_qt/src/gambattemenuhandler.cpp index ba7d1100..f2268b57 100644 --- a/gambatte_qt/src/gambattemenuhandler.cpp +++ b/gambatte_qt/src/gambattemenuhandler.cpp @@ -491,10 +491,12 @@ GambatteMenuHandler::GambatteMenuHandler(MainWindow &mw, cycleBasedAction_->setCheckable(true); cycleBasedAction_->setChecked(QSettings().value("rtc-mode", true).toBool()); rtcModeActions->addAction(cycleBasedAction_); +#ifdef ENABLE_REAL_TIME_RTC realTimeAction_ = rtcModeMenu->addAction(tr("&Real-time")); realTimeAction_->setCheckable(true); realTimeAction_->setChecked(!cycleBasedAction_->isChecked()); rtcModeActions->addAction(realTimeAction_); +#endif connect(rtcModeActions, SIGNAL(triggered(QAction *)), this, SLOT(setRtcMode())); } @@ -502,6 +504,12 @@ GambatteMenuHandler::GambatteMenuHandler(MainWindow &mw, trueColorsAction_->setCheckable(true); trueColorsAction_->setChecked(QSettings().value("true-colors", false).toBool()); connect(trueColorsAction_, SIGNAL(toggled(bool)), &source, SLOT(setTrueColors(bool))); + + settingsm->addSeparator(); + attemptModeAction_ = settingsm->addAction(tr("Attempt &Mode")); + attemptModeAction_->setCheckable(true); + attemptModeAction_->setChecked(QSettings().value("attempt-mode", true).toBool()); + connect(attemptModeAction_, SIGNAL(toggled(bool)), &source, SLOT(setAttemptMode(bool))); settingsm->addSeparator(); fsAct_ = settingsm->addAction(tr("&Full Screen"), this, SLOT(toggleFullScreen()), tr("Ctrl+F")); @@ -549,6 +557,7 @@ GambatteMenuHandler::GambatteMenuHandler(MainWindow &mw, connect(&mw, SIGNAL(dwmCompositionChange()), this, SLOT(reconsiderSyncFrameRateActionEnable())); connect(this, SIGNAL(romLoaded(bool)), romLoadedActions, SLOT(setEnabled(bool))); connect(this, SIGNAL(romLoaded(bool)), gambattePlatformMenu_.group(), SLOT(setDisabled(bool))); + connect(this, SIGNAL(romLoaded(bool)), attemptModeAction_, SLOT(setDisabled(bool))); connect(this, SIGNAL(romLoaded(bool)), stateSlotGroup_->actions().at(0), SLOT(setChecked(bool))); mw.setAspectRatio(QSize(160, 144)); @@ -590,6 +599,7 @@ GambatteMenuHandler::~GambatteMenuHandler() { QSettings settings; settings.setValue("rtc-mode", cycleBasedAction_->isChecked()); settings.setValue("true-colors", trueColorsAction_->isChecked()); + settings.setValue("attempt-mode", attemptModeAction_->isChecked()); } void GambatteMenuHandler::setWindowPrefix(QString const &windowPrefix) { @@ -697,8 +707,9 @@ void GambatteMenuHandler::loadFile(QString const &fileName) { //setDmgPaletteColors(); } - source_.setTrueColors(trueColorsAction_->isChecked()); source_.setTimeMode(cycleBasedAction_->isChecked()); + source_.setTrueColors(trueColorsAction_->isChecked()); + source_.setAttemptMode(attemptModeAction_->isChecked()); gambatte::PakInfo const &pak = source_.pakInfo(); std::cout << romTitle.toStdString() << '\n' @@ -711,16 +722,15 @@ void GambatteMenuHandler::loadFile(QString const &fileName) { // Basic good rom testing for PSR only. Fail doesn't mean it's a bad ROM for anything except English Gen1-2 games!!! QString label; for (GambatteGoodromInfo good : gambatte_goodroms) { - if (romTitle.toStdString() == good.title && pak.crc() == good.crc) { + if (romTitle.toStdString() == good.title && pak.crc() == good.crc && platformId == DEFAULT_GAMBATTE_PLATFORM) { if (!good.label.empty()) label = " " + QString::fromStdString(good.label); - source_.setBreakpoint(good.savBreakpoint); break; } } - setWindowPrefix(strippedName(fileName) + label); + setWindowPrefix(strippedName(fileName) + label + (attemptModeAction_->isChecked() ? " AM" : "")); setCurrentFile(fileName); emit romLoaded(true); @@ -728,6 +738,9 @@ void GambatteMenuHandler::loadFile(QString const &fileName) { mw_.resetAudio(); mw_.run(); + + if (attemptModeAction_->isChecked()) + reset(); // Force reset fadeout for loading ROMs; prevents avoiding the fadeout from closing and re-opening the ROM } void GambatteMenuHandler::open() { @@ -1064,7 +1077,7 @@ void GambatteMenuHandler::saveState() { } void GambatteMenuHandler::loadState() { - if (isResetting_) + if (attemptModeAction_->isChecked() || isResetting_) return; LoadStateFun fun = { source_ }; mw_.callInWorkerThread(fun); @@ -1086,7 +1099,7 @@ void GambatteMenuHandler::saveStateAs() { } void GambatteMenuHandler::loadStateFrom() { - if (isResetting_) + if (attemptModeAction_->isChecked() || isResetting_) return; TmpPauser tmpPauser(mw_, 4); mw_.waitUntilPaused(); @@ -1131,7 +1144,7 @@ void GambatteMenuHandler::setResetting(bool state) { } void GambatteMenuHandler::pauseChange() { - if (isResetting_) { + if (attemptModeAction_->isChecked() || isResetting_) { pauseAction_->setChecked(false); return; } @@ -1142,12 +1155,12 @@ void GambatteMenuHandler::pauseChange() { } void GambatteMenuHandler::frameStep() { - if (isResetting_) + if (attemptModeAction_->isChecked() || isResetting_) return; if (pauseAction_->isChecked()) { mw_.frameStep(); - if (isResetting_) { + if (attemptModeAction_->isChecked() || isResetting_) { pauseAction_->setChecked(false); mw_.unpause(); } diff --git a/gambatte_qt/src/gambattemenuhandler.h b/gambatte_qt/src/gambattemenuhandler.h index f91f7e13..5aa5befe 100644 --- a/gambatte_qt/src/gambattemenuhandler.h +++ b/gambatte_qt/src/gambattemenuhandler.h @@ -168,6 +168,7 @@ class GambatteMenuHandler : public QObject { QAction *cycleBasedAction_; QAction *realTimeAction_; QAction *trueColorsAction_; + QAction *attemptModeAction_; QAction *fsAct_; QMenu *recentMenu_; PaletteDialog *globalPaletteDialog_; diff --git a/gambatte_qt/src/gambattesource.h b/gambatte_qt/src/gambattesource.h index 5a20c5ff..e8e96777 100644 --- a/gambatte_qt/src/gambattesource.h +++ b/gambatte_qt/src/gambattesource.h @@ -111,8 +111,12 @@ class GambatteSource : public QObject, public MediaSource { virtual void generateVideoFrame(PixelBuffer const &fb); public slots: - void setTrueColors(bool trueColors) { gb_.setTrueColors(trueColors); } void setTimeMode(bool useCycles) { gb_.setTimeMode(useCycles); } + void setTrueColors(bool trueColors) { gb_.setTrueColors(trueColors); } + void setAttemptMode(bool attemptMode) { + gb_.setAttemptMode(attemptMode); + attemptMode_ = attemptMode; + } signals: void setTurbo(bool on); @@ -181,6 +185,7 @@ public slots: signed resetCounter_; unsigned resetFade_; unsigned resetStall_; + bool attemptMode_; std::mt19937 rng_; std::uniform_int_distribution dist35112_; @@ -197,16 +202,16 @@ public slots: void enableBreakpoint(bool enable) { gb_.setInterruptAddresses(breakpoint_, enable ? 1 : 0); } int getHitAddress() { return gb_.getHitInterruptAddress(); } - void emitSetTurbo(bool on) { if(!isResetting_) { emit setTurbo(on);} } - void emitPause() { if(!isResetting_) { emit togglePause();} } - void emitFrameStep() { if(!isResetting_) { emit frameStep();} } - void emitDecFrameRate() { if(!isResetting_) { emit decFrameRate();} } - void emitIncFrameRate() { if(!isResetting_) { emit incFrameRate();} } - void emitResetFrameRate() { if(!isResetting_) { emit resetFrameRate();} } + void emitSetTurbo(bool on) { if(!isResetting_ && !attemptMode_) { emit setTurbo(on);} } + void emitPause() { if(!isResetting_ && !attemptMode_) { emit togglePause();} } + void emitFrameStep() { if(!isResetting_ && !attemptMode_) { emit frameStep();} } + void emitDecFrameRate() { if(!isResetting_ && !attemptMode_) { emit decFrameRate();} } + void emitIncFrameRate() { if(!isResetting_ && !attemptMode_) { emit incFrameRate();} } + void emitResetFrameRate() { if(!isResetting_ && !attemptMode_) { emit resetFrameRate();} } void emitPrevStateSlot() { if(!isResetting_) { emit prevStateSlot();} } void emitNextStateSlot() { if(!isResetting_) { emit nextStateSlot();} } void emitSaveState() { if(!isResetting_) { emit saveStateSignal();} } - void emitLoadState() { if(!isResetting_) { emit loadStateSignal();} } + void emitLoadState() { if(!isResetting_ && !attemptMode_) { emit loadStateSignal();} } void emitReset() { emit resetSignal(); } void emitQuit() { emit quit(); } }; diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h index 8cd08cae..e0794989 100644 --- a/libgambatte/include/gambatte.h +++ b/libgambatte/include/gambatte.h @@ -108,12 +108,15 @@ class GB { */ void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32); - /** Use GBP color conversion instead of GBC-screen approximation. */ - void setTrueColors(bool trueColors); - /** Use cycle-based RTC instead of real-time. */ void setTimeMode(bool useCycles); + /** Use GBP color conversion instead of GBC-screen approximation. */ + void setTrueColors(bool trueColors); + + /** Disable unwanted emulator functions for speedrunning attempts. */ + void setAttemptMode(bool attemptMode) { attemptMode_ = attemptMode; } + /** Sets the callback used for getting input state. */ void setInputGetter(InputGetter *getInput, void *p); @@ -283,6 +286,8 @@ class GB { GB(GB const &); GB & operator=(GB const &); + + bool attemptMode_; }; } diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h index 88d10f8f..e07d0a27 100644 --- a/libgambatte/src/cpu.h +++ b/libgambatte/src/cpu.h @@ -69,8 +69,8 @@ class CPU { mem_.setDmgPaletteColor(palNum, colorNum, rgb32); } - void setTrueColors(bool trueColors) { mem_.setTrueColors(trueColors); } void setTimeMode(bool useCycles) { mem_.setTimeMode(useCycles, cycleCounter_); } + void setTrueColors(bool trueColors) { mem_.setTrueColors(trueColors); } void setRtcDivisorOffset(long const rtcDivisorOffset) { mem_.setRtcDivisorOffset(rtcDivisorOffset); } void setGameGenie(std::string const &codes) { mem_.setGameGenie(codes); } diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp index 2ecec11d..b2a8618b 100644 --- a/libgambatte/src/gambatte.cpp +++ b/libgambatte/src/gambatte.cpp @@ -101,7 +101,7 @@ void GB::reset(std::size_t samplesToStall, std::string const &build) { p_->cpu.stall(samplesToStall * 2); if (!build.empty()) - p_->cpu.setOsdElement(newResetElement(build, GB::pakInfo().crc())); + p_->cpu.setOsdElement(newResetElement(build, GB::pakInfo().crc(), attemptMode_)); } } @@ -130,6 +130,7 @@ LoadRes GB::load(std::string const &romfile, unsigned const flags) { setInitState(state, flags & CGB_MODE, flags & SGB_MODE); setInitStateCart(state); p_->cpu.loadState(state); + if (!attemptMode_) p_->cpu.loadSavedata(); p_->stateNo = 1; @@ -186,14 +187,14 @@ void GB::setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) { p_->cpu.setDmgPaletteColor(palNum, colorNum, rgb32); } -void GB::setTrueColors(bool trueColors) { - p_->cpu.setTrueColors(trueColors); -} - void GB::setTimeMode(bool useCycles) { p_->cpu.setTimeMode(useCycles); } +void GB::setTrueColors(bool trueColors) { + p_->cpu.setTrueColors(trueColors); +} + bool GB::loadState(std::string const &filepath) { if (p_->cpu.loaded()) { if (p_->implicitSave()) diff --git a/libgambatte/src/state_osd_elements.cpp b/libgambatte/src/state_osd_elements.cpp index d08282e8..cd2d747c 100644 --- a/libgambatte/src/state_osd_elements.cpp +++ b/libgambatte/src/state_osd_elements.cpp @@ -165,7 +165,7 @@ transfer_ptr newStateSavedOsdElement(unsigned stateNo) { return transfer_ptr(new ShadedTextOsdElment(text::stateSavedWidth, txt)); } -transfer_ptr newResetElement(std::string const &build, unsigned checksum) { +transfer_ptr newResetElement(std::string const &build, unsigned checksum, bool attemptMode) { unsigned checksumPart; char txt[sizeof text::reset]; std::memcpy(txt, text::reset, sizeof txt); @@ -199,6 +199,15 @@ transfer_ptr newResetElement(std::string const &build, unsigned chec txt[idx] = (char) (bitmapfont::A + (checksumPart - 0x0A)); } } + + // Put AM into char array if attempt mode is active + // AM -> Attempt Mode + if (attemptMode) { + int idx = p_len + p_off + 1; // 1 space in between CRC and AM + txt[idx] = bitmapfont::A; + txt[idx + 1] = bitmapfont::M; + } + return transfer_ptr(new ShadedTextOsdElment(bitmapfont::getWidth(txt), txt)); } diff --git a/libgambatte/src/state_osd_elements.h b/libgambatte/src/state_osd_elements.h index 9e5baa3d..fa07bb40 100644 --- a/libgambatte/src/state_osd_elements.h +++ b/libgambatte/src/state_osd_elements.h @@ -28,7 +28,7 @@ namespace gambatte { transfer_ptr newStateLoadedOsdElement(unsigned stateNo); transfer_ptr newStateSavedOsdElement(unsigned stateNo); transfer_ptr newSaveStateOsdElement(const std::string &fileName, unsigned stateNo); -transfer_ptr newResetElement(std::string const &build, unsigned checksum); +transfer_ptr newResetElement(std::string const &build, unsigned checksum, bool attemptMode); } #endif