summaryrefslogtreecommitdiff
path: root/src/toBeSorted/save_manager.cpp
diff options
context:
space:
mode:
authorrobojumper <robojumper@gmail.com>2025-05-01 15:11:11 +0200
committerrobojumper <robojumper@gmail.com>2025-05-02 20:32:04 +0200
commitb148d141a0f49fc20fb61e5472951f4ddb4176cd (patch)
treed1c11a4dea3f40986430d37a82708953ebd5fb97 /src/toBeSorted/save_manager.cpp
parent594bc67d676e944980054b104368e02617428a85 (diff)
save_manager OK
Diffstat (limited to 'src/toBeSorted/save_manager.cpp')
-rw-r--r--src/toBeSorted/save_manager.cpp1758
1 files changed, 1758 insertions, 0 deletions
diff --git a/src/toBeSorted/save_manager.cpp b/src/toBeSorted/save_manager.cpp
index e69de29b..78c2ca0c 100644
--- a/src/toBeSorted/save_manager.cpp
+++ b/src/toBeSorted/save_manager.cpp
@@ -0,0 +1,1758 @@
+#include "toBeSorted/save_manager.h"
+
+#include "common.h"
+#include "d/d_cs_base.h"
+#include "d/d_d2d.h"
+#include "d/d_dvd_unk.h"
+#include "d/d_heap.h"
+#include "d/d_message.h"
+#include "d/d_s_boot.h"
+#include "d/d_sc_game.h"
+#include "d/d_sys.h"
+#include "d/lyt/d_lyt_save_msg_window.h"
+#include "d/lyt/d_lyt_system_window.h"
+#include "egg/core/eggHeap.h"
+#include "m/m_pad.h"
+#include "toBeSorted/arc_managers/layout_arc_manager.h"
+#include "toBeSorted/file_manager.h"
+#include "toBeSorted/nand_request_thread.h"
+#include "toBeSorted/nand_result_tracker.h"
+#include "toBeSorted/reload_color_fader.h"
+#include "toBeSorted/small_sound_mgr.h"
+
+#include "rvl/NAND.h"
+#include "rvl/TPL.h"
+
+#include <cstring>
+
+SaveMgr *SaveMgr::sInstance;
+
+static const char sSaveFileName[] = "wiiking2.sav";
+static const char sSkipDatFileName[] = "skip.dat";
+static const char sBannerBinFileName[] = "banner.bin";
+static const char sTmpBannerBinFileName[] = "/tmp/banner.bin";
+
+#define FILE_PERMS (NAND_PERM_RUSR | NAND_PERM_WUSR | NAND_PERM_RGRP | NAND_PERM_WGRP)
+
+const SaveMgr::StateFunc SaveMgr::sStateFuncs[STATE_MAX] = {
+ &SaveMgr::executeCheckForSave, &SaveMgr::executeCheckForFreeSpace, &SaveMgr::executeCreateFiles,
+ &SaveMgr::executeSaveBanner, &SaveMgr::executeLoadSave, &SaveMgr::executeWriteSave,
+ &SaveMgr::executeWriteSkipDat, &SaveMgr::executeCopySave, &SaveMgr::executeClearSelectedFile,
+ &SaveMgr::executeSave, &SaveMgr::executeDeleteAllData, &SaveMgr::executeError,
+ &SaveMgr::executeNandError,
+};
+
+SaveMgr::SaveMgr()
+ : mCheckIsFileRequest(nullptr),
+ mCheckRequest(nullptr),
+ mCreateRequest(nullptr),
+ mWriteRequest(nullptr),
+ mSaveBannerRequest(nullptr),
+ mLoadSaveRequest(nullptr),
+ mDeleteRequest(nullptr) {
+ sInstance = this;
+ mpWindow = nullptr;
+}
+// Not used but this spawns the weak dtors
+SaveMgr::~SaveMgr() {
+ delete mpWindow;
+}
+
+void SaveMgr::create(EGG::Heap *heap) {
+ new (heap, 4) SaveMgr();
+ sInstance->init();
+}
+
+void SaveMgr::init() {
+ mCurrentState = STATE_MAX;
+ field_0x824 = 2;
+ mCheckForFreeSpaceResult = 0;
+ mCopyToFile = 0;
+ mCopyFromFile = 0;
+ field_0x836 = 0;
+ field_0x837 = 0;
+ field_0x838 = 0;
+ field_0x839 = 0;
+ field_0x83A = 0;
+ field_0x83B = 0;
+ field_0x83C = 0;
+ field_0x83D = 0;
+ field_0x83E = 0;
+ mDelayTimer = 0;
+ FileManager::GetInstance()->setField0xA840(1);
+ if (dCsBase_c::GetInstance() != nullptr) {
+ dCsBase_c::GetInstance()->setField704(false);
+ }
+ if (mpWindow != nullptr) {
+ mpWindow->reset();
+ }
+ field_0x83F = 0;
+}
+
+void SaveMgr::execute() {
+ if (mCurrentState != STATE_MAX) {
+ StateFunc f = sStateFuncs[mCurrentState];
+ if (f != nullptr) {
+ (this->*f)();
+ }
+ }
+}
+
+void SaveMgr::draw() {
+ d2d::defaultSet();
+ if (mpWindow != nullptr) {
+ mpWindow->drawNow();
+ }
+}
+
+void SaveMgr::createSaveMsgWindow() {
+ if (mpWindow == nullptr) {
+ mpWindow = new dLytSaveMsgWindow_c();
+ mpWindow->build(false);
+ }
+}
+
+bool SaveMgr::checkForSave() {
+ if (mCurrentState != STATE_MAX) {
+ return false;
+ }
+ field_0x836 = 0;
+ initializeCheckForSave();
+ return true;
+}
+
+bool SaveMgr::checkForFreeSpace() {
+ if (mCurrentState != STATE_MAX) {
+ return false;
+ }
+ field_0x836 = 0;
+ initializeCheckForFreeSpace();
+ return true;
+}
+
+bool SaveMgr::createFiles() {
+ if (mCurrentState != STATE_MAX) {
+ return false;
+ }
+ field_0x836 = 0;
+ initializeCreateFiles();
+ return true;
+}
+
+bool SaveMgr::loadSave() {
+ if (mCurrentState != STATE_MAX) {
+ return false;
+ }
+ field_0x836 = 0;
+ initializeLoadSave();
+ return true;
+}
+
+bool SaveMgr::save(bool entranceT1LoadFlag, bool full) {
+ if (mCurrentState != STATE_MAX) {
+ return false;
+ }
+ if (FileManager::GetInstance()->get_0xA84C()) {
+ return false;
+ }
+ field_0x836 = 0;
+ if (full == 1) {
+ FileManager::GetInstance()->saveT1SaveInfo(entranceT1LoadFlag);
+ } else {
+ FileManager::GetInstance()->setEntranceLoadFlagT1(entranceT1LoadFlag);
+ }
+ FileManager::GetInstance()->setFileTimes();
+ initializeSave();
+ field_0x83E = 0;
+ return true;
+}
+
+bool SaveMgr::saveAfterCredits() {
+ if (mCurrentState != STATE_MAX) {
+ return false;
+ }
+ if (FileManager::GetInstance()->get_0xA84C()) {
+ return false;
+ }
+ field_0x836 = 0;
+ dDvdUnk::FontUnk::GetInstance()->fn_80052D00(true);
+ FileManager::GetInstance()->setFileTimes();
+ FileManager::GetInstance()->saveAfterCredits();
+ initializeSave();
+ field_0x83E = 0;
+ return true;
+}
+
+bool SaveMgr::writeSkipDat() {
+ if (mCurrentState != STATE_MAX) {
+ return false;
+ }
+ field_0x836 = 0;
+ initializeWriteSkipDat();
+ return true;
+}
+
+bool SaveMgr::copySave(u8 to, u8 from) {
+ if (mCurrentState != STATE_MAX) {
+ return false;
+ }
+ field_0x836 = 0;
+ mCopyToFile = to;
+ mCopyFromFile = from;
+ initializeCopySave();
+ field_0x83F = 0;
+ return true;
+}
+
+bool SaveMgr::clearSelectedFile() {
+ if (mCurrentState != STATE_MAX) {
+ return false;
+ }
+ field_0x836 = 0;
+ initializeClearSelectedFile();
+ field_0x83F = 0;
+ return true;
+}
+
+void SaveMgr::initializeCheckForSave() {
+ beginState(STATE_CHECK_FOR_SAVE);
+ mCheckIsFileRequest.checkIsFile(sSaveFileName);
+ field_0x839 = 0;
+ dDvdUnk::FontUnk::GetInstance()->fn_80052D00(false);
+}
+
+void SaveMgr::executeCheckForSave() {
+ FileManager *fileManager = FileManager::GetInstance();
+ NandResultTracker *t = NandResultTracker::GetInstance();
+ switch (mStep) {
+ case 0:
+ if (mCheckIsFileRequest.isCompleted()) {
+ if (t->isFailure(mCheckIsFileRequest.getResult()) && mCheckIsFileRequest.finish()) {
+ return;
+ }
+ if (mCheckIsFileRequest.getCheckResult()) {
+ field_0x839 |= 2;
+ }
+ if (mCheckIsFileRequest.finish()) {
+ mCheckIsFileRequest.checkIsFile(sSkipDatFileName);
+ mStep = 1;
+ }
+ }
+ break;
+ case 1:
+ if (mCheckIsFileRequest.isCompleted()) {
+ if (t->isFailure(mCheckIsFileRequest.getResult()) && mCheckIsFileRequest.finish()) {
+ return;
+ }
+ if (mCheckIsFileRequest.getCheckResult()) {
+ field_0x839 |= 4;
+ }
+ if (mCheckIsFileRequest.finish()) {
+ mCheckIsFileRequest.checkIsFile(sBannerBinFileName);
+ mStep = 2;
+ }
+ }
+ break;
+ case 2:
+ if (mCheckIsFileRequest.isCompleted()) {
+ if (t->isFailure(mCheckIsFileRequest.getResult()) && mCheckIsFileRequest.finish()) {
+ return;
+ }
+ if (mCheckIsFileRequest.getCheckResult()) {
+ field_0x839 |= 1;
+ }
+ if (mCheckIsFileRequest.finish()) {
+ mStep = 3;
+ }
+ }
+ break;
+ case 3:
+ if (field_0x839 == (1 | 2) || field_0x839 == (1 | 2 | 4)) {
+ fileManager->setField0xA841(1);
+ if (field_0x839 == (1 | 2)) {
+ fileManager->setField0xA842(0);
+ } else {
+ fileManager->setField0xA842(1);
+ }
+ } else {
+ fileManager->setField0xA841(0);
+ fileManager->setField0xA842(0);
+ if (field_0x839) {
+ t->isFailure(NAND_RESULT_AUTHENTICATION);
+ initializeError();
+ return;
+ }
+ }
+ endState();
+ break;
+ }
+}
+
+void SaveMgr::initializeCheckForFreeSpace() {
+ beginState(STATE_CHECK_FOR_FREE_SPACE);
+ dDvdUnk::FontUnk::GetInstance()->fn_80052D00(false);
+ mCheckRequest.check(7, 3);
+ mCheckForFreeSpaceResult = 0;
+}
+
+void SaveMgr::executeCheckForFreeSpace() {
+ if (mCheckRequest.isCompleted()) {
+ if (NandResultTracker::GetInstance()->isFailure(mCheckRequest.getResult()) && mCheckRequest.finish()) {
+ return;
+ }
+ u32 result = mCheckRequest.getCheckResult();
+ if ((result & (NAND_CHECK_TOO_MANY_APP_BLOCKS | NAND_CHECK_TOO_MANY_USER_BLOCKS)) != 0) {
+ if (mCheckRequest.finish()) {
+ mCheckForFreeSpaceResult = 1;
+ initializeNandError();
+ }
+ } else if ((result & (NAND_CHECK_TOO_MANY_APP_FILES | NAND_CHECK_TOO_MANY_USER_FILES)) != 0) {
+ if (mCheckRequest.finish()) {
+ mCheckForFreeSpaceResult = 2;
+ initializeNandError();
+ }
+ } else {
+ if (mCheckRequest.finish()) {
+ if (field_0x838 == 1 || field_0x83A == 1) {
+ initializeCreateFiles();
+ } else {
+ endState();
+ }
+ }
+ }
+ }
+}
+
+void SaveMgr::initializeCreateFiles() {
+ beginState(STATE_CREATE_FILES);
+ field_0x838 = 1;
+ FileManager::GetInstance()->setField0xA84D(1);
+ dDvdUnk::FontUnk::GetInstance()->fn_80052D00(false);
+}
+
+void SaveMgr::executeCreateFiles() {
+ FileManager *fileMgr = FileManager::GetInstance();
+ switch (mStep) {
+ case 0: {
+ s32 numLines = 0;
+ if (field_0x83A != 0) {
+ if (field_0x837 == 1) {
+ // "Restoring save data. Please do not touch the POWER Button or RESET."
+ if (mpWindow->setProperties("SYS_INIT_06", 0, 1, field_0x83E)) {
+ numLines = 2;
+ }
+ } else {
+ // "Creating save data again. Please do not touch the POWER Button or RESET."
+ if (mpWindow->setProperties("SYS_INIT_08", 0, 1, field_0x83E)) {
+ numLines = 2;
+ }
+ }
+ } else {
+ // "Creating save data. Please do not touch the POWER Button or RESET."
+ if (mpWindow->setProperties("SYS_INIT_02", 0, 1, field_0x83E)) {
+ numLines = 2;
+ }
+ }
+ if (numLines != 0) {
+ mDelayTimer = 0;
+ mStep++;
+ mpWindow->setNumLines(numLines);
+ }
+ break;
+ }
+ case 1: {
+ if (mDelayTimer < 30) {
+ mDelayTimer++;
+ } else {
+ mCreateRequest.create(sSaveFileName, FILE_PERMS, 0);
+ mDelayTimer = 0;
+ mStep++;
+ }
+ break;
+ }
+ case 2: {
+ if (!mCreateRequest.isCompleted()) {
+ return;
+ }
+ NANDResult status = mCreateRequest.getResult();
+ if (!mCreateRequest.finish()) {
+ return;
+ }
+ if (NandResultTracker::GetInstance()->isFailure(status)) {
+ return;
+ }
+ fileMgr->setField0xA841(1);
+ mStep++;
+ break;
+ }
+ case 3: {
+ mCreateRequest.create(sSkipDatFileName, FILE_PERMS, 0);
+ mStep++;
+ break;
+ }
+ case 4: {
+ if (!mCreateRequest.isCompleted()) {
+ return;
+ }
+ NANDResult status = mCreateRequest.getResult();
+ if (!mCreateRequest.finish()) {
+ return;
+ }
+ if (NandResultTracker::GetInstance()->isFailure(status)) {
+ return;
+ }
+ if (dScGame_c::GetInstance() != nullptr && dScGame_c::GetInstance()->profile_name == fProfile::GAME) {
+ fileMgr->copySelectedFileSkipData();
+ }
+ fileMgr->setField0xA842(1);
+ initializeWriteSave();
+ mStep = 1; // Skips something in other state!
+ break;
+ }
+ }
+ mpWindow->execute();
+}
+
+void SaveMgr::initializeSaveBanner() {
+ beginState(STATE_SAVE_BANNER);
+ // "Zelda: Skyward Sword"
+ const wchar_t *title = dMessage_c::getTextMessageByLabel("SYS_ZELDA_01", true, nullptr, 0);
+ // Need to stash title as next call to getTextMessageByLabel will reuse internal buffer
+ // Missed optimization: Could've passed mTextBuf directly
+ for (s32 i = 0; i < 0x3FF; i++) {
+ mTextBuf[i] = title[i];
+ }
+ // "A story of Link and Zelda."
+ const wchar_t *subtitle = dMessage_c::getTextMessageByLabel("SYS_ZELDA_02", true, nullptr, 0);
+ void *data = LayoutArcManager::GetInstance()->getData("saveBannerU", "tmp/saveBanner.tpl");
+ mSaveBannerRequest.saveBanner(sTmpBannerBinFileName, (TPLPalette *)data, mTextBuf, subtitle, FILE_PERMS, 0);
+ FileManager::GetInstance()->setField0xA84D(1);
+}
+
+void SaveMgr::executeSaveBanner() {
+ dDvdUnk::FontUnk *fontUnk = dDvdUnk::FontUnk::GetInstance();
+ switch (mStep) {
+ case 0: {
+ mDelayTimer++;
+ if (!mSaveBannerRequest.isCompleted()) {
+ return;
+ }
+ FileManager::GetInstance()->setField0xA84D(0);
+ NANDResult result = mSaveBannerRequest.getResult();
+ bool bFailed = mSaveBannerRequest.hasFailed();
+ if (!mSaveBannerRequest.finish()) {
+ return;
+ }
+ if (NandResultTracker::GetInstance()->isFailure(result)) {
+ mStep = 20;
+ return;
+ }
+ if (bFailed) {
+ // retry
+ mStep = 10;
+ return;
+ }
+ mStep = 1;
+ break;
+ }
+ case 1: {
+ if (mDelayTimer < getFrameRate()) {
+ mDelayTimer++;
+ } else {
+ if (mpWindow->checkIsWait()) {
+ mDelayTimer = 0;
+ mStep++;
+ }
+ }
+ break;
+ }
+ case 2: {
+ if (mpWindow->getWillFinishOut() == 1) {
+ mStep++;
+ }
+ break;
+ }
+ case 3: {
+ bool b = false;
+ if (field_0x83A == 1) {
+ if (field_0x837 != 0) {
+ // "Save data is restored."
+ if (mpWindow->setProperties("SYS_INIT_07", 0, 1, field_0x83E) == true) {
+ b = true;
+ }
+ } else {
+ // "New save data has been created."
+ if (mpWindow->setProperties("SYS_INIT_09", 0, 1, field_0x83E) == true) {
+ b = true;
+ }
+ }
+ } else if (field_0x838 == 1) {
+ // "Save data for The Legend of Zelda: Skyward Sword has been created."
+ if (mpWindow->setProperties("SYS_INIT_03", 0, 1, field_0x83E) == true) {
+ b = true;
+ mpWindow->setNumLines(2);
+ }
+ } else if (field_0x83B == 1) {
+ // "Copying complete."
+ if (mpWindow->setProperties("SYS_COPY_02", 0, 1, field_0x83E) == true) {
+ b = true;
+ }
+ } else if (field_0x83C == 1) {
+ // "Deleting complete."
+ if (mpWindow->setProperties("SYS_DELETE_02", 0, 1, field_0x83E) == true) {
+ b = true;
+ }
+ } else {
+ // "Saved."
+ if (mpWindow->setProperties("SYS_SAVE_02", 0, 1, field_0x83E) == true) {
+ b = true;
+ }
+ }
+
+ if (b == 1) {
+ if (!dDvdUnk::FontUnk::GetInstance()->getField_0x28()) {
+ SmallSoundManager::GetInstance()->playSound(SE_S_SAVE_FINISH);
+ }
+ mDelayTimer = 0;
+ mStep++;
+ }
+ break;
+ }
+
+ case 4: {
+ if (mDelayTimer < getFrameRate() + 30) {
+ mDelayTimer++;
+ } else {
+ if (mpWindow->checkIsWait() == true) {
+ mDelayTimer = 0;
+ mStep++;
+ }
+ }
+ break;
+ }
+ case 5: {
+ if (mpWindow->getWillFinishOut() == 1) {
+ if (fontUnk->getField_0x29() == 1) {
+ fontUnk->fn_80052C90();
+ }
+ field_0x838 = 0;
+ field_0x83A = 0;
+ field_0x837 = 1;
+ endState();
+ }
+ break;
+ }
+ case 10: {
+ // retry
+ initializeSaveBanner();
+ break;
+ }
+ case 20: {
+ if (mpWindow->checkIsWait()) {
+ mStep++;
+ }
+ break;
+ }
+ case 21: {
+ initializeError();
+ break;
+ }
+ }
+ mpWindow->execute();
+}
+
+void SaveMgr::initializeLoadSave() {
+ beginState(STATE_LOAD_SAVE);
+ mLoadSaveRequest.loadSave(sSaveFileName, sizeof(SavedSaveFiles), 0, nullptr);
+}
+
+void SaveMgr::executeLoadSave() {
+ FileManager *fileManager = FileManager::GetInstance();
+ switch (mStep) {
+ case 0: {
+ if (!mLoadSaveRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mLoadSaveRequest.getResult();
+ NandResultTracker *tracker = NandResultTracker::GetInstance();
+ if (tracker->isFailure(result)) {
+ mLoadSaveRequest.remove();
+ if (mLoadSaveRequest.finish()) {
+ initializeError();
+ }
+ return;
+ }
+ if (mLoadSaveRequest.getBuf() != nullptr) {
+ fileManager->saveSaveData(&mLoadSaveRequest, false);
+ }
+ mLoadSaveRequest.remove();
+ if (!mLoadSaveRequest.finish()) {
+ return;
+ }
+ fileManager->checkFileStatus();
+ if (fileManager->isFileInvalid() == true) {
+ tracker->isFailure(NAND_RESULT_AUTHENTICATION);
+ initializeError();
+ } else if (fileManager->getField_0xA842() != 1) {
+ mStep = 10;
+ } else {
+ mStep = 1;
+ }
+ break;
+ }
+ case 1: {
+ mLoadSaveRequest.loadSave(sSkipDatFileName, 0x80, 0, nullptr);
+ mStep = 2;
+ break;
+ }
+ case 2: {
+ if (!mLoadSaveRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mLoadSaveRequest.getResult();
+ NandResultTracker *tracker = NandResultTracker::GetInstance();
+ if (tracker->isFailure(result)) {
+ mLoadSaveRequest.remove();
+ if (mLoadSaveRequest.finish()) {
+ mStep = 30;
+ }
+ return;
+ }
+ if (mLoadSaveRequest.getBuf() != nullptr) {
+ fileManager->saveSaveData(&mLoadSaveRequest, true);
+ }
+ mLoadSaveRequest.remove();
+ if (mLoadSaveRequest.finish()) {
+ if (fileManager->checkSkipDataCRCs() == 1) {
+ mStep = 3;
+ } else {
+ fileManager->updateEmptyFiles();
+ field_0x837 = 1;
+ endState();
+ }
+ }
+ break;
+ }
+ case 3: {
+ for (int i = 0; i < 3; i++) {
+ fileManager->copyFileSkipData(i);
+ }
+ mStep++;
+ break;
+ }
+ case 4: {
+ fileManager->updateEmptyFiles();
+ field_0x837 = 1;
+ initializeWriteSkipDat();
+ break;
+ }
+ case 10: {
+ mCheckRequest.check(1, 1);
+ mStep++;
+ break;
+ }
+ case 11: {
+ if (!mCheckRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mCheckRequest.getResult();
+ if (!NandResultTracker::GetInstance()->isFailure(result) || !mCheckRequest.finish()) {
+ u32 check = mCheckRequest.getCheckResult();
+ if (mCheckRequest.finish()) {
+ if (check) {
+ fileManager->updateEmptyFiles();
+ field_0x837 = 1;
+ endState();
+ } else {
+ mStep += 1;
+ }
+ }
+ }
+ break;
+ }
+ case 12: {
+ fileManager->setField0xA84D(1);
+ mCreateRequest.create(sSkipDatFileName, FILE_PERMS, 0);
+ mStep += 1;
+ break;
+ }
+ case 13: {
+ if (mCreateRequest.isCompleted()) {
+ NANDResult result = mCreateRequest.getResult();
+ if (mCreateRequest.finish()) {
+ if (!NandResultTracker::GetInstance()->isFailure(result)) {
+ for (int i = 0; i < 3; i++) {
+ fileManager->copyFileSkipData(i);
+ }
+ fileManager->setField0xA842(1);
+ mStep = 4;
+ }
+ }
+ }
+ break;
+ }
+ case 30: {
+ fileManager->setField0xA84D(1);
+ mDeleteRequest.doDelete(sSkipDatFileName);
+ mStep += 1;
+ break;
+ }
+ case 31: {
+ if (!mDeleteRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mDeleteRequest.getResult();
+ if (NandResultTracker::GetInstance()->isFailure(result)) {
+ if (mDeleteRequest.finish()) {
+ initializeError();
+ }
+
+ } else {
+ if (mDeleteRequest.finish()) {
+ mStep = 10;
+ }
+ }
+
+ break;
+ }
+ }
+}
+
+void SaveMgr::initializeWriteSave() {
+ beginState(STATE_WRITE);
+ mDelayTimer = 0;
+ dDvdUnk::FontUnk::GetInstance()->fn_80052D00(false);
+ FileManager::GetInstance()->setField0xA84D(1);
+ field_0x83D = 1;
+}
+
+void SaveMgr::executeWriteSave() {
+ FileManager *fileManager = FileManager::GetInstance();
+ switch (mStep) {
+ case 0: {
+ bool anyAction = false;
+ if (field_0x83B == 1) {
+ // "Copying... Please do not touch the POWER Button or RESET."
+ if (mpWindow->setProperties("SYS_COPY_01", 0, 1, field_0x83E)) {
+ anyAction = true;
+ }
+ } else if (field_0x83C == 1) {
+ // "Deleting... Please do not touch the POWER Button or RESET."
+ if (mpWindow->setProperties("SYS_DELETE_01", 0, 1, field_0x83E)) {
+ anyAction = true;
+ }
+ } else {
+ // "Saving in progress. Please do not\\ntouch the POWER Button or RESET."
+ if (mpWindow->setProperties("SYS_SAVE_01", 0, 1, field_0x83E)) {
+ anyAction = true;
+ }
+ }
+
+ if (anyAction == true) {
+ mStep = 1;
+ mDelayTimer = 0;
+ mpWindow->setNumLines(2);
+ }
+ break;
+ }
+ case 1: {
+ if (mDelayTimer >= 30) {
+ fileManager->loadSaveData(&mWriteRequest, sSaveFileName, false);
+ mDelayTimer = 0;
+ mStep++;
+ } else {
+ mDelayTimer++;
+ }
+ break;
+ }
+ case 2: {
+ mDelayTimer++;
+ if (!mWriteRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mWriteRequest.getResult();
+ if (NandResultTracker::GetInstance()->isFailure(result)) {
+ if (mWriteRequest.finish()) {
+ mStep = 10;
+ }
+ return;
+ }
+ if (mWriteRequest.failedWrite() == 1) {
+ if (mWriteRequest.finish()) {
+ mStep = 5;
+ }
+ return;
+ }
+ if (!mWriteRequest.finish()) {
+ return;
+ }
+ if (fileManager->getField_0xA842() == 1) {
+ mStep = 3;
+ } else {
+ mStep = 40;
+ }
+ break;
+ }
+ case 3: {
+ fileManager->loadSaveData(&mWriteRequest, sSkipDatFileName, true);
+ mStep = 4;
+ break;
+ }
+ case 4: {
+ mDelayTimer++;
+ if (!mWriteRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mWriteRequest.getResult();
+ if (NandResultTracker::GetInstance()->isFailure(result)) {
+ if (mWriteRequest.finish()) {
+ mStep = 30;
+ }
+ return;
+ }
+ if (mWriteRequest.failedWrite() == 1) {
+ if (mWriteRequest.finish()) {
+ mStep = 6;
+ }
+ return;
+ }
+ if (!mWriteRequest.finish()) {
+ return;
+ }
+ mStep = 40;
+ break;
+ }
+ case 5: {
+ fileManager->loadSaveData(&mWriteRequest, sSaveFileName, false);
+ mStep = 2;
+ mDelayTimer = 0;
+ break;
+ }
+ case 6: {
+ fileManager->loadSaveData(&mWriteRequest, sSkipDatFileName, true);
+ mStep = 4;
+ mDelayTimer = 0;
+ break;
+ }
+ case 10: {
+ if (mpWindow->checkIsWait()) {
+ initializeError();
+ }
+ break;
+ }
+ case 20: {
+ if (mpWindow->checkIsWait()) {
+ mStep++;
+ }
+ break;
+ }
+ case 21: {
+ if (mpWindow->getWillFinishOut() == true) {
+ fileManager->checkFileStatus();
+ if (fileManager->isFileInvalid() == 1) {
+ NandResultTracker::GetInstance()->isFailure(NAND_RESULT_AUTHENTICATION);
+ initializeError();
+ return;
+ }
+ initializeSaveBanner();
+ }
+ break;
+ }
+ case 30: {
+ mDelayTimer++;
+ mDeleteRequest.doDelete(sSkipDatFileName);
+ mStep++;
+ break;
+ }
+ case 31: {
+ mDelayTimer++;
+ if (!mDeleteRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mDeleteRequest.getResult();
+ if (NandResultTracker::GetInstance()->isFailure(result)) {
+ if (!mDeleteRequest.finish()) {
+ return;
+ }
+ mpWindow->checkIsWait();
+ initializeError();
+ return;
+ }
+ if (!mDeleteRequest.finish()) {
+ return;
+ }
+ fileManager->setField0xA842(0);
+ mStep++;
+ break;
+ }
+ case 32: {
+ mDelayTimer++;
+ mCheckRequest.check(1, 1);
+ mStep++;
+ break;
+ }
+ case 33: {
+ mDelayTimer++;
+ if (!mCheckRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mCheckRequest.getResult();
+ if (NandResultTracker::GetInstance()->isFailure(result) && mCheckRequest.finish()) {
+ mpWindow->checkIsWait();
+ initializeError();
+ } else {
+ u32 result = mCheckRequest.getCheckResult();
+ if (!mCheckRequest.finish()) {
+ return;
+ }
+ if (result) {
+ mStep = 40;
+ } else {
+ mStep++;
+ }
+ }
+ break;
+ }
+ case 34: {
+ mDelayTimer++;
+ mCreateRequest.create(sSkipDatFileName, FILE_PERMS, 0);
+ mStep++;
+ break;
+ }
+ case 35: {
+ mDelayTimer++;
+ if (!mCreateRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mCreateRequest.getResult();
+ if (!mCreateRequest.finish()) {
+ return;
+ }
+ if (NandResultTracker::GetInstance()->isFailure(result)) {
+ mpWindow->checkIsWait();
+ initializeError();
+ return;
+ }
+ for (int i = 0; i < 3; i++) {
+ fileManager->copyFileSkipData(i);
+ }
+ mStep = 3;
+ fileManager->setField0xA842(1);
+ break;
+ }
+ case 40: {
+ fileManager->checkFileStatus();
+ if (fileManager->isFileInvalid() == true) {
+ NandResultTracker::GetInstance()->isFailure(NAND_RESULT_UNKNOWN);
+ mpWindow->checkIsWait();
+ initializeError();
+ return;
+ }
+ u32 oldTimer = mDelayTimer;
+ initializeSaveBanner();
+ mDelayTimer = oldTimer;
+ break;
+ }
+ }
+ mpWindow->execute();
+}
+
+void SaveMgr::initializeWriteSkipDat() {
+ beginState(STATE_WRITE_SKIP_DAT);
+ if (FileManager::GetInstance()->get_0xA84C() || FileManager::GetInstance()->getField_0xA842() != 1) {
+ mStep = 10;
+ } else {
+ FileManager::GetInstance()->setField0xA84D(1);
+ FileManager::GetInstance()->copySelectedFileSkipData();
+ FileManager::GetInstance()->loadSaveData(&mWriteRequest, sSkipDatFileName, true);
+ }
+}
+
+void SaveMgr::executeWriteSkipDat() {
+ FileManager *fileManager = FileManager::GetInstance();
+ switch (mStep) {
+ case 0: {
+ if (mWriteRequest.isCompleted()) {
+ FileManager::GetInstance()->setField0xA84D(0);
+ NANDResult result = mWriteRequest.getResult();
+ if (NandResultTracker::GetInstance()->isFailure(result)) {
+ if (mWriteRequest.finish()) {
+ mStep = 30;
+ }
+ } else {
+ if (mWriteRequest.failedWrite() == true) {
+ if (mWriteRequest.finish()) {
+ mStep = 1;
+ }
+ } else {
+ if (mWriteRequest.finish()) {
+ endState();
+ }
+ }
+ }
+ }
+ break;
+ }
+ case 1: {
+ fileManager->loadSaveData(&mWriteRequest, sSkipDatFileName, true);
+ FileManager::GetInstance()->setField0xA84D(1);
+ mStep = 0;
+ mDelayTimer = 0;
+ break;
+ }
+ case 10: {
+ fileManager->setField0xA84D(0);
+ endState();
+ break;
+ }
+ case 30: {
+ fileManager->setField0xA84D(1);
+ mDeleteRequest.doDelete(sSkipDatFileName);
+ mStep++;
+ break;
+ }
+ case 31: {
+ if (!mDeleteRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mDeleteRequest.getResult();
+ if (NandResultTracker::GetInstance()->isFailure(result)) {
+ if (mDeleteRequest.finish()) {
+ initializeError();
+ }
+ } else {
+ if (mDeleteRequest.finish()) {
+ fileManager->setField0xA842(0);
+ mStep++;
+ }
+ }
+ break;
+ }
+ case 32: {
+ mCheckRequest.check(1, 1);
+ mStep++;
+ break;
+ }
+ case 33: {
+ if (mCheckRequest.isCompleted()) {
+ NANDResult result = mCheckRequest.getResult();
+ if (NandResultTracker::GetInstance()->isFailure(result) && mCheckRequest.finish()) {
+ initializeError();
+ } else {
+ u32 result = mCheckRequest.getCheckResult();
+ if (mCheckRequest.finish()) {
+ if (result) {
+ mStep = 10;
+ } else {
+ mStep++;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case 34: {
+ mDelayTimer++;
+ mCreateRequest.create(sSkipDatFileName, FILE_PERMS, 0);
+ mStep++;
+ break;
+ }
+ case 35: {
+ if (!mCreateRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mCreateRequest.getResult();
+ if (!mCreateRequest.finish()) {
+ return;
+ }
+ if (NandResultTracker::GetInstance()->isFailure(result)) {
+ initializeError();
+ return;
+ }
+ for (int i = 0; i < 3; i++) {
+ fileManager->copyFileSkipData(i);
+ }
+ fileManager->setField0xA842(1);
+ FileManager::GetInstance()->loadSaveData(&mWriteRequest, sSkipDatFileName, true);
+ mStep = 0;
+ break;
+ }
+ }
+}
+
+void SaveMgr::initializeCopySave() {
+ beginState(STATE_COPY_SAVE);
+ FileManager::GetInstance()->setField0xA840(0);
+ field_0x83B = 1;
+}
+
+void SaveMgr::executeCopySave() {
+ FileManager *fileManager = FileManager::GetInstance();
+ fileManager->copyFile(mCopyFromFile, mCopyToFile);
+ fileManager->setSelectedFileNum(mCopyToFile);
+ initializeWriteSave();
+ FileManager::GetInstance()->setField0xA840(1);
+}
+
+void SaveMgr::initializeClearSelectedFile() {
+ beginState(STATE_CLEAR_SELECTED_FILE);
+ FileManager::GetInstance()->setField0xA840(0);
+ field_0x83C = 1;
+}
+
+void SaveMgr::executeClearSelectedFile() {
+ FileManager::GetInstance()->clearFileA();
+ FileManager::GetInstance()->saveFileAToSelectedFile();
+ initializeWriteSave();
+ FileManager::GetInstance()->setField0xA840(1);
+}
+
+void SaveMgr::initializeSave() {
+ beginState(STATE_SAVE);
+ FileManager::GetInstance()->setField0xA840(0);
+ dDvdUnk::FontUnk::GetInstance()->fn_80052D00(false);
+ FileManager::GetInstance()->setField_0xA843(1);
+}
+
+void SaveMgr::executeSave() {
+ FileManager *fileManager = FileManager::GetInstance();
+ switch (mStep) {
+ case 0: {
+ if (fileManager->get_0xA84C() != 1 && fileManager->getField_0xA843()) {
+ if (fileManager->getField_0xA841() == 1) {
+ FileManager::GetInstance()->unsetFileANewFile();
+ FileManager::GetInstance()->copyFileAToSelectedFile();
+ initializeWriteSave();
+ FileManager::GetInstance()->setField0xA840(1);
+ } else {
+ FileManager::GetInstance()->copyFileAToSelectedFile();
+ FileManager::GetInstance()->setField0xA840(1);
+ initializeCheckForFreeSpace();
+ field_0x838 = 1;
+ }
+ }
+ break;
+ }
+ }
+}
+
+void SaveMgr::initializeDeleteAllData() {
+ beginState(STATE_DELETE_ALL_DATA);
+ field_0x83A = 1;
+}
+
+void SaveMgr::executeDeleteAllData() {
+ NandResultTracker *tracker = NandResultTracker::GetInstance();
+ switch (mStep) {
+ case 0: {
+ FileManager::GetInstance()->setField0xA84D(1);
+ mDeleteRequest.doDelete(sBannerBinFileName);
+ if (field_0x837 != 1 || FileManager::GetInstance()->isFileInvalid() == 1) {
+ FileManager::GetInstance()->initBlankSaveFiles();
+ }
+ mStep = 1;
+ break;
+ }
+ case 1: {
+ if (!mDeleteRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mDeleteRequest.getResult();
+ if (tracker->isFailure(result)) {
+ if (mDeleteRequest.finish()) {
+ initializeError();
+ }
+ } else {
+ if (mDeleteRequest.finish()) {
+ mStep = 2;
+ }
+ }
+ break;
+ }
+ case 2: {
+ mDeleteRequest.doDelete(sSaveFileName);
+ mStep = 3;
+ break;
+ }
+ case 3: {
+ if (!mDeleteRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mDeleteRequest.getResult();
+ if (tracker->isFailure(result)) {
+ if (mDeleteRequest.finish()) {
+ initializeError();
+ }
+ } else {
+ if (mDeleteRequest.finish()) {
+ mStep = 4;
+ }
+ }
+ break;
+ }
+ case 4: {
+ mDeleteRequest.doDelete(sSkipDatFileName);
+ mStep = 5;
+ break;
+ }
+ case 5: {
+ if (!mDeleteRequest.isCompleted()) {
+ return;
+ }
+ NANDResult result = mDeleteRequest.getResult();
+ if (tracker->isFailure(result)) {
+ if (mDeleteRequest.finish()) {
+ initializeError();
+ }
+ } else {
+ if (mDeleteRequest.finish()) {
+ initializeCheckForFreeSpace();
+ }
+ }
+ break;
+ }
+ }
+}
+
+void SaveMgr::initializeError() {
+ FileManager::GetInstance()->setField0xA84D(0);
+ field_0x83D = 0;
+ beginState(STATE_ERROR);
+ dDvdUnk::FontUnk::GetInstance()->fn_80052D00(true);
+ field_0x83F = 0;
+}
+
+void SaveMgr::executeError() {
+ dLytSystemWindow_c *systemWindow = dLytSystemWindow_c::GetInstance();
+ FileManager *fileManager = FileManager::GetInstance();
+ switch (mStep) {
+ case 0: {
+ if (dDvdUnk::FontUnk::GetInstance()->getField_0x24() == 4) {
+ if (field_0x837 == true) {
+ // "The save data is corrupted. Save data will be restored."
+ if (systemWindow->setProperties("SYS_INIT_05", false, nullptr) == true) {
+ systemWindow->showMaybe();
+ mStep = 20;
+ }
+ } else if (field_0x838 == true) {
+ // "Save data could not be created. Try again?[1]Yes[2]No"
+ if (systemWindow->setProperties("SYS_INIT_04", false, nullptr) == true) {
+ systemWindow->showMaybe(4);
+ mStep = 1;
+ dCsBase_c::GetInstance()->setField704(true);
+ }
+ } else {
+ // "The file cannot be used because nthe data is corrupted. All data saved up to this point will be
+ // lost. Create new save data?[1]Yes[2]No"
+ if (systemWindow->setProperties("SYS_NAND_07", false, nullptr) == true) {
+ systemWindow->showMaybe(4);
+ mStep = 1;
+ dCsBase_c::GetInstance()->setField704(true);
+ }
+ }
+ }
+ break;
+ }
+ case 1: {
+ if (systemWindow->getField_0xE10() != 0 && mPad::g_currentCore->downTrigger(/* A */ 0x800) &&
+ systemWindow->getField_0xDE0() != 2) {
+ if (systemWindow->getField_0xDE0() == 0) {
+ if (systemWindow->fn_80152F60() == true) {
+ mStep = 2;
+ }
+ } else {
+ if (systemWindow->fn_80152F50() == true) {
+ mStep = 2;
+ }
+ }
+ }
+ break;
+ }
+ case 2: {
+ if (systemWindow->fn_80152F70() == true) {
+ if (systemWindow->getField_0xDE0() == false) {
+ mStep = 3;
+ } else {
+ initializeDeleteAllData();
+ dCsBase_c::GetInstance()->setField704(false);
+ }
+ }
+ break;
+ }
+ case 3: {
+ if (dScBoot_c::GetInstance() != nullptr) {
+ // "You will not be able to save. Do you want to begin your game anyway? [1]Begin[2-]Quit"
+ if (systemWindow->setProperties("SYS_SAVE_10", false, nullptr) == true) {
+ systemWindow->showMaybe(4);
+ mpWindow->setNumLines(2);
+ mStep = 4;
+ }
+ } else {
+ // "It is not possible to save. Continue your adventure anyway? [1]Continue[2]Quit"
+ if (systemWindow->setProperties("SYS_SAVE_11", false, nullptr) == true) {
+ systemWindow->showMaybe(4);
+ mpWindow->setNumLines(2);
+ mStep = 4;
+ }
+ }
+ break;
+ }
+ case 4: {
+ if (mPad::g_currentCore->downTrigger(/* A */ 0x800) && systemWindow->getField_0xDE0() != 2) {
+ if (systemWindow->getField_0xDE0() == 0) {
+ if (systemWindow->fn_80152F60() == true) {
+ mStep = 5;
+ }
+ } else {
+ if (systemWindow->fn_80152F50()) {
+ mStep = 10;
+ }
+ }
+ }
+ break;
+ }
+ case 5: {
+ if (systemWindow->fn_80152F70() == true) {
+ mStep = 6;
+ }
+ break;
+ }
+ case 6: {
+ if (field_0x837 == true) {
+ // "The save data is corrupted. Save data will be restored."
+ if (systemWindow->setProperties("SYS_INIT_05", false, nullptr) == true) {
+ systemWindow->showMaybe(4);
+ mStep = 1;
+ }
+ } else {
+ // "The file cannot be used because nthe data is corrupted. All data saved up to this point will be
+ // lost. Create new save data?[1]Yes[2]No"
+ if (systemWindow->setProperties("SYS_NAND_07", false, nullptr) == true) {
+ systemWindow->showMaybe(4);
+ mStep = 1;
+ }
+ }
+ break;
+ }
+ case 10: {
+ if (systemWindow->fn_80152F70() == true) {
+ dDvdUnk::FontUnk::GetInstance()->fn_80052C90();
+ if (field_0x837 != true) {
+ fileManager->setField0xA84C(1);
+ }
+ dCsBase_c::GetInstance()->setField704(false);
+ endState();
+ }
+ break;
+ }
+ case 20: {
+ if (systemWindow->fn_80152F70() == true) {
+ mStep++;
+ }
+ break;
+ }
+ case 21: {
+ if (systemWindow->getField_0xDFC() == true && mPad::g_currentCore->downTrigger(/* A */ 0x800) &&
+ systemWindow->fn_80152F50() == true) {
+ mStep++;
+ }
+ break;
+ }
+ case 22: {
+ if (systemWindow->fn_80152F70() == true) {
+ initializeDeleteAllData();
+ }
+ }
+ }
+ if (mpWindow != nullptr) {
+ mpWindow->execute();
+ }
+}
+
+void SaveMgr::initializeNandError() {
+ FileManager::GetInstance()->setField0xA84D(0);
+ field_0x83D = 0;
+ dDvdUnk::FontUnk::GetInstance()->fn_80052D00(true);
+ beginState(STATE_NAND_ERROR);
+}
+
+void SaveMgr::executeNandError() {
+ FileManager *fileManager = FileManager::GetInstance();
+ dLytSystemWindow_c *systemWindow = dLytSystemWindow_c::GetInstance();
+ switch (mStep) {
+ case 0: {
+ bool anyAction = false;
+ if (mCheckForFreeSpaceResult == 1) {
+ // "There is not enough available space in Wii system memory. Create 1 block of free space either by
+ // moving data to an SD Card or deleting data in the Wii console's Data Management screen."
+ if (systemWindow->setProperties("SYS_NAND_02", false, nullptr) == true) {
+ anyAction = true;
+ }
+ } else {
+ // "There is not enough available space in Wii system memory. Either move data to an SD Card or delete
+ // data in the Wii console's Data Management screen."
+ if (systemWindow->setProperties("SYS_NAND_03", false, nullptr) == true) {
+ anyAction = true;
+ }
+ }
+ if (anyAction) {
+ systemWindow->showMaybe();
+ mStep = 1;
+ }
+ break;
+ }
+ case 1: {
+ if (systemWindow->fn_80152F70() == 1) {
+ mStep = 2;
+ }
+ break;
+ }
+ case 2: {
+ if (systemWindow->getField_0xDFC() == 1 && mPad::g_currentCore->downTrigger(/* A */ 0x800) &&
+ systemWindow->fn_80152F60() == 1) {
+ mStep = 3;
+ }
+ break;
+ }
+ case 3: {
+ if (systemWindow->fn_80152F70() == 1) {
+ mStep = 4;
+ }
+ break;
+ }
+ case 4: {
+ // "Do you want to go to the Wii console's Data Management screen to edit data? [1]Yes[2]No"
+ if (systemWindow->setProperties("SYS_NAND_04", false, nullptr) == true) {
+ systemWindow->showMaybe(4);
+ dCsBase_c::GetInstance()->setField704(true);
+ mStep = 5;
+ }
+ break;
+ }
+ case 5: {
+ if (systemWindow->fn_80152F70() == 1) {
+ mStep = 6;
+ }
+ break;
+ }
+ case 6: {
+ if (systemWindow->getField_0xE10() != 0) {
+ if (!ReloadColorFader::GetInstance()->fn_80068E80() &&
+ !ReloadColorFader::GetInstance()->fn_80067F60() &&
+ mPad::g_currentCore->downTrigger(/* A */ 0x800) && systemWindow->getField_0xDE0() != 2 &&
+ systemWindow->fn_80152F60() == true) {
+ mStep = 7;
+ }
+ }
+ break;
+ }
+ case 7: {
+ if (systemWindow->fn_80152F70() == 1) {
+ mStep = 8;
+ }
+ break;
+ }
+ case 8: {
+ if (systemWindow->getField_0xDE0() == 0) {
+ mStep = 9;
+ } else {
+ dCsBase_c::GetInstance()->setField704(false);
+ ReloadColorFader::GetInstance()->fn_80067FE0();
+ endState();
+ field_0x836 = 0;
+ }
+ break;
+ }
+ case 9: {
+ // "You will not be able to save. Do you want to begin your game anyway? [1]Begin[2-]Quit"
+ if (systemWindow->setProperties("SYS_SAVE_10", false, nullptr) == true) {
+ systemWindow->showMaybe(4);
+ // Why save mgs window and not system window?
+ mpWindow->setNumLines(2);
+ mStep = 10;
+ }
+ break;
+ }
+ case 10: {
+ if (systemWindow->fn_80152F70() == 1) {
+ mStep = 11;
+ }
+ break;
+ }
+ case 11: {
+ if (systemWindow->getField_0xE10() != 0 && mPad::g_currentCore->downTrigger(/* A */ 0x800) &&
+ systemWindow->getField_0xDE0() != 2) {
+ if (systemWindow->getField_0xDE0() == 0) {
+ if (systemWindow->fn_80152F60() == true) {
+ mStep = 12;
+ }
+ } else {
+ if (systemWindow->fn_80152F50()) {
+ mStep = 13;
+ }
+ }
+ }
+ break;
+ }
+ case 12: {
+ if (systemWindow->fn_80152F70() == 1) {
+ mStep = 0;
+ }
+ break;
+ }
+ case 13: {
+ if (systemWindow->fn_80152F70() == 1) {
+ dCsBase_c::GetInstance()->setField704(false);
+ dDvdUnk::FontUnk::GetInstance()->fn_80052C90();
+ fileManager->setField0xA84C(1);
+ endState();
+ }
+ break;
+ }
+ }
+}
+
+void SaveMgr::beginState(SaveMgrState_e state) {
+ mCurrentState = state;
+ field_0x824 = 2;
+ mStep = 0;
+ mDelayTimer = 0;
+}
+
+void SaveMgr::endState() {
+ field_0x836 = 1;
+ FileManager::GetInstance()->setField0xA840(1);
+ field_0x83D = 0;
+ dDvdUnk::FontUnk::GetInstance()->fn_80052D00(true);
+ field_0x83B = 0;
+ field_0x83C = 0;
+ mCurrentState = STATE_MAX;
+ field_0x83E = 0;
+ field_0x83F = 0;
+}
+
+s32 SaveMgr::getFrameRate() {
+ return 60 / dSys::getFrameRate();
+}
+
+NandRequestCheckIsFile::NandRequestCheckIsFile(const char *path) : mIsFile(0) {
+ mPath = path;
+}
+
+bool NandRequestCheckIsFile::execute() {
+ u8 type = 0;
+ mStatus = NANDGetType(mPath, &type);
+ if (mStatus == NAND_RESULT_OK && type == NAND_FILE_TYPE_FILE) {
+ mIsFile = 1;
+ } else {
+ mIsFile = 0;
+ }
+ return true;
+}
+
+bool NandRequestCheckIsFileHolder::checkIsFile(const char *path) {
+ if (mpRequest != nullptr) {
+ return false;
+ }
+ NandRequestCheckIsFile *req = new NandRequestCheckIsFile(path);
+ if (req == nullptr) {
+ return false;
+ }
+ NandRequestThread::GetInstance()->enqueueRequest(req);
+ mpRequest = req;
+ return true;
+}
+
+bool NandRequestCheckIsFileHolder::getCheckResult() const {
+ return static_cast<NandRequestCheckIsFile *>(mpRequest)->mIsFile;
+}
+
+NandRequestSaveBanner::NandRequestSaveBanner(
+ const char *filePath, TPLPalette *palette, const wchar_t *title, const wchar_t *subtitle, u8 perm, u8 attr
+)
+ : NandRequestCreate(filePath, perm, attr),
+ mpPalette(palette),
+ mpTitle(title),
+ mpSubTitle(subtitle),
+ mFailed(false) {}
+
+bool NandRequestSaveBanner::execute() {
+ if (!NandRequestCreate::execute()) {
+ return true;
+ }
+
+ char homeDir[64];
+ NANDFileInfo info;
+ mStatus = NANDOpen(mFilePath, &info, NAND_ACCESS_WRITE);
+ if (mStatus != NAND_RESULT_OK) {
+ return mStatus;
+ }
+
+ if (writeBannerTpl(&info) != 0x72A0) {
+ NANDResult res = NANDClose(&info);
+ if (res != NAND_RESULT_OK) {
+ mStatus = res;
+ }
+ mFailed = true;
+ return false;
+ }
+
+ mStatus = NANDClose(&info);
+ mStatus = NANDGetHomeDir(homeDir);
+ if (mStatus != NAND_RESULT_OK) {
+ return mStatus;
+ }
+
+ mStatus = NANDMove(mFilePath, homeDir);
+ return true;
+}
+
+#define NUM_BANNER_ICONS 1
+
+u32 NandRequestSaveBanner::writeBannerTpl(NANDFileInfo *info) {
+ static NANDBanner sBanner;
+ NANDInitBanner(&sBanner, 0, getTitle(), getSubTitle());
+ TPLPalette *palette = getPalette();
+ TPLDescriptor *tpl = TPLGet(palette, 0);
+ std::memcpy(&sBanner.bannerTexture, tpl->texHeader->data, NAND_BANNER_TEXTURE_SIZE);
+ for (s32 i = 0; i < NUM_BANNER_ICONS;) {
+ TPLDescriptor *tpl = TPLGet(palette, i + 1);
+ std::memcpy(sBanner.iconTexture[0], tpl->texHeader->data, NAND_BANNER_ICON_TEXTURE_SIZE);
+ // ah yes
+ s32 idx = i++;
+ NAND_SET_ICON_SPEED(&sBanner, idx, 2);
+ }
+ NAND_SET_ICON_SPEED(&sBanner, NUM_BANNER_ICONS, 0);
+ // How is this calculated?
+ return NANDWrite(info, &sBanner, 0x72A0);
+}
+
+bool NandRequestSaveBannerHolder::saveBanner(
+ const char *filePath, TPLPalette *palette, const wchar_t *title, const wchar_t *subtitle, u8 perm, u8 attr
+) {
+ if (mpRequest != nullptr) {
+ return false;
+ }
+ NandRequestSaveBanner *req = new NandRequestSaveBanner(filePath, palette, title, subtitle, perm, attr);
+ if (req == nullptr) {
+ return false;
+ }
+ NandRequestThread::GetInstance()->enqueueRequest(req);
+ mpRequest = req;
+ return true;
+}
+
+bool NandRequestSaveBannerHolder::hasFailed() const {
+ return static_cast<NandRequestSaveBanner *>(mpRequest)->mFailed;
+}
+
+NandRequestLoadSaveFile::NandRequestLoadSaveFile(const char *path, s32 readSize, s32 mountDirection, EGG::Heap *heap)
+ : mpHeap(heap), mpBuf(nullptr), mBufLen(0), mMountDirection(mountDirection), mReadSize(readSize), mUnused(false) {
+ mPath = path;
+ if (mpHeap == nullptr) {
+ mpHeap = dHeap::work2Heap.heap;
+ }
+}
+
+bool NandRequestLoadSaveFile::execute() {
+ NANDFileInfo info;
+ mStatus = NANDOpen(mPath, &info, NAND_ACCESS_READ);
+ if (mStatus != NAND_RESULT_OK) {
+ return true;
+ }
+
+ u32 length;
+ mStatus = NANDGetLength(&info, &length);
+ if (mStatus != NAND_RESULT_OK) {
+ mStatus = NAND_RESULT_AUTHENTICATION; // ??
+ NANDResult res = NANDClose(&info);
+ if (res != NAND_RESULT_OK) {
+ mStatus = res;
+ }
+ return true;
+ }
+
+ if (length != mReadSize) {
+ mStatus = NAND_RESULT_AUTHENTICATION; // ??
+ NANDResult res = NANDClose(&info);
+ if (res != NAND_RESULT_OK) {
+ mStatus = res;
+ }
+ return true;
+ }
+ s32 align = mMountDirection == 0 ? 0x20 : -0x20;
+ mpBuf = mpHeap->alloc(length, align);
+ if (mpBuf == nullptr) {
+ mStatus = NAND_RESULT_AUTHENTICATION; // ??
+ NANDResult res = NANDClose(&info);
+ if (res != NAND_RESULT_OK) {
+ mStatus = res;
+ }
+ return false;
+ }
+
+ mBufLen = length;
+ mStatus = NANDRead(&info, mpBuf, mBufLen);
+ NANDResult res = NANDClose(&info);
+ if (mStatus != mBufLen && mStatus >= NAND_RESULT_OK) {
+ mStatus = NAND_RESULT_AUTHENTICATION; // ??
+ } else if (mStatus != NAND_RESULT_ECC_CRIT && mStatus != NAND_RESULT_AUTHENTICATION) {
+ mStatus = res;
+ }
+ return true;
+}
+
+void NandRequestLoadSaveFile::remove() {
+ if (mpBuf != nullptr) {
+ mpHeap->free(mpBuf);
+ mpBuf = nullptr;
+ mBufLen = 0;
+ }
+}
+
+bool NandRequestLoadSaveFileHolder::loadSave(const char *path, s32 readSize, s32 mountDirection, EGG::Heap *heap) {
+ if (mpRequest != nullptr) {
+ return false;
+ }
+ NandRequestLoadSaveFile *req = new NandRequestLoadSaveFile(path, readSize, mountDirection, heap);
+ if (req == nullptr) {
+ return false;
+ }
+ NandRequestThread::GetInstance()->enqueueRequest(req);
+ mpRequest = req;
+ return true;
+}
+
+void *NandRequestLoadSaveFileHolder::getBuf() const {
+ return static_cast<NandRequestLoadSaveFile *>(mpRequest)->mpBuf;
+}
+
+u32 NandRequestLoadSaveFileHolder::getLen() const {
+ return static_cast<NandRequestLoadSaveFile *>(mpRequest)->mBufLen;
+}
+
+void NandRequestLoadSaveFileHolder::remove() {
+ static_cast<NandRequestLoadSaveFile *>(mpRequest)->remove();
+}
+
+NandRequestDelete::NandRequestDelete(const char *path) {
+ mPath = path;
+}
+
+bool NandRequestDelete::execute() {
+ mStatus = NANDDelete(mPath);
+ return true;
+}
+
+bool NandRequestDeleteHolder::doDelete(const char *path) {
+ if (mpRequest != nullptr) {
+ return false;
+ }
+ NandRequestDelete *req = new NandRequestDelete(path);
+ if (req == nullptr) {
+ return false;
+ }
+ NandRequestThread::GetInstance()->enqueueRequest(req);
+ mpRequest = req;
+ return true;
+}