mirror of
https://github.com/CraftyBoss/SuperMarioOdysseyOnline.git
synced 2024-11-25 12:45:17 +00:00
69d6a732c7
- change: general game mode management more abstract and less H&S oriented
- change: split 8bit updateType into 4bit game mode and 4bit update type.
- change: don't process packets from other game modes (legacy mode for backwards compatibility)
- change: cache game mode of other players in puppet, resend GameModeInf on detected game mode change
- change: send gamemode NONE when H&S is selected but not active
- change: improved distance calculations in squared distance space
- change: change from hider to seeker when dead even if there are no other players
- fix: add hours to the minutes for the H&S GameModeInf packet
- fix: set milliseconds and hours when receiving time from server
- fix: keep the new time from the server for longer than a single frame
- fix: reset H&S icon after receiving a new state from the server
- refac: move code to generate PlayerList into own abstract LayoutPlayerList class.
- refac: to_string() method for GameTime to simplify code in the Game Mode Icon class.
- refac: rename TagInf packet to GameModeInf packet
- refac: remove param from `SocketClient::tryGetPacket()` (unused)
- refac: move all H&S specific files into the same directory (out of layouts)
- refac: move GameModeTimer.cpp from source/server/hns/ to source/server/gamemode/
- refac: clean up some unused, duplicate or complicated imports
- [mod menu] change: use the game mode name in the options & menu title
- [mod menu] change: select the next game mode in the game mode select menu
- [mod menu] change: possibility to always change the gravity setting in the H&S config menu
- [mod menu] add: toggle options to control mario/cappy collision/bounciness
(cherry picked from commit a9b2c87aa0
)
(cherry picked from commit 918f61fbfd619d781d88dc74878d392c48cfa480)
(cherry picked from commit 96aff7dd7167d8244acef7884fa3503d4c3f868a)
(cherry picked from commit 0fb6413ec91bbf679e9f8cea1aa512159101fa46)
(cherry picked from commit ab78a812fd18781655ccf38e803f619ea427d1ac)
Co-authored-by: Robin C. Ladiges <rcl.git@blackpinguin.de>
487 lines
19 KiB
C++
487 lines
19 KiB
C++
#include "main.hpp"
|
|
|
|
#include <cmath>
|
|
#include <math.h>
|
|
|
|
#include "actors/PuppetActor.h"
|
|
|
|
#include "al/execute/ExecuteOrder.h"
|
|
#include "al/execute/ExecuteTable.h"
|
|
#include "al/execute/ExecuteTableHolderDraw.h"
|
|
#include "al/LiveActor/LiveActor.h"
|
|
#include "al/util.hpp"
|
|
#include "al/util/AudioUtil.h"
|
|
#include "al/util/CameraUtil.h"
|
|
#include "al/util/ControllerUtil.h"
|
|
#include "al/util/GraphicsUtil.h"
|
|
#include "al/util/LiveActorUtil.h"
|
|
#include "al/util/NerveUtil.h"
|
|
|
|
#include "debugMenu.hpp"
|
|
|
|
#include "game/GameData/GameDataHolderAccessor.h"
|
|
#include "game/GameData/GameDataFunction.h"
|
|
#include "game/HakoniwaSequence/HakoniwaSequence.h"
|
|
#include "game/Player/PlayerActorBase.h"
|
|
#include "game/Player/PlayerActorHakoniwa.h"
|
|
#include "game/Player/PlayerFunction.h"
|
|
#include "game/Player/PlayerHackKeeper.h"
|
|
#include "game/StageScene/StageScene.h"
|
|
|
|
#include "helpers.hpp"
|
|
|
|
#include "logger.hpp"
|
|
|
|
#include "puppets/PuppetInfo.h"
|
|
|
|
#include "sead/container/seadSafeArray.h"
|
|
#include "sead/gfx/seadPrimitiveRenderer.h"
|
|
#include "sead/heap/seadHeap.h"
|
|
#include "sead/math/seadVector.h"
|
|
|
|
#include "server/Client.hpp"
|
|
#include "server/gamemode/GameModeBase.hpp"
|
|
#include "server/gamemode/GameModeFactory.hpp"
|
|
#include "server/gamemode/GameModeManager.hpp"
|
|
|
|
#include "rs/util.hpp"
|
|
|
|
static int pInfSendTimer = 0;
|
|
static int gameInfSendTimer = 0;
|
|
|
|
void updatePlayerInfo(GameDataHolderAccessor holder, PlayerActorBase* playerBase, bool isYukimaru) {
|
|
if (pInfSendTimer >= 3) {
|
|
Client::sendPlayerInfPacket(playerBase, isYukimaru);
|
|
|
|
if (!isYukimaru) {
|
|
Client::sendHackCapInfPacket(((PlayerActorHakoniwa*)playerBase)->mHackCap);
|
|
|
|
Client::sendCaptureInfPacket((PlayerActorHakoniwa*)playerBase);
|
|
}
|
|
|
|
pInfSendTimer = 0;
|
|
}
|
|
|
|
if (gameInfSendTimer >= 60) {
|
|
if (isYukimaru) {
|
|
Client::sendGameInfPacket(holder);
|
|
} else {
|
|
Client::sendGameInfPacket((PlayerActorHakoniwa*)playerBase, holder);
|
|
}
|
|
|
|
gameInfSendTimer = 0;
|
|
}
|
|
|
|
pInfSendTimer++;
|
|
gameInfSendTimer++;
|
|
}
|
|
|
|
// ------------- Hooks -------------
|
|
|
|
int debugPuppetIndex = 0;
|
|
int debugCaptureIndex = 0;
|
|
static int pageIndex = 0;
|
|
|
|
static const int maxPages = 3;
|
|
|
|
void drawMainHook(HakoniwaSequence* curSequence, sead::Viewport* viewport, sead::DrawContext* drawContext) {
|
|
GameModeManager* gmm = GameModeManager::instance();
|
|
GameModeBase* mode = gmm->getMode<GameModeBase>();
|
|
|
|
if (!mode || !mode->pauseTimeWhenPaused() || !gmm->isPaused()) {
|
|
Time::calcTime(); // this needs to be ran every frame, so running it here works
|
|
}
|
|
|
|
if (!debugMode) {
|
|
al::executeDraw(curSequence->mLytKit, "2Dバック(メイン画面)");
|
|
return;
|
|
}
|
|
|
|
Client* client = Client::instance();
|
|
SocketClient* socket = client->mSocket;
|
|
bool isConnected = socket->isConnected();
|
|
|
|
int dispHeight = al::getLayoutDisplayHeight();
|
|
|
|
gTextWriter->mViewport = viewport;
|
|
|
|
gTextWriter->mColor = sead::Color4f(1.f, 1.f, 1.f, 0.8f);
|
|
|
|
drawBackground((agl::DrawContext*)drawContext);
|
|
|
|
gTextWriter->beginDraw();
|
|
gTextWriter->setCursorFromTopLeft(sead::Vector2f(10.f, 10.f));
|
|
|
|
gTextWriter->printf("FPS: %d\n", static_cast<int>(round(Application::sInstance->mFramework->calcFps())));
|
|
|
|
gTextWriter->setCursorFromTopLeft(sead::Vector2f(10.f, (dispHeight / 3) + 30.f));
|
|
gTextWriter->setScaleFromFontHeight(20.f);
|
|
|
|
if (Client::isServerHidden()) {
|
|
gTextWriter->printf(
|
|
isConnected ? "Server: <hidden> | %d/%d Players\n" : "Server: <hidden>\n",
|
|
isConnected ? Client::getConnectCount() + 1 : 0,
|
|
isConnected ? Client::getMaxPlayerCount() : 0
|
|
);
|
|
} else {
|
|
gTextWriter->printf(
|
|
isConnected ? "Server: %s:%d | %d/%d Players\n" : "Server: %s:%d\n",
|
|
socket->getIP(),
|
|
socket->getPort(),
|
|
isConnected ? Client::getConnectCount() + 1 : 0,
|
|
isConnected ? Client::getMaxPlayerCount() : 0
|
|
);
|
|
}
|
|
gTextWriter->printf("Your TCP status: %s\n", socket->getStateChar());
|
|
gTextWriter->printf("Your UDP status: %s\n", socket->getUdpStateChar());
|
|
|
|
sead::Heap* clientHeap = Client::getClientHeap();
|
|
if (clientHeap) {
|
|
sead::Heap* gmHeap = GameModeManager::instance()->getHeap();
|
|
gTextWriter->printf(
|
|
"Heap Use: %.1f/%.0f (Client) %.1f/%.0f (Gmode)\n",
|
|
0.0009765625 * (clientHeap->getSize() - clientHeap->getFreeSize()),
|
|
0.0009765625 * clientHeap->getSize(),
|
|
0.0009765625 * (gmHeap->getSize() - gmHeap->getFreeSize()),
|
|
0.0009765625 * gmHeap->getSize()
|
|
);
|
|
}
|
|
|
|
gTextWriter->printf(
|
|
"Queue Count: %d/%d (Send) %d/%d (Receive)\n",
|
|
socket->getSendCount(),
|
|
socket->getSendMaxCount(),
|
|
socket->getRecvCount(),
|
|
socket->getRecvMaxCount()
|
|
);
|
|
|
|
#if EMU
|
|
gTextWriter->printf("Mod version: %s for Emulators\n", TOSTRING(BUILDVERSTR));
|
|
#else
|
|
gTextWriter->printf("Mod version: %s for Switch\n", TOSTRING(BUILDVERSTR));
|
|
#endif
|
|
|
|
al::Scene* curScene = curSequence->curScene;
|
|
|
|
if (curScene && isInGame) {
|
|
sead::LookAtCamera* cam = al::getLookAtCamera(curScene, 0);
|
|
sead::Projection* projection = al::getProjectionSead(curScene, 0);
|
|
|
|
PlayerActorBase* playerBase = rs::getPlayerActor(curScene);
|
|
|
|
PuppetActor* curPuppet = Client::getPuppet(debugPuppetIndex - 1);
|
|
PuppetActor* debugPuppet = Client::getDebugPuppet();
|
|
if (debugPuppet) {
|
|
curPuppet = debugPuppet;
|
|
}
|
|
|
|
sead::PrimitiveRenderer* renderer = sead::PrimitiveRenderer::instance();
|
|
renderer->setDrawContext(drawContext);
|
|
renderer->setCamera(*cam);
|
|
renderer->setProjection(*projection);
|
|
|
|
GameMode gameMode = GameModeManager::instance()->getGameMode();
|
|
GameModeBase* gameModeBase = GameModeManager::instance()->getMode<GameModeBase>();
|
|
|
|
gTextWriter->printf("(ZR ←)------------ Page %d/%d -------------(ZR →)\n", pageIndex + 1, maxPages);
|
|
|
|
switch (pageIndex)
|
|
{
|
|
case 0:
|
|
{
|
|
gTextWriter->printf(
|
|
"(ZL ←)----------%s Player %d/%d %s-----------(ZL →)\n\n",
|
|
debugPuppetIndex + 1 < 10 ? "-" : "",
|
|
debugPuppetIndex + 1,
|
|
Client::getMaxPlayerCount(),
|
|
Client::getMaxPlayerCount() < 10 ? "-" : ""
|
|
);
|
|
|
|
if (debugPuppetIndex == 0) {
|
|
gTextWriter->printf("Player Name: %s\n", Client::getClientName());
|
|
gTextWriter->printf("Connection Status: %s\n", isConnected ? "Online" : "Offline");
|
|
gTextWriter->printf("Game mode: %i | %s\n", gameMode, GameModeFactory::getModeName(gameMode));
|
|
gTextWriter->printf("Is in same Stage: Yes\n");
|
|
gTextWriter->printf("Stage: %s\n", client->getLastGameInfPacket()->stageName);
|
|
gTextWriter->printf("Scenario: %u\n", client->getLastGameInfPacket()->scenarioNo);
|
|
gTextWriter->printf("Costume: H: %s B: %s\n", client->getLastCostumeInfPacket()->capModel, client->getLastCostumeInfPacket()->bodyModel);
|
|
gTextWriter->printf("Capture: %s\n", client->getLastCaptureInfPacket()->hackName);
|
|
|
|
PlayerHackKeeper* hackKeeper = playerBase->getPlayerHackKeeper();
|
|
if (hackKeeper) {
|
|
PlayerActorHakoniwa* p1 = (PlayerActorHakoniwa*)playerBase;
|
|
if (hackKeeper->currentHackActor) {
|
|
gTextWriter->printf("Animation: %s\n", al::getActionName(hackKeeper->currentHackActor));
|
|
} else {
|
|
gTextWriter->printf("Animation: %s\n", p1->mPlayerAnimator->mAnimFrameCtrl->getActionName());
|
|
}
|
|
}
|
|
|
|
if (gameModeBase) {
|
|
gameModeBase->debugMenuPlayer(gTextWriter);
|
|
}
|
|
} else if (curPuppet) {
|
|
al::LiveActor* curModel = curPuppet->getCurrentModel();
|
|
|
|
PuppetInfo* curPupInfo = curPuppet->getInfo();
|
|
|
|
if (curModel && curPupInfo) {
|
|
gTextWriter->printf("Player Name: %s\n", curPupInfo->puppetName);
|
|
gTextWriter->printf("Connection Status: %s\n", curPupInfo->isConnected ? "Online" : "Offline");
|
|
gTextWriter->printf("Game mode: %i | %s\n", curPupInfo->gameMode, GameModeFactory::getModeName(curPupInfo->gameMode));
|
|
gTextWriter->printf("Is in same Stage: %s\n", curPupInfo->isInSameStage ? "Yes" : "No");
|
|
gTextWriter->printf("Stage: %s\n", curPupInfo->stageName);
|
|
gTextWriter->printf("Scenario: %u\n", curPupInfo->scenarioNo);
|
|
gTextWriter->printf("Costume: H: %s B: %s\n", curPupInfo->costumeHead, curPupInfo->costumeBody);
|
|
gTextWriter->printf("Capture: %s\n", curPupInfo->isCaptured ? curPupInfo->curHack : "");
|
|
gTextWriter->printf("Animation: %d %s\n", curPupInfo->curAnim, curPupInfo->curAnimStr);
|
|
if (!curPupInfo->isCaptured) {
|
|
gTextWriter->printf("Model Animation: %s\n", al::getActionName(curModel));
|
|
}
|
|
if (gameModeBase) {
|
|
gameModeBase->debugMenuPlayer(gTextWriter, curPupInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
{
|
|
gTextWriter->printf("--------------- Animation & Cappy ---------------\n\n");
|
|
PlayerHackKeeper* hackKeeper = playerBase->getPlayerHackKeeper();
|
|
|
|
if (hackKeeper) {
|
|
PlayerActorHakoniwa* p1 = (PlayerActorHakoniwa*)playerBase; // its safe to assume that we're using a playeractorhakoniwa if the hack keeper isnt null
|
|
|
|
if (hackKeeper->currentHackActor) {
|
|
al::LiveActor* curHack = hackKeeper->currentHackActor;
|
|
|
|
gTextWriter->printf("Current Hack Animation: %s\n", al::getActionName(curHack));
|
|
gTextWriter->printf("Current Hack Name: %s\n", hackKeeper->getCurrentHackName());
|
|
sead::Quatf captureRot = curHack->mPoseKeeper->getQuat();
|
|
gTextWriter->printf("Current Hack Rot: %.3f %.3f %.3f %f\n", captureRot.x, captureRot.y, captureRot.z, captureRot.w);
|
|
sead::Quatf calcRot;
|
|
al::calcQuat(&calcRot, curHack);
|
|
gTextWriter->printf("Calc Hack Rot: %.3f %.3f %.3f %.3f\n", calcRot.x, calcRot.y, calcRot.z, calcRot.w);
|
|
} else {
|
|
gTextWriter->printf("Cur Action: %s\n", p1->mPlayerAnimator->mAnimFrameCtrl->getActionName());
|
|
gTextWriter->printf("Cur Sub Action: %s\n", p1->mPlayerAnimator->curSubAnim.cstr());
|
|
gTextWriter->printf("Is Cappy Flying? %s\n", BTOC(p1->mHackCap->isFlying()));
|
|
if (p1->mHackCap->isFlying()) {
|
|
gTextWriter->printf("Cappy Action: %s\n", al::getActionName(p1->mHackCap));
|
|
sead::Vector3f* capTrans = al::getTransPtr(p1->mHackCap);
|
|
sead::Vector3f* capRot = &p1->mHackCap->mJointKeeper->mJointRot;
|
|
gTextWriter->printf("Cappy: Position Rotation\nX: % 10.3f % 10.3f\nY: % 10.3f % 10.3f\nZ: % 10.3f % 10.3f\n",
|
|
capTrans->x, capRot->x,
|
|
capTrans->y, capRot->y,
|
|
capTrans->z, capRot->z
|
|
);
|
|
gTextWriter->printf("Cappy Skew: %.3f\n", p1->mHackCap->mJointKeeper->mSkew);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
gTextWriter->printf("------------------- Controls --------------------\n\n");
|
|
if (gameModeBase) {
|
|
gameModeBase->debugMenuControls(gTextWriter);
|
|
}
|
|
gTextWriter->printf("\n- ZR + ↑ | Open/close this debug menu\n");
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
renderer->begin();
|
|
|
|
// sead::Matrix34f mat = sead::Matrix34f::ident;
|
|
// mat.setBase(3, sead::Vector3f::zero); // Sets the position of the matrix.
|
|
// For cubes, you need to put this at the location.
|
|
// For spheres, you can leave this at 0 0 0 since you set it in its draw function.
|
|
renderer->setModelMatrix(sead::Matrix34f::ident);
|
|
|
|
if (curPuppet) {
|
|
renderer->drawSphere4x8(curPuppet->getInfo()->playerPos, 20, sead::Color4f(1.f, 0.f, 0.f, 0.25f));
|
|
renderer->drawSphere4x8(al::getTrans(curPuppet), 20, sead::Color4f(0.f, 0.f, 1.f, 0.25f));
|
|
} else if (debugPuppetIndex == 0) {
|
|
renderer->drawSphere4x8(client->getLastPlayerInfPacket()->playerPos, 20, sead::Color4f(1.f, 0.f, 0.f, 0.25f));
|
|
}
|
|
|
|
renderer->end();
|
|
|
|
isInGame = false;
|
|
}
|
|
|
|
gTextWriter->endDraw();
|
|
|
|
al::executeDraw(curSequence->mLytKit, "2Dバック(メイン画面)");
|
|
}
|
|
|
|
void sendShinePacket(GameDataHolderAccessor thisPtr, Shine* curShine) {
|
|
if (!curShine->isGot()) {
|
|
GameDataFile::HintInfo* curHintInfo = &thisPtr.mData->mGameDataFile->mShineHintList[curShine->mShineIdx];
|
|
|
|
Client::sendShineCollectPacket(curHintInfo->mUniqueID);
|
|
}
|
|
|
|
GameDataFunction::setGotShine(thisPtr, curShine->curShineInfo);
|
|
}
|
|
|
|
void stageInitHook(
|
|
al::ActorInitInfo* info,
|
|
StageScene* curScene,
|
|
al::PlacementInfo const* placement,
|
|
al::LayoutInitInfo const* lytInfo,
|
|
al::ActorFactory const* factory,
|
|
al::SceneMsgCtrl* sceneMsgCtrl,
|
|
al::GameDataHolderBase* dataHolder
|
|
) {
|
|
al::initActorInitInfo(info, curScene, placement, lytInfo, factory, sceneMsgCtrl, dataHolder);
|
|
|
|
Client::clearArrays();
|
|
|
|
Client::setSceneInfo(*info, curScene);
|
|
|
|
if (GameModeManager::instance()->getGameMode() != NONE) {
|
|
GameModeInitInfo initModeInfo(info, curScene);
|
|
initModeInfo.initServerInfo(GameModeManager::instance()->getNextGameMode(), Client::getPuppetHolder());
|
|
|
|
GameModeManager::instance()->initScene(initModeInfo);
|
|
}
|
|
|
|
Client::sendGameInfPacket(info->mActorSceneInfo.mSceneObjHolder);
|
|
}
|
|
|
|
PlayerCostumeInfo* setPlayerModel(
|
|
al::LiveActor* player,
|
|
const al::ActorInitInfo& initInfo,
|
|
const char* bodyModel,
|
|
const char* capModel,
|
|
al::AudioKeeper* keeper,
|
|
bool isCloset
|
|
) {
|
|
Client::sendCostumeInfPacket(bodyModel, capModel);
|
|
return PlayerFunction::initMarioModelActor(player, initInfo, bodyModel, capModel, keeper, isCloset);
|
|
}
|
|
|
|
al::SequenceInitInfo* initInfo;
|
|
|
|
ulong constructHook() { // hook for constructing anything we need to globally be accesible
|
|
asm("STR X21, [X19,#0x208]"); // stores WorldResourceLoader into HakoniwaSequence
|
|
|
|
asm("MOV %[result], X20" : [result] "=r"(initInfo)); // Save our scenes init info to a gloabl ptr so we can access it later
|
|
|
|
Client::createInstance(al::getCurrentHeap());
|
|
GameModeManager::createInstance(al::getCurrentHeap()); // Create the GameModeManager on the current al heap
|
|
|
|
return 0x20;
|
|
}
|
|
|
|
bool threadInit(HakoniwaSequence* mainSeq) { // hook for initializing client class
|
|
al::LayoutInitInfo lytInfo = al::LayoutInitInfo();
|
|
|
|
al::initLayoutInitInfo(
|
|
&lytInfo,
|
|
mainSeq->mLytKit,
|
|
0,
|
|
mainSeq->mAudioDirector,
|
|
initInfo->mSystemInfo->mLayoutSys,
|
|
initInfo->mSystemInfo->mMessageSys,
|
|
initInfo->mSystemInfo->mGamePadSys
|
|
);
|
|
|
|
Client::instance()->init(lytInfo, mainSeq->mGameDataHolder);
|
|
|
|
return GameDataFunction::isPlayDemoOpening(mainSeq->mGameDataHolder);
|
|
}
|
|
|
|
bool hakoniwaSequenceHook(HakoniwaSequence* sequence) {
|
|
StageScene* stageScene = (StageScene*)sequence->curScene;
|
|
|
|
bool isFirstStep = al::isFirstStep(sequence);
|
|
|
|
al::PlayerHolder* pHolder = al::getScenePlayerHolder(stageScene);
|
|
PlayerActorBase* playerBase = al::tryGetPlayerActor(pHolder, 0);
|
|
|
|
bool isYukimaru = !playerBase->getPlayerInfo();
|
|
|
|
isInGame = !stageScene->isPause();
|
|
|
|
GameModeManager::instance()->setPaused(stageScene->isPause());
|
|
Client::setStageInfo(stageScene->mHolder);
|
|
|
|
Client::update();
|
|
|
|
updatePlayerInfo(stageScene->mHolder, playerBase, isYukimaru);
|
|
|
|
static bool isDisableMusic = false;
|
|
|
|
if (al::isPadHoldZR(-1)) {
|
|
if (al::isPadTriggerUp(-1)) { // ZR + Up => Debug menu
|
|
debugMode = !debugMode;
|
|
}
|
|
if (debugMode) {
|
|
if (al::isPadTriggerLeft(-1)) { // [Debug menu] ZR + Left => Previous page
|
|
pageIndex--;
|
|
if (pageIndex < 0) {
|
|
pageIndex = maxPages - 1;
|
|
}
|
|
}
|
|
if (al::isPadTriggerRight(-1)) { // [Debug menu] ZR + Right => Next page
|
|
pageIndex++;
|
|
if (pageIndex >= maxPages) {
|
|
pageIndex = 0;
|
|
}
|
|
}
|
|
}
|
|
} else if (al::isPadHoldZL(-1)) {
|
|
if (debugMode && pageIndex == 0) {
|
|
if (al::isPadTriggerLeft(-1)) { // [Debug menu] ZL + Left => Previous player
|
|
debugPuppetIndex--;
|
|
if (debugPuppetIndex < 0) {
|
|
debugPuppetIndex = Client::getMaxPlayerCount() - 1;
|
|
}
|
|
}
|
|
if (al::isPadTriggerRight(-1)) { // [Debug menu] ZL + Right => Next player
|
|
debugPuppetIndex++;
|
|
if (debugPuppetIndex >= Client::getMaxPlayerCount()) {
|
|
debugPuppetIndex = 0;
|
|
}
|
|
}
|
|
}
|
|
} else if (al::isPadHoldL(-1)) {
|
|
if (al::isPadTriggerLeft(-1)) { // L + Left => Activate gamemode
|
|
GameModeManager::instance()->toggleActive();
|
|
}
|
|
if (al::isPadTriggerUp(-1)) { // L + Up => Disable background music
|
|
isDisableMusic = !isDisableMusic;
|
|
}
|
|
}
|
|
|
|
if (isDisableMusic) {
|
|
if (al::isPlayingBgm(stageScene)) {
|
|
al::stopAllBgm(stageScene, 0);
|
|
}
|
|
}
|
|
|
|
if (isFirstStep) {
|
|
GameModeBase* mode = GameModeManager::instance()->getMode<GameModeBase>();
|
|
if (mode) {
|
|
mode->onHakoniwaSequenceFirstStep(sequence);
|
|
}
|
|
}
|
|
|
|
return isFirstStep;
|
|
}
|
|
|
|
void seadPrintHook(const char* fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
|
|
Logger::log(fmt, args);
|
|
|
|
va_end(args);
|
|
}
|