diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b2bb2ae..1648f12 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,10 +34,11 @@ jobs: - uses: actions/checkout@v4 - name: Build the mod - uses: geode-sdk/build-geode-mod@main + uses: hiimjasmine00/build-geode-mod@main with: build-config: ${{ matrix.config.build-config || 'Release' }} export-pdb: true + export-symbols: true combine: true target: ${{ matrix.config.target }} @@ -47,22 +48,10 @@ jobs: needs: ['build'] steps: - - uses: geode-sdk/build-geode-mod/combine@main + - uses: hiimjasmine00/build-geode-mod/combine@main id: build - uses: actions/upload-artifact@v4 with: name: Build Output path: ${{ steps.build.outputs.build-output }} - - release: - name: Release the mod - runs-on: ubuntu-latest - needs: ['package'] - - steps: - - uses: actions/checkout@v4 - - - uses: hiimjustin000/release-geode-mod@main - with: - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..374bdc3 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,36 @@ +name: Release Geode Mod + +on: + workflow_dispatch: + +jobs: + release: + name: Release mod + runs-on: ubuntu-latest + environment: + name: release + url: ${{ steps.mod-release.outputs.url }} + + steps: + - uses: actions/checkout@v4 + + - uses: hiimjasmine00/release-geode-mod@main + id: mod-release + with: + token: ${{ secrets.GITHUB_TOKEN }} + + publish: + name: Publish mod + runs-on: ubuntu-latest + needs: ['release'] + environment: + name: publish + url: ${{ steps.mod-publish.outputs.url }} + + steps: + - uses: actions/checkout@v4 + + - uses: hiimjasmine00/release-geode-mod/publish@main + id: mod-publish + with: + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index a4fcb19..1dcf7ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,12 +3,19 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64") set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(GEODE_DISABLE_PRECOMPILED_HEADERS ON) -project(FakeRate VERSION 1.4.10) +project(FakeRate VERSION 1.4.11) add_library(${PROJECT_NAME} SHARED + src/classes/FRDIBPopup.cpp src/classes/FREditPopup.cpp src/classes/FREffects.cpp + src/classes/FRGDDPPopup.cpp + src/classes/FRGRDPopup.cpp + src/classes/FRSetDifficultyPopup.cpp + src/classes/FRSetFeaturePopup.cpp + src/classes/FRSetStarsPopup.cpp src/classes/TableNode.cpp src/hooks/LevelCell.cpp src/hooks/LevelInfoLayer.cpp diff --git a/LICENSE b/LICENSE index 1828c58..995d55a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 hiimjustin000 +Copyright (c) 2024-2025 hiimjasmine00 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index b1f00b9..30d4bae 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ A mod that allows you to assign a fake rating to online levels. - [Uproxide](https://gdbrowser.com/u/25397826) - Creator of the More Difficulties mod - [ItzKiba](https://gdbrowser.com/u/4569963) - Creator of the Grandpa Demon mod - [Minemaker0430](https://gdbrowser.com/u/6635071) - Creator of the GDDP Integration mod -- [hiimjustin000](https://gdbrowser.com/u/7466002) - Creator of the Demons In Between mod and this mod +- [hiimjasmine00](https://gdbrowser.com/u/7466002) - Creator of the Demons In Between mod and this mod ## Gallery ![Fake Rate Popup](./resources/fake-rate-popup.png)\ diff --git a/about.md b/about.md index 55952d3..a7a3f0a 100644 --- a/about.md +++ b/about.md @@ -10,7 +10,7 @@ A mod that allows you to assign a fake rating to online levels. - [Uproxide](user:25397826) - Creator of the More Difficulties mod - [ItzKiba](user:4569963) - Creator of the Grandpa Demon mod - [Minemaker0430](user:6635071) - Creator of the GDDP Integration mod -- [hiimjustin000](user:7466002) - Creator of the Demons In Between mod and this mod +- [hiimjasmine00](user:7466002) - Creator of the Demons In Between mod and this mod ## Gallery ![Fake Rate Popup](hiimjustin000.fake_rate/fake-rate-popup.png?scale=0.9375)\ diff --git a/changelog.md b/changelog.md index 39d1547..5b0c4c2 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,8 @@ # Fake Rate Changelog +## v1.4.11 (2025-02-20) +- Added node IDs to the fake rate popup and its many sub-elements +- Fixed a few minor bugs + ## v1.4.10 (2024-11-15) - Ported to Geode v4.0.0-beta.1 diff --git a/mod.json b/mod.json index 0f76f29..62732a7 100644 --- a/mod.json +++ b/mod.json @@ -1,22 +1,18 @@ { - "geode": "4.0.0-beta.1", + "geode": "4.2.0", "gd": { "android": "2.2074", "win": "2.2074", "mac": "2.2074" }, - "version": "v1.4.10", + "version": "v1.4.11", "id": "hiimjustin000.fake_rate", "name": "Fake Rate", - "developer": "hiimjustin000", + "developer": "hiimjasmine00", "description": "A mod that allows you to assign a fake rating to online levels.", - "dependencies": [ - { - "id": "geode.node-ids", - "version": ">=v1.12.0", - "importance": "required" - } - ], + "dependencies": { + "geode.node-ids": ">=v1.12.0" + }, "resources": { "sprites": [ "resources/*.png" @@ -27,7 +23,7 @@ }, "links": { "community": "https://discord.gg/QVKmbvBXA7", - "source": "https://github.com/hiimjustin000/FakeRate", + "source": "https://github.com/hiimjasmine00/FakeRate", "homepage": "https://www.hiimjustin000.com" }, "tags": [ diff --git a/src/FakeRate.cpp b/src/FakeRate.cpp index f36ecb1..1a7b26b 100644 --- a/src/FakeRate.cpp +++ b/src/FakeRate.cpp @@ -1,4 +1,7 @@ #include "FakeRate.hpp" +#include +#include +#include using namespace geode::prelude; @@ -48,52 +51,29 @@ void FakeRate::toggle(CCNode* node, bool enabled) { } CCPoint FakeRate::getDIBOffset(int difficulty, GJDifficultyName name) { - if (name == GJDifficultyName::Long) switch (difficulty) { - case 1: return { 0.0f, -5.0f }; - case 2: return { 0.125f, -5.0f }; - case 3: return { 0.0f, -5.0f }; - case 4: return { 0.0f, -5.125f }; - case 5: return { 0.25f, -5.0f }; - case 6: return { 0.125f, -4.75f }; - case 7: return { 0.0f, -5.0f }; - case 8: return { 0.0f, -4.125f }; - case 9: return { -0.125f, -4.125f }; - case 10: return { 0.0f, -4.0f }; - case 11: return { -0.125f, -4.125f }; - case 12: return { 0.0f, -4.125f }; - case 13: return { 0.125f, -4.125f }; - case 14: return { 0.0f, -4.125f }; - case 15: return { 0.0f, -4.125f }; - case 16: return { 0.0f, -3.625f }; - case 17: return { 0.0f, -3.625f }; - case 18: return { 0.0f, -3.5f }; - case 19: return { 0.0f, -3.5f }; - case 20: return { 0.0f, -3.5f }; - } - else if (name == GJDifficultyName::Short) switch (difficulty) { - case 1: return { -0.125f, -0.25f }; - case 2: return { -0.125f, -0.25f }; - case 3: return { -0.125f, -0.25f }; - case 4: return { -0.125f, -0.375f }; - case 5: return { -0.125f, -0.25f }; - case 6: return { -0.125f, -0.25f }; - case 7: return { -0.125f, -0.375f }; - case 8: return { -0.125f, 0.5f }; - case 9: return { -0.125f, 0.5f }; - case 10: return { -0.125f, 0.25f }; - case 11: return { -0.125f, 0.5f }; - case 12: return { 0.125f, 0.5f }; - case 13: return { 0.125f, 0.5f }; - case 14: return { 0.125f, 0.5f }; - case 15: return { 0.0f, 0.5f }; - case 16: return { 0.0f, 1.25f }; - case 17: return { 0.0f, 1.25f }; - case 18: return { 0.0f, 1.125f }; - case 19: return { 0.0f, 1.125f }; - case 20: return { 0.0f, 1.125f }; + switch (difficulty) { + case 1: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -5.0f } : CCPoint { -0.125f, -0.25f }; + case 2: return name == GJDifficultyName::Long ? CCPoint { 0.125f, -5.0f } : CCPoint { -0.125f, -0.25f }; + case 3: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -5.0f } : CCPoint { -0.125f, -0.25f }; + case 4: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -5.125f } : CCPoint { -0.125f, -0.375f }; + case 5: return name == GJDifficultyName::Long ? CCPoint { 0.25f, -5.0f } : CCPoint { -0.125f, -0.25f }; + case 6: return name == GJDifficultyName::Long ? CCPoint { 0.125f, -4.75f } : CCPoint { -0.125f, -0.25f }; + case 7: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -5.0f } : CCPoint { -0.125f, -0.375f }; + case 8: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -4.125f } : CCPoint { -0.125f, 0.5f }; + case 9: return name == GJDifficultyName::Long ? CCPoint { -0.125f, -4.125f } : CCPoint { -0.125f, 0.5f }; + case 10: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -4.0f } : CCPoint { -0.125f, 0.25f }; + case 11: return name == GJDifficultyName::Long ? CCPoint { -0.125f, -4.125f } : CCPoint { -0.125f, 0.5f }; + case 12: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -4.125f } : CCPoint { 0.125f, 0.5f }; + case 13: return name == GJDifficultyName::Long ? CCPoint { 0.125f, -4.125f } : CCPoint { 0.125f, 0.5f }; + case 14: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -4.125f } : CCPoint { 0.125f, 0.5f }; + case 15: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -4.125f } : CCPoint { 0.0f, 0.5f }; + case 16: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -3.625f } : CCPoint { 0.0f, 1.25f }; + case 17: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -3.625f } : CCPoint { 0.0f, 1.25f }; + case 18: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -3.5f } : CCPoint { 0.0f, 1.125f }; + case 19: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -3.5f } : CCPoint { 0.0f, 1.125f }; + case 20: return name == GJDifficultyName::Long ? CCPoint { 0.0f, -3.5f } : CCPoint { 0.0f, 1.125f }; + default: return CCPoint { 0.0f, 0.0f }; } - - return { 0.0f, 0.0f }; } int FakeRate::getGRDOverride(CCSprite* sprite) { @@ -147,3 +127,37 @@ std::string FakeRate::getGDDPFrame(int difficulty, GJDifficultyName name) { return fmt::format("minemaker0430.gddp_integration/DP_{}{}Text.png", diff, name == GJDifficultyName::Short ? "Small" : ""); } + +Result> matjson::Serialize>::fromJson(const matjson::Value& value) { + if (!value.isArray()) return Err("Expected array"); + + return Ok(ranges::map>(value.asArray().unwrap(), [](const matjson::Value& item) { + return FakeRateSaveData { + .id = (int)item["id"].asInt().unwrapOr(0), + .stars = (int)item["stars"].asInt().unwrapOr(0), + .feature = (int)item["feature"].asInt().unwrapOr(0), + .difficulty = (int)item["difficulty"].asInt().unwrapOr(0), + .moreDifficultiesOverride = (int)item["more-difficulties-override"].asInt().unwrapOr(0), + .grandpaDemonOverride = (int)item["grandpa-demon-override"].asInt().unwrapOr(0), + .demonsInBetweenOverride = (int)item["demons-in-between-override"].asInt().unwrapOr(0), + .gddpIntegrationOverride = (int)item["gddp-integration-override"].asInt().unwrapOr(0), + .coins = item["coins"].asBool().unwrapOr(true) + }; + })); +} + +matjson::Value matjson::Serialize>::toJson(const std::vector& vec) { + return ranges::map>(vec, [](const FakeRateSaveData& item) { + return matjson::makeObject({ + { "id", item.id }, + { "stars", item.stars }, + { "feature", item.feature }, + { "difficulty", item.difficulty }, + { "more-difficulties-override", item.moreDifficultiesOverride }, + { "grandpa-demon-override", item.grandpaDemonOverride }, + { "demons-in-between-override", item.demonsInBetweenOverride }, + { "gddp-integration-override", item.gddpIntegrationOverride }, + { "coins", item.coins } + }); + }); +} diff --git a/src/FakeRate.hpp b/src/FakeRate.hpp index 6c7e1e7..1b5bdfa 100644 --- a/src/FakeRate.hpp +++ b/src/FakeRate.hpp @@ -1,3 +1,8 @@ +#pragma once +#include +#include +#include + struct FakeRateSaveData { int id; int stars; @@ -43,42 +48,6 @@ class FakeRate { template<> struct matjson::Serialize> { - static geode::Result> fromJson(matjson::Value const& value) { - if (!value.isArray()) return geode::Err("Expected array"); - - std::vector vec; - for (auto const& item : value.asArray().unwrap()) { - vec.push_back({ - .id = (int)item["id"].asInt().unwrapOr(0), - .stars = (int)item["stars"].asInt().unwrapOr(0), - .feature = (int)item["feature"].asInt().unwrapOr(0), - .difficulty = (int)item["difficulty"].asInt().unwrapOr(0), - .moreDifficultiesOverride = (int)item["more-difficulties-override"].asInt().unwrapOr(0), - .grandpaDemonOverride = (int)item["grandpa-demon-override"].asInt().unwrapOr(0), - .demonsInBetweenOverride = (int)item["demons-in-between-override"].asInt().unwrapOr(0), - .gddpIntegrationOverride = (int)item["gddp-integration-override"].asInt().unwrapOr(0), - .coins = item["coins"].asBool().unwrapOr(true) - }); - } - - return geode::Ok(vec); - } - - static matjson::Value toJson(std::vector const& vec) { - std::vector arr; - for (auto const& item : vec) { - arr.push_back(matjson::makeObject({ - { "id", item.id }, - { "stars", item.stars }, - { "feature", item.feature }, - { "difficulty", item.difficulty }, - { "more-difficulties-override", item.moreDifficultiesOverride }, - { "grandpa-demon-override", item.grandpaDemonOverride }, - { "demons-in-between-override", item.demonsInBetweenOverride }, - { "gddp-integration-override", item.gddpIntegrationOverride }, - { "coins", item.coins } - })); - } - return arr; - } + static geode::Result> fromJson(const matjson::Value& value); + static matjson::Value toJson(const std::vector& vec); }; diff --git a/src/classes/FRDIBPopup.cpp b/src/classes/FRDIBPopup.cpp new file mode 100644 index 0000000..be5180c --- /dev/null +++ b/src/classes/FRDIBPopup.cpp @@ -0,0 +1,64 @@ +#include "FRDIBPopup.hpp" +#include "TableNode.hpp" +#include "../FakeRate.hpp" +#include + +using namespace geode::prelude; + +FRDIBPopup* FRDIBPopup::create(int demonsInBetweenOverride, SetDIBCallback callback) { + auto ret = new FRDIBPopup(); + if (ret->initAnchored(350.0f, 310.0f, demonsInBetweenOverride, callback)) { + ret->autorelease(); + return ret; + } + delete ret; + return nullptr; +} + +bool FRDIBPopup::setup(int demonsInBetweenOverride, SetDIBCallback callback) { + setID("FRDIBPopup"); + setTitle("Demons In Between"); + m_title->setID("demons-in-between-title"); + m_mainLayer->setID("main-layer"); + m_buttonMenu->setID("button-menu"); + m_bgSprite->setID("background"); + m_closeBtn->setID("close-button"); + m_noElasticity = true; + m_demonsInBetweenOverride = demonsInBetweenOverride; + + auto table = TableNode::create(5, 4); + table->setColumnLayout(ColumnLayout::create()->setAxisReverse(true)); + table->setRowLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + table->setRowHeight(60.0f); + table->setRowPrefix("dib-button-row"); + table->setContentSize({ 350.0f, 240.0f }); + table->setPosition({ 175.0f, 160.0f }); + table->setID("dib-buttons"); + m_mainLayer->addChild(table); + + for (int i = 1; i < 21; i++) { + auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(fmt::format("hiimjustin000.demons_in_between/DIB_{:02}_btn2_001.png", i).c_str(), 1.0f, + [this, i](CCMenuItemSpriteExtra* sender) { + m_demonsInBetweenOverride = sender != m_selected ? i : 0; + if (m_selected) FakeRate::toggle(m_selected->getNormalImage(), false); + if (sender != m_selected) FakeRate::toggle(sender->getNormalImage(), true); + m_selected = sender != m_selected ? sender : nullptr; + }); + toggle->setID(fmt::format("dib-button-{}", i)); + FakeRate::toggle(toggle->getNormalImage(), i == m_demonsInBetweenOverride); + m_selected = i == m_demonsInBetweenOverride ? toggle : m_selected; + table->addButton(toggle); + } + + table->updateAllLayouts(); + + auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { + callback(m_demonsInBetweenOverride); + onClose(nullptr); + }); + confirmButton->setPosition({ 175.0f, 25.0f }); + confirmButton->setID("confirm-button"); + m_buttonMenu->addChild(confirmButton); + + return true; +} diff --git a/src/classes/FRDIBPopup.hpp b/src/classes/FRDIBPopup.hpp new file mode 100644 index 0000000..6199bf1 --- /dev/null +++ b/src/classes/FRDIBPopup.hpp @@ -0,0 +1,13 @@ +#include + +typedef const std::function& SetDIBCallback; + +class FRDIBPopup : public geode::Popup { +protected: + int m_demonsInBetweenOverride; + CCMenuItemSpriteExtra* m_selected; + + bool setup(int, SetDIBCallback) override; +public: + static FRDIBPopup* create(int, SetDIBCallback); +}; diff --git a/src/classes/FREditPopup.cpp b/src/classes/FREditPopup.cpp index e2de4fc..b1a091f 100644 --- a/src/classes/FREditPopup.cpp +++ b/src/classes/FREditPopup.cpp @@ -1,10 +1,17 @@ #include "FREditPopup.hpp" #include "FREffects.hpp" -#include "TableNode.hpp" +#include "FRSetDifficultyPopup.hpp" +#include "FRSetFeaturePopup.hpp" +#include "FRSetStarsPopup.hpp" +#include +#include +#include +#include +#include using namespace geode::prelude; -FREditPopup* FREditPopup::create(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRateCallback callback) { +FREditPopup* FREditPopup::create(GJGameLevel* level, const FakeRateSaveData& data, UpdateFakeRateCallback callback) { auto ret = new FREditPopup(); if (ret->initAnchored(300.0f, 200.0f, level, data, callback)) { ret->autorelease(); @@ -14,8 +21,14 @@ FREditPopup* FREditPopup::create(GJGameLevel* level, FakeRateSaveData data, Upda return nullptr; } -bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRateCallback callback) { +bool FREditPopup::setup(GJGameLevel* level, const FakeRateSaveData& data, UpdateFakeRateCallback callback) { + setID("FREditPopup"); setTitle("Fake Rate"); + m_title->setID("fake-rate-title"); + m_mainLayer->setID("main-layer"); + m_buttonMenu->setID("button-menu"); + m_bgSprite->setID("background"); + m_closeBtn->setID("close-button"); m_level = level; m_stars = data.stars; m_feature = data.feature; @@ -29,6 +42,7 @@ bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRat m_difficultySprite = GJDifficultySprite::create(data.difficulty, GJDifficultyName::Long); m_difficultySprite->setPositionX(60.0f); + m_difficultySprite->setID("difficulty-sprite"); m_mainLayer->addChild(m_difficultySprite); if (Loader::get()->isModLoaded("uproxide.more_difficulties")) { @@ -37,23 +51,27 @@ bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRat "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_mdSprite->setID("md-sprite"); 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_grdSprite->setID("grd-sprite"); m_mainLayer->addChild(m_grdSprite); m_grdInfinity = FREffects::grdInfinity(); m_grdInfinity->setPosition({ 59.6f, 119.0f }); m_grdInfinity->setVisible(false); + m_grdInfinity->setID("grd-infinity-sprite"); m_mainLayer->addChild(m_grdInfinity); } 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_dibSprite->setID("dib-sprite"); m_mainLayer->addChild(m_dibSprite); } if (Loader::get()->isModLoaded("minemaker0430.gddp_integration")) { @@ -61,15 +79,18 @@ bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRat m_gddpSprite->setPosition({ 60.25f, 140.0f }); m_gddpSprite->setAnchorPoint({ 0.5f, 1.0f }); m_gddpSprite->setVisible(false); + m_gddpSprite->setID("gddp-sprite"); m_mainLayer->addChild(m_gddpSprite); } m_starSprite = CCSprite::createWithSpriteFrameName(m_level->m_levelLength < 5 ? "star_small01_001.png" : "moon_small01_001.png"); + m_starSprite->setID("star-sprite"); m_mainLayer->addChild(m_starSprite); 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_starsLabel->setID("stars-label"); m_mainLayer->addChild(m_starsLabel); m_coinSprites = CCArray::create(); @@ -79,6 +100,7 @@ bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRat 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)); + coin->setID(fmt::format("coin-sprite-{}", i + 1)); m_mainLayer->addChild(coin); m_coinSprites->addObject(coin); } @@ -100,6 +122,7 @@ bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRat })->show(); }); difficultyButton->setPosition({ 200.0f, 150.0f }); + difficultyButton->setID("difficulty-button"); m_buttonMenu->addChild(difficultyButton); auto starsButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create(m_level->m_levelLength < 5 ? "Stars" : "Moons", @@ -110,6 +133,7 @@ bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRat })->show(); }); starsButton->setPosition({ 200.0f, 110.0f }); + starsButton->setID("stars-button"); m_buttonMenu->addChild(starsButton); auto featureButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Feature", "goldFont.fnt", "GJ_button_02.png", 0.8f), [this](auto) { @@ -126,6 +150,7 @@ bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRat })->show(); }); featureButton->setPosition({ 200.0f, 70.0f }); + featureButton->setID("feature-button"); m_buttonMenu->addChild(featureButton); auto coinsToggle = CCMenuItemExt::createTogglerWithStandardSprites(0.7f, [this](auto) { @@ -134,44 +159,19 @@ bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRat }); coinsToggle->setPosition({ 30.0f, 30.0f }); coinsToggle->toggle(m_coins); + coinsToggle->setID("coins-toggle"); m_buttonMenu->addChild(coinsToggle); auto coinsLabel = CCLabelBMFont::create("Coins", "bigFont.fnt"); coinsLabel->setScale(0.5f); coinsLabel->setPosition({ 70.0f, 30.0f }); + coinsLabel->setID("coins-label"); 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", {}); - std::vector::iterator it = std::find_if(vec.begin(), vec.end(), [this](FakeRateSaveData const& item) { - return item.id == m_level->m_levelID; - }); - if (it != vec.end()) { - it->stars = m_stars; - it->feature = m_feature; - it->difficulty = m_difficulty; - it->moreDifficultiesOverride = m_moreDifficultiesOverride; - it->grandpaDemonOverride = m_grandpaDemonOverride; - it->demonsInBetweenOverride = m_demonsInBetweenOverride; - it->gddpIntegrationOverride = m_gddpIntegrationOverride; - it->coins = m_coins; - } - else { - vec.push_back({ - .id = m_level->m_levelID, - .stars = m_stars, - .feature = m_feature, - .difficulty = m_difficulty, - .moreDifficultiesOverride = m_moreDifficultiesOverride, - .grandpaDemonOverride = m_grandpaDemonOverride, - .demonsInBetweenOverride = m_demonsInBetweenOverride, - .gddpIntegrationOverride = m_gddpIntegrationOverride, - .coins = m_coins - }); - } - Mod::get()->setSavedValue("fake-rate", vec); - callback({ - .id = m_level->m_levelID, + auto levelID = m_level->m_levelID.value(); + FakeRateSaveData data = { + .id = levelID, .stars = m_stars, .feature = m_feature, .difficulty = m_difficulty, @@ -180,20 +180,34 @@ bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRat .demonsInBetweenOverride = m_demonsInBetweenOverride, .gddpIntegrationOverride = m_gddpIntegrationOverride, .coins = m_coins - }, false); + }; + + auto vec = Mod::get()->getSavedValue>("fake-rate", {}); + auto i = ranges::indexOf(vec, [levelID](const FakeRateSaveData& item) { return item.id == levelID; }); + if (i.has_value()) vec[i.value()] = data; + else vec.push_back(data); + Mod::get()->setSavedValue("fake-rate", vec); + + callback(data, false); onClose(nullptr); }); addButton->setPosition({ 150.0f, 30.0f }); + addButton->setID("add-button"); m_buttonMenu->addChild(addButton); auto removeButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Remove", "goldFont.fnt", "GJ_button_06.png", 0.8f), [this, callback](auto) { + auto levelID = m_level->m_levelID.value(); + auto vec = Mod::get()->getSavedValue>("fake-rate", {}); if (vec.empty()) return; - vec.erase(std::remove_if(vec.begin(), vec.end(), [this](FakeRateSaveData const& item) { - return item.id == m_level->m_levelID; - }), vec.end()); + + auto vecSize = vec.size(); + ranges::remove(vec, [levelID](const FakeRateSaveData& item) { return item.id == levelID; }); + if (vec.size() == vecSize) return; + Mod::get()->setSavedValue("fake-rate", vec); - auto stars = m_level->m_stars; + + auto stars = m_level->m_stars.value(); callback({ .id = m_level->m_levelID, .stars = stars, @@ -208,6 +222,7 @@ bool FREditPopup::setup(GJGameLevel* level, FakeRateSaveData data, UpdateFakeRat onClose(nullptr); }); removeButton->setPosition({ 235.0f, 30.0f }); + removeButton->setID("remove-button"); m_buttonMenu->addChild(removeButton); updateLabels(); @@ -231,7 +246,10 @@ void FREditPopup::updateLabels() { } m_difficultySprite->setOpacity(255); auto sfc = CCSpriteFrameCache::get(); - if (Loader::get()->isModLoaded("uproxide.more_difficulties")) { + if (auto moreDifficulties = Loader::get()->getLoadedMod("uproxide.more_difficulties")) { + if (m_moreDifficultiesOverride == 4 && !moreDifficulties->getSavedValue("casual", true)) m_moreDifficultiesOverride = 0; + if (m_moreDifficultiesOverride == 7 && !moreDifficulties->getSavedValue("tough", true)) m_moreDifficultiesOverride = 0; + if (m_moreDifficultiesOverride == 9 && !moreDifficulties->getSavedValue("cruel", true)) m_moreDifficultiesOverride = 0; if (m_moreDifficultiesOverride == 4 || m_moreDifficultiesOverride == 7 || m_moreDifficultiesOverride == 9) { m_mdSprite->setDisplayFrame(sfc->spriteFrameByName( fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", m_moreDifficultiesOverride, m_legacy ? "_Legacy" : "").c_str())); @@ -255,7 +273,8 @@ void FREditPopup::updateLabels() { m_grdInfinity->setVisible(m_grandpaDemonOverride == 5); } - if (Loader::get()->isModLoaded("hiimjustin000.demons_in_between")) { + if (auto demonsInBetween = Loader::get()->getLoadedMod("hiimjustin000.demons_in_between")) { + if (!demonsInBetween->getSettingValue("enable-difficulties")) m_demonsInBetweenOverride = 0; if (m_demonsInBetweenOverride > 0 && m_demonsInBetweenOverride < 21) { auto demonsInBetween = Loader::get()->getLoadedMod("hiimjustin000.demons_in_between"); auto dibFeature = ""; @@ -270,7 +289,8 @@ void FREditPopup::updateLabels() { } else m_dibSprite->setVisible(false); } - if (Loader::get()->isModLoaded("minemaker0430.gddp_integration")) { + if (auto gddpIntegration = Loader::get()->getLoadedMod("minemaker0430.gddp_integration")) { + if (!gddpIntegration->getSettingValue("custom-difficulty-faces")) m_gddpIntegrationOverride = 0; if (m_gddpIntegrationOverride > 0 && m_gddpIntegrationOverride < 16) { m_gddpSprite->setDisplayFrame(sfc->spriteFrameByName( FakeRate::getGDDPFrame(m_gddpIntegrationOverride, GJDifficultyName::Long).c_str())); @@ -286,415 +306,3 @@ void FREditPopup::updateLabels() { FREditPopup::~FREditPopup() { CC_SAFE_RELEASE(m_coinSprites); } - -FRSetDifficultyPopup* FRSetDifficultyPopup::create(FakeRateSaveData data, bool legacy, SetDifficultyCallback callback) { - auto ret = new FRSetDifficultyPopup(); - if (ret->initAnchored(300.0f, 250.0f, data, legacy, callback)) { - ret->autorelease(); - return ret; - } - delete ret; - return nullptr; -} - -bool FRSetDifficultyPopup::setup(FakeRateSaveData data, bool legacy, SetDifficultyCallback callback) { - setTitle("Select Difficulty"); - m_noElasticity = true; - m_difficulty = data.difficulty; - m_moreDifficultiesOverride = data.moreDifficultiesOverride; - m_grandpaDemonOverride = data.grandpaDemonOverride; - m_demonsInBetweenOverride = data.demonsInBetweenOverride; - m_gddpIntegrationOverride = data.gddpIntegrationOverride; - m_legacy = legacy; - - auto table = TableNode::create(Loader::get()->isModLoaded("uproxide.more_difficulties") ? 5 : 4, 3); - table->setColumnLayout(ColumnLayout::create()->setAxisReverse(true)); - table->setRowLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); - table->setRowHeight(63.0f); - table->setContentSize({ 300.0f, 170.0f }); - table->setPosition({ 150.0f, 130.0f }); - m_mainLayer->addChild(table); - - for (auto [d, mdo] : DIFFICULTIES) { - auto num = d == -1 ? "auto" : fmt::format("{:02d}", d); - auto frameName = d > 5 ? fmt::format("difficulty_{}_btn2_001.png", num) : fmt::format("difficulty_{}_btn_001.png", num); - if (Loader::get()->isModLoaded("uproxide.more_difficulties") && mdo > 0) - frameName = fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", mdo, m_legacy ? "_Legacy" : ""); - else if (mdo > 0) continue; - auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(frameName.c_str(), 1.0f, [this, d, mdo](CCMenuItemSpriteExtra* sender) { - if (sender == m_selected) return; - m_difficulty = d; - m_moreDifficultiesOverride = mdo; - m_grandpaDemonOverride = 0; - m_demonsInBetweenOverride = 0; - m_gddpIntegrationOverride = 0; - if (m_selected) FakeRate::toggle(m_selected->getNormalImage(), false); - FakeRate::toggle(sender->getNormalImage(), true); - m_selected = sender; - }); - auto isToggled = mdo == m_moreDifficultiesOverride && (m_moreDifficultiesOverride <= 0 ? d == m_difficulty : true); - FakeRate::toggle(toggle->getNormalImage(), isToggled); - m_selected = isToggled ? toggle : m_selected; - table->addButton(toggle); - } - - table->updateAllLayouts(); - - auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { - callback(m_difficulty, m_moreDifficultiesOverride, m_grandpaDemonOverride, m_demonsInBetweenOverride, m_gddpIntegrationOverride); - onClose(nullptr); - }); - confirmButton->setPosition({ 150.0f, 25.0f }); - m_buttonMenu->addChild(confirmButton); - - auto overrideMenu = CCMenu::create(); - overrideMenu->setLayout(RowLayout::create()->setGap(4.0f)->setAxisAlignment(AxisAlignment::End)); - overrideMenu->setPosition({ 245.0f, 25.0f }); - overrideMenu->setContentSize({ 100.0f, 30.0f }); - m_mainLayer->addChild(overrideMenu); - - if (Loader::get()->isModLoaded("itzkiba.grandpa_demon")) - overrideMenu->addChild(CCMenuItemExt::createSpriteExtraWithFilename("FR_grdBtn_001.png"_spr, 0.65f, [this](auto) { - FRGRDPopup::create(m_grandpaDemonOverride, [this](int grd) { - m_grandpaDemonOverride = grd; - m_demonsInBetweenOverride = 0; - m_gddpIntegrationOverride = 0; - })->show(); - })); - - if (Loader::get()->isModLoaded("hiimjustin000.demons_in_between")) - overrideMenu->addChild(CCMenuItemExt::createSpriteExtraWithFilename("FR_dibBtn_001.png"_spr, 0.75f, [this](auto) { - FRDIBPopup::create(m_demonsInBetweenOverride, [this](int dib) { - m_grandpaDemonOverride = 0; - m_demonsInBetweenOverride = dib; - m_gddpIntegrationOverride = 0; - })->show(); - })); - - if (Loader::get()->isModLoaded("minemaker0430.gddp_integration")) - overrideMenu->addChild(CCMenuItemExt::createSpriteExtraWithFilename("FR_gddpBtn_001.png"_spr, 0.65f, [this](auto) { - FRGDDPPopup::create(m_gddpIntegrationOverride, [this](int gddp) { - m_grandpaDemonOverride = 0; - m_demonsInBetweenOverride = 0; - m_gddpIntegrationOverride = gddp; - })->show(); - })); - - overrideMenu->updateLayout(); - - return true; -} - -FRSetStarsPopup* FRSetStarsPopup::create(int stars, bool platformer, SetIntCallback callback) { - auto ret = new FRSetStarsPopup(); - if (ret->initAnchored(250.0f, 150.0f, stars, platformer, callback)) { - ret->autorelease(); - return ret; - } - delete ret; - return nullptr; -} - -bool FRSetStarsPopup::setup(int stars, bool platformer, SetIntCallback callback) { - setTitle(platformer ? "Set Moons" : "Set Stars"); - m_noElasticity = true; - m_stars = stars; - - m_input = TextInput::create(150.0f, platformer ? "Moons" : "Stars"); - m_input->setCommonFilter(CommonFilter::Int); - m_input->setPosition({ 125.0f, 80.0f }); - m_input->getInputNode()->setLabelPlaceholderColor({ 120, 170, 240 }); - m_input->setString(std::to_string(m_stars)); - m_input->setMaxCharCount(11); - m_input->setCallback([this](std::string const& text) { - auto stars = numFromString(text).unwrapOr(0); - if (stars < INT_MIN) stars = INT_MIN; - if (stars > INT_MAX) stars = INT_MAX; - m_stars = stars; - m_label->setString(std::to_string(m_stars).c_str()); - m_starLayout->updateLayout(); - }); - m_mainLayer->addChild(m_input); - - m_starLayout = CCNode::create(); - m_starLayout->setPosition({ 125.0f, 52.5f }); - m_starLayout->setContentSize({ 250.0f, 15.0f }); - m_starLayout->setAnchorPoint({ 0.5f, 0.5f }); - m_starLayout->setLayout(RowLayout::create()->setGap(1.75f)->setAutoScale(false)); - m_mainLayer->addChild(m_starLayout); - - m_label = CCLabelBMFont::create(std::to_string(m_stars).c_str(), "bigFont.fnt"); - m_label->setScale(0.4f); - m_starLayout->addChild(m_label); - - m_starLayout->addChild(CCSprite::createWithSpriteFrameName(platformer ? "moon_small01_001.png" : "star_small01_001.png")); - - m_starLayout->updateLayout(); - - auto leftButton = CCMenuItemExt::createSpriteExtraWithFrameName("edit_leftBtn_001.png", 1.1f, [this](auto) { - if (m_stars != INT_MIN) m_stars -= 1; - auto stars = std::to_string(m_stars); - m_input->setString(stars); - m_label->setString(stars.c_str()); - m_starLayout->updateLayout(); - }); - leftButton->setPosition({ 30.0f, 80.0f }); - m_buttonMenu->addChild(leftButton); - - auto rightButton = CCMenuItemExt::createSpriteExtraWithFrameName("edit_rightBtn_001.png", 1.1f, [this](auto) { - if (m_stars != INT_MAX) m_stars += 1; - auto stars = std::to_string(m_stars); - m_input->setString(stars); - m_label->setString(stars.c_str()); - m_starLayout->updateLayout(); - }); - rightButton->setPosition({ 220.0f, 80.0f }); - m_buttonMenu->addChild(rightButton); - - auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { - callback(m_stars); - onClose(nullptr); - }); - confirmButton->setPosition({ 125.0f, 25.0f }); - m_buttonMenu->addChild(confirmButton); - - return true; -} - -FRSetFeaturePopup* FRSetFeaturePopup::create(FakeRateSaveData data, bool legacy, SetIntCallback callback) { - auto ret = new FRSetFeaturePopup(); - if (ret->initAnchored(300.0f, 150.0f, data, legacy, callback)) { - ret->autorelease(); - return ret; - } - delete ret; - return nullptr; -} - -bool FRSetFeaturePopup::setup(FakeRateSaveData data, bool legacy, SetIntCallback callback) { - setTitle("Select Feature"); - m_noElasticity = true; - m_feature = static_cast(data.feature); - m_difficulty = data.difficulty; - m_moreDifficultiesOverride = data.moreDifficultiesOverride; - m_grandpaDemonOverride = data.grandpaDemonOverride; - m_demonsInBetweenOverride = data.demonsInBetweenOverride; - m_gddpIntegrationOverride = data.gddpIntegrationOverride; - m_legacy = legacy; - - auto menuRow = CCMenu::create(); - menuRow->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); - menuRow->setPosition({ 150.0f, 80.0f + (data.difficulty > 5 || data.grandpaDemonOverride > 0 || - data.demonsInBetweenOverride > 0 || data.gddpIntegrationOverride > 0 ? 5.0f : 0.0f) }); - menuRow->setContentSize({ 300.0f, 50.0f }); - m_mainLayer->addChild(menuRow); - - for (int i = 0; i < 5; i++) { - auto feature = static_cast(i); - auto difficultySprite = GJDifficultySprite::create(m_difficulty, GJDifficultyName::Long); - difficultySprite->updateFeatureState(feature); - if (Loader::get()->isModLoaded("uproxide.more_difficulties") && m_moreDifficultiesOverride > 0 - && m_grandpaDemonOverride == 0 && m_demonsInBetweenOverride == 0) { - auto mdSprite = CCSprite::createWithSpriteFrameName((m_legacy ? - fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}_Legacy.png", m_moreDifficultiesOverride) - : fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}.png", m_moreDifficultiesOverride)).c_str()); - mdSprite->setPosition(difficultySprite->getContentSize() / 2 + (m_legacy ? CCPoint { 0.0f, 0.0f } : CCPoint { 0.25f, -0.1f })); - difficultySprite->setOpacity(0); - difficultySprite->addChild(mdSprite); - } - 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()); - grdSprite->setPosition(difficultySprite->getContentSize() / 2); - difficultySprite->setOpacity(0); - difficultySprite->addChild(grdSprite); - } - if (Loader::get()->isModLoaded("hiimjustin000.demons_in_between") && m_demonsInBetweenOverride > 0) { - auto demonsInBetween = Loader::get()->getLoadedMod("hiimjustin000.demons_in_between"); - auto dibFeature = ""; - if (i == 3 && demonsInBetween->getSettingValue("enable-legendary")) dibFeature = "_4"; - else if (i == 4 && demonsInBetween->getSettingValue("enable-mythic")) dibFeature = "_5"; - auto dibSprite = CCSprite::createWithSpriteFrameName(fmt::format("hiimjustin000.demons_in_between/DIB_{:02d}{}_btn2_001.png", - m_demonsInBetweenOverride, dibFeature).c_str()); - dibSprite->setPosition(difficultySprite->getContentSize() / 2 + FakeRate::getDIBOffset(m_demonsInBetweenOverride, GJDifficultyName::Long)); - difficultySprite->setOpacity(0); - difficultySprite->addChild(dibSprite); - } - if (Loader::get()->isModLoaded("minemaker0430.gddp_integration") && m_gddpIntegrationOverride > 0) { - auto gddpSprite = CCSprite::createWithSpriteFrameName(FakeRate::getGDDPFrame(m_gddpIntegrationOverride, GJDifficultyName::Long).c_str()); - gddpSprite->setAnchorPoint({ 0.5f, 1.0f }); - gddpSprite->setPosition(difficultySprite->getContentSize() / 2 + CCPoint { 0.25f, 30.0f }); - difficultySprite->setOpacity(0); - difficultySprite->addChild(gddpSprite); - } - auto toggle = CCMenuItemExt::createSpriteExtra(difficultySprite, [this, feature](CCMenuItemSpriteExtra* sender) { - if (sender == m_selected) return; - m_feature = feature; - if (m_selected) { - FakeRate::toggle(m_selected->getNormalImage(), false); - if (auto particleSystem = m_selected->getNormalImage()->getChildByType(0)) particleSystem->setVisible(false); - } - FakeRate::toggle(sender->getNormalImage(), true); - if (auto particleSystem = sender->getNormalImage()->getChildByType(0)) particleSystem->setVisible(true); - m_selected = sender; - }); - FakeRate::toggle(difficultySprite, feature == m_feature); - if (auto particleSystem = difficultySprite->getChildByType(0)) particleSystem->setVisible(feature == m_feature); - m_selected = feature == m_feature ? toggle : m_selected; - menuRow->addChild(toggle); - } - - menuRow->updateLayout(); - - auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { - callback(static_cast(m_feature)); - onClose(nullptr); - }); - confirmButton->setPosition({ 150.0f, 25.0f }); - m_buttonMenu->addChild(confirmButton); - - return true; -} - -FRGRDPopup* FRGRDPopup::create(int grandpaDemonOverride, SetIntCallback 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, SetIntCallback callback) { - setTitle("Grandpa Demon"); - m_noElasticity = true; - m_grandpaDemonOverride = grandpaDemonOverride; - - auto table = TableNode::create(3, 2); - table->setColumnLayout(ColumnLayout::create()->setAxisReverse(true)); - table->setRowLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); - table->setRowHeight(65.0f); - table->setContentSize({ 250.0f, 130.0f }); - table->setPosition({ 125.0f, 107.5f }); - m_mainLayer->addChild(table); - - for (int i = 1; i < 7; i++) { - auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(fmt::format("itzkiba.grandpa_demon/GrD_demon{}_text.png", i - 1).c_str(), 1.0f, - [this, i](CCMenuItemSpriteExtra* sender) { - m_grandpaDemonOverride = sender != m_selected ? i : 0; - if (m_selected) FakeRate::toggle(m_selected->getNormalImage(), false); - if (sender != m_selected) FakeRate::toggle(sender->getNormalImage(), true); - m_selected = sender != m_selected ? sender : nullptr; - }); - FakeRate::toggle(toggle->getNormalImage(), i == m_grandpaDemonOverride); - m_selected = i == m_grandpaDemonOverride ? toggle : m_selected; - table->addButton(toggle); - } - - table->updateAllLayouts(); - - 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; -} - -FRDIBPopup* FRDIBPopup::create(int demonsInBetweenOverride, SetIntCallback callback) { - auto ret = new FRDIBPopup(); - if (ret->initAnchored(350.0f, 310.0f, demonsInBetweenOverride, callback)) { - ret->autorelease(); - return ret; - } - delete ret; - return nullptr; -} - -bool FRDIBPopup::setup(int demonsInBetweenOverride, SetIntCallback callback) { - setTitle("Demons In Between"); - m_noElasticity = true; - m_demonsInBetweenOverride = demonsInBetweenOverride; - - auto table = TableNode::create(5, 4); - table->setColumnLayout(ColumnLayout::create()->setAxisReverse(true)); - table->setRowLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); - table->setRowHeight(60.0f); - table->setContentSize({ 350.0f, 240.0f }); - table->setPosition({ 175.0f, 160.0f }); - m_mainLayer->addChild(table); - - for (int i = 1; i < 21; i++) { - auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(fmt::format("hiimjustin000.demons_in_between/DIB_{:02}_btn2_001.png", i).c_str(), 1.0f, - [this, i](CCMenuItemSpriteExtra* sender) { - m_demonsInBetweenOverride = sender != m_selected ? i : 0; - if (m_selected) FakeRate::toggle(m_selected->getNormalImage(), false); - if (sender != m_selected) FakeRate::toggle(sender->getNormalImage(), true); - m_selected = sender != m_selected ? sender : nullptr; - }); - FakeRate::toggle(toggle->getNormalImage(), i == m_demonsInBetweenOverride); - m_selected = i == m_demonsInBetweenOverride ? toggle : m_selected; - table->addButton(toggle); - } - - table->updateAllLayouts(); - - auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { - callback(m_demonsInBetweenOverride); - onClose(nullptr); - }); - confirmButton->setPosition({ 175.0f, 25.0f }); - m_buttonMenu->addChild(confirmButton); - - return true; -} - -FRGDDPPopup* FRGDDPPopup::create(int gddpIntegrationOverride, SetIntCallback callback) { - auto ret = new FRGDDPPopup(); - if (ret->initAnchored(350.0f, 250.0f, gddpIntegrationOverride, callback)) { - ret->autorelease(); - return ret; - } - delete ret; - return nullptr; -} - -bool FRGDDPPopup::setup(int gddpIntegrationOverride, SetIntCallback callback) { - setTitle("GDDP Integration"); - m_noElasticity = true; - m_gddpIntegrationOverride = gddpIntegrationOverride; - - auto table = TableNode::create(5, 3); - table->setColumnLayout(ColumnLayout::create()->setAxisReverse(true)); - table->setRowLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); - table->setRowHeight(60.0f); - table->setContentSize({ 350.0f, 180.0f }); - table->setPosition({ 175.0f, 130.0f }); - m_mainLayer->addChild(table); - - for (int i = 1; i < 16; i++) { - auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(FakeRate::getGDDPFrame(i, GJDifficultyName::Long).c_str(), 1.0f, - [this, i](CCMenuItemSpriteExtra* sender) { - m_gddpIntegrationOverride = sender != m_selected ? i : 0; - if (m_selected) FakeRate::toggle(m_selected->getNormalImage(), false); - if (sender != m_selected) FakeRate::toggle(sender->getNormalImage(), true); - m_selected = sender != m_selected ? sender : nullptr; - }); - FakeRate::toggle(toggle->getNormalImage(), i == m_gddpIntegrationOverride); - m_selected = i == m_gddpIntegrationOverride ? toggle : m_selected; - table->addButton(toggle); - } - - table->updateAllLayouts(); - - auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { - callback(m_gddpIntegrationOverride); - onClose(nullptr); - }); - confirmButton->setPosition({ 175.0f, 25.0f }); - m_buttonMenu->addChild(confirmButton); - - return true; -} diff --git a/src/classes/FREditPopup.hpp b/src/classes/FREditPopup.hpp index a84411f..5b96ceb 100644 --- a/src/classes/FREditPopup.hpp +++ b/src/classes/FREditPopup.hpp @@ -1,10 +1,9 @@ #include "../FakeRate.hpp" +#include -typedef std::function const& UpdateFakeRateCallback; -typedef std::function const& SetDifficultyCallback; -typedef std::function const& SetIntCallback; +typedef const std::function& UpdateFakeRateCallback; -class FREditPopup : public geode::Popup { +class FREditPopup : public geode::Popup { protected: GJGameLevel* m_level; int m_stars; @@ -26,88 +25,10 @@ class FREditPopup : public geode::Popup { -protected: - inline static std::vector> DIFFICULTIES = { - { 0, 0 }, { -1, 0 }, { 1, 0 }, { 2, 0 }, { 3, 4 }, { 3, 0 }, { 4, 0 }, { 4, 7 }, - { 5, 0 }, { 5, 9 }, { 7, 0 }, { 8, 0 }, { 6, 0 }, { 9, 0 }, { 10, 0 } - }; - - int m_difficulty; - int m_moreDifficultiesOverride; - int m_grandpaDemonOverride; - int m_demonsInBetweenOverride; - int m_gddpIntegrationOverride; - bool m_legacy; - CCMenuItemSpriteExtra* m_selected; - - bool setup(FakeRateSaveData, bool, SetDifficultyCallback) override; -public: - static FRSetDifficultyPopup* create(FakeRateSaveData, bool, SetDifficultyCallback); -}; - -class FRSetStarsPopup : public geode::Popup { -protected: - int m_stars; - geode::TextInput* m_input; - cocos2d::CCLabelBMFont* m_label; - CCNode* m_starLayout; - - bool setup(int, bool, SetIntCallback) override; -public: - static FRSetStarsPopup* create(int, bool, SetIntCallback); -}; - -class FRSetFeaturePopup : public geode::Popup { -protected: - GJFeatureState m_feature; - int m_difficulty; - int m_moreDifficultiesOverride; - int m_grandpaDemonOverride; - int m_demonsInBetweenOverride; - int m_gddpIntegrationOverride; - bool m_legacy; - CCMenuItemSpriteExtra* m_selected; - - bool setup(FakeRateSaveData, bool, SetIntCallback) override; -public: - static FRSetFeaturePopup* create(FakeRateSaveData, bool, SetIntCallback); -}; - -class FRGRDPopup : public geode::Popup { -protected: - int m_grandpaDemonOverride; - CCMenuItemSpriteExtra* m_selected; - - bool setup(int, SetIntCallback) override; -public: - static FRGRDPopup* create(int, SetIntCallback); -}; - -class FRDIBPopup : public geode::Popup { -protected: - int m_demonsInBetweenOverride; - CCMenuItemSpriteExtra* m_selected; - - bool setup(int, SetIntCallback) override; -public: - static FRDIBPopup* create(int, SetIntCallback); -}; - -class FRGDDPPopup : public geode::Popup { -protected: - int m_gddpIntegrationOverride; - CCMenuItemSpriteExtra* m_selected; - - bool setup(int, SetIntCallback) override; -public: - static FRGDDPPopup* create(int, SetIntCallback); -}; diff --git a/src/classes/FREffects.hpp b/src/classes/FREffects.hpp index 95be342..ef46113 100644 --- a/src/classes/FREffects.hpp +++ b/src/classes/FREffects.hpp @@ -1,3 +1,5 @@ +#include + class FREffects { public: static cocos2d::CCSprite* grdInfinity(); diff --git a/src/classes/FRGDDPPopup.cpp b/src/classes/FRGDDPPopup.cpp new file mode 100644 index 0000000..170e66f --- /dev/null +++ b/src/classes/FRGDDPPopup.cpp @@ -0,0 +1,64 @@ +#include "FRGDDPPopup.hpp" +#include "TableNode.hpp" +#include "../FakeRate.hpp" +#include + +using namespace geode::prelude; + +FRGDDPPopup* FRGDDPPopup::create(int gddpIntegrationOverride, SetGDDPCallback callback) { + auto ret = new FRGDDPPopup(); + if (ret->initAnchored(350.0f, 250.0f, gddpIntegrationOverride, callback)) { + ret->autorelease(); + return ret; + } + delete ret; + return nullptr; +} + +bool FRGDDPPopup::setup(int gddpIntegrationOverride, SetGDDPCallback callback) { + setID("FRGDDPPopup"); + setTitle("GDDP Integration"); + m_title->setID("gddp-integration-title"); + m_mainLayer->setID("main-layer"); + m_buttonMenu->setID("button-menu"); + m_bgSprite->setID("background"); + m_closeBtn->setID("close-button"); + m_noElasticity = true; + m_gddpIntegrationOverride = gddpIntegrationOverride; + + auto table = TableNode::create(5, 3); + table->setColumnLayout(ColumnLayout::create()->setAxisReverse(true)); + table->setRowLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + table->setRowHeight(60.0f); + table->setRowPrefix("gddp-button-row"); + table->setContentSize({ 350.0f, 180.0f }); + table->setPosition({ 175.0f, 130.0f }); + table->setID("gddp-buttons"); + m_mainLayer->addChild(table); + + for (int i = 1; i < 16; i++) { + auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(FakeRate::getGDDPFrame(i, GJDifficultyName::Long).c_str(), 1.0f, + [this, i](CCMenuItemSpriteExtra* sender) { + m_gddpIntegrationOverride = sender != m_selected ? i : 0; + if (m_selected) FakeRate::toggle(m_selected->getNormalImage(), false); + if (sender != m_selected) FakeRate::toggle(sender->getNormalImage(), true); + m_selected = sender != m_selected ? sender : nullptr; + }); + toggle->setID(fmt::format("gddp-button-{}", i)); + FakeRate::toggle(toggle->getNormalImage(), i == m_gddpIntegrationOverride); + m_selected = i == m_gddpIntegrationOverride ? toggle : m_selected; + table->addButton(toggle); + } + + table->updateAllLayouts(); + + auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { + callback(m_gddpIntegrationOverride); + onClose(nullptr); + }); + confirmButton->setPosition({ 175.0f, 25.0f }); + confirmButton->setID("confirm-button"); + m_buttonMenu->addChild(confirmButton); + + return true; +} diff --git a/src/classes/FRGDDPPopup.hpp b/src/classes/FRGDDPPopup.hpp new file mode 100644 index 0000000..42302fc --- /dev/null +++ b/src/classes/FRGDDPPopup.hpp @@ -0,0 +1,13 @@ +#include + +typedef const std::function& SetGDDPCallback; + +class FRGDDPPopup : public geode::Popup { +protected: + int m_gddpIntegrationOverride; + CCMenuItemSpriteExtra* m_selected; + + bool setup(int, SetGDDPCallback) override; +public: + static FRGDDPPopup* create(int, SetGDDPCallback); +}; diff --git a/src/classes/FRGRDPopup.cpp b/src/classes/FRGRDPopup.cpp new file mode 100644 index 0000000..96528ad --- /dev/null +++ b/src/classes/FRGRDPopup.cpp @@ -0,0 +1,63 @@ +#include "FRGRDPopup.hpp" +#include "TableNode.hpp" +#include "../FakeRate.hpp" +#include + +using namespace geode::prelude; + +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) { + setID("FRGRDPopup"); + setTitle("Grandpa Demon"); + m_title->setID("grandpa-demon-title"); + m_mainLayer->setID("main-layer"); + m_buttonMenu->setID("button-menu"); + m_bgSprite->setID("background"); + m_closeBtn->setID("close-button"); + m_noElasticity = true; + m_grandpaDemonOverride = grandpaDemonOverride; + + auto table = TableNode::create(3, 2); + table->setColumnLayout(ColumnLayout::create()->setAxisReverse(true)); + table->setRowLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + table->setRowHeight(65.0f); + table->setRowPrefix("grd-button-row"); + table->setContentSize({ 250.0f, 130.0f }); + table->setPosition({ 125.0f, 107.5f }); + table->setID("grd-buttons"); + m_mainLayer->addChild(table); + + for (int i = 1; i < 7; i++) { + auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(fmt::format("itzkiba.grandpa_demon/GrD_demon{}_text.png", i - 1).c_str(), 1.0f, + [this, i](CCMenuItemSpriteExtra* sender) { + m_grandpaDemonOverride = sender != m_selected ? i : 0; + if (m_selected) FakeRate::toggle(m_selected->getNormalImage(), false); + if (sender != m_selected) FakeRate::toggle(sender->getNormalImage(), true); + m_selected = sender != m_selected ? sender : nullptr; + }); + FakeRate::toggle(toggle->getNormalImage(), i == m_grandpaDemonOverride); + m_selected = i == m_grandpaDemonOverride ? toggle : m_selected; + table->addButton(toggle); + } + + table->updateAllLayouts(); + + 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 }); + confirmButton->setID("confirm-button"); + m_buttonMenu->addChild(confirmButton); + + return true; +} diff --git a/src/classes/FRGRDPopup.hpp b/src/classes/FRGRDPopup.hpp new file mode 100644 index 0000000..950d634 --- /dev/null +++ b/src/classes/FRGRDPopup.hpp @@ -0,0 +1,13 @@ +#include + +typedef const std::function& SetGRDCallback; + +class FRGRDPopup : public geode::Popup { +protected: + int m_grandpaDemonOverride; + CCMenuItemSpriteExtra* m_selected; + + bool setup(int, SetGRDCallback) override; +public: + static FRGRDPopup* create(int, SetGRDCallback); +}; diff --git a/src/classes/FRSetDifficultyPopup.cpp b/src/classes/FRSetDifficultyPopup.cpp new file mode 100644 index 0000000..baf4849 --- /dev/null +++ b/src/classes/FRSetDifficultyPopup.cpp @@ -0,0 +1,143 @@ +#include "FRSetDifficultyPopup.hpp" +#include "FRDIBPopup.hpp" +#include "FRGDDPPopup.hpp" +#include "FRGRDPopup.hpp" +#include "TableNode.hpp" +#include +#include + +using namespace geode::prelude; + +FRSetDifficultyPopup* FRSetDifficultyPopup::create(const FakeRateSaveData& data, bool legacy, SetDifficultyCallback callback) { + auto ret = new FRSetDifficultyPopup(); + if (ret->initAnchored(300.0f, 250.0f, data, legacy, callback)) { + ret->autorelease(); + return ret; + } + delete ret; + return nullptr; +} + +bool FRSetDifficultyPopup::setup(const FakeRateSaveData& data, bool legacy, SetDifficultyCallback callback) { + setID("FRSetDifficultyPopup"); + setTitle("Select Difficulty"); + m_title->setID("select-difficulty-title"); + m_mainLayer->setID("main-layer"); + m_buttonMenu->setID("button-menu"); + m_bgSprite->setID("background"); + m_closeBtn->setID("close-button"); + m_noElasticity = true; + m_difficulty = data.difficulty; + m_moreDifficultiesOverride = data.moreDifficultiesOverride; + m_grandpaDemonOverride = data.grandpaDemonOverride; + m_demonsInBetweenOverride = data.demonsInBetweenOverride; + m_gddpIntegrationOverride = data.gddpIntegrationOverride; + m_legacy = legacy; + + auto casual = false; + auto tough = false; + auto cruel = false; + if (auto moreDifficulties = Loader::get()->getLoadedMod("uproxide.more_difficulties")) { + casual = moreDifficulties->getSavedValue("casual", true); + tough = moreDifficulties->getSavedValue("tough", true); + cruel = moreDifficulties->getSavedValue("cruel", true); + } + + auto table = TableNode::create(Loader::get()->isModLoaded("uproxide.more_difficulties") && (casual || tough || cruel) ? 5 : 4, 3); + table->setColumnLayout(ColumnLayout::create()->setAxisReverse(true)); + table->setRowLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + table->setRowHeight(63.0f); + table->setRowPrefix("difficulty-button-row"); + table->setContentSize({ 300.0f, 170.0f }); + table->setPosition({ 150.0f, 130.0f }); + table->setID("difficulty-buttons"); + m_mainLayer->addChild(table); + + int i = 1; + for (auto& [d, mdo] : DIFFICULTIES) { + auto num = d == -1 ? "auto" : fmt::format("{:02d}", d); + auto frameName = d > 5 ? fmt::format("difficulty_{}_btn2_001.png", num) : fmt::format("difficulty_{}_btn_001.png", num); + if (auto moreDifficulties = Loader::get()->getLoadedMod("uproxide.more_difficulties"); moreDifficulties && mdo > 0) { + if (mdo == 4 && !casual) continue; + if (mdo == 7 && !tough) continue; + if (mdo == 9 && !cruel) continue; + frameName = fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", mdo, m_legacy ? "_Legacy" : ""); + } + else if (mdo > 0) continue; + auto toggle = CCMenuItemExt::createSpriteExtraWithFrameName(frameName.c_str(), 1.0f, [this, d, mdo](CCMenuItemSpriteExtra* sender) { + if (sender == m_selected) return; + m_difficulty = d; + m_moreDifficultiesOverride = mdo; + m_grandpaDemonOverride = 0; + m_demonsInBetweenOverride = 0; + m_gddpIntegrationOverride = 0; + if (m_selected) FakeRate::toggle(m_selected->getNormalImage(), false); + FakeRate::toggle(sender->getNormalImage(), true); + m_selected = sender; + }); + toggle->setID(fmt::format("difficulty-button-{}", i++)); + auto isToggled = mdo == m_moreDifficultiesOverride && (m_moreDifficultiesOverride <= 0 ? d == m_difficulty : true); + FakeRate::toggle(toggle->getNormalImage(), isToggled); + m_selected = isToggled ? toggle : m_selected; + table->addButton(toggle); + } + + table->updateAllLayouts(); + + auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { + callback(m_difficulty, m_moreDifficultiesOverride, m_grandpaDemonOverride, m_demonsInBetweenOverride, m_gddpIntegrationOverride); + onClose(nullptr); + }); + confirmButton->setPosition({ 150.0f, 25.0f }); + confirmButton->setID("confirm-button"); + m_buttonMenu->addChild(confirmButton); + + auto overrideMenu = CCMenu::create(); + overrideMenu->setLayout(RowLayout::create()->setGap(4.0f)->setAxisAlignment(AxisAlignment::End)); + overrideMenu->setPosition({ 245.0f, 25.0f }); + overrideMenu->setContentSize({ 100.0f, 30.0f }); + overrideMenu->setID("override-menu"); + m_mainLayer->addChild(overrideMenu); + + 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_grandpaDemonOverride = grd; + m_demonsInBetweenOverride = 0; + m_gddpIntegrationOverride = 0; + })->show(); + }); + grdButton->setID("grd-button"); + overrideMenu->addChild(grdButton); + } + + if (auto demonsInBetween = Loader::get()->getLoadedMod("hiimjustin000.demons_in_between"); + demonsInBetween && demonsInBetween->getSettingValue("enable-difficulties")) { + auto dibButton = CCMenuItemExt::createSpriteExtraWithFilename("FR_dibBtn_001.png"_spr, 0.75f, [this](auto) { + FRDIBPopup::create(m_demonsInBetweenOverride, [this](int dib) { + m_grandpaDemonOverride = 0; + m_demonsInBetweenOverride = dib; + m_gddpIntegrationOverride = 0; + })->show(); + }); + dibButton->setID("dib-button"); + overrideMenu->addChild(dibButton); + } + + if (auto gddpIntegration = Loader::get()->getLoadedMod("minemaker0430.gddp_integration"); + gddpIntegration && gddpIntegration->getSettingValue("custom-difficulty-faces")) { + auto gddpButton = CCMenuItemExt::createSpriteExtraWithFilename("FR_gddpBtn_001.png"_spr, 0.65f, [this](auto) { + FRGDDPPopup::create(m_gddpIntegrationOverride, [this](int gddp) { + m_grandpaDemonOverride = 0; + m_demonsInBetweenOverride = 0; + m_gddpIntegrationOverride = gddp; + })->show(); + }); + gddpButton->setID("gddp-button"); + overrideMenu->addChild(gddpButton); + } + + overrideMenu->updateLayout(); + + return true; +} diff --git a/src/classes/FRSetDifficultyPopup.hpp b/src/classes/FRSetDifficultyPopup.hpp new file mode 100644 index 0000000..51106b1 --- /dev/null +++ b/src/classes/FRSetDifficultyPopup.hpp @@ -0,0 +1,24 @@ +#include "../FakeRate.hpp" +#include + +typedef const std::function& SetDifficultyCallback; + +class FRSetDifficultyPopup : public geode::Popup { +protected: + inline static constexpr std::array, 15> DIFFICULTIES = { std::pair + { 0, 0 }, { -1, 0 }, { 1, 0 }, { 2, 0 }, { 3, 4 }, { 3, 0 }, { 4, 0 }, { 4, 7 }, + { 5, 0 }, { 5, 9 }, { 7, 0 }, { 8, 0 }, { 6, 0 }, { 9, 0 }, { 10, 0 } + }; + + int m_difficulty; + int m_moreDifficultiesOverride; + int m_grandpaDemonOverride; + int m_demonsInBetweenOverride; + int m_gddpIntegrationOverride; + bool m_legacy; + CCMenuItemSpriteExtra* m_selected; + + bool setup(const FakeRateSaveData&, bool, SetDifficultyCallback) override; +public: + static FRSetDifficultyPopup* create(const FakeRateSaveData&, bool, SetDifficultyCallback); +}; diff --git a/src/classes/FRSetFeaturePopup.cpp b/src/classes/FRSetFeaturePopup.cpp new file mode 100644 index 0000000..28cb2f8 --- /dev/null +++ b/src/classes/FRSetFeaturePopup.cpp @@ -0,0 +1,109 @@ +#include "FRSetFeaturePopup.hpp" +#include +#include +#include + +using namespace geode::prelude; + +FRSetFeaturePopup* FRSetFeaturePopup::create(const FakeRateSaveData& data, bool legacy, SetFeatureCallback callback) { + auto ret = new FRSetFeaturePopup(); + if (ret->initAnchored(300.0f, 150.0f, data, legacy, callback)) { + ret->autorelease(); + return ret; + } + delete ret; + return nullptr; +} + +bool FRSetFeaturePopup::setup(const FakeRateSaveData& data, bool legacy, SetFeatureCallback callback) { + setID("FRSetFeaturePopup"); + setTitle("Select Feature"); + m_title->setID("select-feature-title"); + m_mainLayer->setID("main-layer"); + m_buttonMenu->setID("button-menu"); + m_bgSprite->setID("background"); + m_closeBtn->setID("close-button"); + m_noElasticity = true; + m_feature = (GJFeatureState)data.feature; + m_difficulty = data.difficulty; + m_moreDifficultiesOverride = data.moreDifficultiesOverride; + m_grandpaDemonOverride = data.grandpaDemonOverride; + m_demonsInBetweenOverride = data.demonsInBetweenOverride; + m_gddpIntegrationOverride = data.gddpIntegrationOverride; + m_legacy = legacy; + + auto menuRow = CCMenu::create(); + menuRow->setLayout(RowLayout::create()->setAxisAlignment(AxisAlignment::Even)); + menuRow->setPosition({ 150.0f, 80.0f + (data.difficulty > 5 || data.grandpaDemonOverride > 0 || + data.demonsInBetweenOverride > 0 || data.gddpIntegrationOverride > 0 ? 5.0f : 0.0f) }); + menuRow->setContentSize({ 300.0f, 50.0f }); + menuRow->setID("feature-buttons"); + m_mainLayer->addChild(menuRow); + + for (int i = 0; i < 5; i++) { + auto feature = (GJFeatureState)i; + auto difficultySprite = GJDifficultySprite::create(m_difficulty, GJDifficultyName::Long); + difficultySprite->updateFeatureState(feature); + if (Loader::get()->isModLoaded("uproxide.more_difficulties") && m_moreDifficultiesOverride > 0 + && m_grandpaDemonOverride == 0 && m_demonsInBetweenOverride == 0) { + auto mdSprite = CCSprite::createWithSpriteFrameName((m_legacy ? + fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}_Legacy.png", m_moreDifficultiesOverride) + : fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}.png", m_moreDifficultiesOverride)).c_str()); + mdSprite->setPosition(difficultySprite->getContentSize() / 2 + (m_legacy ? CCPoint { 0.0f, 0.0f } : CCPoint { 0.25f, -0.1f })); + difficultySprite->setOpacity(0); + difficultySprite->addChild(mdSprite); + } + 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()); + grdSprite->setPosition(difficultySprite->getContentSize() / 2); + difficultySprite->setOpacity(0); + difficultySprite->addChild(grdSprite); + } + if (Loader::get()->isModLoaded("hiimjustin000.demons_in_between") && m_demonsInBetweenOverride > 0) { + auto demonsInBetween = Loader::get()->getLoadedMod("hiimjustin000.demons_in_between"); + auto dibFeature = ""; + if (i == 3 && demonsInBetween->getSettingValue("enable-legendary")) dibFeature = "_4"; + else if (i == 4 && demonsInBetween->getSettingValue("enable-mythic")) dibFeature = "_5"; + auto dibSprite = CCSprite::createWithSpriteFrameName(fmt::format("hiimjustin000.demons_in_between/DIB_{:02d}{}_btn2_001.png", + m_demonsInBetweenOverride, dibFeature).c_str()); + dibSprite->setPosition(difficultySprite->getContentSize() / 2 + FakeRate::getDIBOffset(m_demonsInBetweenOverride, GJDifficultyName::Long)); + difficultySprite->setOpacity(0); + difficultySprite->addChild(dibSprite); + } + if (Loader::get()->isModLoaded("minemaker0430.gddp_integration") && m_gddpIntegrationOverride > 0) { + auto gddpSprite = CCSprite::createWithSpriteFrameName(FakeRate::getGDDPFrame(m_gddpIntegrationOverride, GJDifficultyName::Long).c_str()); + gddpSprite->setAnchorPoint({ 0.5f, 1.0f }); + gddpSprite->setPosition(difficultySprite->getContentSize() / 2 + CCPoint { 0.25f, 30.0f }); + difficultySprite->setOpacity(0); + difficultySprite->addChild(gddpSprite); + } + auto toggle = CCMenuItemExt::createSpriteExtra(difficultySprite, [this, feature](CCMenuItemSpriteExtra* sender) { + if (sender == m_selected) return; + m_feature = feature; + if (m_selected) { + FakeRate::toggle(m_selected->getNormalImage(), false); + if (auto particleSystem = m_selected->getNormalImage()->getChildByType(0)) particleSystem->setVisible(false); + } + FakeRate::toggle(sender->getNormalImage(), true); + if (auto particleSystem = sender->getNormalImage()->getChildByType(0)) particleSystem->setVisible(true); + m_selected = sender; + }); + toggle->setID(fmt::format("feature-button-{}", i + 1)); + FakeRate::toggle(difficultySprite, feature == m_feature); + if (auto particleSystem = difficultySprite->getChildByType(0)) particleSystem->setVisible(feature == m_feature); + m_selected = feature == m_feature ? toggle : m_selected; + menuRow->addChild(toggle); + } + + menuRow->updateLayout(); + + auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { + callback((int)m_feature); + onClose(nullptr); + }); + confirmButton->setPosition({ 150.0f, 25.0f }); + confirmButton->setID("confirm-button"); + m_buttonMenu->addChild(confirmButton); + + return true; +} diff --git a/src/classes/FRSetFeaturePopup.hpp b/src/classes/FRSetFeaturePopup.hpp new file mode 100644 index 0000000..229fdea --- /dev/null +++ b/src/classes/FRSetFeaturePopup.hpp @@ -0,0 +1,20 @@ +#include "../FakeRate.hpp" +#include + +typedef const std::function& SetFeatureCallback; + +class FRSetFeaturePopup : public geode::Popup { +protected: + GJFeatureState m_feature; + int m_difficulty; + int m_moreDifficultiesOverride; + int m_grandpaDemonOverride; + int m_demonsInBetweenOverride; + int m_gddpIntegrationOverride; + bool m_legacy; + CCMenuItemSpriteExtra* m_selected; + + bool setup(const FakeRateSaveData&, bool, SetFeatureCallback) override; +public: + static FRSetFeaturePopup* create(const FakeRateSaveData&, bool, SetFeatureCallback); +}; diff --git a/src/classes/FRSetStarsPopup.cpp b/src/classes/FRSetStarsPopup.cpp new file mode 100644 index 0000000..cf996ba --- /dev/null +++ b/src/classes/FRSetStarsPopup.cpp @@ -0,0 +1,94 @@ +#include "FRSetStarsPopup.hpp" +#include + +using namespace geode::prelude; + +FRSetStarsPopup* FRSetStarsPopup::create(int stars, bool platformer, SetStarsCallback callback) { + auto ret = new FRSetStarsPopup(); + if (ret->initAnchored(250.0f, 150.0f, stars, platformer, callback)) { + ret->autorelease(); + return ret; + } + delete ret; + return nullptr; +} + +bool FRSetStarsPopup::setup(int stars, bool platformer, SetStarsCallback callback) { + setID("FRSetStarsPopup"); + setTitle(platformer ? "Set Moons" : "Set Stars"); + m_title->setID("set-stars-title"); + m_mainLayer->setID("main-layer"); + m_buttonMenu->setID("button-menu"); + m_bgSprite->setID("background"); + m_closeBtn->setID("close-button"); + m_noElasticity = true; + m_stars = stars; + + m_input = TextInput::create(150.0f, platformer ? "Moons" : "Stars"); + m_input->setCommonFilter(CommonFilter::Int); + m_input->setPosition({ 125.0f, 80.0f }); + m_input->getInputNode()->setLabelPlaceholderColor({ 120, 170, 240 }); + m_input->setString(std::to_string(m_stars)); + m_input->setMaxCharCount(11); + m_input->setCallback([this](const std::string& text) { + auto stars = numFromString(text).unwrapOr(0); + if (stars < INT_MIN) stars = INT_MIN; + if (stars > INT_MAX) stars = INT_MAX; + m_stars = stars; + m_label->setString(std::to_string(m_stars).c_str()); + m_starLayout->updateLayout(); + }); + m_input->setID("stars-input"); + m_mainLayer->addChild(m_input); + + m_starLayout = CCNode::create(); + m_starLayout->setPosition({ 125.0f, 52.5f }); + m_starLayout->setContentSize({ 250.0f, 15.0f }); + m_starLayout->setAnchorPoint({ 0.5f, 0.5f }); + m_starLayout->setLayout(RowLayout::create()->setGap(1.75f)->setAutoScale(false)); + m_starLayout->setID("stars-layout"); + m_mainLayer->addChild(m_starLayout); + + m_label = CCLabelBMFont::create(std::to_string(m_stars).c_str(), "bigFont.fnt"); + m_label->setScale(0.4f); + m_label->setID("stars-label"); + m_starLayout->addChild(m_label); + + auto starSprite = CCSprite::createWithSpriteFrameName(platformer ? "moon_small01_001.png" : "star_small01_001.png"); + starSprite->setID("star-sprite"); + m_starLayout->addChild(starSprite); + + m_starLayout->updateLayout(); + + auto leftButton = CCMenuItemExt::createSpriteExtraWithFrameName("edit_leftBtn_001.png", 1.1f, [this](auto) { + if (m_stars != INT_MIN) m_stars--; + auto stars = std::to_string(m_stars); + m_input->setString(stars); + m_label->setString(stars.c_str()); + m_starLayout->updateLayout(); + }); + leftButton->setPosition({ 30.0f, 80.0f }); + leftButton->setID("left-button"); + m_buttonMenu->addChild(leftButton); + + auto rightButton = CCMenuItemExt::createSpriteExtraWithFrameName("edit_rightBtn_001.png", 1.1f, [this](auto) { + if (m_stars != INT_MAX) m_stars++; + auto stars = std::to_string(m_stars); + m_input->setString(stars); + m_label->setString(stars.c_str()); + m_starLayout->updateLayout(); + }); + rightButton->setPosition({ 220.0f, 80.0f }); + rightButton->setID("right-button"); + m_buttonMenu->addChild(rightButton); + + auto confirmButton = CCMenuItemExt::createSpriteExtra(ButtonSprite::create("Confirm", "goldFont.fnt", "GJ_button_01.png", 0.8f), [this, callback](auto) { + callback(m_stars); + onClose(nullptr); + }); + confirmButton->setPosition({ 125.0f, 25.0f }); + confirmButton->setID("confirm-button"); + m_buttonMenu->addChild(confirmButton); + + return true; +} diff --git a/src/classes/FRSetStarsPopup.hpp b/src/classes/FRSetStarsPopup.hpp new file mode 100644 index 0000000..0a5bfa5 --- /dev/null +++ b/src/classes/FRSetStarsPopup.hpp @@ -0,0 +1,16 @@ +#include +#include + +typedef const std::function& SetStarsCallback; + +class FRSetStarsPopup : public geode::Popup { +protected: + int m_stars; + geode::TextInput* m_input; + cocos2d::CCLabelBMFont* m_label; + CCNode* m_starLayout; + + bool setup(int, bool, SetStarsCallback) override; +public: + static FRSetStarsPopup* create(int, bool, SetStarsCallback); +}; diff --git a/src/classes/TableNode.cpp b/src/classes/TableNode.cpp index 94d30af..fe53f54 100644 --- a/src/classes/TableNode.cpp +++ b/src/classes/TableNode.cpp @@ -1,4 +1,5 @@ #include "TableNode.hpp" +#include using namespace geode::prelude; @@ -43,6 +44,14 @@ void TableNode::setRowHeight(float rowHeight) { } } +void TableNode::setRowPrefix(const std::string& rowPrefix) { + m_rowPrefix = rowPrefix; + for (int i = 0; i < m_menus->count(); i++) { + auto menu = static_cast(m_menus->objectAtIndex(i)); + menu->setID(fmt::format("{}-{}", rowPrefix, i + 1)); + } +} + void TableNode::updateAllLayouts() { for (auto menu : CCArrayExt(m_menus)) { menu->updateLayout(); @@ -50,12 +59,13 @@ void TableNode::updateAllLayouts() { updateLayout(); } -void TableNode::addButton(CCMenuItemSpriteExtra* button) { +void TableNode::addButton(CCMenuItem* button) { CCMenu* menu = nullptr; if (m_menus->count() <= 0 || static_cast(m_menus->objectAtIndex(m_menus->count() - 1))->getChildrenCount() >= m_columns) { menu = CCMenu::create(); menu->setContentSize({ m_obContentSize.width, m_rowHeight }); menu->setLayout(m_rowLayout); + menu->setID(fmt::format("{}-{}", m_rowPrefix, m_menus->count() + 1)); addChild(menu); m_menus->addObject(menu); } else menu = static_cast(m_menus->objectAtIndex(m_menus->count() - 1)); diff --git a/src/classes/TableNode.hpp b/src/classes/TableNode.hpp index f3de053..b7fe478 100644 --- a/src/classes/TableNode.hpp +++ b/src/classes/TableNode.hpp @@ -1,3 +1,5 @@ +#include + class TableNode : public cocos2d::CCNode { protected: cocos2d::CCArray* m_menus; @@ -6,6 +8,7 @@ class TableNode : public cocos2d::CCNode { int m_columns; int m_rows; float m_rowHeight; + std::string m_rowPrefix; bool init(int columns, int rows); public: @@ -14,8 +17,9 @@ class TableNode : public cocos2d::CCNode { void setColumnLayout(geode::AxisLayout*); void setRowLayout(geode::AxisLayout*); void setRowHeight(float); + void setRowPrefix(const std::string&); void updateAllLayouts(); - void addButton(CCMenuItemSpriteExtra*); + void addButton(cocos2d::CCMenuItem*); ~TableNode() override; }; diff --git a/src/hooks/LevelCell.cpp b/src/hooks/LevelCell.cpp index b679195..a17d042 100644 --- a/src/hooks/LevelCell.cpp +++ b/src/hooks/LevelCell.cpp @@ -1,216 +1,229 @@ #include "../FakeRate.hpp" #include "../classes/FREffects.hpp" +#include +#include +#include +#include +#include +#include using namespace geode::prelude; -#include class $modify(FRLevelCell, LevelCell) { - static void onModify(auto& self) { + static void onModify(ModifyBase>& self) { (void)self.setHookPriority("LevelCell::loadFromLevel", -100); } void loadFromLevel(GJGameLevel* level) { LevelCell::loadFromLevel(level); + auto difficultyContainer = m_mainLayer->getChildByID("difficulty-container"); if (!difficultyContainer) difficultyContainer = m_mainLayer->getChildByID("grd-demon-icon-layer"); - if (difficultyContainer) { - auto vec = Mod::get()->getSavedValue>("fake-rate", {}); - auto it = std::find_if(vec.begin(), vec.end(), [level](FakeRateSaveData const& item) { return item.id == level->m_levelID; }); - if (it != vec.end()) { - auto difficultySprite = static_cast(difficultyContainer->getChildByID("difficulty-sprite")); - if (auto betweenDifficultySprite = static_cast(difficultyContainer->getChildByID("hiimjustin000.demons_in_between/between-difficulty-sprite"))) { - betweenDifficultySprite->setVisible(false); - difficultySprite->setOpacity(255); - } - auto gddpOverride = false; - if (auto gddpDifficultySprite = static_cast(difficultyContainer->getChildByID("gddp-difficulty"))) { - gddpOverride = true; - gddpDifficultySprite->setVisible(false); - if (FakeRate::getSpriteName(gddpDifficultySprite).find("Plus") != std::string::npos) { - if (auto epicSprite = getChildBySpriteFrameName(difficultySprite, "GJ_epicCoin_001.png")) - epicSprite->setVisible(!Loader::get()->isModLoaded("uproxide.animated_fire")); - } - difficultySprite->setOpacity(255); - } - if (difficultyContainer->getID() == "grd-demon-icon-layer" && !gddpOverride) { - difficultyContainer->removeChildByTag(69420); - if (Loader::get()->isModLoaded("uproxide.animated_fire")) difficultyContainer->removeChildByTag(69420); - difficultySprite->setVisible(true); - if (auto grdInfinity = static_cast(difficultyContainer->getChildByID("grd-infinity"))) { - grdInfinity->setVisible(false); - static_cast(difficultyContainer->getChildren()->objectAtIndex(difficultyContainer->getChildrenCount() - 2))->setVisible(false); - } - else static_cast(difficultyContainer->getChildren()->lastObject())->setVisible(false); - if (auto featureGlow = difficultySprite->getChildByTag(69420)) - featureGlow->setPosition(difficultySprite->getContentSize() / 2); - } + if (!difficultyContainer) return; - 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; - 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::get(); - if (showStars) { - auto starsIcon = static_cast(difficultyContainer->getChildByID("stars-icon")); - if (!starsIcon) { - starsIcon = CCSprite::createWithSpriteFrameName(level->m_levelLength < 5 ? "star_small01_001.png" : "moon_small01_001.png"); - starsIcon->setPosition({ difficultySprite->getPositionX() + 8.0f, difficultySprite->getPositionY() - 30.0f }); - starsIcon->setID("stars-icon"); - difficultyContainer->addChild(starsIcon); - } - auto starsLabel = static_cast(difficultyContainer->getChildByID("stars-label")); - if (!starsLabel) { - starsLabel = CCLabelBMFont::create("0", "bigFont.fnt"); - starsLabel->setPosition({ starsIcon->getPositionX() - 8.0f, starsIcon->getPositionY() }); - starsLabel->setScale(0.4f); - starsLabel->setAnchorPoint({ 1.0f, 0.5f }); - starsLabel->setID("stars-label"); - difficultyContainer->addChild(starsLabel); - } - starsLabel->setString(std::to_string(fakeRateData.stars).c_str()); - if (gsm->hasCompletedLevel(level)) starsLabel->setColor({ 255, 255, 50 }); - } - else { - if (auto starsIcon = static_cast(difficultyContainer->getChildByID("stars-icon"))) starsIcon->removeFromParent(); - if (auto starsLabel = static_cast(difficultyContainer->getChildByID("stars-label"))) starsLabel->removeFromParent(); - } - auto coinParent = m_compactView ? m_mainLayer : difficultyContainer; - for (int i = 1; i <= 3; i++) { - if (auto coin = static_cast(coinParent->getChildByID("coin-icon-" + std::to_string(i)))) { - if (!m_compactView) coin->setPositionY(difficultySprite->getPositionY() - 31.5f - (showStars ? 14.0f : 0.0f) - - (level->m_gauntletLevel || level->m_dailyID > 0 ? 14.5f : 0.0f)); - auto coinStr = fmt::format("{}_{}", level->m_levelID.value(), i); - if (level->m_dailyID > 0) coinStr += "_" + std::to_string(level->m_dailyID); - else if (level->m_gauntletLevel) coinStr += "_g"; - coin->setColor(gsm->hasUserCoin(coinStr.c_str()) || gsm->hasPendingUserCoin(coinStr.c_str()) ? - ccColor3B { 255, 255, 255 } : ccColor3B { 165, 165, 165 }); - } - } + auto vec = Mod::get()->getSavedValue>("fake-rate", {}); + auto levelID = level->m_levelID.value(); + auto i = ranges::indexOf(vec, [levelID](const FakeRateSaveData& item) { return item.id == levelID; }); + if (!i.has_value()) return; - if (level->m_dailyID > 0) { - auto diamondLabel = static_cast(difficultyContainer->getChildByID("diamond-label")); - auto diamondIcon = static_cast(difficultyContainer->getChildByID("diamond-icon")); - auto diamonds = fakeRateData.stars > 1 ? fakeRateData.stars + 2 : 0; - diamondLabel->setString(fmt::format("{}/{}", (int)floorf(diamonds * level->m_normalPercent / 100.0f), diamonds).c_str()); - diamondIcon->setPositionX(difficultySprite->getPositionX() + diamondLabel->getScaledContentWidth() * 0.5f + 2.0f); - diamondLabel->setPositionX(diamondIcon->getPositionX() - 8.0f); - } + auto difficultySprite = static_cast(difficultyContainer->getChildByID("difficulty-sprite")); + if (auto betweenDifficultySprite = static_cast(difficultyContainer->getChildByID("hiimjustin000.demons_in_between/between-difficulty-sprite"))) { + betweenDifficultySprite->setVisible(false); + difficultySprite->setOpacity(255); + } + auto gddpOverride = false; + if (auto gddpDifficultySprite = static_cast(difficultyContainer->getChildByID("gddp-difficulty"))) { + gddpOverride = true; + gddpDifficultySprite->setVisible(false); + if (FakeRate::getSpriteName(gddpDifficultySprite).find("Plus") != std::string::npos) { + if (auto epicSprite = getChildBySpriteFrameName(difficultySprite, "GJ_epicCoin_001.png")) + epicSprite->setVisible(!Loader::get()->isModLoaded("uproxide.animated_fire")); + } + difficultySprite->setOpacity(255); + } + if (difficultyContainer->getID() == "grd-demon-icon-layer" && !gddpOverride) { + difficultyContainer->removeChildByTag(69420); + if (Loader::get()->isModLoaded("uproxide.animated_fire")) difficultyContainer->removeChildByTag(69420); + difficultySprite->setVisible(true); + if (auto grdInfinity = static_cast(difficultyContainer->getChildByID("grd-infinity"))) { + grdInfinity->setVisible(false); + static_cast(difficultyContainer->getChildren()->objectAtIndex(difficultyContainer->getChildrenCount() - 2))->setVisible(false); + } + else static_cast(difficultyContainer->getChildren()->lastObject())->setVisible(false); + if (auto featureGlow = difficultySprite->getChildByTag(69420)) + featureGlow->setPosition(difficultySprite->getContentSize() / 2); + } - auto padding = (showStars ? 18.0f : 25.0f) * (m_compactView ? 0.8f : 1.0f); - auto lengthLabel = static_cast(m_mainLayer->getChildByID("length-label")); - auto downloadsIcon = static_cast(m_mainLayer->getChildByID("downloads-icon")); - auto downloadsLabel = static_cast(m_mainLayer->getChildByID("downloads-label")); - downloadsIcon->setPositionX(lengthLabel->getPositionX() + lengthLabel->getScaledContentWidth() + padding); - downloadsLabel->setPositionX(downloadsIcon->getPositionX() + 9.0f); - auto likesLabel = static_cast(m_mainLayer->getChildByID("likes-label")); - auto likesIcon = static_cast(m_mainLayer->getChildByID("likes-icon")); - likesIcon->setPositionX(downloadsLabel->getPositionX() + downloadsLabel->getScaledContentWidth() + padding); - likesLabel->setPositionX(likesIcon->getPositionX() + 10.0f); - if (showStars) { - auto orbsIcon = static_cast(m_mainLayer->getChildByID("orbs-icon")); - if (!orbsIcon) { - orbsIcon = CCSprite::createWithSpriteFrameName("currencyOrbIcon_001.png"); - orbsIcon->setScale(m_compactView ? 0.4f : 0.6f); - orbsIcon->setPosition({ likesLabel->getPositionX() + likesLabel->getScaledContentWidth() + padding, likesLabel->getPositionY() }); - orbsIcon->setID("orbs-icon"); - m_mainLayer->addChild(orbsIcon); - } - auto orbsLabel = static_cast(m_mainLayer->getChildByID("orbs-label")); - if (!orbsLabel) { - orbsLabel = CCLabelBMFont::create("", "bigFont.fnt"); - orbsLabel->setScale(m_compactView ? 0.3f : 0.4f); - orbsLabel->setAnchorPoint({ 0.0f, 0.5f }); - orbsLabel->setPosition({ orbsIcon->getPositionX() + 10.0f, orbsIcon->getPositionY() }); - orbsLabel->setID("orbs-label"); - m_mainLayer->addChild(orbsLabel); - } - auto orbs = FakeRate::getBaseCurrency(fakeRateData.stars); - int totalOrbs = floorf(orbs * 1.25f); - auto percent = level->m_normalPercent.value(); - auto savedLevel = GameLevelManager::get()->getSavedLevel(level); - if (savedLevel) percent = savedLevel->m_normalPercent.value(); - orbsLabel->setString((percent == 100 ? fmt::format("{}", totalOrbs) : fmt::format("{}/{}", (int)floorf(orbs * percent / 100.0f), totalOrbs)).c_str()); - orbsLabel->limitLabelWidth(45.0f, m_compactView ? 0.3f : 0.4f, 0.0f); - if (percent == 100) orbsLabel->setColor({ 100, 255, 255 }); - } - else { - if (auto orbsIcon = static_cast(m_mainLayer->getChildByID("orbs-icon"))) orbsIcon->removeFromParent(); - if (auto orbsLabel = static_cast(m_mainLayer->getChildByID("orbs-label"))) orbsLabel->removeFromParent(); - } + auto& fakeRateData = vec[i.value()]; + difficultySprite->updateFeatureState((GJFeatureState)fakeRateData.feature); + difficultySprite->updateDifficultyFrame(fakeRateData.difficulty, GJDifficultyName::Short); + auto addCoins = level->m_coins > 0 && !m_compactView; + auto dailyID = level->m_dailyID.value(); + auto showStars = fakeRateData.stars != 0 || dailyID > 0; + difficultySprite->setPositionY((showStars || addCoins ? 5.0f : 0.0f) + (showStars && addCoins ? 9.0f : 0.0f) + (dailyID > 0 ? 10.0f : 0.0f)); + auto gsm = GameStatsManager::get(); + if (showStars) { + auto starsIcon = static_cast(difficultyContainer->getChildByID("stars-icon")); + if (!starsIcon) { + starsIcon = CCSprite::createWithSpriteFrameName(level->m_levelLength < 5 ? "star_small01_001.png" : "moon_small01_001.png"); + starsIcon->setPosition({ difficultySprite->getPositionX() + 8.0f, difficultySprite->getPositionY() - 30.0f }); + starsIcon->setID("stars-icon"); + difficultyContainer->addChild(starsIcon); + } + auto starsLabel = static_cast(difficultyContainer->getChildByID("stars-label")); + if (!starsLabel) { + starsLabel = CCLabelBMFont::create("0", "bigFont.fnt"); + starsLabel->setPosition({ starsIcon->getPositionX() - 8.0f, starsIcon->getPositionY() }); + starsLabel->setScale(0.4f); + starsLabel->setAnchorPoint({ 1.0f, 0.5f }); + starsLabel->setID("stars-label"); + difficultyContainer->addChild(starsLabel); + } + starsLabel->setString(std::to_string(fakeRateData.stars).c_str()); + if (gsm->hasCompletedLevel(level)) starsLabel->setColor({ 255, 255, 50 }); + } + else { + if (auto starsIcon = static_cast(difficultyContainer->getChildByID("stars-icon"))) starsIcon->removeFromParent(); + if (auto starsLabel = static_cast(difficultyContainer->getChildByID("stars-label"))) starsLabel->removeFromParent(); + } - auto& position = difficultySprite->getPosition(); - auto gdo = fakeRateData.grandpaDemonOverride; - auto dbo = fakeRateData.demonsInBetweenOverride; - auto gio = fakeRateData.gddpIntegrationOverride; - - if (Loader::get()->isModLoaded("uproxide.more_difficulties")) fixMoreDifficultiesIncompatibility(fakeRateData.moreDifficultiesOverride, gdo, dbo, gio); - - 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); - if (gdo == 5) { - auto grdInfinity = FREffects::grdInfinity(); - grdInfinity->setID("grandpa-demon-infinity"_spr); - grdInfinity->setPosition(position + CCPoint { -0.4f, 14.0f }); - difficultyContainer->addChild(grdInfinity); - } - difficultySprite->setOpacity(0); - } + auto coinParent = m_compactView ? m_mainLayer : difficultyContainer; + auto coinSuffix = dailyID > 0 ? fmt::format("_{}", dailyID) : level->m_gauntletLevel ? "_g" : ""; + auto coinY = difficultySprite->getPositionY() - 31.5f - (showStars ? 14.0f : 0.0f) - (level->m_gauntletLevel || dailyID > 0 ? 14.5f : 0.0f); + auto coins = fakeRateData.coins; + for (int i = 1; i <= 3; i++) { + if (auto coin = static_cast(coinParent->getChildByID(fmt::format("coin-icon-{}", i)))) { + if (!m_compactView) coin->setPositionY(coinY); + auto coinStr = fmt::format("{}_{}{}", levelID, i, coinSuffix); + 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 (Loader::get()->isModLoaded("hiimjustin000.demons_in_between") && dbo > 0 && dbo < 21) { - auto demonsInBetween = Loader::get()->getLoadedMod("hiimjustin000.demons_in_between"); - auto dibFeature = ""; - if (fakeRateData.feature == 3 && demonsInBetween->getSettingValue("enable-legendary")) dibFeature = "_4"; - else if (fakeRateData.feature == 4 && demonsInBetween->getSettingValue("enable-mythic")) dibFeature = "_5"; - auto dibSprite = CCSprite::createWithSpriteFrameName(fmt::format("hiimjustin000.demons_in_between/DIB_{:02d}{}_btn_001.png", dbo, dibFeature).c_str()); - dibSprite->setID("between-difficulty-sprite"_spr); - dibSprite->setPosition(position + FakeRate::getDIBOffset(dbo, GJDifficultyName::Short)); - difficultyContainer->addChild(dibSprite, 3); - difficultySprite->setOpacity(0); - } + if (dailyID > 0) { + auto diamondLabel = static_cast(difficultyContainer->getChildByID("diamond-label")); + auto diamondIcon = static_cast(difficultyContainer->getChildByID("diamond-icon")); + auto diamonds = fakeRateData.stars > 1 ? fakeRateData.stars + 2 : 0; + diamondLabel->setString(fmt::format("{}/{}", (int)floorf(diamonds * level->m_normalPercent.value() / 100.0f), diamonds).c_str()); + diamondIcon->setPositionX(difficultySprite->getPositionX() + diamondLabel->getScaledContentWidth() * 0.5f + 2.0f); + diamondLabel->setPositionX(diamondIcon->getPositionX() - 8.0f); + } - if (Loader::get()->isModLoaded("minemaker0430.gddp_integration") && gio > 0 && gio < 16) { - auto gddpSprite = CCSprite::createWithSpriteFrameName(FakeRate::getGDDPFrame(gio, GJDifficultyName::Short).c_str()); - gddpSprite->setID("gddp-difficulty"_spr); - gddpSprite->setPosition(position + CCPoint { 0.5f, 0.0f }); - difficultyContainer->addChild(gddpSprite, 3); - difficultySprite->setOpacity(0); - } + auto padding = (showStars ? 18.0f : 25.0f) * (m_compactView ? 0.8f : 1.0f); + auto lengthLabel = static_cast(m_mainLayer->getChildByID("length-label")); + auto downloadsIcon = static_cast(m_mainLayer->getChildByID("downloads-icon")); + auto downloadsLabel = static_cast(m_mainLayer->getChildByID("downloads-label")); + downloadsIcon->setPositionX(lengthLabel->getPositionX() + lengthLabel->getScaledContentWidth() + padding); + downloadsLabel->setPositionX(downloadsIcon->getPositionX() + 9.0f); + auto likesLabel = static_cast(m_mainLayer->getChildByID("likes-label")); + auto likesIcon = static_cast(m_mainLayer->getChildByID("likes-icon")); + likesIcon->setPositionX(downloadsLabel->getPositionX() + downloadsLabel->getScaledContentWidth() + padding); + likesLabel->setPositionX(likesIcon->getPositionX() + 10.0f); + if (showStars) { + auto orbsIcon = static_cast(m_mainLayer->getChildByID("orbs-icon")); + if (!orbsIcon) { + orbsIcon = CCSprite::createWithSpriteFrameName("currencyOrbIcon_001.png"); + orbsIcon->setScale(m_compactView ? 0.4f : 0.6f); + orbsIcon->setPosition({ likesLabel->getPositionX() + likesLabel->getScaledContentWidth() + padding, likesLabel->getPositionY() }); + orbsIcon->setID("orbs-icon"); + m_mainLayer->addChild(orbsIcon); + } + auto orbsLabel = static_cast(m_mainLayer->getChildByID("orbs-label")); + if (!orbsLabel) { + orbsLabel = CCLabelBMFont::create("", "bigFont.fnt"); + orbsLabel->setScale(m_compactView ? 0.3f : 0.4f); + orbsLabel->setAnchorPoint({ 0.0f, 0.5f }); + orbsLabel->setPosition({ orbsIcon->getPositionX() + 10.0f, orbsIcon->getPositionY() }); + orbsLabel->setID("orbs-label"); + m_mainLayer->addChild(orbsLabel); } + auto orbs = FakeRate::getBaseCurrency(fakeRateData.stars); + int totalOrbs = floorf(orbs * 1.25f); + auto percent = level->m_normalPercent.value(); + auto savedLevel = GameLevelManager::get()->getSavedLevel(level); + if (savedLevel) percent = savedLevel->m_normalPercent.value(); + orbsLabel->setString((percent == 100 ? fmt::format("{}", totalOrbs) : fmt::format("{}/{}", (int)floorf(orbs * percent / 100.0f), totalOrbs)).c_str()); + orbsLabel->limitLabelWidth(45.0f, m_compactView ? 0.3f : 0.4f, 0.0f); + if (percent == 100) orbsLabel->setColor({ 100, 255, 255 }); + } + else { + if (auto orbsIcon = static_cast(m_mainLayer->getChildByID("orbs-icon"))) orbsIcon->removeFromParent(); + if (auto orbsLabel = static_cast(m_mainLayer->getChildByID("orbs-label"))) orbsLabel->removeFromParent(); } - } - void fixMoreDifficultiesIncompatibility(int mdo, int gdo, int dbo, int gio) { - auto difficultyContainer = m_mainLayer->getChildByID("difficulty-container"); - if (!difficultyContainer) difficultyContainer = m_mainLayer->getChildByID("grd-demon-icon-layer"); - auto moreDifficultiesSprite = static_cast(difficultyContainer->getChildByID("uproxide.more_difficulties/more-difficulties-spr")); - if (moreDifficultiesSprite) moreDifficultiesSprite->setVisible(false); + auto& position = difficultySprite->getPosition(); + auto mdo = fakeRateData.moreDifficultiesOverride; + auto gdo = fakeRateData.grandpaDemonOverride; + auto dbo = fakeRateData.demonsInBetweenOverride; + auto gio = fakeRateData.gddpIntegrationOverride; - auto difficultySprite = static_cast(difficultyContainer->getChildByID("difficulty-sprite")); - difficultySprite->setOpacity(255); - if ((mdo != 4 && mdo != 7 && mdo != 9) || gdo > 0 || dbo > 0 || gio > 0) return; - difficultySprite->setOpacity(0); - - auto legacy = Loader::get()->getLoadedMod("uproxide.more_difficulties")->getSettingValue("legacy-difficulties"); - if (!moreDifficultiesSprite) { - moreDifficultiesSprite = CCSprite::createWithSpriteFrameName(fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", - mdo, legacy ? "_Legacy" : "").c_str()); - moreDifficultiesSprite->setID("uproxide.more_difficulties/more-difficulties-spr"); - difficultyContainer->addChild(moreDifficultiesSprite, 3); + if (auto moreDifficulties = Loader::get()->getLoadedMod("uproxide.more_difficulties")) { + auto moreDifficultiesSprite = static_cast(difficultyContainer->getChildByID("uproxide.more_difficulties/more-difficulties-spr")); + if (moreDifficultiesSprite) moreDifficultiesSprite->setVisible(false); + + difficultySprite->setOpacity(255); + if (mdo == 4 && !moreDifficulties->getSavedValue("casual", true)) mdo = 0; + if (mdo == 7 && !moreDifficulties->getSavedValue("tough", true)) mdo = 0; + if (mdo == 9 && !moreDifficulties->getSavedValue("cruel", true)) mdo = 0; + + if ((mdo == 4 || mdo == 7 || mdo == 9) && gdo <= 0 && dbo <= 0 && gio <= 0) { + auto legacy = moreDifficulties->getSettingValue("legacy-difficulties"); + if (!moreDifficultiesSprite) { + moreDifficultiesSprite = CCSprite::createWithSpriteFrameName(fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", + mdo, legacy ? "_Legacy" : "").c_str()); + moreDifficultiesSprite->setID("uproxide.more_difficulties/more-difficulties-spr"); + difficultyContainer->addChild(moreDifficultiesSprite, 3); + } + else { + moreDifficultiesSprite->setDisplayFrame(CCSpriteFrameCache::get()->spriteFrameByName( + fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", mdo, legacy ? "_Legacy" : "").c_str())); + moreDifficultiesSprite->setVisible(true); + } + + moreDifficultiesSprite->setPosition({ + difficultySprite->getPositionX() + (legacy ? 0.0f : 0.25f), + difficultySprite->getPositionY() - (legacy ? 0.0f : 0.1f) + }); + difficultySprite->setOpacity(0); + } } - else { - moreDifficultiesSprite->setDisplayFrame(CCSpriteFrameCache::get()->spriteFrameByName( - fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", mdo, legacy ? "_Legacy" : "").c_str())); - moreDifficultiesSprite->setVisible(true); + + 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); + if (gdo == 5) { + auto grdInfinity = FREffects::grdInfinity(); + grdInfinity->setID("grandpa-demon-infinity"_spr); + grdInfinity->setPosition(position + CCPoint { -0.4f, 14.0f }); + difficultyContainer->addChild(grdInfinity); + } + difficultySprite->setOpacity(0); + } + + if (Loader::get()->isModLoaded("hiimjustin000.demons_in_between") && dbo > 0 && dbo < 21) { + auto demonsInBetween = Loader::get()->getLoadedMod("hiimjustin000.demons_in_between"); + if (demonsInBetween->getSettingValue("enable-difficulties")) { + auto dibFeature = ""; + if (fakeRateData.feature == 3 && demonsInBetween->getSettingValue("enable-legendary")) dibFeature = "_4"; + else if (fakeRateData.feature == 4 && demonsInBetween->getSettingValue("enable-mythic")) dibFeature = "_5"; + auto dibSprite = CCSprite::createWithSpriteFrameName(fmt::format("hiimjustin000.demons_in_between/DIB_{:02d}{}_btn_001.png", dbo, dibFeature).c_str()); + dibSprite->setID("between-difficulty-sprite"_spr); + dibSprite->setPosition(position + FakeRate::getDIBOffset(dbo, GJDifficultyName::Short)); + difficultyContainer->addChild(dibSprite, 3); + difficultySprite->setOpacity(0); + } } - moreDifficultiesSprite->setPosition({ - difficultySprite->getPositionX() + (legacy ? 0.0f : 0.25f), - difficultySprite->getPositionY() - (legacy ? 0.0f : 0.1f) - }); + if (Loader::get()->isModLoaded("minemaker0430.gddp_integration") && gio > 0 && gio < 16 && + Loader::get()->getLoadedMod("minemaker0430.gddp_integration")->getSettingValue("custom-difficulty-faces")) { + auto gddpSprite = CCSprite::createWithSpriteFrameName(FakeRate::getGDDPFrame(gio, GJDifficultyName::Short).c_str()); + gddpSprite->setID("gddp-difficulty"_spr); + gddpSprite->setPosition(position + CCPoint { 0.5f, 0.0f }); + difficultyContainer->addChild(gddpSprite, 3); + difficultySprite->setOpacity(0); + } } }; diff --git a/src/hooks/LevelInfoLayer.cpp b/src/hooks/LevelInfoLayer.cpp index 5977383..1497c3a 100644 --- a/src/hooks/LevelInfoLayer.cpp +++ b/src/hooks/LevelInfoLayer.cpp @@ -1,9 +1,14 @@ #include "../classes/FREditPopup.hpp" #include "../classes/FREffects.hpp" +#include +#include +#include +#include +#include +#include using namespace geode::prelude; -#include class $modify(FRLevelInfoLayer, LevelInfoLayer) { struct Fields { FakeRateSaveData m_fakeRateData; @@ -18,7 +23,6 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { static void onModify(auto& self) { (void)self.setHookPriority("LevelInfoLayer::init", -100); (void)self.setHookPriority("LevelInfoLayer::levelDownloadFinished", -100); - (void)self.setHookPriority("LevelInfoLayer::levelUpdateFinished", -100); (void)self.setHookPriority("LevelInfoLayer::likedItem", -100); } @@ -49,11 +53,6 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { checkFakeRate(); } - void levelUpdateFinished(GJGameLevel* level, UpdateResponse response) override { - LevelInfoLayer::levelUpdateFinished(level, response); - checkFakeRate(); - } - void likedItem(LikeItemType type, int id, bool liked) override { LevelInfoLayer::likedItem(type, id, liked); checkFakeRate(); @@ -61,30 +60,47 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { void checkFakeRate() { auto vec = Mod::get()->getSavedValue>("fake-rate", {}); - 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; + auto level = m_level; + auto levelID = level->m_levelID.value(); + auto i = ranges::indexOf(vec, [levelID](const FakeRateSaveData& item) { return item.id == levelID; }); + auto stars = level->m_stars.value(); + auto starsRequested = level->m_starsRequested; auto grandpaDemon = static_cast(getChildByID("grd-difficulty")); auto demonInBetween = static_cast(getChildByID("hiimjustin000.demons_in_between/between-difficulty-sprite")); auto gddpDifficulty = static_cast(getChildByID("gddp-difficulty")); auto gddpOverride = Loader::get()->isModLoaded("minemaker0430.gddp_integration") ? Loader::get()->getLoadedMod("minemaker0430.gddp_integration")->getSettingValue("override-grandpa-demon") : false; - 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, - .grandpaDemonOverride = grandpaDemon && (!gddpOverride || !gddpDifficulty) ? FakeRate::getGRDOverride(grandpaDemon) : 0, - .demonsInBetweenOverride = demonInBetween ? FakeRate::getDIBOverride(demonInBetween) : 0, - .gddpIntegrationOverride = gddpDifficulty && (!grandpaDemon || gddpOverride) && !demonInBetween ? FakeRate::getGDDPOverride(gddpDifficulty) : 0, - .coins = m_level->m_coinsVerified > 0 - }; + if (i.has_value()) updateFakeRate(vec[i.value()], false); + else { + auto mdo = 0; + if (auto moreDifficulties = Loader::get()->getLoadedMod("uproxide.more_difficulties")) { + auto casual = moreDifficulties->getSavedValue("casual", true); + auto tough = moreDifficulties->getSavedValue("tough", true); + auto cruel = moreDifficulties->getSavedValue("cruel", true); + if (stars == 4 && casual) mdo = 4; + else if (stars == 7 && tough) mdo = 7; + else if (stars == 9 && cruel) mdo = 9; + else if (stars == 0) { + if (starsRequested == 4 && casual) mdo = 4; + else if (starsRequested == 7 && tough) mdo = 7; + else if (starsRequested == 9 && cruel) mdo = 9; + } + } + m_fields->m_fakeRateData = { + .id = level->m_levelID, + .stars = stars, + .feature = level->m_featured > 1 ? level->m_isEpic + 1 : 0, + .difficulty = FakeRate::getDifficultyFromLevel(m_level), + .moreDifficultiesOverride = mdo, + .grandpaDemonOverride = grandpaDemon && (!gddpOverride || !gddpDifficulty) ? FakeRate::getGRDOverride(grandpaDemon) : 0, + .demonsInBetweenOverride = demonInBetween ? FakeRate::getDIBOverride(demonInBetween) : 0, + .gddpIntegrationOverride = gddpDifficulty && (!grandpaDemon || gddpOverride) && !demonInBetween ? FakeRate::getGDDPOverride(gddpDifficulty) : 0, + .coins = level->m_coinsVerified > 0 + }; + } } - void updateFakeRate(FakeRateSaveData data, bool remove) { + void updateFakeRate(const FakeRateSaveData& data, bool remove) { auto stars = data.stars; auto feature = data.feature; auto difficulty = data.difficulty; @@ -93,9 +109,11 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { auto dbo = data.demonsInBetweenOverride; auto gio = data.gddpIntegrationOverride; auto coins = data.coins; + auto level = m_level; + auto levelID = level->m_levelID.value(); auto f = m_fields.self(); f->m_fakeRateData = { - .id = m_level->m_levelID, + .id = levelID, .stars = stars, .feature = feature, .difficulty = difficulty, @@ -179,8 +197,10 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { featureGlow->setPosition(m_difficultySprite->getContentSize() / 2); f->m_fakeRateData.grandpaDemonOverride = hasDemon && remove ? FakeRate::getGRDOverride(static_cast(getChildByID("grd-difficulty"))) : gdo; } + auto gsm = GameStatsManager::get(); - auto showStars = stars != 0 || m_level->m_dailyID > 0 || m_level->m_gauntletLevel; + auto dailyID = level->m_dailyID.value(); + auto showStars = stars != 0 || dailyID > 0 || level->m_gauntletLevel; m_difficultySprite->updateFeatureState((GJFeatureState)feature); m_difficultySprite->updateDifficultyFrame(difficulty, GJDifficultyName::Long); auto isDemon = difficulty > 5 || gdo > 0 || dbo > 0 || gio > 0; @@ -192,28 +212,31 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { m_starsLabel->setString(std::to_string(stars).c_str()); m_starsLabel->setVisible(showStars); if (gsm->hasCompletedLevel(m_level)) m_starsLabel->setColor({ 255, 255, 50 }); + + auto coinY = position.y - 31.5f - (showStars ? 14.0f : 0.0f) - (level->m_gauntletLevel || dailyID > 0 ? 14.5f : 0.0f) - (isDemon ? 9.0f : 0.0f); + auto coinSuffix = dailyID > 0 ? fmt::format("_{}", dailyID) : level->m_gauntletLevel ? "_g" : ""; for (int i = 0; i < m_coins->count(); i++) { auto coin = static_cast(m_coins->objectAtIndex(i)); - coin->setPositionY(position.y - 31.5f - (showStars ? 14.0f : 0.0f) - - (m_level->m_gauntletLevel || m_level->m_dailyID > 0 ? 14.5f : 0.0f) - (isDemon ? 9.0f : 0.0f)); - 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"; + coin->setPositionY(coinY); + auto coinStr = fmt::format("{}_{}{}", levelID, i + 1, coinSuffix); 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 normalPercent = level->m_normalPercent.value(); + if (dailyID > 0 || level->m_gauntletLevel) { auto diamondLabel = static_cast(getChildByID("diamond-label")); auto diamondIcon = getChildByID("diamond-icon"); auto diamonds = stars > 1 ? stars + 2 : 0; - diamondLabel->setString(fmt::format("{}/{}", (int)floorf(diamonds * m_level->m_normalPercent / 100.0f), diamonds).c_str()); + diamondLabel->setString(fmt::format("{}/{}", (int)floorf(diamonds * normalPercent / 100.0f), diamonds).c_str()); diamondIcon->setPosition({ position.x + diamondLabel->getScaledContentWidth() * 0.5f + 2.0f, position.y - (isDemon ? 9.0f : 0.0f) - 44.5f }); diamondLabel->setPosition({ diamondIcon->getPositionX() - 8.0f, diamondIcon->getPositionY() }); } + auto yPos = winSize.height / 2 + 51.0f + (showStars ? 10.0f : 0.0f); auto yOffset = showStars ? 28.0f : 30.0f; auto downloadsIcon = static_cast(m_icons->objectAtIndex(1)); @@ -231,15 +254,48 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { m_orbsLabel->setPositionY(m_orbsIcon->getPositionY()); auto orbs = FakeRate::getBaseCurrency(stars); int totalOrbs = floorf(orbs * 1.25f); - m_orbsLabel->setString(fmt::format("{}/{}", - (int)floorf(m_level->m_normalPercent != 100 ? orbs * m_level->m_normalPercent / 100.0f : totalOrbs), totalOrbs).c_str()); + m_orbsLabel->setString(fmt::format("{}/{}", (int)floorf(normalPercent != 100 ? orbs * normalPercent / 100.0f : totalOrbs), totalOrbs).c_str()); m_orbsLabel->limitLabelWidth(60.0f, 0.5f, 0.0f); } if (m_exactLengthLabel->isVisible()) m_exactLengthLabel->setPositionY(m_lengthLabel->getPositionY() - 14.0f); m_difficultySprite->setOpacity(hide ? 0 : 255); - if (Loader::get()->isModLoaded("uproxide.more_difficulties")) fixMoreDifficultiesIncompatibility(mdo, remove, hide, gdo, dbo, gio); + if (auto moreDifficulties = Loader::get()->getLoadedMod("uproxide.more_difficulties")) { + auto moreDifficultiesSprite = static_cast(getChildByID("uproxide.more_difficulties/more-difficulties-spr")); + if (moreDifficultiesSprite) moreDifficultiesSprite->setVisible(false); + m_difficultySprite->setOpacity(hide ? 0 : 255); + + auto moreDifficultiesOverride = mdo; + auto starsRequested = level->m_starsRequested; + auto stars = level->m_stars.value(); + if (remove && stars == 0 && (starsRequested == 4 || starsRequested == 7 || starsRequested == 9)) moreDifficultiesOverride = starsRequested; + if (remove && (stars == 4 || stars == 7 || stars == 9)) moreDifficultiesOverride = stars; + if (moreDifficultiesOverride == 4 && !moreDifficulties->getSavedValue("casual", true)) moreDifficultiesOverride = 0; + if (moreDifficultiesOverride == 7 && !moreDifficulties->getSavedValue("tough", true)) moreDifficultiesOverride = 0; + if (moreDifficultiesOverride == 9 && !moreDifficulties->getSavedValue("cruel", true)) moreDifficultiesOverride = 0; + + if ((moreDifficultiesOverride == 4 || moreDifficultiesOverride == 7 || moreDifficultiesOverride == 9) && gdo <= 0 && dbo <= 0 && gio <= 0) { + auto legacy = moreDifficulties->getSettingValue("legacy-difficulties"); + if (!moreDifficultiesSprite) { + moreDifficultiesSprite = CCSprite::createWithSpriteFrameName(fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", + moreDifficultiesOverride, legacy ? "_Legacy" : "").c_str()); + moreDifficultiesSprite->setID("uproxide.more_difficulties/more-difficulties-spr"); + addChild(moreDifficultiesSprite, 3); + } + else { + moreDifficultiesSprite->setDisplayFrame(CCSpriteFrameCache::get()->spriteFrameByName( + fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", moreDifficultiesOverride, legacy ? "_Legacy" : "").c_str())); + moreDifficultiesSprite->setVisible(true); + } + + moreDifficultiesSprite->setPosition({ + m_difficultySprite->getPositionX() + (legacy ? 0.0f : 0.25f), + m_difficultySprite->getPositionY() - (legacy ? 0.0f : 0.1f) + }); + m_difficultySprite->setOpacity(0); + } + } auto grandpaDemon = Loader::get()->getLoadedMod("itzkiba.grandpa_demon"); auto showBackground = (hasEffects && remove) || (gdo > 2 && (grandpaDemon ? !grandpaDemon->getSettingValue("infinite-demon-disable") : false)); @@ -365,37 +421,25 @@ class $modify(FRLevelInfoLayer, LevelInfoLayer) { } else if (auto gddpSprite = getChildByID("gddp-difficulty"_spr)) gddpSprite->removeFromParent(); } +}; - void fixMoreDifficultiesIncompatibility(int mdo, bool remove, bool hide, int gdo, int dbo, int gio) { - auto moreDifficultiesSprite = static_cast(getChildByID("uproxide.more_difficulties/more-difficulties-spr")); - if (moreDifficultiesSprite) moreDifficultiesSprite->setVisible(false); - m_difficultySprite->setOpacity(hide ? 0 : 255); - - auto moreDifficultiesOverride = mdo; - auto starsRequested = m_level->m_starsRequested; - auto stars = m_level->m_stars.value(); - if (remove && stars == 0 && (starsRequested == 4 || starsRequested == 7 || starsRequested == 9)) moreDifficultiesOverride = starsRequested; - if (remove && (stars == 4 || stars == 7 || stars == 9)) moreDifficultiesOverride = stars; - if ((moreDifficultiesOverride != 4 && moreDifficultiesOverride != 7 && moreDifficultiesOverride != 9) - || gdo > 0 || dbo > 0 || gio > 0) return; - - auto legacy = Loader::get()->getLoadedMod("uproxide.more_difficulties")->getSettingValue("legacy-difficulties"); - if (!moreDifficultiesSprite) { - moreDifficultiesSprite = CCSprite::createWithSpriteFrameName(fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", - moreDifficultiesOverride, legacy ? "_Legacy" : "").c_str()); - moreDifficultiesSprite->setID("uproxide.more_difficulties/more-difficulties-spr"); - addChild(moreDifficultiesSprite, 3); - } - else { - moreDifficultiesSprite->setDisplayFrame(CCSpriteFrameCache::get()->spriteFrameByName( - fmt::format("uproxide.more_difficulties/MD_Difficulty{:02d}{}.png", moreDifficultiesOverride, legacy ? "_Legacy" : "").c_str())); - moreDifficultiesSprite->setVisible(true); - } - - moreDifficultiesSprite->setPosition({ - m_difficultySprite->getPositionX() + (legacy ? 0.0f : 0.25f), - m_difficultySprite->getPositionY() - (legacy ? 0.0f : 0.1f) - }); - m_difficultySprite->setOpacity(0); - } +#ifdef GEODE_IS_MACOS // Stupid likedItem inline expansion hook +static_assert(GEODE_COMP_GD_VERSION == 22074, "Please update this hook for the current GD version"); + +#define LevelInfoLayer_likedItem_432 base::get() + GEODE_ARM_MAC(0x256f58) GEODE_INTEL_MAC(0x2b1040) +void LevelInfoLayer_likedItem(void* self, LikeItemType type, int id, bool liked) { + reinterpret_cast((reinterpret_cast(self) - 0x1b0))->checkFakeRate(); + reinterpret_cast(LevelInfoLayer_likedItem_432)(self, type, id, liked); +} + +$execute { + auto hookRes = Mod::get()->hook( + reinterpret_cast(LevelInfoLayer_likedItem_432), + &LevelInfoLayer_likedItem, + "LevelInfoLayer::likedItem (+0x1b0)", + tulip::hook::TulipConvention::Thiscall + ); + if (hookRes.isErr()) log::error("Failed to hook LevelInfoLayer::likedItem (+0x1b0): {}", hookRes.unwrapErr()); + else hookRes.unwrap()->setPriority(-100); }; +#endif