mirror of
https://github.com/CraftyBoss/SuperMarioOdysseyOnline.git
synced 2024-11-22 03:05:16 +00:00
new: custom boot screen before main menu
- Show "SMOO made by CraftyBoss" for about 5 seconds - Then show "Freeze-Tag & Sardines made by Amethyst-szs" for about 5 seconds. - This does only overlay the game starting normally and does not slow down the process additionally. --- Changes compared to the original cherry-picked version: - Put all into the speedboot namespace instead of only a few things. - Don't load into the game, but stay in the main menu - (Because of issues with new save files) - Added text: "Made by CraftyBoss" - Added text: "& Sardines" - Speed up transition animation between the two screens - (Because it is now shown for a shorter total time) Instead of directly (speed)booting into the game like in the original cherry-picked commit, this stays in the main menu. The original behavior can be restored by setting `speedbootAutoload` to `true` inside `BootHooks.cpp`. This is to prevent issues with new empty save files. They normally don't get to the main menu but to an extra menu that now is invisible behind the custom boot screen. The game doesn't load automatically then but the player needs to blindly navigate the invisible menu to start the game. Till Cap Kingdom is fully loaded only the custom boot screen is visible (e.g. during the first cutscene video). (cherry picked from commit c1eac0852eb839560dbc2ccafe373176c9911684) Co-authored-by: Robin C. Ladiges <rcl.git@blackpinguin.de>
This commit is contained in:
parent
6af21f1b8f
commit
7fa8c659e1
10 changed files with 342 additions and 3 deletions
|
@ -36,6 +36,7 @@ SOURCES := \
|
|||
source/sead/time \
|
||||
source/sead \
|
||||
source/puppets \
|
||||
source/speedboot \
|
||||
source/server/hns \
|
||||
source/server/sardines \
|
||||
source/server/freeze-tag \
|
||||
|
|
|
@ -121,6 +121,7 @@ namespace al
|
|||
void setPaneLocalSize( al::IUseLayout* layout, const char* paneName, sead::Vector2f const&);
|
||||
void setPaneLocalScale( al::IUseLayout* layout, const char* paneName, sead::Vector2f const&);
|
||||
void setPaneLocalRotate(al::IUseLayout* layout, const char* paneName, sead::Vector3f const&);
|
||||
void setPaneVtxColor(al::IUseLayout const* layout, char const* paneName, sead::Color4u8 const&);
|
||||
|
||||
sead::Vector3f& getPaneLocalTrans(const al::IUseLayout* layout, const char* paneName);
|
||||
void getPaneLocalSize(sead::Vector2f*, const al::IUseLayout* layout, const char* paneName);
|
||||
|
|
|
@ -19,17 +19,17 @@ class WorldResourceLoader : public al::HioNode {
|
|||
void requestLoadWorldResource(int);
|
||||
void createResourcePlayer(void);
|
||||
void tryDestroyWorldResourceOnlyCap(void);
|
||||
void calcLoadPercent(void);
|
||||
float calcLoadPercent(void) const;
|
||||
void getLoadWorldId(void);
|
||||
bool tryLoadResource(char const*, char const*, char const*);
|
||||
void loadWorldResource(int, int, bool, char const*);
|
||||
void calcWorldResourceHeapSize(void);
|
||||
|
||||
al::AsyncFunctorThread* mResourceLoadThread; // 0x08
|
||||
sead::Heap* mWorldResHeap = nullptr; // 0x10
|
||||
sead::Heap* mSceneHeap = nullptr; // 0x10
|
||||
sead::Heap* mCapHeap = nullptr; // 0x18
|
||||
sead::Heap* mWaterfallHeap = nullptr; // 0x20
|
||||
int mCurWorld = -1; // 0x28
|
||||
int mCurLoadedWorldId = -1; // 0x28
|
||||
int mCurScenario = -1; // 0x2C
|
||||
bool unkBool = true; // 0x30
|
||||
bool mIsCancelLoad = true; // 0x31
|
||||
|
|
22
include/speedboot/CustomBootNerve.hpp
Normal file
22
include/speedboot/CustomBootNerve.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "al/nerve/Nerve.h"
|
||||
#include "al/nerve/NerveKeeper.h"
|
||||
#include "al/util/NerveUtil.h"
|
||||
#include "game/HakoniwaSequence/HakoniwaSequence.h"
|
||||
|
||||
NERVE_HEADER(HakoniwaSequence, LoadStage);
|
||||
NERVE_HEADER(HakoniwaSequence, LoadWorldResourceWithBoot);
|
||||
NERVE_IMPL(HakoniwaSequence, LoadStage);
|
||||
NERVE_IMPL(HakoniwaSequence, LoadWorldResourceWithBoot);
|
||||
|
||||
namespace speedboot {
|
||||
class CustomBootNerve : public al::Nerve {
|
||||
public:
|
||||
void execute(al::NerveKeeper* keeper) override {
|
||||
if (al::updateNerveState(keeper->mParent)) {
|
||||
al::setNerve(keeper->mParent, &nrvHakoniwaSequenceLoadStage);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
79
include/speedboot/HakoniwaSequenceSpeedboot.hpp
Normal file
79
include/speedboot/HakoniwaSequenceSpeedboot.hpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
#include "al/nerve/NerveStateBase.h"
|
||||
#include "al/util/NerveUtil.h"
|
||||
|
||||
#include "game/GameData/GameDataFunction.h"
|
||||
#include "game/HakoniwaSequence/HakoniwaSequence.h"
|
||||
|
||||
namespace speedboot {
|
||||
namespace {
|
||||
NERVE_HEADER(HakoniwaSequenceSpeedboot, InitThread)
|
||||
NERVE_HEADER(HakoniwaSequenceSpeedboot, LoadStage)
|
||||
NERVE_HEADER(HakoniwaSequenceSpeedboot, WipeToKill)
|
||||
}
|
||||
|
||||
struct HakoniwaSequenceSpeedboot : public al::NerveStateBase {
|
||||
public:
|
||||
HakoniwaSequenceSpeedboot(HakoniwaSequence* sequence) : al::NerveStateBase("Speedboot"), mSequence(sequence) {
|
||||
initNerve(&nrvHakoniwaSequenceSpeedbootLoadStage, 0);
|
||||
}
|
||||
|
||||
void exeInitThread() {
|
||||
if (al::isFirstStep(this)) {
|
||||
mSequence->mInitThread->start();
|
||||
}
|
||||
|
||||
if (mSequence->mInitThread->isDone()) {
|
||||
al::setNerve(this, &nrvHakoniwaSequenceSpeedbootLoadStage);
|
||||
}
|
||||
}
|
||||
|
||||
bool isDoneLoading() const {
|
||||
return mSequence->mResourceLoader->isEndLoadWorldResource()
|
||||
&& mSequence->mInitThread->isDone()
|
||||
;
|
||||
}
|
||||
|
||||
void exeLoadStage() {
|
||||
if (al::isFirstStep(this)) {
|
||||
mSequence->mInitThread->start();
|
||||
const char* name = GameDataFunction::getNextStageName(this->mSequence->mGameDataHolder);
|
||||
if (name == nullptr) {
|
||||
name = GameDataFunction::getMainStageName(this->mSequence->mGameDataHolder, 0);
|
||||
}
|
||||
int scenario = GameDataFunction::calcNextScenarioNo(this->mSequence->mGameDataHolder);
|
||||
if (scenario == -1) {
|
||||
scenario = 1;
|
||||
}
|
||||
int world = this->mSequence->mGameDataHolder.mData->mWorldList->tryFindWorldIndexByStageName(name);
|
||||
if (world > -1) {
|
||||
mSequence->mResourceLoader->requestLoadWorldHomeStageResource(world, scenario);
|
||||
}
|
||||
}
|
||||
|
||||
if (isDoneLoading()) {
|
||||
al::setNerve(this, &nrvHakoniwaSequenceSpeedbootWipeToKill);
|
||||
}
|
||||
}
|
||||
|
||||
void exeWipeToKill() {
|
||||
if (al::isFirstStep(this)) {
|
||||
mSequence->mWipeHolder->startClose("FadeWhite", -1);
|
||||
}
|
||||
|
||||
if (mSequence->mWipeHolder->isCloseEnd()) {
|
||||
kill();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HakoniwaSequence* mSequence;
|
||||
};
|
||||
|
||||
namespace {
|
||||
NERVE_IMPL(HakoniwaSequenceSpeedboot, InitThread);
|
||||
NERVE_IMPL(HakoniwaSequenceSpeedboot, LoadStage);
|
||||
NERVE_IMPL(HakoniwaSequenceSpeedboot, WipeToKill);
|
||||
}
|
||||
}
|
60
include/speedboot/SpeedbootLoad.hpp
Normal file
60
include/speedboot/SpeedbootLoad.hpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include "al/layout/LayoutActor.h"
|
||||
#include "al/layout/LayoutInitInfo.h"
|
||||
#include "al/util/NerveUtil.h"
|
||||
|
||||
#include "game/WorldList/WorldResourceLoader.h"
|
||||
|
||||
#include "sead/math/seadVector.h"
|
||||
|
||||
namespace speedboot {
|
||||
class SpeedbootLoad : public al::LayoutActor {
|
||||
public:
|
||||
SpeedbootLoad(
|
||||
WorldResourceLoader* resourceLoader,
|
||||
const al::LayoutInitInfo& initInfo,
|
||||
float autoCloseAfter
|
||||
);
|
||||
|
||||
void exeAppear();
|
||||
void exeWait();
|
||||
void exeDecrease();
|
||||
void exeEnd();
|
||||
|
||||
float mTime = 0.f;
|
||||
float mProgression = 0.f;
|
||||
float mRotTime = 0.f;
|
||||
|
||||
// Online logo part
|
||||
sead::Vector2f mOnlineLogoTrans = sead::Vector2f::zero;
|
||||
sead::Vector2f mOnlineLogoTransTarget = sead::Vector2f::zero;
|
||||
float mOnlineLogoScale = 0.f;
|
||||
float mOnlineLogoScaleTarget = 0.f;
|
||||
float mOnlineCreditScale = 1.f;
|
||||
float mOnlineCreditScaleTarget = 1.f;
|
||||
|
||||
// Freze tag logo root
|
||||
float mFreezeLogoTransX = 1000.f;
|
||||
float mFreezeLogoTransXTarget = 1000.f;
|
||||
|
||||
// Borders
|
||||
sead::Vector2f mFreezeBorder = { 700.f, 420.f };
|
||||
sead::Vector2f mFreezeBorderTarget = { 700.f, 420.f };
|
||||
|
||||
// Backgrounds
|
||||
float mFreezeBGTransX = 0.f;
|
||||
float mFreezeBGTransXTarget = 0.f;
|
||||
|
||||
private:
|
||||
float mAutoCloseAfter = 0.f;
|
||||
WorldResourceLoader* worldResourceLoader;
|
||||
};
|
||||
|
||||
namespace {
|
||||
NERVE_HEADER(SpeedbootLoad, Appear)
|
||||
NERVE_HEADER(SpeedbootLoad, Wait)
|
||||
NERVE_HEADER(SpeedbootLoad, Decrease)
|
||||
NERVE_HEADER(SpeedbootLoad, End)
|
||||
}
|
||||
}
|
|
@ -132,3 +132,8 @@ B59E28 B seadPrintHook // sead::system::print
|
|||
538A94 B freezePlayerHitPointDamage // Reimplements the damage function, disabling it's functionality in Freeze Tag
|
||||
51B280 B freezeKidsMode // Forces kids mode to be enabled during Freeze Tag
|
||||
1CFBA0 BL freezeMoonHitboxDisable // When mode enabled, disable hitboxes with moons to avoid softlocks
|
||||
|
||||
// custom bootscreen hooks
|
||||
50EF28 BL speedboot::hakoniwaSetNerveSetup
|
||||
50EB88 ORR w2, wzr, #0x1f // nerve state count
|
||||
50EB64 BL speedboot::prepareLayoutInitInfo
|
||||
|
|
BIN
romfs/LayoutData/SpeedbootLoad.szs
Normal file
BIN
romfs/LayoutData/SpeedbootLoad.szs
Normal file
Binary file not shown.
40
source/speedboot/BootHooks.cpp
Normal file
40
source/speedboot/BootHooks.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
|
||||
#include "al/layout/LayoutInitInfo.h"
|
||||
#include "al/nerve/Nerve.h"
|
||||
#include "al/util/NerveUtil.h"
|
||||
#include "game/HakoniwaSequence/HakoniwaSequence.h"
|
||||
|
||||
#include "speedboot/SpeedbootLoad.hpp"
|
||||
#include "speedboot/CustomBootNerve.hpp"
|
||||
#include "speedboot/HakoniwaSequenceSpeedboot.hpp"
|
||||
|
||||
namespace speedboot {
|
||||
CustomBootNerve nrvSpeedboot;
|
||||
const bool speedbootAutoload = false; // set this to true, to automatically load the game, which skips the main menu (this has issues with empty save files)
|
||||
|
||||
al::LayoutInitInfo copiedInitInfo;
|
||||
|
||||
HakoniwaSequenceSpeedboot* deezNutsState;
|
||||
|
||||
extern "C" void _ZN10BootLayoutC1ERKN2al14LayoutInitInfoE(BootLayout* layout, const al::LayoutInitInfo& layoutInitInfo);
|
||||
|
||||
void prepareLayoutInitInfo(BootLayout* layout, const al::LayoutInitInfo& layoutInitInfo) {
|
||||
register HakoniwaSequence* sequence asm("x19");
|
||||
new SpeedbootLoad(
|
||||
sequence->mResourceLoader,
|
||||
layoutInitInfo,
|
||||
speedbootAutoload ? 0.f : 10.f
|
||||
);
|
||||
_ZN10BootLayoutC1ERKN2al14LayoutInitInfoE(layout, layoutInitInfo);
|
||||
}
|
||||
|
||||
void hakoniwaSetNerveSetup(al::IUseNerve* useNerve, al::Nerve* nerve) {
|
||||
if (!speedbootAutoload) {
|
||||
return;
|
||||
}
|
||||
al::setNerve(useNerve, &nrvSpeedboot);
|
||||
auto* sequence = static_cast<HakoniwaSequence*>(useNerve);
|
||||
deezNutsState = new HakoniwaSequenceSpeedboot(sequence);
|
||||
al::initNerveState(useNerve, deezNutsState, &nrvSpeedboot, "Speedboot");
|
||||
}
|
||||
}
|
131
source/speedboot/SpeedbootLoad.cpp
Normal file
131
source/speedboot/SpeedbootLoad.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
#include "speedboot/SpeedbootLoad.hpp"
|
||||
|
||||
#include "al/util.hpp"
|
||||
#include "al/util/LayoutUtil.h"
|
||||
#include "al/util/LiveActorUtil.h"
|
||||
#include "al/util/MathUtil.h"
|
||||
|
||||
#include "sead/gfx/seadColor.h"
|
||||
#include "sead/math/seadMathCalcCommon.h"
|
||||
#include "sead/prim/seadSafeString.h"
|
||||
|
||||
#include "server/DeltaTime.hpp"
|
||||
|
||||
namespace speedboot {
|
||||
SpeedbootLoad::SpeedbootLoad(
|
||||
WorldResourceLoader* resourceLoader,
|
||||
const al::LayoutInitInfo& initInfo,
|
||||
float autoCloseAfter
|
||||
) : al::LayoutActor("SpeedbootLoad"), worldResourceLoader(resourceLoader), mAutoCloseAfter(autoCloseAfter) {
|
||||
al::initLayoutActor(this, initInfo, "SpeedbootLoad", nullptr);
|
||||
initNerve(&nrvSpeedbootLoadAppear, 0);
|
||||
appear();
|
||||
}
|
||||
|
||||
void SpeedbootLoad::exeAppear() {
|
||||
if (al::isFirstStep(this)) {
|
||||
al::startAction(this, "Appear", nullptr);
|
||||
}
|
||||
|
||||
if (al::isActionEnd(this, nullptr)) {
|
||||
al::setNerve(this, &nrvSpeedbootLoadWait);
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedbootLoad::exeWait() {
|
||||
if (al::isActionEnd(this, nullptr)) {
|
||||
al::setNerve(this, &nrvSpeedbootLoadDecrease);
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedbootLoad::exeDecrease() {
|
||||
mTime += 0.016666f;
|
||||
|
||||
mProgression = (
|
||||
mAutoCloseAfter <= 0.1f
|
||||
? worldResourceLoader->calcLoadPercent() / 100.0f
|
||||
: mTime / mAutoCloseAfter
|
||||
);
|
||||
|
||||
float rotation = cosf(mTime) * 3;
|
||||
|
||||
// Debug stuff
|
||||
sead::WFormatFixedSafeString<0x40> string(u"Time: %.02f\nSine Value: %.02f", mTime, rotation);
|
||||
al::setPaneString(this, "TxtDebug", string.cstr(), 0);
|
||||
|
||||
if (mProgression < 1.f) {
|
||||
// Target setup
|
||||
if (
|
||||
(mAutoCloseAfter <= 0.1f && mTime < 7.f)
|
||||
|| (mAutoCloseAfter > 0.1f && mTime < (mAutoCloseAfter * 0.5f))
|
||||
) {
|
||||
mOnlineLogoTransTarget = { 0.f, 0.f };
|
||||
mOnlineLogoScaleTarget = 1.f;
|
||||
mOnlineCreditScaleTarget = 1.f;
|
||||
|
||||
mFreezeLogoTransXTarget = 1000.f;
|
||||
|
||||
mFreezeBorderTarget = sead::Vector2f(700.f, 420.f);
|
||||
|
||||
mFreezeBGTransXTarget = 0.f;
|
||||
} else {
|
||||
mOnlineLogoTransTarget = { -520.f, 260.f };
|
||||
mOnlineLogoScaleTarget = 0.3f;
|
||||
mOnlineCreditScaleTarget = 0.f;
|
||||
|
||||
mFreezeLogoTransXTarget = 0.f;
|
||||
|
||||
mFreezeBorderTarget = sead::Vector2f(640.f, 360.f);
|
||||
|
||||
mFreezeBGTransXTarget = -1280.f;
|
||||
}
|
||||
|
||||
// SMOO logo
|
||||
mOnlineLogoTrans.x = al::lerpValue(mOnlineLogoTrans.x, mOnlineLogoTransTarget.x, 0.06f);
|
||||
mOnlineLogoTrans.y = al::lerpValue(mOnlineLogoTrans.y, mOnlineLogoTransTarget.y, 0.06f);
|
||||
mOnlineLogoScale = al::lerpValue(mOnlineLogoScale, mOnlineLogoScaleTarget, 0.06f);
|
||||
mOnlineCreditScale = al::lerpValue(mOnlineCreditScale, mOnlineCreditScaleTarget, 0.06f);
|
||||
al::setPaneLocalTrans(this, "PartOnlineLogo", mOnlineLogoTrans);
|
||||
al::setPaneLocalScale(this, "PartOnlineLogo", { mOnlineLogoScale, mOnlineLogoScale });
|
||||
al::setPaneLocalScale(this, "PicCraftyBossCredit", { mOnlineCreditScale, mOnlineCreditScale });
|
||||
|
||||
// Freeze-Tag logo
|
||||
mFreezeLogoTransX = al::lerpValue(mFreezeLogoTransX, mFreezeLogoTransXTarget, 0.04f);
|
||||
al::setPaneLocalTrans(this, "FreezeLogoRoot", { mFreezeLogoTransX, 0.f });
|
||||
al::setPaneLocalRotate(this, "PicFreezeLogo", { 0.f, 0.f, rotation });
|
||||
|
||||
// Freeze borders
|
||||
mFreezeBorder.x = al::lerpValue(mFreezeBorder.x, mFreezeBorderTarget.x, 0.02f);
|
||||
mFreezeBorder.y = al::lerpValue(mFreezeBorder.y, mFreezeBorderTarget.y, 0.02f);
|
||||
al::setPaneLocalTrans(this, "PicFreezeEdgeLeft", { -mFreezeBorder.x, 0.f });
|
||||
al::setPaneLocalTrans(this, "PicFreezeEdgeRight", { mFreezeBorder.x, 0.f });
|
||||
al::setPaneLocalTrans(this, "PicFreezeEdgeTop", { 0.f, mFreezeBorder.y });
|
||||
al::setPaneLocalTrans(this, "PicFreezeEdgeBot", { 0.f, -mFreezeBorder.y });
|
||||
|
||||
// Freeze BG
|
||||
mFreezeBGTransX = al::lerpValue(mFreezeBGTransX, mFreezeBGTransXTarget, 0.04f);
|
||||
al::setPaneLocalTrans(this, "BackgroundsRoot", { mFreezeBGTransX, 0.f });
|
||||
}
|
||||
|
||||
if (mProgression >= 1.f) {
|
||||
al::setNerve(this, &nrvSpeedbootLoadEnd);
|
||||
}
|
||||
}
|
||||
|
||||
void SpeedbootLoad::exeEnd() {
|
||||
if (al::isFirstStep(this)) {
|
||||
al::startAction(this, "End", nullptr);
|
||||
}
|
||||
|
||||
if (al::isActionEnd(this, nullptr)) {
|
||||
kill();
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
NERVE_IMPL(SpeedbootLoad, Appear)
|
||||
NERVE_IMPL(SpeedbootLoad, Wait)
|
||||
NERVE_IMPL(SpeedbootLoad, Decrease)
|
||||
NERVE_IMPL(SpeedbootLoad, End)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue