diff --git a/include/GC2D/PauseMenu2.hpp b/include/GC2D/PauseMenu2.hpp index 8ba13e20f..b7040df79 100644 --- a/include/GC2D/PauseMenu2.hpp +++ b/include/GC2D/PauseMenu2.hpp @@ -1,7 +1,9 @@ #ifndef GC2D_PAUSE_MENU_2_HPP #define GC2D_PAUSE_MENU_2_HPP +#include #include +#include class J2DPicture; class J2DSetScreen; @@ -18,46 +20,77 @@ class TPauseMenu2 : public JDrama::TViewObj { void loadAfter(); void appearWindow(); void disappearWindow(); - void perform(u32, JDrama::TGraphics*); + void perform(u32 flags, JDrama::TGraphics* gfx); u8 getNextState(); void setDrawStart(); void setDrawEnd(); - void drawAppearPane(J2DPicture*, f32, JUTRect&, f32); + void drawAppearPane(J2DPicture* picture, f32 anim, JUTRect& rect, + f32 rotation); + + // fabricated; smells fake + void setEmitterScale(f32 x, f32 y, f32 z) + { + mEmitter->setScale2(JGeometry::TVec3(x, y, z)); + } + + // fabricated + inline void draw(JDrama::TGraphics* gfx); public: - /* 0x10 */ u32 unk10; - /* 0x14 */ J2DSetScreen* unk14; - /* 0x18 */ J2DPane* unk18; - /* 0x1C */ J2DPane* unk1C; - /* 0x20 */ J2DPane* unk20[5]; - /* 0x34 */ JUTRect unk34[5]; - /* 0x84 */ f32 unk84; - /* 0x88 */ f32 unk88; - /* 0x8C */ f32 unk8C; - /* 0x90 */ f32 unk90; - /* 0x94 */ u32 unk94; - /* 0x98 */ J2DPane* unk98[3]; - /* 0xA4 */ JUTRect unkA4[3]; - /* 0xD4 */ J2DTextBox* unkD4; - /* 0xD8 */ J2DPane* unkD8; - /* 0xDC */ J2DTextBox* unkDC; - /* 0xE0 */ u8 unkE0; - /* 0xE4 */ u32 unkE4; - /* 0xE8 */ u32 unkE8; - /* 0xEC */ u32 unkEC; - /* 0xF0 */ char unkF0[4]; - /* 0xF4 */ u32 unkF4; - /* 0xF8 */ u16 unkF8; - /* 0xFC */ u32 unkFC; - /* 0x100 */ u16 unk100; - /* 0x102 */ u16 unk102; - /* 0x104 */ int unk104; - /* 0x108 */ u8 unk108; - /* 0x109 */ u8 unk109; - /* 0x110 */ JPABaseEmitter* unk110; - /* 0x10C */ TMarioGamePad* unk10C; - /* 0x114 */ u32 unk114; - /* 0x118 */ TCardSave* unk118; + enum PauseMenuState { + MENU_APPEARING = 0, + MENU_OPEN = 1, + UNK2 = 2, + MENU_SAVING = 3, + MENU_DISAPPEARING = 4, + MENU_CLOSED = 5 + }; + + // Menu state. + /* 0x10 */ PauseMenuState mState; + + // Screen and menu/background panes. + /* 0x14 */ J2DSetScreen* mScreen; + /* 0x18 */ J2DPane* mBackground; + /* 0x1C */ J2DPane* mMenuPane; + + // "Pause" letters. + /* 0x20 */ J2DPicture* mPauseLetters[5]; + /* 0x34 */ JUTRect mOrigLetterBounds[5]; + /* 0x84 */ f32 mOrigLetterAngles[5]; + + // Menu items. + /* 0x98 */ J2DPicture* mMenuItems[3]; + /* 0xA4 */ JUTRect mOrigItemBounds[3]; + + // Stage and scenario name. + /* 0xD4 */ J2DTextBox* mStageName; + /* 0xD8 */ J2DPane* mStagePane; + /* 0xDC */ J2DTextBox* mScenarioName; + + // Menu option items. + /* 0xE0 */ u8 mSelectedItem; + /* 0xE4 */ u32 mItemColor; + /* 0xE8 */ f32 mBounceAnim; + + // Appear/disappear animation. + /* 0xEC */ f32 mFadeAnim; + /* 0xF0 */ u8 mBackgroundAlpha; + /* 0xF4 */ f32 mBackgroundFadeInSpeed; + /* 0xF8 */ s16 mFirstItemAngle; + /* 0xFC */ u32 unkFC; // unused? + + // "Spark" effect for the bouncing animation. + /* 0x100 */ s16 mEffectKeyFrame; + /* 0x102 */ u16 mEffectStretch; + + /* 0x104 */ s32 mNumItems; + /* 0x108 */ bool mPressedB; + /* 0x109 */ bool mSelectionConfirmed; + /* 0x10C */ TMarioGamePad* mGamePad; + /* 0x110 */ JPABaseEmitter* mEmitter; + /* 0x114 */ u32 unk114; // unused? + /* 0x118 */ TCardSave* mCardSave; }; #endif diff --git a/include/JSystem/J2D/J2DPane.hpp b/include/JSystem/J2D/J2DPane.hpp index 241439554..b3f48a32f 100644 --- a/include/JSystem/J2D/J2DPane.hpp +++ b/include/JSystem/J2D/J2DPane.hpp @@ -100,7 +100,14 @@ class J2DPane { // fabricated const JUTRect& getBounds() const { return mBounds; } void setBounds(const JUTRect& bounds) { mBounds = bounds; } + void setBounds(s32 x1, s32 x2, s32 y1, s32 y2) + { + mBounds = JUTRect(x1, x2, y1, y2); + } const JUTRect& getGlobalBounds() const { return mGlobalBounds; } + f32 getRotation() const { return mRotation; } + + const JUTRect& getScissorBounds() const { return mScissorBounds; } void setInfluenceAlpha(bool influence) { mIsInfluencedAlpha = influence; } diff --git a/include/JSystem/J2D/J2DPicture.hpp b/include/JSystem/J2D/J2DPicture.hpp index 0d8f89247..54c24442e 100644 --- a/include/JSystem/J2D/J2DPicture.hpp +++ b/include/JSystem/J2D/J2DPicture.hpp @@ -98,6 +98,9 @@ class J2DPicture : public J2DPane { setBlendKonstAlpha(); } + // fabricated + JUtility::TColor getWhite() const { return mWhite; } + public: /* 0xEC */ JUTTexture* mTextures[4]; /* 0xFC */ u8 mTextureNum; diff --git a/include/JSystem/JParticle/JPAEmitter.hpp b/include/JSystem/JParticle/JPAEmitter.hpp index c627b3c35..b5af4622a 100644 --- a/include/JSystem/JParticle/JPAEmitter.hpp +++ b/include/JSystem/JParticle/JPAEmitter.hpp @@ -147,6 +147,12 @@ class JPABaseEmitter { void setUnk190(f32 x, f32 y, f32 z) { mScale.set(x, y, z); } + // fabricated + void setScale2(JGeometry::TVec3 scale) + { + mScale.x = scale.x, mScale.y = scale.y, mScale.z = scale.z; + } + void setRotation(s16 x, s16 y, s16 z) { unk16C.x = x; diff --git a/src/GC2D/PauseMenu2.cpp b/src/GC2D/PauseMenu2.cpp index 8b1378917..1fbcb4d29 100644 --- a/src/GC2D/PauseMenu2.cpp +++ b/src/GC2D/PauseMenu2.cpp @@ -1 +1,600 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +extern JPAEmitterManager* gpEmitterManager4D2; +MSound* gpMSound; + +// rogue includes needed for matching sinit & bss +#include +#include +#include +#include + +// fabricated +void TPauseMenu2::draw(JDrama::TGraphics* gfx) +{ + J2DOrthoGraph graph(gfx->getViewport()); + graph.setup2D(); + mScreen->draw(0, 0, &graph); + gfx->setScissor(gfx->getScissor()); +} + +TPauseMenu2::TPauseMenu2(const char* pName) + : JDrama::TViewObj(pName) + , mState(MENU_CLOSED) + , mScreen(nullptr) + , mBackground(nullptr) + , mMenuPane(nullptr) + , mStageName(nullptr) + , mStagePane(nullptr) + , mScenarioName(nullptr) + , mSelectedItem(0) + , mBounceAnim(0.0f) + , mFadeAnim(0.0f) + , mFirstItemAngle(0) + , unkFC(6) + , mEffectKeyFrame(3) + , mEffectStretch(129) + , mNumItems(3) + , mPressedB(false) + , mSelectionConfirmed(false) + , mEmitter(nullptr) + , unk114(0) +{ +} + +void TPauseMenu2::load(JSUMemoryInputStream& pStream) +{ + JDrama::TViewObj::load(pStream); + + JKRArchive* arch = (JKRArchive*)JKRFileLoader::getVolume("game_6"); + mScreen = new J2DSetScreen("pause_1.blo", arch); + mScreen->setCullBack(GX_CULL_BACK); + + if (gpApplication.mCurrArea.unk0 <= 1) { + // Hide "Exit Area" option in Delfino Plaza. + mNumItems = 2; + } + + mBackground = mScreen->search('mask'); + mMenuPane = mScreen->search('t_0'); + + for (s32 i = 0; i < 5; i++) { + mPauseLetters[i] = (J2DPicture*)mScreen->search('t_0' + i); + } + + for (s32 i = 0; i < 3; i++) { + mMenuItems[i] = (J2DPicture*)mScreen->search('tx_1' + i); + + if (mNumItems == 2) { + mMenuItems[i]->add(0, 14); + } + mMenuItems[i]->mVisible = false; + } + + mStageName = (J2DTextBox*)mScreen->search('map'); + mStageName->setFont(gpSystemFont); + + mScenarioName = (J2DTextBox*)mScreen->search('task'); + SMSMakeTextBuffer(mScenarioName, 0x80); + mScenarioName->setFont(gpSystemFont); + + mStagePane = mScreen->search('brek'); + + u32 shineStage = SMS_getShineStage(gpMarDirector->mMap); + s32 flag = TFlagManager::getInstance()->getFlag(0x40003); + + mStageName->setString(SMSGetMessageData( + JKRFileLoader::getGlbResource("/common/2d/stagename.bmg"), shineStage)); + + if (gpMarDirector->mMap != 0xF) { + void* scenarioBmg + = JKRFileLoader::getGlbResource("/common/2d/scenarioname.bmg"); + s16 shineID = SMS_getShineID(shineStage, flag, false); + const char* scenarioName; + if (scenarioBmg == nullptr || shineID == -1 || shineStage == 0) { + scenarioName = ""; + mStageName->add(0, 0xF); + mMenuPane->add(0, 0x1E); + } else { + // TODO: This doesn't match for some reason. + scenarioName + = SMSGetMessageData(scenarioBmg, SMS_getNormalStage(shineID)); + } + snprintf(mScenarioName->getStringPtr(), 0x80, "%s", scenarioName); + } +} + +void TPauseMenu2::loadAfter() +{ + // "Save data" + mCardSave = JDrama::TNameRefGen::search("データセーブ"); + + mItemColor = mMenuItems[0]->getWhite(); + + for (s32 i = 0; i < mNumItems; i++) { + mOrigItemBounds[i] = mMenuItems[i]->getBounds(); + } + + for (s32 i = 0; i < 5; i++) { + mOrigLetterBounds[i] = mPauseLetters[i]->getBounds(); + mOrigLetterAngles[i] = mPauseLetters[i]->getRotation(); + } + + mBackgroundAlpha = mBackground->mAlpha; + mBackgroundFadeInSpeed = mBackgroundAlpha / 45.0f; + + mFirstItemAngle = mMenuItems[0]->mRotation; + + if (mFirstItemAngle > 180) { + mFirstItemAngle -= 360; + } + + mGamePad = gpMarDirector->unk18[0]; +} + +void TPauseMenu2::appearWindow() +{ + if (mFadeAnim <= 45.0f) { + for (s32 i = 0; i < 5; i++) { + // Animate each letter with a delay. + f32 letterAnim = mFadeAnim - 5.0f * i; + drawAppearPane(mPauseLetters[i], letterAnim, mOrigLetterBounds[i], + (180.0f + mOrigLetterAngles[i] - 9.0f * letterAnim)); + } + + // Fade in background. + s32 bgrAlpha = mBackgroundFadeInSpeed * mFadeAnim * 1.5f; + bgrAlpha = bgrAlpha > mBackgroundAlpha ? mBackgroundAlpha : bgrAlpha; + mBackground->mAlpha = bgrAlpha; + } + + // Fade in stage/shine panel. + s32 stageAlpha = mFadeAnim * mBackgroundFadeInSpeed * 1.5f; + if (stageAlpha > mBackgroundAlpha) { + stageAlpha = 0xFF; + } + mStagePane->mAlpha = stageAlpha; + + // Animate in menu items. + if (mFadeAnim >= 30.0f) { + for (s32 i = 0; i < mNumItems; ++i) { + if (!mMenuItems[i]->mVisible) { + mMenuItems[i]->mVisible = true; + mMenuItems[i]->mAlpha = 0; + } + + JUTRect rect = mOrigItemBounds[i]; + + if (mFadeAnim <= 40.0f) { + s32 hx = 3.0f * (mFadeAnim - 35.0f); + s32 hy = 1.5f * (mFadeAnim - 35.0f); + rect.reform(-hx, -hy, hx, hy); + + mMenuItems[i]->setBounds(rect); + + // TODO: This looks a bit fake... + f32 alphaF = 26.0f * (mFadeAnim - 30.0f); + s32 alpha = alphaF; + if ((s32)alphaF > 0xFF) { + alpha = 0xFF; + } + mMenuItems[i]->mAlpha = alpha; + + // The first item gets some extra "bounce". + if (i == 0) { + s16 angle = mFirstItemAngle * 0.1f * (mFadeAnim - 30.0f); + mMenuItems[i]->mRotation = angle; + } + } else if (mFadeAnim <= 45.0f) { + s32 hx = 3.0f * (mFadeAnim - 45.0f); + s32 hy = 1.5f * (mFadeAnim - 45.0f); + rect.reform(hx, hy, -hx, -hy); + + mMenuItems[i]->setBounds(rect); + } else if (mFadeAnim <= 46.0f) { + // Fade in animation complete; set state to open. + if (mState != MENU_OPEN) { + mState = MENU_OPEN; + } + } + } + } + + mFadeAnim += 0.5f; +} + +void TPauseMenu2::disappearWindow() +{ + // Delete emitter and reset selected item back to its original size. + if (mFadeAnim == 0.0f && mEmitter != 0) { + gpEmitterManager4D2->forceDeleteEmitter(mEmitter); + mMenuItems[mSelectedItem]->setBounds(mOrigItemBounds[mSelectedItem]); + } + + if (mFadeAnim <= 10.0f) { + + // Fade out menu, background, and shine/stage panel. + s32 alpha + = (mMenuPane->getAlpha() - 12) < 0 ? 0 : mMenuPane->getAlpha() - 12; + + mMenuPane->setAlpha(alpha); + + if (alpha < mBackground->getAlpha()) { + mBackground->setAlpha(alpha); + } + + if (alpha < mStagePane->getAlpha()) { + mStagePane->setAlpha(alpha); + } + + // Shrink letters... + for (s32 i = 0; i < 5; i++) { + JUTRect rect = mPauseLetters[i]->getBounds(); + + rect.add(0.25f * -rect.y1 + 0.01f * rect.getWidth(), + 0.25f * -rect.x1 + 0.01f * rect.getHeight()); + + rect.resize(0.98f * rect.getWidth(), 0.98f * rect.getHeight()); + + mPauseLetters[i]->setBounds(rect); + } + + // ... and now shrink the menu items in the same manner. + for (s32 i = 0; i < mNumItems; i++) { + JUTRect rect = mMenuItems[i]->getBounds(); + rect.add(0.25f * -rect.y1 + 0.01f * rect.getWidth(), + 0.25f * -rect.x1 + 0.01f * rect.getHeight()); + rect.resize(0.98f * rect.getWidth(), 0.98f * rect.getHeight()); + mMenuItems[i]->setBounds(rect); + } + + // Rotate menu clockwise. + mMenuPane->mRotation = -mFadeAnim * 2.0f; + } else { + // Fade out animation complete; set state to MENU_CLOSED. + mState = MENU_CLOSED; + } + + mFadeAnim += 0.5f; +} + +void TPauseMenu2::perform(u32 flags, JDrama::TGraphics* gfx) +{ + if (gpMarDirector->mState == TMarDirector::STATE_UNK5) { + if (mState == MENU_SAVING) { + if (flags & 0x1) { + if (mCardSave->unk2DF != 0) { + mSelectionConfirmed = false; + mState = MENU_OPEN; + } + + s16 alpha = mMenuPane->getAlpha(); + + alpha -= 16; + if (alpha < 0) { + alpha = 0; + } + + mMenuPane->setAlpha(alpha); + } + if (flags & 0x8) { + switch (mState) { + + case MENU_APPEARING: + draw(gfx); + break; + case MENU_OPEN: + case UNK2: + case MENU_SAVING: + case MENU_DISAPPEARING: + draw(gfx); + break; + default: + break; + } + } + } else { + if (flags & 0x1) { + switch (mState) { + case MENU_APPEARING: + appearWindow(); + break; + case MENU_OPEN: { + s32 curSelectedItem = mSelectedItem; + if (mGamePad->checkFrameMeaning(0x21)) { + // Confirm currently selected item. + switch (curSelectedItem) { + case 0: + mSelectionConfirmed = true; + SMSRumbleMgr->finishPause(); + gpMSound->pauseOff(0); + gpMarDirector->getConsole()->pauseOut(); + mFadeAnim = 0.0f; + mState = MENU_APPEARING; + break; + case 2: + mSelectionConfirmed = true; + setDrawEnd(); + break; + case 3: + mSelectionConfirmed = true; + setDrawEnd(); + break; + case 1: + SMSGetMSound()->startSoundSystemSE( + MSD_SE_SY_PAUSE_ON, 0, nullptr, 0); + + mSelectionConfirmed = true; + mCardSave->init(0); + mState = MENU_SAVING; + default: + break; + } + } else if (mGamePad->checkFrameMeaning(0x40)) { + // Close pause menu by pressing B. + mPressedB = true; + mFadeAnim = 0.0f; + setDrawEnd(); + } else if (mGamePad->checkFrameMeaning(0x4)) { + // Select the next item. + if (mNumItems > 2) { + mSelectedItem = curSelectedItem < (mNumItems - 1) + ? curSelectedItem + 1 + : 0; + } else { + // don't loop back around with less than three items + mSelectedItem = mNumItems - 1; + } + if (mSelectedItem != curSelectedItem) { + SMSGetMSound()->startSoundSystemSE(MSD_SE_SY_CURSOR, + 0, nullptr, 0); + + JUTRect& bounds = mOrigItemBounds[curSelectedItem]; + mMenuItems[mSelectedItem]->mWhite = mItemColor; + mMenuItems[curSelectedItem]->mWhite + = JUtility::TColor(); + mMenuItems[curSelectedItem]->setBounds(bounds); + + mBounceAnim = 0.0f; // reset animation + + // Remove spark particles. + if (mEmitter != nullptr) { + gpEmitterManager4D2->forceDeleteEmitter( + mEmitter); + } + } + } else if (mGamePad->checkFrameMeaning(0x2)) { + // Select the previous item. + if (mNumItems > 2) { + mSelectedItem = (curSelectedItem == 0u) + ? mNumItems - 1 + : curSelectedItem - 1; + } else { + mSelectedItem = 0; + } + + if (mSelectedItem != curSelectedItem) { + SMSGetMSound()->startSoundSystemSE(MSD_SE_SY_CURSOR, + 0, nullptr, 0); + + JUTRect& bounds = mOrigItemBounds[curSelectedItem]; + mMenuItems[mSelectedItem]->mWhite = mItemColor; + mMenuItems[curSelectedItem]->mWhite + = JUtility::TColor(); + mMenuItems[curSelectedItem]->setBounds(bounds); + + mBounceAnim = 0.0f; + + if (mEmitter != nullptr) { + gpEmitterManager4D2->forceDeleteEmitter( + mEmitter); + } + } + } + + JUTRect animItemBounds = mOrigItemBounds[mSelectedItem]; + if (mBounceAnim == mEffectKeyFrame) { + // Spawn a "spark" effect from the selected item. + f32 width = mMenuItems[mSelectedItem]->getWidth(); + f32 emitterWidth = width / mEffectStretch; + + JUTRect itemBounds + = mMenuItems[mSelectedItem]->getGlobalBounds(); + + // TODO: This doesn't fully match. + gpEmitterManager4D2->createEmitter( + JGeometry::TVec3( + itemBounds.x1 + 0.5f * itemBounds.getWidth(), + itemBounds.y1 + 0.5f * itemBounds.getHeight(), + 0.0f), + 0x1FA, nullptr, nullptr); + + mEmitter = gpEmitterManager4D2->unkC8[0][0]; + setEmitterScale(4.0f * emitterWidth, 1.0f, 1.0f); + } + + if (mBounceAnim < 18.0f) { + s32 hw = mBounceAnim; + s32 hh = 0.5f * mBounceAnim; + animItemBounds.reform(-hw, -hh, hw, hh); + mMenuItems[mSelectedItem]->setBounds(animItemBounds); + + s32 colorShift = 10.0f * mBounceAnim; + mMenuItems[mSelectedItem]->mWhite + = mItemColor + (colorShift << 24); + } else if (mBounceAnim < 35.0f) { + s32 hw = mBounceAnim - 35.0f; + s32 hh = 0.5f * (mBounceAnim - 35.0f); + animItemBounds.reform(-hw, -hh, hw, hh); + mMenuItems[mSelectedItem]->setBounds(animItemBounds); + + s32 colorShift = (35.0f - mBounceAnim) * 10.0f; + mMenuItems[mSelectedItem]->mWhite + = mItemColor + (colorShift << 24); + } else { + // Loop animation. + mBounceAnim = -0.5f; + unkFC = -unkFC; + } + + mBounceAnim += 0.5f; + } break; + case MENU_DISAPPEARING: + disappearWindow(); + break; + default: + break; + } + } + + if (flags & 0x8) { + switch (mState) { + case MENU_APPEARING: + draw(gfx); + break; + case MENU_OPEN: + case UNK2: + case MENU_SAVING: + case MENU_DISAPPEARING: + draw(gfx); + break; + default: + break; + } + } + } + } +} + +u8 TPauseMenu2::getNextState() +{ + u8 state = 2; + if (mSelectionConfirmed) { + switch (mSelectedItem) { + case 0: + if (mState == MENU_CLOSED) { + state = 0; + } + break; + case 1: + if (mState == MENU_CLOSED) { + state = mCardSave->getNextState(); + } + break; + case 2: + if (mState == MENU_CLOSED) { + state = 5; + } + break; + default: + state = 0; + break; + } + } else { + if (mPressedB && mState == MENU_CLOSED) { + state = 0; + } + } + return state; +} + +void TPauseMenu2::setDrawStart() +{ + mPressedB = false; + mSelectionConfirmed = false; + mSelectedItem = 0; + mFadeAnim = 0.0f; + mState = MENU_APPEARING; + mBounceAnim = 0.0f; + mMenuItems[0]->mWhite = mItemColor; + mMenuItems[0]->mVisible = false; + + for (s32 i = 1; i < mNumItems; ++i) { + mMenuItems[i]->mWhite = 0xFFFFFFFF; + mMenuItems[i]->mVisible = false; + } + + mPauseLetters[0]->mRotation = u16(mOrigLetterAngles[0] + 180.0f); + mPauseLetters[1]->mRotation = u16(mOrigLetterAngles[1] + 180.0f); + mPauseLetters[2]->mRotation = u16(mOrigLetterAngles[2] + 180.0f); + mPauseLetters[3]->mRotation = u16(mOrigLetterAngles[3] + 180.0f); + mPauseLetters[4]->mRotation = u16(mOrigLetterAngles[4] + 180.0f); + + mMenuPane->setAlpha(255); + mMenuPane->mRotation = 0.0f; + gpMarDirector->getConsole()->pauseIn(); + SMSRumbleMgr->startPause(); + gpMSound->pauseOn(true); +} + +void TPauseMenu2::setDrawEnd() +{ + SMSRumbleMgr->finishPause(); + gpMSound->pauseOff(0); + gpMarDirector->getConsole()->pauseOut(); + mFadeAnim = 0.0f; + mState = MENU_DISAPPEARING; +} + +void TPauseMenu2::drawAppearPane(J2DPicture* picture, f32 anim, JUTRect& rect, + f32 rotation) +{ + if (anim < 0.0f) { + if (picture->isVisible()) { + picture->hide(); + } + } else if (!(anim >= 20.0f) && !picture->isVisible()) { + picture->show(); + picture->setAlpha(0); + + if (anim == 2.0f) { + JUTRect rect = picture->getGlobalBounds(); + + // TODO: This doesn't fully match. + gpEmitterManager4D2->createEmitter( + JGeometry::TVec3(rect.x1 + 0.5f * rect.getWidth(), + rect.y1 + 0.5f * rect.getHeight(), 0.0f), + 0x1F9, nullptr, nullptr); + } + + f32 normalisedAngle = 0.05f * anim; + s32 shrink = 2.0f * normalisedAngle * (1.0f - normalisedAngle) * 80.0f; + s32 offset = 0.75f * (19.0f - anim); + picture->mRotation = rotation; + picture->setBounds(rect.x1 + offset, rect.y1 - shrink + offset, + rect.x2 - offset, rect.y2 - shrink - offset); + + u16 alpha = anim * 12.8f; + if (alpha > 255) { + alpha = 255; + } + picture->setAlpha(alpha); + } +} diff --git a/src/System/MarDirectorDirect.cpp b/src/System/MarDirectorDirect.cpp index ccf57cda2..9d000f91b 100644 --- a/src/System/MarDirectorDirect.cpp +++ b/src/System/MarDirectorDirect.cpp @@ -365,7 +365,7 @@ int TMarDirector::changeState() break; case STATE_UNK11: { - switch (unkAC->unk118->getNextState()) { + switch (unkAC->mCardSave->getNextState()) { case 0: if (unk261 == 7) { TFlagManager::smInstance->restore(); @@ -731,7 +731,7 @@ void TMarDirector::nextStateInitialize(u8 next_state) if (currSeq.unk0 == 1) THPPlayerPause(); SMSRumbleMgr->startPause(); - unkAC->unk118->init(unk261); + unkAC->mCardSave->init(unk261); for (int i = 0; i < 4; ++i) JUTGamePad::CRumble::stopMotor(unk18[i]->mPortNum); unk18[0]->onFlag(0x1);