Skip to content

Commit

Permalink
v1.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
hiimjasmine00 committed Jun 22, 2024
1 parent 407fb14 commit 47091af
Show file tree
Hide file tree
Showing 10 changed files with 565 additions and 449 deletions.
1 change: 0 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ jobs:
with:
build-config: RelWithDebInfo
export-pdb: true
sdk: v3.0.0-beta.1
combine: true
target: ${{ matrix.config.target }}

Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64")
set(CMAKE_CXX_VISIBILITY_PRESET hidden)

project(FakeRate VERSION 1.1.9)
project(FakeRate VERSION 1.2.0)

add_library(${PROJECT_NAME} SHARED
src/FakeRate.cpp
src/FREditPopup.cpp
src/FRLevelInfoLayer.cpp
src/main.cpp
)

Expand Down
4 changes: 2 additions & 2 deletions mod.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"geode": "3.0.0-beta.1",
"geode": "3.0.0-beta.5",
"gd": {
"android": "2.206",
"win": "2.206",
"mac": "2.206"
},
"version": "v1.1.9",
"version": "v1.2.0",
"id": "hiimjustin000.fake_rate",
"name": "Fake Rate",
"developer": "hiimjustin000",
Expand Down
549 changes: 226 additions & 323 deletions src/FREditPopup.cpp

Large diffs are not rendered by default.

96 changes: 34 additions & 62 deletions src/FREditPopup.hpp
Original file line number Diff line number Diff line change
@@ -1,83 +1,55 @@
#include <vector>
#include "FakeRate.hpp"
#include "FRLevelInfoLayer.hpp"

struct FakeRateSaveData {
int id;
int stars;
int feature;
int difficulty;
};

#include <Geode/modify/LevelInfoLayer.hpp>
class FRLevelInfoLayerDummy; struct FRLevelInfoLayer : Modify<FRLevelInfoLayer, LevelInfoLayer> {
struct Fields {
FakeRateSaveData m_fakeRateData;
};
static void onModify(auto& self);
bool init(GJGameLevel*, bool);
void levelDownloadFinished(GJGameLevel*);
void levelUpdateFinished(GJGameLevel*, UpdateResponse);
void likedItem(LikeItemType, int, bool);
void checkFakeRate();
void updateFakeRate(int, int, int, bool, bool);
void fixMoreDifficultiesIncompatibility(CCNode*);
};

class FREditPopup : public Popup<FRLevelInfoLayer*, GJGameLevel*, int, int, int> {
class FREditPopup : public Popup<FRLevelInfoLayer*, GJGameLevel*, int, int, int, int>, SetIDPopupDelegate {
protected:
FRLevelInfoLayer* m_delegate;
GJGameLevel* m_level;
int m_stars;
int m_feature;
int m_difficulty;
int m_moreDifficultiesOverride;
bool m_legacy;
GJDifficultySprite* m_difficultySprite;
CCSprite* m_casualSprite;
CCSprite* m_toughSprite;
CCSprite* m_cruelSprite;
CCSprite* m_starSprite;
CCLabelBMFont* m_starsLabel;
CCMenuItemSpriteExtra* m_starLeftArrow;
CCMenuItemSpriteExtra* m_starRightArrow;
CCMenuItemSpriteExtra* m_difficultyLeftArrow;
CCMenuItemSpriteExtra* m_difficultyRightArrow;
CCMenuItemSpriteExtra* m_featureLeftArrow;
CCMenuItemSpriteExtra* m_featureRightArrow;
CCArray* m_coins;

bool setup(FRLevelInfoLayer*, GJGameLevel*, int, int, int) override;
bool setup(FRLevelInfoLayer*, GJGameLevel*, int, int, int, int) override;
void updateLabels();
public:
static FREditPopup* create(FRLevelInfoLayer*, GJGameLevel*, int, int, int);
static FREditPopup* create(FRLevelInfoLayer*, GJGameLevel*, int, int, int, int);

void setIDPopupClosed(SetIDPopup*, int) override;

~FREditPopup() override;
};

template<>
struct matjson::Serialize<std::vector<FakeRateSaveData>> {
static std::vector<FakeRateSaveData> from_json(matjson::Value const& value) {
auto vec = std::vector<FakeRateSaveData>{};
for (auto const& item : value.as_array()) {
vec.push_back({
.id = item["id"].as_int(),
.stars = item["stars"].as_int(),
.feature = item["feature"].as_int(),
.difficulty = item["difficulty"].as_int()
});
}
return vec;
}
class FRSetDifficultyPopup : public Popup<int, int, bool, MiniFunction<void(int, int)>> {
protected:
int m_difficulty;
int m_moreDifficultiesOverride;
bool m_legacy;
CCMenuItemSpriteExtra* m_selected;

bool setup(int, int, bool, MiniFunction<void(int, int)>) override;
void createDifficultyToggle(CCMenu*, int, int);
public:
static FRSetDifficultyPopup* create(int, int, bool, MiniFunction<void(int, int)>);
};

static matjson::Value to_json(std::vector<FakeRateSaveData> const& vec) {
auto arr = matjson::Array{};
for (auto const& item : vec) {
arr.push_back(matjson::Object {
{ "id", item.id },
{ "stars", item.stars },
{ "feature", item.feature },
{ "difficulty", item.difficulty }
});
}
return arr;
}
class FRSetFeaturePopup : public Popup<int, int, int, bool, MiniFunction<void(int)>> {
protected:
GJFeatureState m_feature;
int m_difficulty;
int m_moreDifficultiesOverride;
bool m_legacy;
CCMenuItemSpriteExtra* m_selected;

static bool is_json(matjson::Value const& value) {
return value.is_array();
}
bool setup(int, int, int, bool, MiniFunction<void(int)>) override;
void createFeatureToggle(CCMenu*, GJFeatureState);
public:
static FRSetFeaturePopup* create(int, int, int, bool, MiniFunction<void(int)>);
};
208 changes: 208 additions & 0 deletions src/FRLevelInfoLayer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
#include "FREditPopup.hpp"

void FRLevelInfoLayer::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);
}

