diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9d0307f..6ca4a0e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,10 +33,12 @@ jobs: - uses: actions/checkout@v4 - name: Build the mod - uses: geode-sdk/build-geode-mod@main + uses: hiimjustin000/build-geode-mod@commit-hash with: build-config: RelWithDebInfo export-pdb: true + sdk: 49c8d38 + cli: nightly combine: true target: ${{ matrix.config.target }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 97ec93d..190d86c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64") set(CMAKE_CXX_VISIBILITY_PRESET hidden) -project(FakeRate VERSION 1.2.9) +project(FakeRate VERSION 1.3.0) add_library(${PROJECT_NAME} SHARED src/FakeRate.cpp diff --git a/README.md b/README.md index ab643e8..c761312 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,20 @@ A mod that allows you to assign a fake rating to online levels. # Features -- Ability to give online levels a fake rating -- This can be done either through a button in the level info screen or by editing save data -- The popup allows you to independently rate the level's difficulty, stars, and featured status +- Ability to give online levels a fake rating, which can be done either through a button in the level info screen or by editing save data +- A popup that allows you to independently rate the level's difficulty, stars, feature status, and coin verification status + +# Credits +- [Uproxide](https://gdbrowser.com/u/25397826) - Some inspiration for the mod +- [hiimjustin000](https://gdbrowser.com/u/7466002) - Creator of the mod + +# Gallery +![Fake Rate Popup](./resources/image1.png)\ +![Difficulty Popup](./resources/image2.png)\ +![Grandpa Demon Popup](./resources/image3.png)\ +![Demons In Between Popup](./resources/image4.png)\ +![Stars Popup](./resources/image5.png)\ +![Feature Popup](./resources/image6.png) # License This mod is licensed under the [MIT License](./LICENSE). \ No newline at end of file diff --git a/about.md b/about.md index cd4b53c..9bcb389 100644 --- a/about.md +++ b/about.md @@ -2,6 +2,17 @@ A mod that allows you to assign a fake rating to online levels. # Features -- Ability to give online levels a fake rating -- This can be done either through a button in the level info screen or by editing save data -- The popup allows you to independently rate the level's difficulty, stars, and featured status \ No newline at end of file +- Ability to give online levels a fake rating, which can be done either through a button in the level info screen or by editing save data +- A popup that allows you to independently rate the level's difficulty, stars, feature status, and coin verification status + +# Credits +- [Uproxide](user:25397826) - Some inspiration for the mod +- [hiimjustin000](user:7466002) - Creator of the mod + +# Gallery +![Fake Rate Popup](hiimjustin000.fake_rate/image1.png?scale=0.9)\ +![Difficulty Popup](hiimjustin000.fake_rate/image2.png?scale=0.9)\ +![Grandpa Demon Popup](hiimjustin000.fake_rate/image3.png?scale=1.2)\ +![Demons In Between Popup](hiimjustin000.fake_rate/image4.png?scale=0.9)\ +![Stars Popup](hiimjustin000.fake_rate/image5.png?scale=1.4)\ +![Feature Popup](hiimjustin000.fake_rate/image6.png?scale=0.9) \ No newline at end of file diff --git a/changelog.md b/changelog.md index 835e1c7..306f019 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,10 @@ # Fake Rate Changelog +## v1.3.0 (2024-07-25) +- Added Grandpa Demon and Demons In Between support +- Added the ability to customize coin verification status +- Added the ability to set negative stars +- Added a gallery to the mod's about page + ## v1.2.9 (2024-07-05) - Fixed a bug that caused two difficulty faces to be toggled in the difficulty selection popup with More Difficulties enabled - Fixed incompatibility with the mod "GodlikeFaces" by adyagmd diff --git a/mod.json b/mod.json index c4fbaed..d680374 100644 --- a/mod.json +++ b/mod.json @@ -1,11 +1,11 @@ { - "geode": "3.1.1", + "geode": "3.3.0", "gd": { "android": "2.206", "win": "2.206", "mac": "2.206" }, - "version": "v1.2.9", + "version": "v1.3.0", "id": "hiimjustin000.fake_rate", "name": "Fake Rate", "developer": "hiimjustin000", diff --git a/resources/FR_dibBtn_001.png b/resources/FR_dibBtn_001.png new file mode 100644 index 0000000..8d84b1a Binary files /dev/null and b/resources/FR_dibBtn_001.png differ diff --git a/resources/FR_grdBtn_001.png b/resources/FR_grdBtn_001.png new file mode 100644 index 0000000..09243e8 Binary files /dev/null and b/resources/FR_grdBtn_001.png differ diff --git a/resources/image1.png b/resources/image1.png new file mode 100644 index 0000000..17781be Binary files /dev/null and b/resources/image1.png differ diff --git a/resources/image2.png b/resources/image2.png new file mode 100644 index 0000000..1724fd8 Binary files /dev/null and b/resources/image2.png differ diff --git a/resources/image3.png b/resources/image3.png new file mode 100644 index 0000000..1d51ac6 Binary files /dev/null and b/resources/image3.png differ diff --git a/resources/image4.png b/resources/image4.png new file mode 100644 index 0000000..9ecab2f Binary files /dev/null and b/resources/image4.png differ diff --git a/resources/image5.png b/resources/image5.png new file mode 100644 index 0000000..50ea83f Binary files /dev/null and b/resources/image5.png differ diff --git a/resources/image6.png b/resources/image6.png new file mode 100644 index 0000000..63cf607 Binary files /dev/null and b/resources/image6.png differ diff --git a/src/FREditPopup.cpp b/src/FREditPopup.cpp index 4f454fa..d94133d 100644 --- a/src/FREditPopup.cpp +++ b/src/FREditPopup.cpp @@ -1,8 +1,8 @@ #include "FREditPopup.hpp" -FREditPopup* FREditPopup::create(GJGameLevel* level, int stars, int feature, int difficulty, int mdo, UpdateFakeRateCallback callback) { +FREditPopup* FREditPopup::create(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRateCallback callback) { auto ret = new FREditPopup(); - if (ret->initAnchored(300.0f, 200.0f, level, stars, feature, difficulty, mdo, callback)) { + if (ret->initAnchored(300.0f, 200.0f, level, data, callback)) { ret->autorelease(); return ret; } @@ -10,70 +10,77 @@ FREditPopup* FREditPopup::create(GJGameLevel* level, int stars, int feature, int return nullptr; } -bool FREditPopup::setup(GJGameLevel* level, int stars, int feature, int difficulty, int mdo, UpdateFakeRateCallback callback) { +bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRateCallback callback) { setTitle("Fake Rate"); m_level = level; - m_stars = stars; - m_feature = feature; - m_difficulty = difficulty; - m_moreDifficultiesOverride = mdo; + m_stars = data.stars; + m_feature = data.feature; + m_difficulty = data.difficulty; + m_moreDifficultiesOverride = data.moreDifficultiesOverride; + m_grandpaDemonOverride = data.grandpaDemonOverride; + m_demonsInBetweenOverride = data.demonsInBetweenOverride; + m_coins = data.coins; m_legacy = false; - m_difficultySprite = GJDifficultySprite::create(difficulty, GJDifficultyName::Long); + m_difficultySprite = GJDifficultySprite::create(data.difficulty, GJDifficultyName::Long); m_difficultySprite->setPositionX(60.0f); m_mainLayer->addChild(m_difficultySprite); if (Loader::get()->isModLoaded("uproxide.more_difficulties")) { m_legacy = Loader::get()->getLoadedMod("uproxide.more_difficulties")->getSettingValue("legacy-difficulties"); - auto pos = m_legacy ? CCPoint { 60.0f, 100.0f } : CCPoint { 60.25f, 99.9f }; - - m_casualSprite = CCSprite::createWithSpriteFrameName(m_legacy ? "uproxide.more_difficulties/MD_Difficulty04_Legacy.png" : "uproxide.more_difficulties/MD_Difficulty04.png"); - m_casualSprite->setPosition(pos); - m_casualSprite->setVisible(false); - m_mainLayer->addChild(m_casualSprite); - - m_toughSprite = CCSprite::createWithSpriteFrameName(m_legacy ? "uproxide.more_difficulties/MD_Difficulty07_Legacy.png" : "uproxide.more_difficulties/MD_Difficulty07.png"); - m_toughSprite->setPosition(pos); - m_toughSprite->setVisible(false); - m_mainLayer->addChild(m_toughSprite); - - m_cruelSprite = CCSprite::createWithSpriteFrameName(m_legacy ? "uproxide.more_difficulties/MD_Difficulty09_Legacy.png" : "uproxide.more_difficulties/MD_Difficulty09.png"); - m_cruelSprite->setPosition(pos); - m_cruelSprite->setVisible(false); - m_mainLayer->addChild(m_cruelSprite); + m_mdSprite = CCSprite::createWithSpriteFrameName(m_legacy ? "uproxide.more_difficulties/MD_Difficulty04_Legacy.png" : "uproxide.more_difficulties/MD_Difficulty04.png"); + m_mdSprite->setPosition(m_legacy ? CCPoint { 60.0f, 100.0f } : CCPoint { 60.25f, 99.9f }); + m_mdSprite->setVisible(false); + m_mainLayer->addChild(m_mdSprite); + } + if (Loader::get()->isModLoaded("itzkiba.grandpa_demon")) { + m_grdSprite = CCSprite::createWithSpriteFrameName("itzkiba.grandpa_demon/GrD_demon0_text.png"); + m_grdSprite->setPosition({ 60.0f, 105.0f }); + m_grdSprite->setVisible(false); + m_mainLayer->addChild(m_grdSprite); + } + if (Loader::get()->isModLoaded("hiimjustin000.demons_in_between")) { + m_dibSprite = CCSprite::createWithSpriteFrameName("hiimjustin000.demons_in_between/DIB_01_btn2_001.png"); + m_dibSprite->setPosition({ 60.0f, 105.0f }); + m_dibSprite->setVisible(false); + m_mainLayer->addChild(m_dibSprite); } m_starSprite = CCSprite::createWithSpriteFrameName(m_level->m_levelLength < 5 ? "star_small01_001.png" : "moon_small01_001.png"); m_mainLayer->addChild(m_starSprite); - m_starsLabel = CCLabelBMFont::create(std::to_string(stars).c_str(), "bigFont.fnt"); + m_starsLabel = CCLabelBMFont::create(std::to_string(data.stars).c_str(), "bigFont.fnt"); m_starsLabel->setScale(0.4f); m_starsLabel->setAnchorPoint({ 1.0f, 0.5f }); m_mainLayer->addChild(m_starsLabel); - m_coins = CCArray::create(); - m_coins->retain(); + m_coinSprites = CCArray::create(); + m_coinSprites->retain(); for (int i = 0; i < m_level->m_coins; i++) { auto coin = CCSprite::createWithSpriteFrameName("usercoin_small01_001.png"); coin->setPositionX(60.0f + (i == 2 ? 10.0f : i == 1 && m_level->m_coins == 2 ? 5.0f : i == 0 && m_level->m_coins == 2 ? -5.0f : i == 0 && m_level->m_coins == 3 ? -10.0f : 0.0f)); m_mainLayer->addChild(coin); - m_coins->addObject(coin); + m_coinSprites->addObject(coin); } auto difficultyButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Difficulty", "goldFont.fnt", "GJ_button_02.png", 0.8f), [this](auto) { - FRSetDifficultyPopup::create(m_difficulty, m_moreDifficultiesOverride, m_legacy, [this](int difficulty, int mdo) { - m_difficulty = difficulty; - m_moreDifficultiesOverride = mdo; - updateLabels(); - })->show(); + FRSetDifficultyPopup::create(m_difficulty, m_moreDifficultiesOverride, m_grandpaDemonOverride, m_demonsInBetweenOverride, m_legacy, + [this](int difficulty, int mdo, int gdo, int dbo) { + m_difficulty = difficulty; + m_moreDifficultiesOverride = mdo; + m_grandpaDemonOverride = gdo; + m_demonsInBetweenOverride = dbo; + updateLabels(); + })->show(); }); difficultyButton->setPosition(200.0f, 150.0f); m_buttonMenu->addChild(difficultyButton); - auto starsButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Stars", "goldFont.fnt", "GJ_button_02.png", 0.8f), [this, stars](auto) { - auto popup = SetIDPopup::create(m_stars, 0, 127, "Set Stars", "Set", true, stars, 0.0f, false, false); + auto starsButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Stars", "goldFont.fnt", "GJ_button_02.png", 0.8f), [this, data](auto) { + auto popup = SetIDPopup::create(m_stars, -128, 127, "Set Stars", "Set", true, data.stars, 0.0f, false, false); + popup->m_inputNode->setAllowedChars("0123456789-"); popup->m_delegate = this; popup->show(); }); @@ -81,14 +88,28 @@ bool FREditPopup::setup(GJGameLevel* level, int stars, int feature, int difficul m_buttonMenu->addChild(starsButton); auto featureButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Feature", "goldFont.fnt", "GJ_button_02.png", 0.8f), [this](auto) { - FRSetFeaturePopup::create(m_feature, m_difficulty, m_moreDifficultiesOverride, m_legacy, [this](int feature) { - m_feature = feature; - updateLabels(); - })->show(); + FRSetFeaturePopup::create(m_feature, m_difficulty, m_moreDifficultiesOverride, m_grandpaDemonOverride, m_demonsInBetweenOverride, m_legacy, + [this](int feature) { + m_feature = feature; + updateLabels(); + })->show(); }); featureButton->setPosition(200.0f, 70.0f); m_buttonMenu->addChild(featureButton); + auto coinsToggle = CCMenuItemExt::createTogglerWithStandardSprites(0.7f, [this](auto) { + m_coins = !m_coins; + updateLabels(); + }); + coinsToggle->setPosition(30.0f, 30.0f); + coinsToggle->toggle(m_coins); + m_buttonMenu->addChild(coinsToggle); + + auto coinsLabel = CCLabelBMFont::create("Coins", "bigFont.fnt"); + coinsLabel->setScale(0.5f); + coinsLabel->setPosition(70.0f, 30.0f); + m_mainLayer->addChild(coinsLabel); + auto addButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Add", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { auto vec = Mod::get()->getSavedValue>("fake-rate", {}); auto it = std::find_if(vec.begin(), vec.end(), [this](FakeRateSaveData const& item) { @@ -99,6 +120,9 @@ bool FREditPopup::setup(GJGameLevel* level, int stars, int feature, int difficul it->feature = m_feature; it->difficulty = m_difficulty; it->moreDifficultiesOverride = m_moreDifficultiesOverride; + it->grandpaDemonOverride = m_grandpaDemonOverride; + it->demonsInBetweenOverride = m_demonsInBetweenOverride; + it->coins = m_coins; } else { vec.push_back({ @@ -106,11 +130,23 @@ bool FREditPopup::setup(GJGameLevel* level, int stars, int feature, int difficul .stars = m_stars, .feature = m_feature, .difficulty = m_difficulty, - .moreDifficultiesOverride = m_moreDifficultiesOverride + .moreDifficultiesOverride = m_moreDifficultiesOverride, + .grandpaDemonOverride = m_grandpaDemonOverride, + .demonsInBetweenOverride = m_demonsInBetweenOverride, + .coins = m_coins }); } Mod::get()->setSavedValue("fake-rate", vec); - callback(m_stars, m_feature, m_difficulty, m_moreDifficultiesOverride, true, true); + callback({ + .id = m_level->m_levelID, + .stars = m_stars, + .feature = m_feature, + .difficulty = m_difficulty, + .moreDifficultiesOverride = m_moreDifficultiesOverride, + .grandpaDemonOverride = m_grandpaDemonOverride, + .demonsInBetweenOverride = m_demonsInBetweenOverride, + .coins = m_coins + }, false); onClose(nullptr); }); addButton->setPosition(150.0f, 30.0f); @@ -124,8 +160,16 @@ bool FREditPopup::setup(GJGameLevel* level, int stars, int feature, int difficul }), vec.end()); Mod::get()->setSavedValue("fake-rate", vec); auto stars = m_level->m_stars; - callback(m_level->m_stars, m_level->m_featured > 1 ? m_level->m_isEpic + 1 : 0, FakeRate::getDifficultyFromLevel(m_level), - stars == 4 || stars == 7 || stars == 9 ? stars : 0, true, false); + callback({ + .id = m_level->m_levelID, + .stars = stars, + .feature = m_level->m_featured > 1 ? m_level->m_isEpic + 1 : 0, + .difficulty = FakeRate::getDifficultyFromLevel(m_level), + .moreDifficultiesOverride = stars == 4 || stars == 7 || stars == 9 ? stars : 0, + .grandpaDemonOverride = 0, + .demonsInBetweenOverride = 0, + .coins = m_level->m_coinsVerified > 0 + }, true); onClose(nullptr); }); removeButton->setPosition(235.0f, 30.0f); @@ -144,35 +188,58 @@ void FREditPopup::setIDPopupClosed(SetIDPopup*, int stars) { void FREditPopup::updateLabels() { m_difficultySprite->updateFeatureState((GJFeatureState)m_feature); m_difficultySprite->updateDifficultyFrame(m_difficulty, GJDifficultyName::Long); - m_difficultySprite->setPositionY(100.0f + (m_difficulty > 5 ? 5.0f : 0.0f) + (m_stars > 0 ? 10.0f : 0.0f)); + m_difficultySprite->setPositionY(100.0f + (m_difficulty > 5 ? 5.0f : 0.0f) + (m_stars != 0 ? 10.0f : 0.0f)); m_starSprite->setPosition({ m_difficultySprite->getPositionX() + 8.0f, m_difficultySprite->getPositionY() - 30.0f - (m_difficulty > 5 ? 9.0f : 0.0f) }); - m_starSprite->setVisible(m_stars > 0); + m_starSprite->setVisible(m_stars != 0); m_starsLabel->setPosition(m_starSprite->getPositionX() - 8.0f, m_starSprite->getPositionY()); m_starsLabel->setString(std::to_string(m_stars).c_str()); - m_starsLabel->setVisible(m_stars > 0); - auto coins = reinterpret_cast(m_coins->data->arr); + m_starsLabel->setVisible(m_stars != 0); + auto coins = reinterpret_cast(m_coinSprites->data->arr); for (int i = 0; i < m_level->m_coins; i++) { - coins[i]->setPositionY(m_difficultySprite->getPositionY() - 31.5f - (m_stars > 0 ? 14.0f : 0.0f) - (m_difficulty > 5 ? 9.0f : 0.0f)); + coins[i]->setPositionY(m_difficultySprite->getPositionY() - 31.5f - (m_stars != 0 ? 14.0f : 0.0f) - (m_difficulty > 5 ? 9.0f : 0.0f)); + coins[i]->setColor(m_coins ? ccColor3B { 255, 255, 255 } : ccColor3B { 255, 175, 75 }); } + auto difficultyVisible = true; + m_difficultySprite->setOpacity(255); if (Loader::get()->isModLoaded("uproxide.more_difficulties")) { - auto pos = m_difficultySprite->getPosition() + (m_legacy ? CCPoint { 0.0f, 0.0f } : CCPoint { 0.25f, -0.1f }); - m_casualSprite->setPosition(pos); - m_toughSprite->setPosition(pos); - m_cruelSprite->setPosition(pos); - m_casualSprite->setVisible(m_moreDifficultiesOverride == 4); - m_toughSprite->setVisible(m_moreDifficultiesOverride == 7); - m_cruelSprite->setVisible(m_moreDifficultiesOverride == 9); - m_difficultySprite->setOpacity(m_moreDifficultiesOverride != 4 && m_moreDifficultiesOverride != 7 && m_moreDifficultiesOverride != 9 ? 255 : 0); + if (m_moreDifficultiesOverride == 4 || m_moreDifficultiesOverride == 7 || m_moreDifficultiesOverride == 9) { + m_mdSprite->setDisplayFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName( + fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}.png{}", m_moreDifficultiesOverride, m_legacy ? "_Legacy" : "").c_str())); + m_mdSprite->setPosition(m_difficultySprite->getPosition() + (m_legacy ? CCPoint { 0.0f, 0.0f } : CCPoint { 0.25f, -0.1f })); + m_mdSprite->setVisible(true); + m_difficultySprite->setOpacity(0); + } + else m_mdSprite->setVisible(false); + } + if (Loader::get()->isModLoaded("itzkiba.grandpa_demon")) { + if (m_grandpaDemonOverride > 0 && m_grandpaDemonOverride < 7) { + m_grdSprite->setDisplayFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName( + fmt::format("itzkiba.grandpa_demon/GrD_demon{}_text.png", m_grandpaDemonOverride - 1).c_str())); + m_grdSprite->setPosition(m_difficultySprite->getPosition()); + m_grdSprite->setVisible(true); + m_difficultySprite->setOpacity(0); + } + else m_grdSprite->setVisible(false); + } + if (Loader::get()->isModLoaded("hiimjustin000.demons_in_between")) { + if (m_demonsInBetweenOverride > 0 && m_demonsInBetweenOverride < 21) { + m_dibSprite->setDisplayFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName( + fmt::format("hiimjustin000.demons_in_between/DIB_{:02d}_btn2_001.png", m_demonsInBetweenOverride).c_str())); + m_dibSprite->setPosition(m_difficultySprite->getPosition() + FakeRate::getDIBOffset(m_demonsInBetweenOverride, GJDifficultyName::Long)); + m_dibSprite->setVisible(true); + m_difficultySprite->setOpacity(0); + } + else m_dibSprite->setVisible(false); } } FREditPopup::~FREditPopup() { - m_coins->release(); + m_coinSprites->release(); } -FRSetDifficultyPopup* FRSetDifficultyPopup::create(int difficulty, int moreDifficultiesOverride, bool legacy, SetDifficultyCallback callback) { +FRSetDifficultyPopup* FRSetDifficultyPopup::create(int difficulty, int mdo, int gdo, int dbo, bool legacy, SetDifficultyCallback callback) { auto ret = new FRSetDifficultyPopup(); - if (ret->initAnchored(300.0f, 250.0f, difficulty, moreDifficultiesOverride, legacy, callback)) { + if (ret->initAnchored(300.0f, 250.0f, difficulty, mdo, gdo, dbo, legacy, callback)) { ret->autorelease(); return ret; } @@ -180,10 +247,12 @@ FRSetDifficultyPopup* FRSetDifficultyPopup::create(int difficulty, int moreDiffi return nullptr; } -bool FRSetDifficultyPopup::setup(int difficulty, int moreDifficultiesOverride, bool legacy, SetDifficultyCallback callback) { +bool FRSetDifficultyPopup::setup(int difficulty, int mdo, int gdo, int dbo, bool legacy, SetDifficultyCallback callback) { setTitle("Select Difficulty"); m_difficulty = difficulty; - m_moreDifficultiesOverride = moreDifficultiesOverride; + m_moreDifficultiesOverride = mdo; + m_grandpaDemonOverride = gdo; + m_demonsInBetweenOverride = dbo; m_legacy = legacy; auto menuRow1 = CCMenu::create(); @@ -202,6 +271,7 @@ bool FRSetDifficultyPopup::setup(int difficulty, int moreDifficultiesOverride, b menuRow3->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); menuRow3->setPosition(150.0f, 80.0f); menuRow3->setContentSize({ 300.0f, 65.0f }); + menuRow3->setTag(3); m_mainLayer->addChild(menuRow3); createDifficultyToggle(menuRow1, 0, 0); @@ -226,12 +296,44 @@ bool FRSetDifficultyPopup::setup(int difficulty, int moreDifficultiesOverride, b menuRow3->updateLayout(); auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { - callback(m_difficulty, m_moreDifficultiesOverride); + callback(m_difficulty, m_moreDifficultiesOverride, m_grandpaDemonOverride, m_demonsInBetweenOverride); onClose(nullptr); }); - confirmButton->setPosition(150.0f, 30.0f); + confirmButton->setPosition(150.0f, 25.0f); m_buttonMenu->addChild(confirmButton); + auto demonsInBetween = Loader::get()->isModLoaded("hiimjustin000.demons_in_between"); + if (Loader::get()->isModLoaded("itzkiba.grandpa_demon")) { + auto grdButton = CCMenuItemExt::createSpriteExtraWithFilename("FR_grdBtn_001.png"_spr, 0.65f, [this](auto) { + FRGRDPopup::create(m_grandpaDemonOverride, [this](int grd) { + m_difficulty = 10; + m_grandpaDemonOverride = grd; + m_demonsInBetweenOverride = 0; + auto sender = static_cast(m_mainLayer->getChildByTag(3)->getChildByTag(10)); + FakeRate::toggle(m_selected->getNormalImage(), false); + FakeRate::toggle(sender->getNormalImage(), true); + m_selected = sender; + })->show(); + }); + grdButton->setPosition(275.0f - (demonsInBetween ? 30.0f : 0.0f), 25.0f); + m_buttonMenu->addChild(grdButton); + } + if (demonsInBetween) { + auto dibButton = CCMenuItemExt::createSpriteExtraWithFilename("FR_dibBtn_001.png"_spr, 0.75f, [this](auto) { + FRDIBPopup::create(m_difficulty, m_demonsInBetweenOverride, [this](int diff, int dib) { + m_difficulty = diff; + m_grandpaDemonOverride = 0; + m_demonsInBetweenOverride = dib; + auto sender = static_cast(m_mainLayer->getChildByTag(3)->getChildByTag(diff)); + FakeRate::toggle(m_selected->getNormalImage(), false); + FakeRate::toggle(sender->getNormalImage(), true); + m_selected = sender; + })->show(); + }); + dibButton->setPosition(275.0f, 25.0f); + m_buttonMenu->addChild(dibButton); + } + return true; } @@ -243,21 +345,33 @@ void FRSetDifficultyPopup::createDifficultyToggle(CCMenu* menu, int difficulty, : fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}.png", moreDifficultiesOverride); else if (moreDifficultiesOverride > 0) return; auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(frameName.c_str(), 1.0f, [this, difficulty, moreDifficultiesOverride](CCMenuItemSpriteExtra* sender) { + if (sender == m_selected) return; m_difficulty = difficulty; m_moreDifficultiesOverride = moreDifficultiesOverride; + if (m_difficulty < 10 && m_grandpaDemonOverride > 0) m_grandpaDemonOverride = 0; + if (m_difficulty < 6 && m_demonsInBetweenOverride > 0) m_demonsInBetweenOverride = 0; + else if (m_difficulty > 5 && m_demonsInBetweenOverride > 0) switch (m_difficulty) { + case 7: m_demonsInBetweenOverride = 4; break; + case 8: m_demonsInBetweenOverride = 7; break; + case 6: m_demonsInBetweenOverride = 11; break; + case 9: m_demonsInBetweenOverride = 15; break; + case 10: m_demonsInBetweenOverride = 20; break; + default: m_demonsInBetweenOverride = 0; break; + } FakeRate::toggle(m_selected->getNormalImage(), false); FakeRate::toggle(sender->getNormalImage(), true); m_selected = sender; }); + if (difficulty > 5) toggle->setTag(difficulty); auto isToggled = moreDifficultiesOverride == m_moreDifficultiesOverride && (m_moreDifficultiesOverride <= 0 ? difficulty == m_difficulty : true); FakeRate::toggle(toggle->getNormalImage(), isToggled); m_selected = isToggled ? toggle : m_selected; menu->addChild(toggle); } -FRSetFeaturePopup* FRSetFeaturePopup::create(int feature, int difficulty, int moreDifficultiesOverride, bool legacy, SetFeatureCallback callback) { +FRSetFeaturePopup* FRSetFeaturePopup::create(int feature, int difficulty, int mdo, int gdo, int dbo, bool legacy, SetFeatureCallback callback) { auto ret = new FRSetFeaturePopup(); - if (ret->initAnchored(300.0f, 150.0f, feature, difficulty, moreDifficultiesOverride, legacy, callback)) { + if (ret->initAnchored(300.0f, 150.0f, feature, difficulty, mdo, gdo, dbo, legacy, callback)) { ret->autorelease(); return ret; } @@ -265,11 +379,13 @@ FRSetFeaturePopup* FRSetFeaturePopup::create(int feature, int difficulty, int mo return nullptr; } -bool FRSetFeaturePopup::setup(int feature, int difficulty, int moreDifficultiesOverride, bool legacy, SetFeatureCallback callback) { +bool FRSetFeaturePopup::setup(int feature, int difficulty, int mdo, int gdo, int dbo, bool legacy, SetFeatureCallback callback) { setTitle("Select Feature"); m_feature = static_cast(feature); m_difficulty = difficulty; - m_moreDifficultiesOverride = moreDifficultiesOverride; + m_moreDifficultiesOverride = mdo; + m_grandpaDemonOverride = gdo; + m_demonsInBetweenOverride = dbo; m_legacy = legacy; auto menuRow = CCMenu::create(); @@ -289,7 +405,7 @@ bool FRSetFeaturePopup::setup(int feature, int difficulty, int moreDifficultiesO callback(static_cast(m_feature)); onClose(nullptr); }); - confirmButton->setPosition(150.0f, 30.0f); + confirmButton->setPosition(150.0f, 25.0f); m_buttonMenu->addChild(confirmButton); return true; @@ -305,7 +421,20 @@ void FRSetFeaturePopup::createFeatureToggle(CCMenu* menu, GJFeatureState feature mdSprite->setPosition(difficultySprite->getContentSize() / 2 + (m_legacy ? CCPoint { 0.0f, 0.0f } : CCPoint { 0.25f, -0.1f })); difficultySprite->setOpacity(0); } + if (Loader::get()->isModLoaded("itzkiba.grandpa_demon") && m_grandpaDemonOverride > 0) { + auto grdSprite = CCSprite::createWithSpriteFrameName(fmt::format("itzkiba.grandpa_demon/GrD_demon{}_text.png", m_grandpaDemonOverride - 1).c_str()); + difficultySprite->addChild(grdSprite); + grdSprite->setPosition(difficultySprite->getContentSize() / 2); + difficultySprite->setOpacity(0); + } + if (Loader::get()->isModLoaded("hiimjustin000.demons_in_between") && m_demonsInBetweenOverride > 0) { + auto dibSprite = CCSprite::createWithSpriteFrameName(fmt::format("hiimjustin000.demons_in_between/DIB_{:02d}_btn2_001.png", m_demonsInBetweenOverride).c_str()); + difficultySprite->addChild(dibSprite); + dibSprite->setPosition(difficultySprite->getContentSize() / 2 + FakeRate::getDIBOffset(m_demonsInBetweenOverride, GJDifficultyName::Long)); + difficultySprite->setOpacity(0); + } auto toggle = CCMenuItemExt::createSpriteExtra(difficultySprite, [this, feature](CCMenuItemSpriteExtra* sender) { + if (sender == m_selected) return; m_feature = feature; FakeRate::toggle(m_selected->getNormalImage(), false); if (auto particleSystem = getChildOfType(m_selected->getNormalImage(), 0)) particleSystem->setVisible(false); @@ -318,3 +447,171 @@ void FRSetFeaturePopup::createFeatureToggle(CCMenu* menu, GJFeatureState feature m_selected = feature == m_feature ? toggle : m_selected; menu->addChild(toggle); } + +FRGRDPopup* FRGRDPopup::create(int grandpaDemonOverride, SetGRDCallback callback) { + auto ret = new FRGRDPopup(); + if (ret->initAnchored(250.0f, 200.0f, grandpaDemonOverride, callback)) { + ret->autorelease(); + return ret; + } + delete ret; + return nullptr; +} + +bool FRGRDPopup::setup(int grandpaDemonOverride, SetGRDCallback callback) { + setTitle("Grandpa Demon"); + m_grandpaDemonOverride = grandpaDemonOverride; + + auto menuRow1 = CCMenu::create(); + menuRow1->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + menuRow1->setPosition(125.0f, 140.0f); + menuRow1->setContentSize({ 250.0f, 65.0f }); + m_mainLayer->addChild(menuRow1); + + createGRDToggle(menuRow1, 1); + createGRDToggle(menuRow1, 2); + createGRDToggle(menuRow1, 3); + menuRow1->updateLayout(); + + auto menuRow2 = CCMenu::create(); + menuRow2->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + menuRow2->setPosition(125.0f, 75.0f); + menuRow2->setContentSize({ 250.0f, 65.0f }); + m_mainLayer->addChild(menuRow2); + + createGRDToggle(menuRow2, 4); + createGRDToggle(menuRow2, 5); + createGRDToggle(menuRow2, 6); + menuRow2->updateLayout(); + + auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { + callback(m_grandpaDemonOverride); + onClose(nullptr); + }); + confirmButton->setPosition(125.0f, 25.0f); + m_buttonMenu->addChild(confirmButton); + + return true; +} + +void FRGRDPopup::createGRDToggle(CCMenu* menu, int grandpaDemonOverride) { + auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(fmt::format("itzkiba.grandpa_demon/GrD_demon{}_text.png", grandpaDemonOverride - 1).c_str(), 1.0f, + [this, grandpaDemonOverride](CCMenuItemSpriteExtra* sender) { + if (sender == m_selected) return; + m_grandpaDemonOverride = grandpaDemonOverride; + if (m_selected) FakeRate::toggle(m_selected->getNormalImage(), false); + FakeRate::toggle(sender->getNormalImage(), true); + m_selected = sender; + }); + FakeRate::toggle(toggle->getNormalImage(), grandpaDemonOverride == m_grandpaDemonOverride); + m_selected = grandpaDemonOverride == m_grandpaDemonOverride ? toggle : m_selected; + menu->addChild(toggle); +} + +FRDIBPopup* FRDIBPopup::create(int difficulty, int demonsInBetweenOverride, SetDIBCallback callback) { + auto ret = new FRDIBPopup(); + if (ret->initAnchored(350.0f, 310.0f, difficulty, demonsInBetweenOverride, callback)) { + ret->autorelease(); + return ret; + } + delete ret; + return nullptr; +} + +bool FRDIBPopup::setup(int difficulty, int demonsInBetweenOverride, SetDIBCallback callback) { + setTitle("Demons In Between"); + m_difficulty = difficulty; + m_demonsInBetweenOverride = demonsInBetweenOverride; + if (demonsInBetweenOverride <= 0) switch (m_difficulty) { + case 7: m_demonsInBetweenOverride = 4; break; + case 8: m_demonsInBetweenOverride = 7; break; + case 6: m_demonsInBetweenOverride = 11; break; + case 9: m_demonsInBetweenOverride = 15; break; + case 10: m_demonsInBetweenOverride = 20; break; + default: m_demonsInBetweenOverride = 0; break; + } + + auto menuRow1 = CCMenu::create(); + menuRow1->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + menuRow1->setPosition(175.0f, 250.0f); + menuRow1->setContentSize({ 350.0f, 60.0f }); + m_mainLayer->addChild(menuRow1); + + createDIBToggle(menuRow1, 1, 0); + createDIBToggle(menuRow1, 2, 0); + createDIBToggle(menuRow1, 3, 0); + createDIBToggle(menuRow1, 4, 7); + createDIBToggle(menuRow1, 5, 0); + menuRow1->updateLayout(); + + auto menuRow2 = CCMenu::create(); + menuRow2->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + menuRow2->setPosition(175.0f, 190.0f); + menuRow2->setContentSize({ 350.0f, 60.0f }); + m_mainLayer->addChild(menuRow2); + + createDIBToggle(menuRow2, 6, 0); + createDIBToggle(menuRow2, 7, 8); + createDIBToggle(menuRow2, 8, 0); + createDIBToggle(menuRow2, 9, 0); + createDIBToggle(menuRow2, 10, 0); + menuRow2->updateLayout(); + + auto menuRow3 = CCMenu::create(); + menuRow3->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + menuRow3->setPosition(175.0f, 130.0f); + menuRow3->setContentSize({ 350.0f, 60.0f }); + m_mainLayer->addChild(menuRow3); + + createDIBToggle(menuRow3, 11, 6); + createDIBToggle(menuRow3, 12, 0); + createDIBToggle(menuRow3, 13, 0); + createDIBToggle(menuRow3, 14, 0); + createDIBToggle(menuRow3, 15, 9); + menuRow3->updateLayout(); + + auto menuRow4 = CCMenu::create(); + menuRow4->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + menuRow4->setPosition(175.0f, 70.0f); + menuRow4->setContentSize({ 350.0f, 60.0f }); + m_mainLayer->addChild(menuRow4); + + createDIBToggle(menuRow4, 16, 0); + createDIBToggle(menuRow4, 17, 0); + createDIBToggle(menuRow4, 18, 0); + createDIBToggle(menuRow4, 19, 0); + createDIBToggle(menuRow4, 20, 10); + menuRow4->updateLayout(); + + auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { + auto diff = 0; + switch (m_demonsInBetweenOverride) { + case 1: case 2: case 3: case 4: diff = 7; break; + case 5: case 6: case 7: case 8: diff = 8; break; + case 9: case 10: case 11: case 12: diff = 6; break; + case 13: case 14: case 15: case 16: diff = 9; break; + case 17: case 18: case 19: case 20: diff = 10; break; + } + callback(diff, m_demonsInBetweenOverride); + onClose(nullptr); + }); + confirmButton->setPosition(175.0f, 25.0f); + m_buttonMenu->addChild(confirmButton); + + return true; +} + +void FRDIBPopup::createDIBToggle(CCMenu* menu, int demonsInBetweenOverride, int difficulty) { + auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(fmt::format("hiimjustin000.demons_in_between/DIB_{:02}_btn2_001.png", demonsInBetweenOverride).c_str(), + 1.0f, [this, demonsInBetweenOverride](CCMenuItemSpriteExtra* sender) { + if (sender == m_selected) return; + m_demonsInBetweenOverride = demonsInBetweenOverride; + if (m_selected) FakeRate::toggle(m_selected->getNormalImage(), false); + FakeRate::toggle(sender->getNormalImage(), true); + m_selected = sender; + }); + auto isToggled = m_difficulty > 5 && (m_demonsInBetweenOverride <= 0 ? difficulty == m_difficulty : demonsInBetweenOverride == m_demonsInBetweenOverride); + FakeRate::toggle(toggle->getNormalImage(), isToggled); + m_selected = isToggled ? toggle : m_selected; + menu->addChild(toggle); +} diff --git a/src/FREditPopup.hpp b/src/FREditPopup.hpp index 2e64e84..b0b0644 100644 --- a/src/FREditPopup.hpp +++ b/src/FREditPopup.hpp @@ -1,58 +1,90 @@ #include "FakeRate.hpp" -typedef MiniFunction UpdateFakeRateCallback; -typedef MiniFunction SetDifficultyCallback; +typedef MiniFunction UpdateFakeRateCallback; +typedef MiniFunction SetDifficultyCallback; typedef MiniFunction SetFeatureCallback; +typedef MiniFunction SetGRDCallback; +typedef MiniFunction SetDIBCallback; -class FREditPopup : public Popup, SetIDPopupDelegate { +class FREditPopup : public Popup, SetIDPopupDelegate { protected: GJGameLevel* m_level; int m_stars; int m_feature; int m_difficulty; int m_moreDifficultiesOverride; + int m_grandpaDemonOverride; + int m_demonsInBetweenOverride; + bool m_coins; bool m_legacy; GJDifficultySprite* m_difficultySprite; - CCSprite* m_casualSprite; - CCSprite* m_toughSprite; - CCSprite* m_cruelSprite; + CCSprite* m_mdSprite; + CCSprite* m_grdSprite; + CCSprite* m_dibSprite; CCSprite* m_starSprite; CCLabelBMFont* m_starsLabel; - CCArray* m_coins; + CCArray* m_coinSprites; - bool setup(GJGameLevel*, int, int, int, int, UpdateFakeRateCallback) override; + bool setup(GJGameLevel*, FakeRateSaveData, UpdateFakeRateCallback) override; void updateLabels(); public: - static FREditPopup* create(GJGameLevel*, int, int, int, int, UpdateFakeRateCallback); + static FREditPopup* create(GJGameLevel*, FakeRateSaveData, UpdateFakeRateCallback); void setIDPopupClosed(SetIDPopup*, int) override; ~FREditPopup() override; }; -class FRSetDifficultyPopup : public Popup { +class FRSetDifficultyPopup : public Popup { protected: int m_difficulty; int m_moreDifficultiesOverride; + int m_grandpaDemonOverride; + int m_demonsInBetweenOverride; bool m_legacy; CCMenuItemSpriteExtra* m_selected; - bool setup(int, int, bool, SetDifficultyCallback) override; + bool setup(int, int, int, int, bool, SetDifficultyCallback) override; void createDifficultyToggle(CCMenu*, int, int); public: - static FRSetDifficultyPopup* create(int, int, bool, SetDifficultyCallback); + static FRSetDifficultyPopup* create(int, int, int, int, bool, SetDifficultyCallback); }; -class FRSetFeaturePopup : public Popup { +class FRSetFeaturePopup : public Popup { protected: GJFeatureState m_feature; int m_difficulty; int m_moreDifficultiesOverride; + int m_grandpaDemonOverride; + int m_demonsInBetweenOverride; bool m_legacy; CCMenuItemSpriteExtra* m_selected; - bool setup(int, int, int, bool, SetFeatureCallback) override; + bool setup(int, int, int, int, int, bool, SetFeatureCallback) override; void createFeatureToggle(CCMenu*, GJFeatureState); public: - static FRSetFeaturePopup* create(int, int, int, bool, SetFeatureCallback); + static FRSetFeaturePopup* create(int, int, int, int, int, bool, SetFeatureCallback); +}; + +class FRGRDPopup : public Popup { +protected: + int m_grandpaDemonOverride; + CCMenuItemSpriteExtra* m_selected; + + bool setup(int, SetGRDCallback) override; + void createGRDToggle(CCMenu*, int); +public: + static FRGRDPopup* create(int, SetGRDCallback); +}; + +class FRDIBPopup : public Popup { +protected: + int m_difficulty; + int m_demonsInBetweenOverride; + CCMenuItemSpriteExtra* m_selected; + + bool setup(int, int, SetDIBCallback) override; + void createDIBToggle(CCMenu*, int, int); +public: + static FRDIBPopup* create(int, int, SetDIBCallback); }; diff --git a/src/FakeRate.cpp b/src/FakeRate.cpp index 89813f9..a0137e8 100644 --- a/src/FakeRate.cpp +++ b/src/FakeRate.cpp @@ -46,3 +46,33 @@ void FakeRate::toggle(CCNode* node, bool enabled) { } } } + +CCPoint FakeRate::getDIBOffset(int difficulty, GJDifficultyName name) { + if (difficulty < 1 || difficulty > 20) return { 0.0f, 0.0f }; + return name == GJDifficultyName::Long ? LONG_OFFSETS[difficulty - 1] : SHORT_OFFSETS[difficulty - 1]; +} + +int FakeRate::getGRDOverride(CCSprite* sprite) { + auto sprName = getSpriteName(sprite); + if (sprName.substr(sprName.size() - 5) == "_text") sprName = sprName.substr(0, sprName.size() - 5); + + auto pos = sprName.find("GrD_demon"); + if (pos != std::string::npos) { + auto num = sprName.substr(pos + 9); + return std::stoi(num) + 1; + } + else return 0; +} + +int FakeRate::getDIBOverride(CCSprite* sprite) { + auto sprName = getSpriteName(sprite); + if (sprName.substr(sprName.size() - 12) == "_btn_001.png") sprName = sprName.substr(0, sprName.size() - 12); + else if (sprName.substr(sprName.size() - 13) == "_btn2_001.png") sprName = sprName.substr(0, sprName.size() - 13); + + auto pos = sprName.find("DIB_"); + if (pos != std::string::npos) { + auto num = sprName.substr(pos + 4, 2); + return std::stoi(num); + } + else return 0; +} diff --git a/src/FakeRate.hpp b/src/FakeRate.hpp index 5f68dca..83900c3 100644 --- a/src/FakeRate.hpp +++ b/src/FakeRate.hpp @@ -8,14 +8,33 @@ struct FakeRateSaveData { int feature; int difficulty; int moreDifficultiesOverride; + int grandpaDemonOverride; + int demonsInBetweenOverride; + bool coins; }; class FakeRate { +private: + inline static std::vector LONG_OFFSETS = { + { 0.0f, -5.0f }, { 0.125f, -5.0f }, { 0.0f, -5.0f }, { 0.0f, -5.125f }, { 0.25f, -5.0f }, + { 0.125f, -4.75f }, { 0.0f, -5.0f }, { 0.0f, -4.125f }, { -0.125f, -4.125f }, { 0.0f, -4.0f }, + { -0.125f, -4.125f }, { 0.0f, -4.125f }, { 0.125f, -4.125f }, { 0.0f, -4.125f }, { 0.0f, -4.125f }, + { 0.0f, -3.625f }, { 0.0f, -3.625f }, { 0.0f, -3.5f }, { 0.0f, -3.5f }, { 0.0f, -3.5f } + }; + inline static std::vector SHORT_OFFSETS = { + { -0.125f, -0.25f }, { -0.125f, -0.25f }, { -0.125f, -0.25f }, { -0.125f, -0.375f }, { -0.125f, -0.25f }, + { -0.125f, -0.25f }, { -0.125f, -0.375f }, { -0.125f, 0.5f }, { -0.125f, 0.5f }, { -0.125f, 0.25f }, + { -0.125f, 0.5f }, { 0.125f, 0.5f }, { 0.125f, 0.5f }, { 0.125f, 0.5f }, { 0.0f, 0.5f }, + { 0.0f, 1.25f }, { 0.0f, 1.25f }, { 0.0f, 1.125f }, { 0.0f, 1.125f }, { 0.0f, 1.125f } + }; public: static int getBaseCurrency(int); static int getDifficultyFromLevel(GJGameLevel*); static std::string getSpriteName(CCSprite*); static void toggle(CCNode*, bool); + static CCPoint getDIBOffset(int, GJDifficultyName); + static int getGRDOverride(CCSprite*); + static int getDIBOverride(CCSprite*); }; template<> @@ -28,7 +47,10 @@ struct matjson::Serialize> { .stars = item["stars"].as_int(), .feature = item["feature"].as_int(), .difficulty = item["difficulty"].as_int(), - .moreDifficultiesOverride = item.contains("more-difficulties-override") ? item["more-difficulties-override"].as_int() : 0 + .moreDifficultiesOverride = item.contains("more-difficulties-override") ? item["more-difficulties-override"].as_int() : 0, + .grandpaDemonOverride = item.contains("grandpa-demon-override") ? item["grandpa-demon-override"].as_int() : 0, + .demonsInBetweenOverride = item.contains("demons-in-between-override") ? item["demons-in-between-override"].as_int() : 0, + .coins = item.contains("coins") ? item["coins"].as_bool() : true }); } return vec; @@ -42,7 +64,10 @@ struct matjson::Serialize> { { "stars", item.stars }, { "feature", item.feature }, { "difficulty", item.difficulty }, - { "more-difficulties-override", item.moreDifficultiesOverride } + { "more-difficulties-override", item.moreDifficultiesOverride }, + { "grandpa-demon-override", item.grandpaDemonOverride }, + { "demons-in-between-override", item.demonsInBetweenOverride }, + { "coins", item.coins } }); } return arr; diff --git a/src/main.cpp b/src/main.cpp index f0583f4..43f4cf9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,11 +19,7 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { auto buttonSprite = CircleButtonSprite::createWithSprite("FR_fakeRateBtn_001.png"_spr, 1.0f, CircleBaseColor::Green, CircleBaseSize::Medium); buttonSprite->getTopNode()->setScale(1.0f); auto fakeRateButton = CCMenuItemExt::createSpriteExtra(buttonSprite, [this](auto) { - FREditPopup::create(m_level, m_fields->m_fakeRateData.stars, m_fields->m_fakeRateData.feature, - m_fields->m_fakeRateData.difficulty, m_fields->m_fakeRateData.moreDifficultiesOverride, - [this](int stars, int feature, int difficulty, int mdo, bool update, bool coins) { - updateFakeRate(stars, feature, difficulty, mdo, update, coins); - })->show(); + FREditPopup::create(m_level, m_fields->m_fakeRateData, [this](FakeRateSaveData data, bool remove) { updateFakeRate(data, remove); })->show(); }); fakeRateButton->setID("fake-rate-button"_spr); auto leftSideMenu = getChildByID("left-side-menu"); @@ -55,72 +51,80 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { auto it = std::find_if(vec.begin(), vec.end(), [this](FakeRateSaveData const& item) { return item.id == m_level->m_levelID; }); auto stars = m_level->m_stars.value(); auto starsRequested = m_level->m_starsRequested; - if (it != vec.end()) updateFakeRate(it->stars, it->feature, it->difficulty, it->moreDifficultiesOverride, false, true); + auto grandpaDemon = static_cast(getChildByID("grd-difficulty")); + auto demonInBetween = static_cast(getChildByID("hiimjustin000.demons_in_between/between-difficulty-sprite")); + if (it != vec.end()) updateFakeRate(*it, false); else m_fields->m_fakeRateData = { .id = m_level->m_levelID, .stars = stars, .feature = m_level->m_featured > 1 ? m_level->m_isEpic + 1 : 0, .difficulty = FakeRate::getDifficultyFromLevel(m_level), .moreDifficultiesOverride = Loader::get()->isModLoaded("uproxide.more_difficulties") ? stars == 4 || stars == 7 || stars == 9 ? stars : - stars == 0 && (starsRequested == 4 || starsRequested == 7 || starsRequested == 9) ? starsRequested : 0 : 0 + stars == 0 && (starsRequested == 4 || starsRequested == 7 || starsRequested == 9) ? starsRequested : 0 : 0, + .grandpaDemonOverride = grandpaDemon ? FakeRate::getGRDOverride(grandpaDemon) : 0, + .demonsInBetweenOverride = demonInBetween ? FakeRate::getDIBOverride(demonInBetween) : 0, + .coins = m_level->m_coinsVerified > 0 }; } - void updateFakeRate(int stars, int feature, int difficulty, int mdo, bool update, bool coins) { + void updateFakeRate(FakeRateSaveData data, bool remove) { + auto stars = data.stars; + auto feature = data.feature; + auto difficulty = data.difficulty; + auto mdo = data.moreDifficultiesOverride; + auto gdo = data.grandpaDemonOverride; + auto dbo = data.demonsInBetweenOverride; + auto coins = data.coins; m_fields->m_fakeRateData = { .id = m_level->m_levelID, .stars = stars, .feature = feature, .difficulty = difficulty, - .moreDifficultiesOverride = mdo + .moreDifficultiesOverride = mdo, + .grandpaDemonOverride = gdo, + .demonsInBetweenOverride = dbo, + .coins = coins }; + auto hideDifficulty = false; if (auto betweenDifficultySprite = static_cast(getChildByID("hiimjustin000.demons_in_between/between-difficulty-sprite"))) { - betweenDifficultySprite->setVisible(false); - m_difficultySprite->setOpacity(255); + betweenDifficultySprite->setVisible(remove); + m_difficultySprite->setOpacity(remove ? 0 : 255); + hideDifficulty = remove || hideDifficulty; + m_fields->m_fakeRateData.demonsInBetweenOverride = remove ? FakeRate::getDIBOverride(betweenDifficultySprite) : dbo; } auto gddpOverride = false; if (auto gddpDifficultySprite = static_cast(getChildByID("gddp-difficulty"))) { gddpOverride = gddpDifficultySprite->isVisible(); - gddpDifficultySprite->setVisible(false); - m_difficultySprite->setOpacity(255); + gddpDifficultySprite->setVisible(remove); + m_difficultySprite->setOpacity(remove ? 0 : 255); + hideDifficulty = remove || hideDifficulty; } if (Loader::get()->isModLoaded("itzkiba.grandpa_demon") && !gddpOverride) { removeChildByTag(69420); + auto hasDemon = false; auto children = reinterpret_cast(getChildren()->data->arr); for (int i = 0; i < getChildrenCount(); i++) { - if (children[i]->getID() == "grd-difficulty") children[i]->setVisible(false); + if (children[i]->getID() == "grd-difficulty") { + children[i]->setVisible(remove); + hasDemon = true; + } } - if (auto grdInfinity = getChildByID("grd-infinity")) grdInfinity->setVisible(false); + if (auto grdInfinity = getChildByID("grd-infinity")) grdInfinity->setVisible(remove); m_difficultySprite->setVisible(true); + m_difficultySprite->setOpacity(hasDemon && remove ? 0 : 255); + hideDifficulty = hasDemon && remove || hideDifficulty; if (auto featureGlow = m_difficultySprite->getChildByTag(69420)) - featureGlow->setPosition(m_difficultySprite->getContentSize() * 0.5f); + featureGlow->setPosition(m_difficultySprite->getContentSize() / 2); + m_fields->m_fakeRateData.grandpaDemonOverride = hasDemon && remove ? FakeRate::getGRDOverride(static_cast(getChildByID("grd-difficulty"))) : gdo; } auto winSize = CCDirector::sharedDirector()->getWinSize(); auto gsm = GameStatsManager::sharedState(); - auto showStars = stars > 0 || m_level->m_dailyID > 0 || m_level->m_gauntletLevel; + auto showStars = stars != 0 || m_level->m_dailyID > 0 || m_level->m_gauntletLevel; m_difficultySprite->updateFeatureState((GJFeatureState)feature); m_difficultySprite->updateDifficultyFrame(difficulty, GJDifficultyName::Long); - CCNode* nodeToSetPosition = m_difficultySprite; - CCNode* difficultySpriteParent = m_difficultySprite->getParent(); - if (Loader::get()->isModLoaded("acaruso.horn")) { - auto children = getChildren(); - for (int i = 0; i < children->count(); i++) { - if (auto child = typeinfo_cast(children->objectAtIndex(i))) { - auto grandchildren = child->getChildren(); - if (!grandchildren || grandchildren->count() < 1) continue; - if (auto button = typeinfo_cast(grandchildren->objectAtIndex(0))) { - if (button->getNormalImage() == m_difficultySprite) { - nodeToSetPosition = child; - difficultySpriteParent = button; - break; - } - } - } - } - } - nodeToSetPosition->setPositionY(winSize.height / 2 + 56.0f + (difficulty > 5 ? 5.0f : 0.0f) + (showStars ? 10.0f : 0.0f)); - auto& position = nodeToSetPosition->getPosition(); + m_difficultySprite->setPositionY(winSize.height / 2 + 56.0f + (difficulty > 5 ? 5.0f : 0.0f) + (showStars ? 10.0f : 0.0f)); + auto& position = m_difficultySprite->getPosition(); m_starsIcon->setPosition({ position.x + 8.0f, position.y - 30.0f - (difficulty > 5 ? 9.0f : 0.0f) }); m_starsIcon->setVisible(showStars); m_starsLabel->setPosition(m_starsIcon->getPositionX() - 8.0f, m_starsIcon->getPositionY()); @@ -134,9 +138,9 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { auto coinStr = fmt::format("{}_{}", m_level->m_levelID.value(), i + 1); if (m_level->m_dailyID > 0) coinStr += "_" + std::to_string(m_level->m_dailyID); else if (m_level->m_gauntletLevel) coinStr += "_g"; - if (coins || m_level->m_coinsVerified == 1) - coin->setColor(gsm->hasUserCoin(coinStr.c_str()) || gsm->hasPendingUserCoin(coinStr.c_str()) ? ccColor3B { 255, 255, 255 } : ccColor3B { 165, 165, 165 }); - else coin->setColor(gsm->hasUserCoin(coinStr.c_str()) || gsm->hasPendingUserCoin(coinStr.c_str()) ? ccColor3B { 255, 175, 75 } : ccColor3B { 165, 113, 48 }); + auto hasCoin = gsm->hasUserCoin(coinStr.c_str()) || gsm->hasPendingUserCoin(coinStr.c_str()); + if (coins) coin->setColor(hasCoin ? ccColor3B { 255, 255, 255 } : ccColor3B { 165, 165, 165 }); + else coin->setColor(hasCoin ? ccColor3B { 255, 175, 75 } : ccColor3B { 165, 113, 48 }); } if (m_level->m_dailyID > 0 || m_level->m_gauntletLevel) { auto diamondLabel = static_cast(getChildByID("diamond-label")); @@ -171,10 +175,27 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { } if (m_exactLengthLabel->isVisible()) m_exactLengthLabel->setPositionY(m_lengthLabel->getPositionY() - 14.0f); - if (Loader::get()->isModLoaded("uproxide.more_difficulties")) fixMoreDifficultiesIncompatibility(difficultySpriteParent, mdo, !coins); + m_difficultySprite->setOpacity(hideDifficulty ? 0 : 255); + if (Loader::get()->isModLoaded("uproxide.more_difficulties")) fixMoreDifficultiesIncompatibility(mdo, remove); + if (Loader::get()->isModLoaded("itzkiba.grandpa_demon") && gdo > 0 && gdo < 7) { + auto grdSprite = CCSprite::createWithSpriteFrameName(fmt::format("itzkiba.grandpa_demon/GrD_demon{}_text.png", gdo - 1).c_str()); + grdSprite->setID("grandpa-demon-sprite"_spr); + grdSprite->setPosition(position); + addChild(grdSprite, 3); + m_difficultySprite->setOpacity(0); + } + else if (auto grdSprite = getChildByID("grandpa-demon-sprite"_spr)) grdSprite->removeFromParentAndCleanup(true); + if (Loader::get()->isModLoaded("hiimjustin000.demons_in_between") && dbo > 0 && dbo < 21) { + auto dibSprite = CCSprite::createWithSpriteFrameName(fmt::format("hiimjustin000.demons_in_between/DIB_{:02d}_btn2_001.png", dbo).c_str()); + dibSprite->setID("between-difficulty-sprite"_spr); + dibSprite->setPosition(position + FakeRate::getDIBOffset(dbo, GJDifficultyName::Long)); + addChild(dibSprite, 3); + m_difficultySprite->setOpacity(0); + } + else if (auto dibSprite = getChildByID("between-difficulty-sprite"_spr)) dibSprite->removeFromParentAndCleanup(true); } - void fixMoreDifficultiesIncompatibility(CCNode* difficultySpriteParent, int mdo, bool remove) { + void fixMoreDifficultiesIncompatibility(int mdo, bool remove) { auto spriteName = std::string(); auto moreDifficultiesSprite = static_cast(getChildByID("uproxide.more_difficulties/more-difficulties-spr")); if (moreDifficultiesSprite) { @@ -209,10 +230,10 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { moreDifficultiesSprite->initWithSpriteFrameName(frameName); moreDifficultiesSprite->setVisible(true); } - moreDifficultiesSprite->setPosition(difficultySpriteParent->convertToWorldSpace({ + moreDifficultiesSprite->setPosition({ m_difficultySprite->getPositionX() + (legacy ? 0.0f : 0.25f), m_difficultySprite->getPositionY() - (legacy ? 0.0f : 0.1f) - })); + }); m_difficultySprite->setOpacity(0); } } @@ -252,14 +273,14 @@ class $modify(FRLevelCell, LevelCell) { } else static_cast(difficultyContainer->getChildren()->lastObject())->setVisible(false); if (auto featureGlow = difficultySprite->getChildByTag(69420)) - featureGlow->setPosition(difficultySprite->getContentSize() * 0.5f); + featureGlow->setPosition(difficultySprite->getContentSize() / 2); } auto& fakeRateData = *it; difficultySprite->updateFeatureState((GJFeatureState)fakeRateData.feature); difficultySprite->updateDifficultyFrame(fakeRateData.difficulty, GJDifficultyName::Short); auto addCoins = level->m_coins > 0 && !m_compactView; - auto showStars = fakeRateData.stars > 0 || level->m_dailyID > 0; + auto showStars = fakeRateData.stars != 0 || level->m_dailyID > 0; difficultySprite->setPositionY((showStars || addCoins ? 5.0f : 0.0f) + (showStars && addCoins ? 9.0f : 0.0f) + (level->m_dailyID > 0 ? 10.0f : 0.0f)); auto gsm = GameStatsManager::sharedState(); if (showStars) { @@ -349,7 +370,24 @@ class $modify(FRLevelCell, LevelCell) { if (auto orbsLabel = static_cast(m_mainLayer->getChildByID("orbs-label"))) orbsLabel->removeFromParent(); } + auto& position = difficultySprite->getPosition(); if (Loader::get()->isModLoaded("uproxide.more_difficulties")) fixMoreDifficultiesIncompatibility(fakeRateData); + auto gdo = fakeRateData.grandpaDemonOverride; + if (Loader::get()->isModLoaded("itzkiba.grandpa_demon") && gdo > 0 && gdo < 7) { + auto grdSprite = CCSprite::createWithSpriteFrameName(fmt::format("itzkiba.grandpa_demon/GrD_demon{}.png", gdo - 1).c_str()); + grdSprite->setID("grandpa-demon-sprite"_spr); + grdSprite->setPosition(position); + difficultyContainer->addChild(grdSprite, 3); + difficultySprite->setOpacity(0); + } + auto dbo = fakeRateData.demonsInBetweenOverride; + if (Loader::get()->isModLoaded("hiimjustin000.demons_in_between") && dbo > 0 && dbo < 21) { + auto dibSprite = CCSprite::createWithSpriteFrameName(fmt::format("hiimjustin000.demons_in_between/DIB_{:02d}_btn_001.png", dbo).c_str()); + dibSprite->setID("between-difficulty-sprite"_spr); + dibSprite->setPosition(position + FakeRate::getDIBOffset(dbo, GJDifficultyName::Short)); + difficultyContainer->addChild(dibSprite, 3); + difficultySprite->setOpacity(0); + } } } }