diff --git a/jukebox/jukebox/hooks/custom_song_widget.cpp b/jukebox/jukebox/hooks/custom_song_widget.cpp index 0f4dd55..4e67911 100644 --- a/jukebox/jukebox/hooks/custom_song_widget.cpp +++ b/jukebox/jukebox/hooks/custom_song_widget.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -662,3 +664,4 @@ class $modify(JBLevelInfoLayer, LevelInfoLayer) { return true; } }; + diff --git a/jukebox/jukebox/hooks/level_select_layer.cpp b/jukebox/jukebox/hooks/level_select_layer.cpp new file mode 100644 index 0000000..33ea277 --- /dev/null +++ b/jukebox/jukebox/hooks/level_select_layer.cpp @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace geode::prelude; +using namespace jukebox; + +class $modify(JBLevelSelectLayer, LevelSelectLayer) { + struct Fields { + CCMenuItemSpriteExtra* m_jbBtn = nullptr; + }; + + void onJukebox(CCObject*) { + if (!m_scrollLayer) { + return; + } + + GJGameLevel* level = nullptr; + if (auto pageLayer = m_scrollLayer->getPage(m_scrollLayer->m_page)) { + if (auto page = typeinfo_cast(pageLayer)) { + level = page->m_level; + } + } + if (!level && m_scrollLayer->m_page > 0) { + if (auto pageLayer = m_scrollLayer->getPage(m_scrollLayer->m_page - 1)) { + if (auto page = typeinfo_cast(pageLayer)) { + level = page->m_level; + } + } + } + if (!level) { + return; + } + + const bool isRobtopSong = level->m_songID == 0; + const int rawSongID = isRobtopSong ? level->m_audioTrack : level->m_songID; + const int adjustedID = NongManager::get().adjustSongID(rawSongID, isRobtopSong); + if (adjustedID == 0) { + return; + } + + if (!NongManager::get().hasSongID(adjustedID)) { + auto title = LevelTools::getAudioTitle(rawSongID); + int artistID = LevelTools::artistForAudio(rawSongID); + std::string artist = LevelTools::nameForArtist(artistID); + + auto obj = SongInfoObject::create(rawSongID, title, artist, artistID, 0.0f, + "", "", "", 0, "", false, 0, 0); + if (!obj) { + return; + } + + auto res = NongManager::get().initSongID(obj, rawSongID, isRobtopSong); + if (res.isErr()) { + FLAlertLayer::create("Error", res.unwrapErr(), "Ok")->show(); + return; + } + } + + auto layer = NongDropdownLayer::create({adjustedID}, nullptr, adjustedID, std::nullopt); + if (!layer) { + FLAlertLayer::create("Error", "Failed to open Jukebox popup", "Ok") + ->show(); + return; + } + layer->setZOrder(106); + layer->show(); + } + + void ensureJukeboxButton() { + if (m_fields->m_jbBtn && m_fields->m_jbBtn->getParent()) { + return; + } + m_fields->m_jbBtn = nullptr; + + auto infoMenu = this->getChildByIDRecursive("info-menu"); + if (!infoMenu) { + return; + } + + auto menu = typeinfo_cast(infoMenu); + if (!menu) { + return; + } + + auto infoBtn = menu->getChildByID("info-button"); + if (!infoBtn) { + return; + } + + auto spr = CCSprite::createWithSpriteFrameName("JB_PinDisc.png"_spr); + if (!spr) { + return; + } + spr->setScale(0.65f); + spr->setID("nong-pin"_spr); + + auto btn = CCMenuItemSpriteExtra::create( + spr, this, menu_selector(JBLevelSelectLayer::onJukebox)); + btn->setID("nong-button"_spr); + + constexpr float gap = 6.f; + auto pos = infoBtn->getPosition(); + float infoBtnWidth = infoBtn->getScaledContentSize().width; + float x = pos.x - infoBtnWidth / 2.f - btn->getScaledContentSize().width / 2.f - gap; + btn->setPosition({x, pos.y}); + + menu->addChild(btn, infoBtn->getZOrder()); + m_fields->m_jbBtn = btn; + } + + bool init(int page) { + if (!LevelSelectLayer::init(page)) { + return false; + } + this->ensureJukeboxButton(); + return true; + } + + void scrollLayerMoved(cocos2d::CCPoint position) { + LevelSelectLayer::scrollLayerMoved(position); + this->ensureJukeboxButton(); + } +}; + diff --git a/mod.json b/mod.json index bfd1c38..ac89f5f 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "4.6.2", + "geode": "4.10.0", "version": "3.4.0", "id": "fleym.nongd", "name": "Jukebox",