bool FRLevelInfoLayer::init(GJGameLevel* level, bool challenge) {
if (!LevelInfoLayer::init(level, challenge)) return false;

auto buttonSprite = CircleButtonSprite::createWithSprite("FR_fakeRateBtn_001.png"_spr, 1.0f, CircleBaseColor::Green, CircleBaseSize::Medium);
buttonSprite->getTopNode()->setScale(1.0f);
auto fakeRateButton = CCMenuItemExt::createSpriteExtra(buttonSprite, [this](auto) {
FREditPopup::create(this, m_level, m_fields->m_fakeRateData.stars, m_fields->m_fakeRateData.feature,
m_fields->m_fakeRateData.difficulty, m_fields->m_fakeRateData.moreDifficultiesOverride)->show();
});
fakeRateButton->setID("fake-rate-button"_spr);
auto leftSideMenu = getChildByID("left-side-menu");
leftSideMenu->addChild(fakeRateButton);
leftSideMenu->updateLayout();

checkFakeRate();

return true;
}

void FRLevelInfoLayer::levelDownloadFinished(GJGameLevel* level) {
LevelInfoLayer::levelDownloadFinished(level);
checkFakeRate();
}

void FRLevelInfoLayer::levelUpdateFinished(GJGameLevel* level, UpdateResponse response) {
LevelInfoLayer::levelUpdateFinished(level, response);
checkFakeRate();
}

void FRLevelInfoLayer::likedItem(LikeItemType type, int id, bool liked) {
LevelInfoLayer::likedItem(type, id, liked);
checkFakeRate();
}

void FRLevelInfoLayer::checkFakeRate() {
auto vec = Mod::get()->getSavedValue<std::vector<FakeRateSaveData>>("fake-rate", {});
auto it = std::find_if(vec.begin(), vec.end(), [this](auto const& item) { return item.id == m_level->m_levelID; });
auto stars = m_level->m_stars;
if (it != vec.end()) updateFakeRate(it->stars, it->feature, it->difficulty, it->moreDifficultiesOverride, false, true);
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 = stars == 4 || stars == 7 || stars == 9 ? stars : 0
};
}

void FRLevelInfoLayer::updateFakeRate(int stars, int feature, int difficulty, int mdo, bool update, bool coins) {
m_fields->m_fakeRateData = {
.id = m_level->m_levelID,
.stars = stars,
.feature = feature,
.difficulty = difficulty,
.moreDifficultiesOverride = mdo
};

if (auto betweenDifficultySprite = static_cast<CCSprite*>(getChildByID("hiimjustin000.demons_in_between/between-difficulty-sprite"))) {
betweenDifficultySprite->setVisible(false);
m_difficultySprite->setOpacity(255);
}
auto gddpOverride = false;
if (auto gddpDifficultySprite = static_cast<CCSprite*>(getChildByID("gddp-difficulty"))) {
gddpOverride = gddpDifficultySprite->isVisible();
gddpDifficultySprite->setVisible(false);
m_difficultySprite->setOpacity(255);
}
if (Loader::get()->isModLoaded("itzkiba.grandpa_demon") && !gddpOverride) {
removeChildByTag(69420);
auto children = reinterpret_cast<CCNode**>(getChildren()->data->arr);
for (int i = 0; i < getChildrenCount(); i++) {
if (children[i]->getID() == "grd-difficulty") children[i]->setVisible(false);
}
if (auto grdInfinity = getChildByID("grd-infinity")) grdInfinity->setVisible(false);
m_difficultySprite->setVisible(true);
if (auto featureGlow = m_difficultySprite->getChildByTag(69420))
featureGlow->setPosition(m_difficultySprite->getContentSize() * 0.5f);
}
auto winSize = CCDirector::sharedDirector()->getWinSize();
auto gsm = GameStatsManager::sharedState();
auto showStars = stars > 0 || m_level->m_dailyID > 0 || m_level->m_gauntletLevel;
m_difficultySprite->updateDifficultyFrame(difficulty, GJDifficultyName::Long);
m_difficultySprite->updateFeatureState((GJFeatureState)feature);
CCNode* nodeToSetPosition = m_difficultySprite;
CCNode* difficultySpriteParent = m_difficultySprite->getParent();
if (Loader::get()->isModLoaded("acaruso.horn")) {
auto children = getChildren();
for (int i = 0; i < children->count(); i++) {
if (auto child = typeinfo_cast<CCMenu*>(children->objectAtIndex(i))) {
auto grandchildren = child->getChildren();
if (!grandchildren || grandchildren->count() < 1) continue;
if (auto button = typeinfo_cast<CCMenuItemSpriteExtra*>(grandchildren->objectAtIndex(0))) {
if (button->getNormalImage() == m_difficultySprite) {
nodeToSetPosition = child;
difficultySpriteParent = button;
break;
}
}
}
}
}
nodeToSetPosition->setPositionY(winSize.height / 2 + 56.0f + (difficulty > 5 ? 5.0f : 0.0f) + (showStars ? 10.0f : 0.0f));
auto& position = nodeToSetPosition->getPosition();
m_starsIcon->setPosition({ position.x + 8.0f, position.y - 30.0f - (difficulty > 5 ? 9.0f : 0.0f) });
m_starsIcon->setVisible(showStars);
m_starsLabel->setPosition(m_starsIcon->getPositionX() - 8.0f, m_starsIcon->getPositionY());
m_starsLabel->setString(std::to_string(stars).c_str());
m_starsLabel->setVisible(showStars);
m_starsLabel->setColor({ 255, 255, (unsigned char)(gsm->hasCompletedLevel(m_level) ? 50 : 255) });
for (int i = 0; i < m_coins->count(); i++) {
auto coin = static_cast<CCSprite*>(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) - (difficulty > 5 ? 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";
if (coins || m_level->m_coinsVerified == 1)
coin->setColor(gsm->hasUserCoin(coinStr.c_str()) || gsm->hasPendingUserCoin(coinStr.c_str()) ? ccColor3B { 255, 255, 255 } : ccColor3B { 165, 165, 165 });
else coin->setColor(gsm->hasUserCoin(coinStr.c_str()) || gsm->hasPendingUserCoin(coinStr.c_str()) ? ccColor3B { 255, 175, 75 } : ccColor3B { 165, 113, 48 });
}
if (m_level->m_dailyID > 0 || m_level->m_gauntletLevel) {
auto diamondLabel = static_cast<CCLabelBMFont*>(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());
diamondIcon->setPosition({
position.x + diamondLabel->getScaledContentSize().width * 0.5f + 2.0f,
position.y - (difficulty > 5 ? 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<CCSprite*>(m_icons->objectAtIndex(1));
downloadsIcon->setPositionY(yPos + yOffset);
m_downloadsLabel->setPositionY(downloadsIcon->getPositionY());
m_likesIcon->setPositionY(yPos + 1.0f);
m_likesLabel->setPositionY(m_likesIcon->getPositionY());
auto lengthIcon = static_cast<CCSprite*>(m_icons->objectAtIndex(0));
lengthIcon->setPositionY(yPos - yOffset);
m_lengthLabel->setPositionY(lengthIcon->getPositionY() + (m_exactLengthLabel->isVisible() ? 6.0f : 0.0f));
m_orbsIcon->setVisible(showStars);
m_orbsLabel->setVisible(showStars);
if (showStars) {
m_orbsIcon->setPositionY(yPos - yOffset * 2.0f);
m_orbsLabel->setPositionY(m_orbsIcon->getPositionY());
auto orbs = FakeRate::getBaseCurrency(stars);
auto totalOrbs = (int)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->limitLabelWidth(60.0f, 0.5f, 0.0f);
}
if (m_exactLengthLabel->isVisible()) m_exactLengthLabel->setPositionY(m_lengthLabel->getPositionY() - 14.0f);

if (Loader::get()->isModLoaded("uproxide.more_difficulties")) fixMoreDifficultiesIncompatibility(difficultySpriteParent, mdo, !coins);
}

void FRLevelInfoLayer::fixMoreDifficultiesIncompatibility(CCNode* difficultySpriteParent, int mdo, bool remove) {
auto spriteName = std::string();
auto moreDifficultiesSprite = static_cast<CCSprite*>(getChildByID("uproxide.more_difficulties/more-difficulties-spr"));
if (moreDifficultiesSprite) {
moreDifficultiesSprite->setVisible(false);
spriteName = FakeRate::getSpriteName(moreDifficultiesSprite);
}
m_difficultySprite->setOpacity(255);

auto legacy = Loader::get()->getLoadedMod("uproxide.more_difficulties")->getSettingValue<bool>("legacy-difficulties");
auto pos = difficultySpriteParent->convertToWorldSpace({
m_difficultySprite->getPositionX() + (legacy ? 0.0f : 0.25f),
m_difficultySprite->getPositionY() - (legacy ? 0.0f : 0.1f)
});
auto frameName = "";
auto stars = m_fields->m_fakeRateData.stars;
if (spriteName == "uproxide.more_difficulties/MD_DifficultyCP.png") {
moreDifficultiesSprite->setVisible(true);
m_difficultySprite->setOpacity(0);
}
else {
auto moreDifficultiesOverride = mdo;
auto starsRequested = m_level->m_starsRequested;
if (remove && (starsRequested == 4 || starsRequested == 7 || starsRequested == 9)) moreDifficultiesOverride = starsRequested;
if (moreDifficultiesOverride == 0) return;
switch (moreDifficultiesOverride) {
case 4: frameName = legacy ? "uproxide.more_difficulties/MD_Difficulty04_Legacy.png" : "uproxide.more_difficulties/MD_Difficulty04.png"; break;
case 7: frameName = legacy ? "uproxide.more_difficulties/MD_Difficulty07_Legacy.png" : "uproxide.more_difficulties/MD_Difficulty07.png"; break;
case 9: frameName = legacy ? "uproxide.more_difficulties/MD_Difficulty09_Legacy.png" : "uproxide.more_difficulties/MD_Difficulty09.png"; break;
}
if (!moreDifficultiesSprite) {
moreDifficultiesSprite = CCSprite::createWithSpriteFrameName(frameName);
moreDifficultiesSprite->setID("uproxide.more_difficulties/more-difficulties-spr");
addChild(moreDifficultiesSprite, 3);
}
else {
moreDifficultiesSprite->initWithSpriteFrameName(frameName);
moreDifficultiesSprite->setVisible(true);
}
moreDifficultiesSprite->setPosition(pos);
m_difficultySprite->setOpacity(0);
}
}
16 changes: 16 additions & 0 deletions src/FRLevelInfoLayer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "FakeRate.hpp"

#include <Geode/modify/LevelInfoLayer.hpp>
class $modify(FRLevelInfoLayer, LevelInfoLayer) {
struct Fields {
FakeRateSaveData m_fakeRateData;
};
static void onModify(auto& self);
bool init(GJGameLevel*, bool);
void levelDownloadFinished(GJGameLevel*) override;
void levelUpdateFinished(GJGameLevel*, UpdateResponse) override;
void likedItem(LikeItemType, int, bool) override;
void checkFakeRate();
void updateFakeRate(int, int, int, int, bool, bool);
void fixMoreDifficultiesIncompatibility(CCNode*, int, bool);
};
Loading

0 comments on commit 47091af

Please sign in to comment.