#include "m_card.h" #include "card/__card.h" #include "libultra/libultra.h" #include "m_malloc.h" #include "libc64/sleep.h" #include "m_common_data.h" #include "m_font.h" #include "jsyswrap.h" #include "zurumode.h" #include "m_house.h" #include "m_cockroach.h" typedef struct card_bg_info { CARDFileInfo fileInfo; s32 fileNo; int space_proc; int tries; void* data; s32 offset; s32 length; } mCD_bg_info_c; enum { mCD_WBC_CHECK_SLOT, mCD_WBC_INIT, mCD_WBC_CHECK_FILESYSTEM, mCD_WBC_OPEN_FILE, mCD_WBC_READ, mCD_WBC_WRITE, mCD_WBC_FINISHED, mCD_WBC_NUM = mCD_WBC_FINISHED }; enum { mCD_SAVEHOME_BG_PROC_GET_AREA, mCD_SAVEHOME_BG_PROC_ERASE_DUMMY, mCD_SAVEHOME_BG_PROC_CHECK_SLOT, mCD_SAVEHOME_BG_PROC_READ_SEND_PRESENT, mCD_SAVEHOME_BG_PROC_WRITE_PRESENT, mCD_SAVEHOME_BG_PROC_GET_SLOT, mCD_SAVEHOME_BG_PROC_CREATE_FILE, mCD_SAVEHOME_BG_PROC_CHECK_REPAIR_LAND, mCD_SAVEHOME_BG_PROC_REPAIR_LAND, mCD_SAVEHOME_BG_PROC_SET_FILE_PERMISSION, mCD_SAVEHOME_BG_PROC_SET_DATA, mCD_SAVEHOME_BG_PROC_WRITE_MAIN_2, mCD_SAVEHOME_BG_PROC_WRITE_BK, mCD_SAVEHOME_BG_PROC_SET_OTHERS, mCD_SAVEHOME_BG_PROC_WRITE_OTHERS, mCD_SAVEHOME_BG_PROC_GET_STATUS_2, mCD_SAVEHOME_BG_PROC_SET_STATUS_2, mCD_SAVEHOME_BG_PROC_RENAME, mCD_SAVEHOME_BG_PROC_NUM }; static char mCD_file_name[32] = "DobutsunomoriP_MURA"; static int l_mcd_err_debug[mCD_ERROR_NUM] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }; static s32 l_mcd_err_result = CARD_RESULT_READY; static mCD_bg_info_c l_mcd_bg_info; static void mCD_ClearErrInfo(void) { bzero(l_mcd_err_debug, sizeof(l_mcd_err_debug)); l_mcd_err_result = 0; } static void mCD_OnErrInfo(int err) { if (err >= 0 && err < mCD_ERROR_NUM) { l_mcd_err_debug[err] = TRUE; } } static void mCD_OffErrInfo(int err) { if (err >= 0 && err < mCD_ERROR_NUM) { l_mcd_err_debug[err] = FALSE; } } static void mCD_SetErrResult(s32 result) { l_mcd_err_result = result; } extern void mCD_PrintErrInfo(gfxprint_t* gfxprint) { gfxprint_color(gfxprint, 250, 100, 250, 255); gfxprint_locate8x8(gfxprint, 22, 3); if (l_mcd_err_debug[mCD_ERROR_NOT_ENABLED]) { gfxprint_printf(gfxprint, "N"); } if (l_mcd_err_debug[mCD_ERROR_AREA]) { gfxprint_printf(gfxprint, "A"); } if (l_mcd_err_debug[mCD_ERROR_WRITE]) { gfxprint_printf(gfxprint, "W"); } if (l_mcd_err_debug[mCD_ERROR_READ]) { gfxprint_printf(gfxprint, "R"); } if (l_mcd_err_debug[mCD_ERROR_CHECKSUM]) { gfxprint_printf(gfxprint, "C"); } if (l_mcd_err_debug[mCD_ERROR_OUTDATED]) { gfxprint_printf(gfxprint, "O"); } if (l_mcd_err_debug[mCD_ERROR_CREATE]) { gfxprint_printf(gfxprint, "c"); } if (l_mcd_err_result != CARD_RESULT_READY) { gfxprint_printf(gfxprint, "%d", l_mcd_err_result); } } static void* mCD_malloc_32(u32 size) { return zelda_malloc_align(size, 32); } static int mCD_check_card_common(s32* result, s32 req_sector_size, s32 chan) { s32 mem_size = 0; s32 sector_size = 0; int res = mCD_RESULT_BUSY; *result = CARDProbeEx(chan, &mem_size, §or_size); if (*result == CARD_RESULT_READY && sector_size == req_sector_size) { res = mCD_RESULT_SUCCESS; } else if (*result != CARD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } return res; } static int mCD_check_card(s32* result, s32 req_sector_size, s32 chan) { int ms = 0; int check_common_res = mCD_RESULT_BUSY; int res = mCD_RESULT_ERROR; while (check_common_res == mCD_RESULT_BUSY && ms < 500) { check_common_res = mCD_check_card_common(result, req_sector_size, chan); if (check_common_res == mCD_RESULT_BUSY) { msleep(1); ms++; } } if (check_common_res == mCD_RESULT_SUCCESS) { res = mCD_RESULT_SUCCESS; } return res; } static int mCD_check_sector_size(u32 req_sector_size, int chan) { s32 mem_size = 0; s32 sector_size = 0; int ms = 0; s32 result = CARD_RESULT_BUSY; int res = mCD_RESULT_ERROR; while (result == CARD_RESULT_BUSY && ms < 500) { result = CARDProbeEx((s32)chan, &mem_size, §or_size); if (result == CARD_RESULT_BUSY) { msleep(1); ms++; } } if (result == CARD_RESULT_READY) { if (req_sector_size == sector_size) { res = mCD_RESULT_SUCCESS; } else { res = mCD_RESULT_BUSY; } } return res; } static int mCD_get_file_num_com(int chan) { CARDFileInfo fileInfo; s32 num = 0; s32 file_no; for (file_no = 0; file_no < CARD_MAX_FILE; file_no++) { s32 result = CARDFastOpen(chan, file_no, &fileInfo); if (result == CARD_RESULT_READY) { num++; CARDClose(&fileInfo); } } return num; } static int mCD_get_file_num(void* workArea, int chan) { int num = 0; s32 result; if (workArea != NULL && mCD_check_card(&result, mCD_MEMCARD_SECTORSIZE, chan) == mCD_RESULT_SUCCESS) { result = CARDMount((s32)chan, workArea, NULL); if (result == CARD_RESULT_READY || result == CARD_RESULT_BROKEN) { result = CARDCheck((s32)chan); num = mCD_get_file_num_com(chan); CARDUnmount((s32)chan); } else if (result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } } return num; } extern void mCD_init_card(void) { CARDInit(); } static void mCD_ClearCardBgInfo(mCD_bg_info_c* bg_info) { bzero(bg_info, sizeof(mCD_bg_info_c)); } static void mCD_StartSetCardBgInfo(void) { mCD_ClearCardBgInfo(&l_mcd_bg_info); } static int mCD_get_space_bg_get_slot(s32* freeBlocks, mCD_bg_info_c* bg_info, s32 chan, s32* result, void* workArea) { int res; bg_info->tries++; res = mCD_check_card_common(result, mCD_MEMCARD_SECTORSIZE, (s32)chan); if (res == mCD_RESULT_SUCCESS && workArea != NULL) { *freeBlocks = 0; *result = CARDMountAsync((s32)chan, workArea, NULL, NULL); if (*result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } else if (*result != CARD_RESULT_READY && *result != CARD_RESULT_BROKEN) { res = mCD_RESULT_ERROR; } bg_info->tries = 0; } else if (res != mCD_RESULT_BUSY) { *freeBlocks = 0; res = mCD_RESULT_ERROR; bg_info->tries = 0; } else if (bg_info->tries >= 100) { *freeBlocks = 0; res = mCD_RESULT_ERROR; bg_info->tries = 0; } return res; } static int mCD_get_space_bg_main(s32* freeBlocks, mCD_bg_info_c* bg_info, s32 chan, s32* result, void* workArea) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY || *result == CARD_RESULT_BROKEN) { *result = CARDCheck((s32)chan); if (*result == CARD_RESULT_READY) { s32 freeFiles; *result = CARDFreeBlocks((s32)chan, freeBlocks, &freeFiles); if (*result == CARD_RESULT_READY) { res = mCD_RESULT_SUCCESS; } else { res = mCD_RESULT_ERROR; } } else { res = mCD_RESULT_ERROR; } CARDUnmount((s32)chan); } else if (*result != CARD_RESULT_BUSY) { if (*result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } res = mCD_RESULT_ERROR; } return res; } typedef int (*mCD_GET_SPACE_BG_PROC)(s32*, mCD_bg_info_c*, s32, s32*, void*); static int mCD_get_space_bg(s32* freeBlocks, s32 chan, s32* result, void* workArea) { static mCD_GET_SPACE_BG_PROC get_proc[mCD_SPACE_BG_NUM] = { &mCD_get_space_bg_get_slot, &mCD_get_space_bg_main }; mCD_bg_info_c* bg_info = &l_mcd_bg_info; u8 proc_type = bg_info->space_proc; int res = mCD_RESULT_BUSY; *freeBlocks = 0; if (proc_type < mCD_SPACE_BG_NUM) { int proc_res = (*get_proc[proc_type])(freeBlocks, bg_info, chan, result, workArea); if (proc_res == mCD_RESULT_SUCCESS) { bg_info->space_proc++; if (bg_info->space_proc >= mCD_SPACE_BG_NUM) { res = mCD_RESULT_SUCCESS; mCD_ClearCardBgInfo(bg_info); } } else if (proc_res != mCD_RESULT_BUSY) { res = mCD_RESULT_ERROR; mCD_ClearCardBgInfo(bg_info); } } else { res = mCD_RESULT_ERROR; mCD_ClearCardBgInfo(bg_info); } return res; } static void mCD_close_and_unmount(CARDFileInfo* fileInfo, s32 chan) { CARDClose(fileInfo); CARDUnmount(chan); } static int mCD_bg_check_slot(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; int common_res = mCD_check_card_common(result, mCD_MEMCARD_SECTORSIZE, chan); bg_info->tries++; if (common_res == mCD_RESULT_SUCCESS) { bg_info->space_proc++; bg_info->tries = 0; res = mCD_RESULT_SUCCESS; } else if (common_res != mCD_RESULT_BUSY || bg_info->tries >= 100) { bg_info->tries = 0; res = mCD_RESULT_ERROR; } return res; } static int mCD_bg_init_com(mCD_bg_info_c* bg_info, s32 chan, s32* result, void** workArea_p, void** read_p, int read) { int res; *workArea_p = mCD_malloc_32(CARD_WORKAREA_SIZE); if (read == TRUE) { *read_p = mCD_malloc_32(mCD_MEMCARD_SECTORSIZE); } if (*workArea_p != NULL && (read == FALSE || (read == TRUE && *read_p != NULL))) { *result = CARDMountAsync((s32)chan, *workArea_p, NULL, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else if (*result == CARD_RESULT_BROKEN) { *result = CARDCheckAsync((s32)chan, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc = 3; res = mCD_RESULT_SUCCESS; } else { if (*result == CARD_RESULT_BROKEN || *result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } res = mCD_RESULT_ERROR; } } else { if (*result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } res = mCD_RESULT_ERROR; } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_bg_init(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { return mCD_bg_init_com(bg_info, chan, result, workArea_p, read_p, FALSE); } static int mCD_bg_check_filesystem(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDCheckAsync((s32)chan, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } return res; } static int mCD_write_bg_open_file(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDOpen((s32)chan, filename, &bg_info->fileInfo); if (*result == CARD_RESULT_READY) { CARDStat stat; bg_info->fileNo = bg_info->fileInfo.fileNo; *result = CARDGetStatus((s32)chan, bg_info->fileNo, &stat); if (*result == CARD_RESULT_READY && stat.length == length) { *result = CARDWriteAsync(&bg_info->fileInfo, data, data_len, offset, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { mCD_close_and_unmount(&bg_info->fileInfo, (s32)chan); res = mCD_RESULT_ERROR; } } else { mCD_close_and_unmount(&bg_info->fileInfo, (s32)chan); res = mCD_RESULT_ERROR; } } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } return res; } static int mCD_write_bg_write(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode(chan); if (*result == CARD_RESULT_READY) { *result = CARDWriteAsync(&bg_info->fileInfo, data, data_len, offset, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { mCD_close_and_unmount(&bg_info->fileInfo, chan); res = mCD_RESULT_ERROR; } return res; } static int mCD_write_bg_cleanup(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode(chan); if (*result != CARD_RESULT_BUSY) { mCD_close_and_unmount(&bg_info->fileInfo, chan); bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } return res; } typedef int (*mCD_BG_PROC)(mCD_bg_info_c*, s32, s32*, void*, const char*, s32, u32, s32, void**, void**, CARDStat*); /* @unused static int mCD_write_bg(void* data, const char* filename, s32 data_len, u32 length, s32 offset, s32 chan, * s32* result) */ static int mCD_write_bg(void* data, const char* filename, s32 data_len, u32 length, s32 offset, s32 chan, s32* result) { static void* work_p = NULL; // clang-format off static mCD_BG_PROC wbg_proc[] = { &mCD_bg_check_slot, &mCD_bg_init, &mCD_bg_check_filesystem, &mCD_write_bg_open_file, &mCD_write_bg_write, &mCD_write_bg_cleanup, }; // clang-format on return 0; } static int mCD_bg_init_write_comp(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_bg_init_com(bg_info, chan, result, workArea_p, read_p, TRUE); if (res == mCD_RESULT_SUCCESS) { bg_info->data = data; bg_info->offset = offset; if (data_len < mCD_MEMCARD_SECTORSIZE) { bg_info->length = data_len; } else { bg_info->length = mCD_MEMCARD_SECTORSIZE; } } return res; } static int mCD_write_comp_bg_open_file(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDOpen((s32)chan, filename, &bg_info->fileInfo); if (*result == CARD_RESULT_READY) { CARDStat stat; bg_info->fileNo = bg_info->fileInfo.fileNo; *result = CARDGetStatus((s32)chan, bg_info->fileNo, &stat); if (*result == CARD_RESULT_READY && stat.length == length) { bzero(*read_p, mCD_MEMCARD_SECTORSIZE); *result = CARDReadAsync(&bg_info->fileInfo, *read_p, bg_info->length, bg_info->offset, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { res = mCD_RESULT_ERROR; mCD_close_and_unmount(&bg_info->fileInfo, chan); } } else { mCD_close_and_unmount(&bg_info->fileInfo, chan); res = mCD_RESULT_ERROR; } } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } return res; } static int mCD_write_comp_bg_read(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode(chan); if (*result == CARD_RESULT_READY) { if (mem_cmp((u8*)*read_p, (u8*)bg_info->data, bg_info->length) == 0) { *result = CARDWriteAsync(&bg_info->fileInfo, bg_info->data, bg_info->length, bg_info->offset, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { mCD_close_and_unmount(&bg_info->fileInfo, chan); res = mCD_RESULT_ERROR; } } else { int ofs; bg_info->offset += mCD_MEMCARD_SECTORSIZE; ofs = bg_info->offset - offset; if (ofs >= data_len) { mCD_close_and_unmount(&bg_info->fileInfo, chan); bg_info->space_proc = mCD_WBC_FINISHED; res = mCD_RESULT_SUCCESS; } else { if (data_len - ofs < mCD_MEMCARD_SECTORSIZE) { bg_info->length = data_len - ofs; /* Remaining size less than memcard sector size */ } else { bg_info->length = mCD_MEMCARD_SECTORSIZE; } bg_info->data = (void*)((u32)data + ofs); bzero(*read_p, mCD_MEMCARD_SECTORSIZE); *result = CARDReadAsync(&bg_info->fileInfo, *read_p, bg_info->length, bg_info->offset, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc = mCD_WBC_READ; res = mCD_RESULT_SUCCESS; } else { mCD_close_and_unmount(&bg_info->fileInfo, chan); res = mCD_RESULT_ERROR; } } } } else if (*result != CARD_RESULT_BUSY) { mCD_close_and_unmount(&bg_info->fileInfo, chan); res = mCD_RESULT_ERROR; } return res; } static int mCD_write_comp_bg_write(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; int ofs; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { bg_info->offset += mCD_MEMCARD_SECTORSIZE; ofs = bg_info->offset - offset; if (ofs >= data_len) { mCD_close_and_unmount(&bg_info->fileInfo, chan); bg_info->space_proc = mCD_WBC_FINISHED; res = mCD_RESULT_SUCCESS; } else { if (data_len - ofs < mCD_MEMCARD_SECTORSIZE) { bg_info->length = data_len - ofs; /* Remaining size less than memcard sector size */ } else { bg_info->length = mCD_MEMCARD_SECTORSIZE; } bg_info->data = (void*)((u32)data + ofs); bzero(*read_p, mCD_MEMCARD_SECTORSIZE); *result = CARDReadAsync(&bg_info->fileInfo, *read_p, bg_info->length, bg_info->offset, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc = mCD_WBC_READ; res = mCD_RESULT_SUCCESS; } else { mCD_close_and_unmount(&bg_info->fileInfo, chan); res = mCD_RESULT_ERROR; } } } else if (*result != CARD_RESULT_BUSY) { mCD_close_and_unmount(&bg_info->fileInfo, chan); res = mCD_RESULT_ERROR; } return res; } static int mCD_write_comp_bg(void* data, const char* filename, s32 data_len, u32 length, s32 offset, s32 chan, s32* result) { static void* work_p = NULL; static void* read_p = NULL; // clang-format off static mCD_BG_PROC wcbg_proc[] = { &mCD_bg_check_slot, &mCD_bg_init_write_comp, &mCD_bg_check_filesystem, &mCD_write_comp_bg_open_file, &mCD_write_comp_bg_read, &mCD_write_comp_bg_write, }; // clang-format on int res = mCD_RESULT_BUSY; mCD_bg_info_c* bg_info = &l_mcd_bg_info; int proc = bg_info->space_proc; if (proc >= 0 && proc < mCD_WBC_NUM) { int success = (*wcbg_proc[proc])(bg_info, chan, result, data, filename, data_len, length, offset, &work_p, &read_p, NULL); if (success == mCD_RESULT_SUCCESS && bg_info->space_proc == mCD_WBC_FINISHED) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_SUCCESS; } else if (success == mCD_RESULT_ERROR) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_ERROR; } if (res != mCD_RESULT_BUSY) { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } if (read_p != NULL) { zelda_free(read_p); read_p = NULL; } } } else { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } if (read_p != NULL) { zelda_free(read_p); read_p = NULL; } mCD_ClearCardBgInfo(bg_info); work_p = NULL; // extra set res = mCD_RESULT_ERROR; } /* Debug display for error state */ if (ZURUMODE2_ENABLED()) { if (res == mCD_RESULT_ERROR) { mCD_OnErrInfo(mCD_ERROR_WRITE); mCD_SetErrResult(*result); } else if (res == mCD_RESULT_SUCCESS) { mCD_OffErrInfo(mCD_ERROR_WRITE); mCD_SetErrResult(*result); } } return res; } static int mCD_read_bg_open_file(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDOpen((s32)chan, filename, &bg_info->fileInfo); if (*result == CARD_RESULT_READY) { *result = CARDReadAsync(&bg_info->fileInfo, data, data_len, offset, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc = 4; res = mCD_RESULT_SUCCESS; } else { mCD_close_and_unmount(&bg_info->fileInfo, chan); res = mCD_RESULT_ERROR; } } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { if (*result == CARD_RESULT_BROKEN || *result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } res = mCD_RESULT_ERROR; } return res; } static int mCD_read_bg_cleanup(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode(chan); if (*result != CARD_RESULT_BUSY) { mCD_close_and_unmount(&bg_info->fileInfo, chan); bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } return res; } /* @unused */ static int mCD_read_bg(void* data, const char* filename, s32 data_len, u32 length, s32 offset, s32 chan, s32* result) { static void* work_p = NULL; // clang-format off static mCD_BG_PROC rbg_proc[] = { &mCD_bg_check_slot, &mCD_bg_init, &mCD_bg_check_filesystem, &mCD_read_bg_open_file, &mCD_read_bg_cleanup, }; // clang-format on return 0; } static int mCD_read_fg(void* buf, const char* filename, s32 length, s32 offset, s32 chan, s32* result) { void* workArea; int res = mCD_RESULT_ERROR; if (buf != NULL && IS_ALIGNED((u32)buf, 32)) { int card_res = mCD_check_card(result, mCD_MEMCARD_SECTORSIZE, chan); if (card_res == mCD_RESULT_SUCCESS) { workArea = mCD_malloc_32(CARD_WORKAREA_SIZE); if (workArea != NULL) { *result = CARDMount((s32)chan, workArea, NULL); if (*result == CARD_RESULT_READY || *result == CARD_RESULT_BROKEN) { *result = CARDCheck((s32)chan); if (*result == CARD_RESULT_READY) { CARDFileInfo fileInfo; *result = CARDOpen((s32)chan, filename, &fileInfo); if (*result == CARD_RESULT_READY) { *result = CARDRead(&fileInfo, buf, length, offset); if (*result == CARD_RESULT_READY) { res = mCD_RESULT_SUCCESS; } mCD_close_and_unmount(&fileInfo, chan); } else { CARDUnmount((s32)chan); } } else { CARDUnmount((s32)chan); } } else if (*result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } if (workArea != NULL) { zelda_free(workArea); } } } } else { *result = CARD_RESULT_FATAL_ERROR; res = mCD_RESULT_ERROR; } return res; } static int mCD_find_fg(const char* filename, void* workArea, s32 chan, s32* result) { int res = FALSE; if (mCD_check_card(result, mCD_MEMCARD_SECTORSIZE, chan) == mCD_RESULT_SUCCESS && workArea != NULL) { *result = CARDMount((s32)chan, workArea, NULL); if (*result == CARD_RESULT_READY || *result == CARD_RESULT_BROKEN) { *result = CARDCheck((s32)chan); if (*result == CARD_RESULT_READY) { CARDFileInfo fileInfo; *result = CARDOpen((s32)chan, filename, &fileInfo); if (*result == CARD_RESULT_READY) { mCD_close_and_unmount(&fileInfo, chan); res = TRUE; } else { CARDUnmount((s32)chan); } } else { CARDUnmount((s32)chan); } } else if (*result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } } return res; } static int mCD_format_bg_mount(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { *workArea_p = mCD_malloc_32(CARD_WORKAREA_SIZE); if (*workArea_p != NULL) { *result = CARDMountAsync(chan, *workArea_p, NULL, NULL); if (*result == CARD_RESULT_READY || *result == CARD_RESULT_BROKEN || *result == CARD_RESULT_ENCODING) { bg_info->space_proc++; return mCD_RESULT_SUCCESS; } else { return mCD_RESULT_ERROR; } } else { return mCD_RESULT_ERROR; } } static int mCD_format_bg_open_file(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY || *result == CARD_RESULT_ENCODING || *result == CARD_RESULT_BROKEN) { *result = CARDFormatAsync((s32)chan, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } return res; } static int mCD_format_bg_cleanup(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result != CARD_RESULT_BUSY) { res = *result == CARD_RESULT_READY ? mCD_RESULT_SUCCESS : mCD_RESULT_ERROR; CARDUnmount((s32)chan); bg_info->space_proc++; } return res; } static int mCD_format_bg(s32 chan, s32* result) { static void* work_p = NULL; // clang-format off static mCD_BG_PROC fbg_proc[] = { &mCD_bg_check_slot, &mCD_format_bg_mount, &mCD_format_bg_open_file, &mCD_format_bg_cleanup, }; // clang-format on int res = mCD_RESULT_BUSY; mCD_bg_info_c* const bg_info = &l_mcd_bg_info; if (bg_info->space_proc >= 0 && bg_info->space_proc < 4) { int success = (*fbg_proc[bg_info->space_proc])(&l_mcd_bg_info, chan, result, NULL, NULL, 0, 0, 0, &work_p, NULL, NULL); if (success == mCD_RESULT_SUCCESS && bg_info->space_proc == 4) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_SUCCESS; } else if (success == mCD_RESULT_ERROR) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_ERROR; } if (res != mCD_RESULT_BUSY) { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } } } else { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } res = mCD_RESULT_ERROR; } return res; } static int mCD_set_file_status_bg_open_file(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDOpen((s32)chan, filename, &bg_info->fileInfo); if (*result == CARD_RESULT_READY) { bg_info->fileNo = bg_info->fileInfo.fileNo; *result = CARDSetStatusAsync((s32)chan, bg_info->fileNo, stat, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { mCD_close_and_unmount(&bg_info->fileInfo, chan); res = mCD_RESULT_ERROR; } } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } return res; } static int mCD_set_file_status_bg_cleanup(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode(chan); if (*result != CARD_RESULT_BUSY) { res = *result == CARD_RESULT_READY ? mCD_RESULT_SUCCESS : mCD_RESULT_ERROR; mCD_close_and_unmount(&bg_info->fileInfo, chan); bg_info->space_proc++; } return res; } static int mCD_set_file_status_bg(CARDStat* stat, const char* filename, s32 chan, s32* result) { static void* work_p = NULL; // clang-format off static mCD_BG_PROC ssbg_proc[] = { &mCD_bg_check_slot, &mCD_bg_init, &mCD_bg_check_filesystem, &mCD_set_file_status_bg_open_file, &mCD_set_file_status_bg_cleanup, }; // clang-format on int res = mCD_RESULT_BUSY; mCD_bg_info_c* const bg_info = &l_mcd_bg_info; if (bg_info->space_proc >= 0 && bg_info->space_proc < 5) { int success = (*ssbg_proc[bg_info->space_proc])(bg_info, chan, result, NULL, filename, 0, 0, 0, &work_p, NULL, stat); if (success == mCD_RESULT_SUCCESS && bg_info->space_proc == 5) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_SUCCESS; } else if (success == mCD_RESULT_ERROR) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_ERROR; } if (res != mCD_RESULT_BUSY) { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } } } else { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } res = mCD_RESULT_ERROR; } return res; } static int mCD_get_file_status_bg_open_file(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDOpen((s32)chan, filename, &bg_info->fileInfo); if (*result == CARD_RESULT_READY) { bg_info->fileNo = bg_info->fileInfo.fileNo; *result = CARDGetStatus((s32)chan, bg_info->fileNo, stat); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { res = mCD_RESULT_ERROR; } mCD_close_and_unmount(&bg_info->fileInfo, chan); } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } return res; } static int mCD_get_file_status_bg(CARDStat* stat, const char* filename, s32 chan, s32* result) { static void* work_p = NULL; // clang-format off static mCD_BG_PROC gsbg_proc[] = { &mCD_bg_check_slot, &mCD_bg_init, &mCD_bg_check_filesystem, &mCD_get_file_status_bg_open_file, }; // clang-format on int res = mCD_RESULT_BUSY; mCD_bg_info_c* const bg_info = &l_mcd_bg_info; if (bg_info->space_proc >= 0 && bg_info->space_proc < 4) { int success = (*gsbg_proc[bg_info->space_proc])(bg_info, chan, result, NULL, filename, 0, 0, 0, &work_p, NULL, stat); if (success == mCD_RESULT_SUCCESS && bg_info->space_proc == 4) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_SUCCESS; } else if (success == mCD_RESULT_ERROR) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_ERROR; } if (res != mCD_RESULT_BUSY) { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } } } else { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } res = mCD_RESULT_ERROR; } return res; } static int mCD_create_file_bg_create(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDCreateAsync((s32)chan, filename, length, &bg_info->fileInfo, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } return res; } static int mCD_create_file_bg_set_not_copy(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { CARDDir dir; bg_info->fileNo = bg_info->fileInfo.fileNo; *result = __CARDGetStatusEx((s32)chan, bg_info->fileNo, &dir); if (*result == CARD_RESULT_READY) { dir.permission |= data_len; /* @bug - missing *result = ? */ __CARDSetStatusEx((s32)chan, bg_info->fileNo, &dir); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { res = mCD_RESULT_ERROR; } } else { res = mCD_RESULT_ERROR; } mCD_close_and_unmount(&bg_info->fileInfo, chan); } else if (*result != CARD_RESULT_BUSY) { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } return res; } static int mCD_create_file_bg(const char* filename, s32 perms, u32 length, s32 chan, s32* result, s32* fileNo) { static void* work_p = NULL; // clang-format off static mCD_BG_PROC cbg_proc[] = { &mCD_bg_check_slot, &mCD_bg_init, &mCD_bg_check_filesystem, &mCD_create_file_bg_create, &mCD_create_file_bg_set_not_copy, }; // clang-format on int res; mCD_bg_info_c* bg_info; int proc; res = mCD_RESULT_BUSY; bg_info = &l_mcd_bg_info; proc = bg_info->space_proc; *fileNo = 0; if (proc >= 0 && proc < 5) { int success = (*cbg_proc[proc])(bg_info, chan, result, NULL, filename, perms, length, 0, &work_p, NULL, NULL); if (success == mCD_RESULT_SUCCESS && bg_info->space_proc == 5) { *fileNo = bg_info->fileNo; mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_SUCCESS; } else if (success == mCD_RESULT_ERROR) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_ERROR; } if (res != mCD_RESULT_BUSY) { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } } } else { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } res = mCD_RESULT_ERROR; } /* Debug display for error state */ if (ZURUMODE2_ENABLED()) { if (res == mCD_RESULT_ERROR) { mCD_OnErrInfo(mCD_ERROR_CREATE); mCD_SetErrResult(*result); } else if (res == mCD_RESULT_SUCCESS) { mCD_OffErrInfo(mCD_ERROR_CREATE); mCD_SetErrResult(*result); } } return res; } static int mCD_set_file_permission_bg_set(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDOpen((s32)chan, filename, &bg_info->fileInfo); if (*result == CARD_RESULT_READY) { CARDDir dir; bg_info->fileNo = bg_info->fileInfo.fileNo; *result = __CARDGetStatusEx((s32)chan, bg_info->fileNo, &dir); if (*result == CARD_RESULT_READY) { dir.permission |= data_len; /* @bug - missing *result = ? */ __CARDSetStatusEx((s32)chan, bg_info->fileNo, &dir); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { res = mCD_RESULT_ERROR; } } else { res = mCD_RESULT_ERROR; } mCD_close_and_unmount(&bg_info->fileInfo, chan); } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } return res; } static int mCD_set_file_permission_bg(const char* filename, s32 perms, s32 chan, s32* result, s32* fileNo) { static void* work_p = NULL; // clang-format off static mCD_BG_PROC sp_proc[] = { &mCD_bg_check_slot, &mCD_bg_init, &mCD_bg_check_filesystem, &mCD_set_file_permission_bg_set, }; // clang-format on int res = mCD_RESULT_BUSY; mCD_bg_info_c* bg_info = &l_mcd_bg_info; int proc = bg_info->space_proc; if (fileNo != NULL) { *fileNo = 0; } if (proc >= 0 && proc < 4) { int success = (*sp_proc[proc])(bg_info, chan, result, NULL, filename, perms, 0, 0, &work_p, NULL, NULL); if (success == mCD_RESULT_SUCCESS && bg_info->space_proc == 4) { if (fileNo != NULL) { *fileNo = bg_info->fileNo; } mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_SUCCESS; } else if (success == mCD_RESULT_ERROR) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_ERROR; } if (res != mCD_RESULT_BUSY) { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } } } else { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } res = mCD_RESULT_ERROR; } /* Debug display for error state */ if (ZURUMODE2_ENABLED()) { if (res == mCD_RESULT_ERROR) { mCD_OnErrInfo(mCD_ERROR_CREATE); mCD_SetErrResult(*result); } else if (res == mCD_RESULT_SUCCESS) { mCD_OffErrInfo(mCD_ERROR_CREATE); mCD_SetErrResult(*result); } } return res; } static int mCD_erase_file_bg_erase(mCD_bg_info_c* bg_info, s32 chan, s32* result, void* data, const char* filename, s32 data_len, u32 length, s32 offset, void** workArea_p, void** read_p, CARDStat* stat) { int res = mCD_RESULT_BUSY; *result = CARDGetResultCode((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDDeleteAsync((s32)chan, filename, NULL); if (*result == CARD_RESULT_READY) { bg_info->space_proc++; res = mCD_RESULT_SUCCESS; } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else if (*result != CARD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } return res; } static int mCD_erase_file_bg(const char* filename, s32 chan, s32* result) { static void* work_p = NULL; // clang-format off static mCD_BG_PROC ebg_proc[] = { &mCD_bg_check_slot, &mCD_bg_init, &mCD_bg_check_filesystem, &mCD_erase_file_bg_erase, &mCD_format_bg_cleanup, }; // clang-format on int res = mCD_RESULT_BUSY; mCD_bg_info_c* bg_info = &l_mcd_bg_info; int proc = bg_info->space_proc; if (proc >= 0 && proc < 5) { int success = (*ebg_proc[proc])(bg_info, chan, result, NULL, filename, 0, 0, 0, &work_p, NULL, NULL); if (success == mCD_RESULT_SUCCESS && bg_info->space_proc == 5) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_SUCCESS; } else if (success == mCD_RESULT_ERROR) { mCD_ClearCardBgInfo(bg_info); res = mCD_RESULT_ERROR; } if (res != mCD_RESULT_BUSY) { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } } } else { if (work_p != NULL) { zelda_free(work_p); work_p = NULL; } res = mCD_RESULT_ERROR; } return res; } static int mCD_erase_file_fg(const char* filename, s32 chan, s32* result, void* workArea) { int res = FALSE; if (chan != -1 && workArea != NULL && mCD_check_card(result, mCD_MEMCARD_SECTORSIZE, chan) == mCD_RESULT_SUCCESS) { *result = CARDMount((s32)chan, workArea, NULL); if (*result == CARD_RESULT_READY || *result == CARD_RESULT_BUSY) { *result = CARDCheck((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDDelete((s32)chan, filename); if (*result == CARD_RESULT_READY) { res = TRUE; } } CARDUnmount((s32)chan); } else if (*result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } } return res; } static int mCD_rename_file_fg(const char* new_filename, const char* filename, s32 chan, s32* result, void* workArea) { int res = FALSE; if (chan != -1 && workArea != NULL && mCD_check_card(result, mCD_MEMCARD_SECTORSIZE, (s32)chan) == mCD_RESULT_SUCCESS) { *result = CARDMount((s32)chan, workArea, NULL); if (*result == CARD_RESULT_READY || *result == CARD_RESULT_BUSY) { *result = CARDCheck((s32)chan); if (*result == CARD_RESULT_READY) { *result = CARDRename((s32)chan, filename, new_filename); if (*result == CARD_RESULT_READY) { res = TRUE; } } CARDUnmount((s32)chan); } else if (*result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } } return res; } static u16 l_mcd_copy_protect = 0xFFFF; // clang-format off static u8 l_mcd_font_1[256] ATTRIBUTE_ALIGN(4) = { 0xa1, 0xbf, 0xc4, 0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdf, 0xde, 0xe0, 0xa0, 0x21, 0x94, 0xe1, 0xe2, 0x25, 0x26, 0xb4, 0x28, 0x29, 0x7e, 0x97, 0x82, 0x2d, 0x2e, 0x97, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x97, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0xe3, 0x97, 0xe4, 0xe5, 0x5f, 0xe7, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0xe8, 0xe9, 0xea, 0xeb, 0x97, 0x97, 0xec, 0xed, 0xee, 0xef, 0x95, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0x96, 0xfb, 0xfc, 0xfd, 0xff, 0xfe, 0xdd, 0x7c, 0xa7, 0x97, 0x97, 0xb6, 0xb5, 0xb3, 0xb2, 0xb9, 0xaf, 0xac, 0xc6, 0xe6, 0x84, 0xbb, 0xab, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x2f, 0x97, 0x97, 0x97, 0x97, 0x97, 0x2b, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0xf7, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x3b, 0x23, 0xa0, 0xa0, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97 }; // clang-format on static char l_comment_0_str[32] ATTRIBUTE_ALIGN(4) = "Animal Crossing"; static char l_comment_1_str[32] ATTRIBUTE_ALIGN(4) = " Town Data"; static char l_comment_erase_land[32] ATTRIBUTE_ALIGN(4) = "Letters and Designs Data"; static char l_comment_player_0_str[32] ATTRIBUTE_ALIGN(4) = "Animal Crossing"; static char l_comment_player_1_str[32] ATTRIBUTE_ALIGN(4) = " is traveling"; static char l_comment_present_0_str[32] ATTRIBUTE_ALIGN(4) = "Animal Crossing"; static char l_comment_present_1_str[32] ATTRIBUTE_ALIGN(4) = "Bonus Letters:"; static char l_comment_gift_1_str[32] ATTRIBUTE_ALIGN(4) = "Gift Letters:"; static char l_mCD_land_file_name[32] ATTRIBUTE_ALIGN(4) = "DobutsunomoriP_MURA"; static char l_mCD_land_file_name_dummy[32] ATTRIBUTE_ALIGN(4) = "DobutsunomoriP_MURA_d"; static char l_mCD_player_file_name[32] ATTRIBUTE_ALIGN(4) = "DobutsunomoriP_PL_"; static char l_mCD_present_file_name[32] ATTRIBUTE_ALIGN(4) = "DobutsunomoriP_Omake_"; typedef struct { const char* filename; /* filename */ int filesize; /* size of the entire file */ int entrysize; /* size of the sub-entry */ } mCD_file_entry_c; static mCD_file_entry_c l_mcd_file_table[] = { { l_mCD_land_file_name, mCD_LAND_SAVE_SIZE, sizeof(Save) }, { l_mCD_land_file_name, mCD_LAND_SAVE_SIZE, sizeof(Save) }, { l_mCD_land_file_name, mCD_LAND_SAVE_SIZE, sizeof(Save) }, { l_mCD_land_file_name, mCD_LAND_SAVE_SIZE, mCD_MAIL_SAVE_SIZE }, { l_mCD_land_file_name, mCD_LAND_SAVE_SIZE, mCD_ORIGINAL_SAVE_SIZE }, { l_mCD_land_file_name, mCD_LAND_SAVE_SIZE, mCD_DIARY_SAVE_SIZE }, { l_mCD_present_file_name, mCD_PRESENT_SAVE_SIZE, mCD_PRESENT_SAVE_SIZE }, { l_mCD_player_file_name, mCD_PLAYER_SAVE_SIZE, mCD_PLAYER_SAVE_SIZE }, }; static int l_keepSave_set; static int l_mcd_keep_startCond = 0; static int l_aram_access_bit = 0; static void mCD_clear_aram_access_bit(void) { l_aram_access_bit = 0; } static u32 l_aram_alloc_size_table[mCD_ARAM_DATA_NUM] = { ALIGN_NEXT(sizeof(mCD_keep_original_c), 32), ALIGN_NEXT(sizeof(mCD_keep_mail_c), 32), ALIGN_NEXT(sizeof(mCD_keep_diary_c), 32), }; static u32 l_aram_real_size_32_table[mCD_ARAM_DATA_NUM] = { ALIGN_NEXT(sizeof(mCD_keep_original_c), 32), ALIGN_NEXT(sizeof(mCD_keep_mail_c), 32), ALIGN_NEXT(sizeof(mCD_keep_diary_c), 32), }; static void* l_aram_block_p_table[mCD_ARAM_DATA_NUM]; extern void mCD_save_data_aram_malloc(void) { int i; for (i = 0; i < mCD_ARAM_DATA_NUM; i++) { l_aram_block_p_table[i] = JC__JKRAllocFromAram(l_aram_alloc_size_table[i]); } } extern int mCD_save_data_aram_to_main(void* dst, u32 size, u32 idx) { int res = FALSE; void* aram_block; if (idx >= mCD_ARAM_DATA_NUM) { idx = 0; } aram_block = l_aram_block_p_table[idx]; if (aram_block != NULL) { JC__JKRAramToMainRam_block(aram_block, dst, size); DCFlushRange(dst, size); res = TRUE; } return res; } extern int mCD_save_data_main_to_aram(void* src, u32 size, u32 idx) { int res = FALSE; void* aram_block; if (idx >= mCD_ARAM_DATA_NUM) { idx = 0; } aram_block = l_aram_block_p_table[idx]; if (aram_block != NULL) { DCFlushRange(src, size); JC__JKRMainRamToAram_block(src, aram_block, size); res = TRUE; } return res; } static u32 mCD_get_aram_save_data_max_size(void) { u32 size = 0; int i; for (i = 0; i < mCD_ARAM_DATA_NUM; i++) { if (l_aram_alloc_size_table[i] > size) { size = l_aram_alloc_size_table[i]; } } return size; } static void mCD_set_init_mail_data(u8* buf) { mCD_keep_mail_c* keep_mail = (mCD_keep_mail_c*)buf; Mail_c* mail = (Mail_c*)keep_mail->mail; int i; int j; for (i = 0; i < mCD_KEEP_MAIL_PAGE_COUNT; i++) { mem_clear(keep_mail->folder_names[i], sizeof(keep_mail->folder_names[i]), CHAR_SPACE); for (j = 0; j < mCD_KEEP_MAIL_COUNT; j++) { mMl_clear_mail(mail); mail++; } } } static void mCD_set_init_original_data(u8* buf) { mCD_keep_original_c* keep_original = (mCD_keep_original_c*)buf; int i; int j; for (i = 0; i < mCD_KEEP_ORIGINAL_PAGE_COUNT; i++) { mem_clear(keep_original->folder_names[i], sizeof(keep_original->folder_names[i]), CHAR_SPACE); for (j = 0; j < mCD_KEEP_ORIGINAL_COUNT; j++) { mNW_InitOriginalData(&keep_original->original[i][j]); } } } static void mCD_set_init_diary_data(u8* buf) { mCD_keep_diary_c* keep_diary = (mCD_keep_diary_c*)buf; mDi_entry_c* entry_p; int i; int j; for (i = 0; i < mCD_KEEP_DIARY_COUNT; i++) { entry_p = keep_diary->entries[i]; for (j = 0; j < mCD_KEEP_DIARY_ENTRY_COUNT; j++) { mDi_init_diary(entry_p); entry_p++; } } } typedef void (*mCD_DATA_INIT_PROC)(u8*); extern void mCD_set_aram_save_data(void) { static mCD_DATA_INIT_PROC init_proc[] = { &mCD_set_init_original_data, &mCD_set_init_mail_data, &mCD_set_init_diary_data, }; u32 max_size = mCD_get_aram_save_data_max_size(); u8* buf = (u8*)mCD_malloc_32(max_size); if (buf != NULL) { int i; for (i = 0; i < mCD_ARAM_DATA_NUM; i++) { if (l_aram_block_p_table[i] != NULL) { bzero(buf, max_size); (*init_proc[i])(buf); mCD_save_data_main_to_aram(buf, l_aram_real_size_32_table[i], i); } } zelda_free(buf); mCD_clear_aram_access_bit(); } } static int mCD_TransErrorCode(s32 result_code) { switch (result_code) { case CARD_RESULT_READY: return mCD_TRANS_ERR_NONE; case CARD_RESULT_NOCARD: case CARD_RESULT_WRONGDEVICE: return mCD_TRANS_ERR_NOCARD; case CARD_RESULT_IOERROR: return mCD_TRANS_ERR_IOERROR; case CARD_RESULT_BROKEN: case CARD_RESULT_ENCODING: return mCD_TRANS_ERR_BROKEN_WRONGENCODING; case CARD_RESULT_NOENT: case CARD_RESULT_INSSPACE: return mCD_TRANS_ERR_NO_SPACE; case CARD_RESULT_EXIST: case CARD_RESULT_CANCELED: case CARD_RESULT_FATAL_ERROR: case CARD_RESULT_NAMETOOLONG: case CARD_RESULT_LIMIT: case CARD_RESULT_NOPERM: case CARD_RESULT_NOFILE: return mCD_TRANS_ERR_GENERIC; case CARD_RESULT_BUSY: return mCD_TRANS_ERR_BUSY; default: return mCD_TRANS_ERR_GENERIC; } } static int mCD_TransErrorCode_nes(s32 result_code) { switch (result_code) { case CARD_RESULT_READY: return mCD_TRANS_ERR_NONE; case CARD_RESULT_WRONGDEVICE: return mCD_TRANS_ERR_WRONGDEVICE; case CARD_RESULT_NOCARD: return mCD_TRANS_ERR_NOCARD; case CARD_RESULT_IOERROR: return mCD_TRANS_ERR_IOERROR; case CARD_RESULT_BROKEN: case CARD_RESULT_ENCODING: return mCD_TRANS_ERR_BROKEN_WRONGENCODING; case CARD_RESULT_NOENT: case CARD_RESULT_INSSPACE: return mCD_TRANS_ERR_NO_SPACE; case CARD_RESULT_EXIST: case CARD_RESULT_CANCELED: case CARD_RESULT_FATAL_ERROR: case CARD_RESULT_NAMETOOLONG: case CARD_RESULT_LIMIT: case CARD_RESULT_NOPERM: case CARD_RESULT_NOFILE: return mCD_TRANS_ERR_GENERIC; case CARD_RESULT_BUSY: return mCD_TRANS_ERR_BUSY; default: return mCD_TRANS_ERR_GENERIC; } } static int mCD_get_offset(int idx) { mCD_file_entry_c* entry = l_mcd_file_table; int ofs = 0; int i; if (idx >= mCD_FILE_SAVE_MAIN && idx <= mCD_FILE_SAVE_DIARY) { for (i = idx - 1; i >= 0; i--) { ofs += entry->entrysize; entry++; } } return ofs; } static int mCD_get_size(int idx) { int size = 0; if (idx >= 0 && idx < mCD_FILE_NUM) { size = l_mcd_file_table[idx].entrysize; } return size; } static Save l_keepSave; static mCD_memMgr_c l_memMgr; static void mCD_ClearMemMgr_com(mCD_memMgr_c* mgr) { bzero(mgr, sizeof(mCD_memMgr_c)); mgr->chan = -1; mgr->land_saved = -1; mgr->copy_protect = -1; mgr->broken_file_idx = -1; } static void mCD_ClearMemMgr_com2(mCD_memMgr_c* mgr) { if (mgr->workArea != NULL) { zelda_free(mgr->workArea); } if (mgr->cards[0].workArea != NULL) { zelda_free(mgr->cards[0].workArea); } if (mgr->cards[1].workArea != NULL) { zelda_free(mgr->cards[1].workArea); } mCD_ClearMemMgr_com(mgr); } static void mCD_ClearKeepLand(void) { bzero(&l_keepSave, sizeof(l_keepSave)); l_keepSave_set = FALSE; } static void mCD_ClearMemMgr(void) { mCD_ClearMemMgr_com(&l_memMgr); } typedef struct { PersonalID_c pid; char filename[32]; } mCD_cardPrivate_c; static mCD_cardPrivate_c l_mcd_card_private_table[19]; static mCD_cardPrivate_c l_mcd_card_private; static void mCD_ClearCardPrivateTable_com(mCD_cardPrivate_c* priv, int count) { for (count; count != 0; count--) { mPr_ClearPersonalID(&priv->pid); mem_clear((u8*)priv->filename, sizeof(priv->filename), 0); priv++; } } static void mCD_ClearCardPrivateTable(void) { mCD_ClearCardPrivateTable_com(l_mcd_card_private_table, ARRAY_COUNT(l_mcd_card_private_table)); } static void mCD_SetCardPrivateTable(mCD_cardPrivate_c* priv, PersonalID_c* pid, char* filename) { mPr_CopyPersonalID(&priv->pid, pid); bcopy(filename, priv->filename, sizeof(priv->filename)); } typedef struct { u16 checksum; Private_c priv; Animal_c remove_animal; u16 copy_protect; u8 _2DEA[54]; } mCD_foreigner_c; typedef union { struct { char comment[CARD_COMMENT_SIZE]; u8 banner[0xC00 + 0x200]; u8 icon[0x400 * 8 + 0x200]; mCD_foreigner_c file; }; u8 sector_align[mCD_ALIGN_SECTORSIZE(sizeof(MemcardHeader_c) + sizeof(mCD_foreigner_c))]; } ForeignerFile_c; static union { mCD_foreigner_c file; u8 sector_align[mCD_ALIGN_SECTORSIZE(sizeof(mCD_foreigner_c))]; } l_mcd_foreigner_file; static void mCD_ClearForeignerFile(mCD_foreigner_c* foreigner) { bzero(foreigner, sizeof(l_mcd_foreigner_file)); foreigner->checksum = 0; mPr_ClearPrivateInfo(&foreigner->priv); mNpc_ClearAnimalInfo(&foreigner->remove_animal); foreigner->copy_protect = 0xFFFF; } typedef struct { u16 code[4]; } mCD_LandProtectCode_c; static mCD_LandProtectCode_c l_keep_noLandCode; static void mCD_ClearNoLandProtectCode(mCD_LandProtectCode_c* protect_code) { bzero(protect_code, sizeof(mCD_LandProtectCode_c)); } static int mCD_CheckInitProtectCode(mCD_LandProtectCode_c* protect_code) { u16* code_p = protect_code->code; int res = FALSE; int i; for (i = 0; i < 4; i++) { if (*code_p != 0) { break; } code_p++; } if (i == 4) { res = TRUE; } return res; } static int mCD_CheckProtectCode(u16* protect_code) { int res = FALSE; int i; if (*protect_code == 0x3C1C) { protect_code++; for (i = 0; i < 3; i++) { if (*protect_code == 0) { break; } protect_code++; } if (i == 3) { res = TRUE; } } return res; } static void mCD_MakeProtectCode(mCD_LandProtectCode_c* protect_code) { int i; u16* code_p = protect_code->code; *code_p = mCD_LAND_PROTECT_CODE_MAGIC0; code_p++; for (i = 0; i < 3; i++) { *code_p = RANDOM(0xFFFE); *code_p = *code_p + 1; code_p++; } } static int mCD_CompNoLandCode(u16* code0, u16* code1) { int res = FALSE; if (mCD_CheckProtectCode(code0) == TRUE) { int i; for (i = 0; i < 4; i++) { if (*code0 != *code1) { break; } code0++; code1++; } if (i == 4) { res = TRUE; } } return res; } static void mCD_SetForeignerFile(mCD_foreigner_c* foreigner, Private_c* priv, Animal_c* animal) { mPr_CopyPrivateInfo(&foreigner->priv, priv); bcopy(animal, &foreigner->remove_animal, sizeof(Animal_c)); foreigner->checksum = mFRm_GetFlatCheckSum((u16*)foreigner, sizeof(mCD_foreigner_c), foreigner->checksum); } static void mCD_clear_all_control(void); extern void mCD_InitAll(void) { mCD_StartSetCardBgInfo(); mCD_ClearMemMgr(); mCD_ClearKeepLand(); mCD_ClearCardPrivateTable(); mCD_ClearCardPrivateTable_com(&l_mcd_card_private, 1); mCD_clear_all_control(); l_mcd_copy_protect = 0xFFFF; mCD_ClearForeignerFile(&l_mcd_foreigner_file.file); mCD_ClearNoLandProtectCode(&l_keep_noLandCode); mCD_ClearErrInfo(); } static int mCD_save_file(void* data, int file_idx, s32 chan, s32* result) { int res = mCD_RESULT_ERROR; if (data != NULL && file_idx >= 0 && file_idx < mCD_FILE_NUM) { mCD_file_entry_c* file = &l_mcd_file_table[file_idx]; int ofs = mCD_get_offset(file_idx); res = mCD_write_comp_bg(data, file->filename, file->entrysize, file->filesize, ofs, chan, result); } return res; } static int mCD_load_file(void* buf, int file_idx, s32 chan, s32* result) { int res = mCD_RESULT_ERROR; if (buf != NULL && file_idx >= 0 && file_idx < mCD_FILE_NUM) { mCD_file_entry_c* file = &l_mcd_file_table[file_idx]; int ofs = mCD_get_offset(file_idx); res = mCD_read_fg(buf, file->filename, file->entrysize, ofs, chan, result); } return res; } /* This struct seems to be stubbed */ typedef struct { int _00; int _04; int _08; int _0C; int _10; mCD_LandProtectCode_c protect_code; // assumed? int _1C; int _20; int _24; int _28; int _2C; int _30; } mCD_wctrl_c; static mCD_wctrl_c l_mCD_wctrl; static void mCD_clear_write_control_common(mCD_wctrl_c* write_control) { write_control->_00 = 0; write_control->_04 = 0; write_control->_08 = 0; write_control->_0C = 0; bzero(&write_control->protect_code, sizeof(mCD_LandProtectCode_c)); write_control->_1C = 0; write_control->_20 = 0; write_control->_24 = 0; write_control->_28 = 0; write_control->_30 = 0; } static void mCD_clear_all_control(void) { mCD_clear_write_control_common(&l_mCD_wctrl); } static int mCD_GetHighPriority_common(mCD_memMgr_c* mgr, int prio0, int prio1) { mgr->chan = 0; if (prio1 < prio0) { mgr->chan = 1; prio0 = prio1; } return prio0; } static int mCD_check_Land_exist_com(s32 chan) { int res = FALSE; if (chan == 0 || chan == 1) { CARDFileInfo fileInfo; if (CARDOpen(chan, l_mCD_land_file_name, &fileInfo) == CARD_RESULT_READY) { res = TRUE; } } return res; } static int mCD_check_Land_exist(s32 chan, void* workArea) { int res = FALSE; if ((chan == 0 || chan == 1) && workArea != NULL) { s32 result; if (mCD_check_card(&result, mCD_MEMCARD_SECTORSIZE, chan) == mCD_RESULT_SUCCESS) { result = CARDMount((s32)chan, workArea, NULL); if (result == CARD_RESULT_READY || result == CARD_RESULT_BROKEN) { result = CARDCheck((s32)chan); if (result == CARD_RESULT_READY) { res = mCD_check_Land_exist_com(chan); } CARDUnmount((s32)chan); } else if (result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } } } return res; } static int mCD_CheckFilename(const char* name0, const char* name1, int len) { int i = 0; int j = 0; int res = FALSE; while (name0 != NULL && j < len && *name0 != '\0') { if (*name0 != *name1) { break; } i++; name0++; name1++; j++; } if (i == len) { res = TRUE; } return res; } static int mCD_CheckPresentFilename(CARDStat* stat) { return mCD_CheckFilename(stat->fileName, l_mCD_present_file_name, 21); } static int mCD_CheckPresentFileStatus(CARDStat* stat) { int res = FALSE; if (stat->company[0] == '0' && stat->company[1] == '1') { res = mCD_CheckPresentFilename(stat); } return res; } static int mCD_CheckPassportFilename(CARDStat* stat) { return mCD_CheckFilename(stat->fileName, l_mCD_player_file_name, 18); } static int mCD_CheckPassportFileStatus(CARDStat* stat) { int res = FALSE; if (stat->company[0] == '0' && stat->company[1] == '1') { res = mCD_CheckPassportFilename(stat); } return res; } static int mCD_set_to_num(char* c) { int n = 0; int num = 0; int i = 0; if (c != NULL) { for (i; i < 3; i++) { if (c[i] == '\0') { break; } if (num != 0) { num *= 10; } else { num = 1; } } for (i; i != 0; i--) { n += (*c - '0') * num; num /= 10; c++; } } return n; } static int mCD_GetPassportFileIdx(char* filename) { return mCD_set_to_num(&filename[18]); } static int mCD_CheckPassportFile_slot(s32 chan, void* workArea) { int i; int res = FALSE; if ((chan == 0 || chan == 1) && workArea != NULL) { s32 result; if (mCD_check_card(&result, mCD_MEMCARD_SECTORSIZE, chan) == mCD_RESULT_SUCCESS) { result = CARDMount((s32)chan, workArea, NULL); if (result == CARD_RESULT_READY || result == CARD_RESULT_BROKEN) { result = CARDCheck((s32)chan); if (result == CARD_RESULT_READY) { /* Check all files on the memcard */ CARDStat stat; for (i = 0; i < CARD_MAX_FILE; i++) { result = CARDGetStatus((s32)chan, i, &stat); if (result == CARD_RESULT_READY) { if (mCD_CheckPassportFileStatus(&stat) == TRUE) { res = TRUE; break; } } } } CARDUnmount((s32)chan); } else if (result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } } } return res; } static int mCD_GetSpaceSlot_bg2(mCD_memMgr_c* mgr, int size) { mCD_memMgr_card_info_c* card_info; int chan; int res; u8 _0010; chan = 0; res = mCD_RESULT_BUSY; _0010 = mgr->_0010; if ((_0010 & 1) == 1) { chan = 1; } card_info = &mgr->cards[chan]; if (card_info->workArea != NULL) { int space_res = mCD_get_space_bg(&card_info->freeBlocks, chan, &card_info->result, card_info->workArea); if (space_res == mCD_RESULT_SUCCESS) { if (card_info->freeBlocks >= size) { if (mCD_check_Land_exist(chan, card_info->workArea) == TRUE) { card_info->game_result = mCD_TRANS_ERR_LAND_EXIST; } else if (mCD_CheckPassportFile_slot(chan, card_info->workArea) == TRUE) { card_info->game_result = mCD_TRANS_ERR_PASSPORT_EXIST; } else if (mCD_get_file_num(card_info->workArea, chan) >= CARD_MAX_FILE) { card_info->game_result = mCD_TRANS_ERR_NO_FILES; } else { mgr->chan = chan; res = mCD_RESULT_SUCCESS; } } else { card_info->result = CARD_RESULT_INSSPACE; } mgr->_0010 |= 1 << chan; } else if (space_res != mCD_RESULT_BUSY) { if (mCD_check_sector_size(mCD_MEMCARD_SECTORSIZE, chan) == FALSE) { card_info->game_result = mCD_TRANS_ERR_NOT_MEMCARD; } mgr->_0010 |= 1 << chan; } } else { _0010 |= 1 << chan; mgr->_0010 = _0010; res = mCD_RESULT_ERROR; } if (card_info->game_result != mCD_TRANS_ERR_LAND_EXIST && card_info->game_result != mCD_TRANS_ERR_PASSPORT_EXIST && card_info->game_result != mCD_TRANS_ERR_NOT_MEMCARD && card_info->game_result != mCD_TRANS_ERR_NO_FILES) { card_info->game_result = mCD_TransErrorCode_nes(card_info->result); } /* If no memcard was chosen */ if (mgr->_0010 == 0b11 && res == mCD_RESULT_BUSY) { mCD_GetHighPriority_common(mgr, mgr->cards[0].game_result, mgr->cards[1].game_result); if (mgr->chan == -1 || mgr->cards[mgr->chan].game_result != mCD_TRANS_ERR_NONE) { res = mCD_RESULT_ERROR; } else { res = mCD_RESULT_SUCCESS; } } return res; } static int mCD_check_noLand_file(mCD_LandProtectCode_c* protect_code, u8* data, s32 chan) { int res = FALSE; if (data != NULL) { s32 result; if (mCD_load_file(data, mCD_FILE_SAVE_MISC, chan, &result) == mCD_RESULT_SUCCESS) { if (mCD_CheckProtectCode((u16*)(data + mCD_SAVE_DATA_OFS)) == TRUE) { if (protect_code != NULL) { bcopy((mCD_LandProtectCode_c*)(data + mCD_SAVE_DATA_OFS), protect_code, sizeof(mCD_LandProtectCode_c)); } res = TRUE; } } } return res; } static int mCD_GetNoLandSlot_bg(mCD_memMgr_c* mgr) { s32 chan = 0; mCD_memMgr_card_info_c* card_info; int res = mCD_RESULT_BUSY; u8 _0010 = mgr->_0010; if ((_0010 & 1) == 1) { chan = 1; } card_info = &mgr->cards[chan]; if (card_info->workArea != NULL) { static mCD_LandProtectCode_c noLand_code; if (mCD_check_noLand_file(&noLand_code, mgr->workArea, chan) == TRUE && mCD_CompNoLandCode(noLand_code.code, l_keep_noLandCode.code) == TRUE) { mgr->chan = chan; res = mCD_RESULT_SUCCESS; } else { mgr->_0010 |= 1 << chan; card_info->game_result = mCD_TRANS_ERR_INVALID_NOLAND_CODE; } } else { _0010 |= 1 << chan; mgr->_0010 = _0010; res = mCD_RESULT_ERROR; } if (card_info->game_result != mCD_TRANS_ERR_INVALID_NOLAND_CODE) { card_info->game_result = mCD_TransErrorCode(card_info->result); } if (mgr->_0010 == 0b11 && res == mCD_RESULT_BUSY) { mCD_GetHighPriority_common(mgr, mgr->cards[0].game_result, mgr->cards[1].game_result); res = mCD_RESULT_ERROR; } return res; } static int mCD_CheckThisLandSlot(s32* result, s32* game_result, s32 chan, Save_t* buf_save) { int res = mCD_RESULT_ERROR; if (buf_save != NULL) { int i; for (i = 0; i < 2; i++) { int read_res; *result = CARD_RESULT_NOCARD; read_res = mCD_read_fg(buf_save, l_mCD_land_file_name, CARD_WORKAREA_SIZE, mCD_get_offset(mCD_FILE_SAVE_MAIN + i), chan, result); if (read_res == mCD_RESULT_SUCCESS) { if (mFRm_CheckSaveData_common(&buf_save->save_check, buf_save->land_info.id) == TRUE) { if (mLd_CheckThisLand(buf_save->land_info.name, buf_save->land_info.id) == TRUE) { *game_result = mCD_TRANS_ERR_NONE; res = mCD_RESULT_SUCCESS; break; } else if (mLd_CheckId(buf_save->land_info.id) == TRUE) { *game_result = mCD_TRANS_ERR_OTHER_TOWN; res = mCD_RESULT_BUSY; break; } else { *game_result = mCD_TRANS_ERR_TOWN_INVALID; res = mCD_RESULT_BUSY; } } else { *game_result = mCD_TRANS_ERR_TOWN_INVALID; res = mCD_RESULT_BUSY; } } } } return res; } static void mCD_set_1byte(char* c, int idx) { *c = l_mcd_font_1[idx]; } static void mCD_set_number_str(char* str, u8 num) { int n = num; int f = FALSE; int fig_table[3]; int i; bzero(fig_table, sizeof(fig_table)); for (i = 0; i < 3; i++) { fig_table[i] = n % 10; n /= 10; } for (i = 2; i > 0; i--) { if (fig_table[i] > 0 || f == TRUE) { *str++ = fig_table[i] + '0'; f = TRUE; } } *str = fig_table[0] + '0'; } static void mCD_get_land_comment1(char* comment1, u8* town_name) { int n; int i; int spaces = 0; u8* town_name_p; char* comment_p; town_name_p = town_name; mem_clear((u8*)comment1, 32, 0); for (i = LAND_NAME_SIZE; i != 0; i--) { u8 c = *town_name++; if (c != CHAR_SPACE) { spaces = 0; } else { spaces++; } } town_name = town_name_p; n = LAND_NAME_SIZE - spaces; for (i = 0; i < n; i++) { mCD_set_1byte(comment1, *town_name); comment1++; town_name++; } comment_p = l_comment_1_str; for (i = 0; i < 32; i++) { *comment1 = *comment_p; if (*comment_p == '\0') { break; } comment1++; comment_p++; } } static void mCD_get_passport_comment1(char* comment1, u8* player_name) { int i; int n; int spaces = 0; u8* player_name_p; char* comment_p; player_name_p = player_name; mem_clear((u8*)comment1, 32, 0); for (i = LAND_NAME_SIZE; i != 0; i--) { u8 c = *player_name++; if (c != CHAR_SPACE) { spaces = 0; } else { spaces++; } } player_name = player_name_p; n = PLAYER_NAME_LEN - spaces; for (i = 0; i < n; i++) { mCD_set_1byte(comment1, *player_name); comment1++; player_name++; } comment_p = l_comment_player_1_str; for (i = 0; i < 32; i++) { *comment1 = *comment_p; if (*comment_p == '\0') { break; } comment1++; comment_p++; } } static void mCD_get_present_comment1(char* comment1, int num, const char* src_comment, int src_len) { int i; mem_clear((u8*)comment1, 32, 0); for (i = 0; i < src_len; i++) { *comment1++ = *src_comment++; } if (num >= 0) { num %= 10; mCD_set_1byte(comment1, '0' + num); } } extern int mCD_card_format_bg(s32 chan) { s32 result; return mCD_format_bg(chan, &result); } static int mCD_get_this_land_slot_no(mCD_memMgr_c* mgr) { mCD_memMgr_card_info_c* card_info = mgr->cards; Save_t* buf_save = (Save_t*)mgr->workArea; int i; int res = mCD_RESULT_ERROR; for (i = 0; i < CARD_NUM_CHANS; i++) { card_info[i].result = CARD_RESULT_NOCARD; card_info[i].game_result = mCD_TRANS_ERR_NOCARD; } if (buf_save != NULL) { for (i = 0; i < CARD_NUM_CHANS; i++) { int t_res = mCD_CheckThisLandSlot(&card_info->result, &card_info->game_result, i, buf_save); if (t_res == mCD_RESULT_SUCCESS) { mgr->chan = i; card_info->game_result = mCD_TRANS_ERR_NONE; res = mCD_RESULT_SUCCESS; break; } if (card_info->game_result == mCD_TRANS_ERR_NOCARD || t_res == mCD_RESULT_ERROR) { card_info->game_result = mCD_TransErrorCode(card_info->result); } card_info++; } } return res; } static int mCD_get_this_land_slot_no_game_start(mCD_memMgr_c* mgr) { mCD_memMgr_card_info_c* card_info = mgr->cards; Save_t* buf_save = (Save_t*)mgr->workArea; int i; int res = mCD_RESULT_ERROR; for (i = 0; i < CARD_NUM_CHANS; i++) { card_info[i].result = CARD_RESULT_NOCARD; card_info[i].game_result = mCD_TRANS_ERR_NOCARD; } if (buf_save != NULL) { for (i = 0; i < CARD_NUM_CHANS; i++) { int t_res = mCD_CheckThisLandSlot(&card_info->result, &card_info->game_result, i, buf_save); if (t_res == mCD_RESULT_SUCCESS) { mgr->chan = i; res = mCD_RESULT_SUCCESS; break; } if (card_info->game_result == mCD_TRANS_ERR_NOCARD || t_res == mCD_RESULT_ERROR) { card_info->game_result = mCD_TransErrorCode(card_info->result); } else { card_info->game_result = mCD_TRANS_ERR_WRONG_LAND; mgr->chan = i; } card_info++; } } return res; } static int mCD_get_this_land_slot_no_nes(mCD_memMgr_c* mgr) { mCD_memMgr_card_info_c* card_info = mgr->cards; Save_t* buf_save = (Save_t*)mgr->workArea; int i; int res = mCD_RESULT_ERROR; for (i = 0; i < CARD_NUM_CHANS; i++) { card_info[i].result = CARD_RESULT_NOCARD; card_info[i].game_result = mCD_TRANS_ERR_NOCARD; } if (buf_save != NULL) { for (i = 0; i < CARD_NUM_CHANS; i++) { int t_res = mCD_CheckThisLandSlot(&card_info->result, &card_info->game_result, i, buf_save); if (t_res == mCD_RESULT_SUCCESS) { mgr->chan = i; res = mCD_RESULT_SUCCESS; break; } if (mCD_check_sector_size(mCD_MEMCARD_SECTORSIZE, i) == FALSE) { card_info->game_result = mCD_TRANS_ERR_NOT_MEMCARD; mgr->chan = i; } else if (card_info->game_result == mCD_TRANS_ERR_NOCARD || t_res == mCD_RESULT_ERROR) { card_info->game_result = mCD_TransErrorCode(card_info->result); } card_info++; } } if (res == mCD_RESULT_ERROR) { mCD_GetHighPriority_common(mgr, mgr->cards[0].game_result, mgr->cards[1].game_result); } return res; } static int mCD_check_copyProtect(Save_t* buf_save, s32 chan) { int i; int res = FALSE; if (chan != -1 && buf_save != NULL) { for (i = 0; i < 2; i++) { s32 result; int t_res = mCD_read_fg(buf_save, l_mCD_land_file_name, 0x200, mCD_get_offset(mCD_FILE_SAVE_MAIN + i), chan, &result); if (t_res == mCD_RESULT_SUCCESS && buf_save->copy_protect == Common_Get(copy_protect)) { res = TRUE; break; } } } return res; } static int mCD_bg_get_area_common(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo, int file_idx, int sound_idx) { static u8 sound_table[mCD_HOME_SFX_NUM] = { NA_SE_47, NA_SE_53 }; mCD_memMgr_card_info_c* card_info = mgr->cards; int stages_compl = 0; int res = mCD_RESULT_BUSY; /* Start playing sound effect if necessary */ if (mgr->_017C == 0 && sound_idx >= 0 && sound_idx < mCD_HOME_SFX_NUM) { sAdo_SysLevStart(sound_table[sound_idx]); } if (mgr->_017C < 100) { int i; for (i = 0; i < CARD_NUM_CHANS; i++) { if (card_info->workArea == NULL) { card_info->workArea = mCD_malloc_32(CARD_WORKAREA_SIZE); } if (card_info->workArea != NULL) { stages_compl++; } card_info++; } if (mgr->workArea == NULL) { mgr->workArea_size = mCD_get_size(file_idx); mgr->workArea = mCD_malloc_32(mgr->workArea_size); } if (mgr->workArea != NULL) { stages_compl++; } if (stages_compl == 3) { fileInfo->proc++; res = mCD_RESULT_SUCCESS; } else { mgr->_017C++; } } else { /* Unable to allocate work area buffers */ mCD_OnErrInfo(mCD_ERROR_AREA); res = mCD_RESULT_ERROR; } return res; } static int mCD_SaveHome_bg_get_area(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { SoftResetEnable = FALSE; return mCD_bg_get_area_common(mgr, fileInfo, mCD_FILE_SAVE_MAIN, mCD_HOME_SFX_NORMAL); } static int mCD_SaveHome_bg_erase_dummy(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* card_info = mgr->cards; int i; for (i = 0; i < CARD_NUM_CHANS; i++) { s32 result; mCD_erase_file_fg(l_mCD_land_file_name_dummy, i, &result, card_info->workArea); card_info++; } fileInfo->proc++; return mCD_RESULT_SUCCESS; } static int mCD_send_present(PresentSaveFile_c* present_file, int length) { Mail_c* letter = present_file->save.letters; int res = FALSE; u32 player_no = Common_Get(player_no); u16 checksum = mFRm_ReturnCheckSum((u16*)present_file, length); if (checksum == 0 && present_file->save.present_count <= mCD_PRESENT_MAX) { int i; for (i = 0; i < mCD_PRESENT_MAX; i++, letter++) { if (mPr_NullCheckPersonalID(&letter->header.recipient.personalID) == TRUE) { Private_c* priv; mHm_hs_c* house; int free_idx; if (player_no >= PLAYER_NUM) { break; } priv = Now_Private; if (priv == NULL) { break; } house = &Save_Get(homes[mHS_get_arrange_idx(player_no)]); if (mPr_CheckCmpPersonalID(&priv->player_ID, &house->ownerID) != TRUE) { break; } free_idx = mMl_chk_mail_free_space(house->mailbox, HOME_MAILBOX_SIZE); if (free_idx == -1) { break; } letter->content.font = mMl_FONT_RECV; mPr_CopyPersonalID(&letter->header.recipient.personalID, &priv->player_ID); letter->header.recipient.type = mMl_NAME_TYPE_PLAYER; mMl_copy_mail(&house->mailbox[free_idx], letter); res = TRUE; present_file->save.present_count--; if (present_file->save.present_count <= 0) { break; } } } } return res; } static int mCD_SaveHome_bg_check_slot(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { int res = mCD_RESULT_BUSY; if (mgr->cards[0].workArea != NULL && mgr->cards[1].workArea != NULL && mgr->workArea != NULL) { if (Save_Get(save_exist) == FALSE) { if (mCD_CheckInitProtectCode(&l_keep_noLandCode) == FALSE && mCD_CheckProtectCode(l_keep_noLandCode.code) == TRUE) { int slot_res = mCD_GetNoLandSlot_bg(mgr); if (slot_res == mCD_RESULT_SUCCESS) { mgr->land_saved = Save_Get(save_exist); mgr->copy_protect = Common_Get(copy_protect); mgr->_0010 = 0b00; fileInfo->proc++; res = mCD_RESULT_SUCCESS; } else if (slot_res != mCD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } } else { int space_res = mCD_GetSpaceSlot_bg2(mgr, mCD_LAND_SAVE_SIZE); if (space_res == TRUE) { if (mgr->chan != -1) { fileInfo->proc++; mgr->land_saved = Save_Get(save_exist); mgr->copy_protect = Common_Get(copy_protect); mgr->_0010 = 0b00; res = mCD_RESULT_SUCCESS; } else { res = mCD_RESULT_ERROR; } } else if (space_res != mCD_RESULT_BUSY) { mgr->_0010 = 0b00; res = mCD_RESULT_ERROR; } } } else { int land_slot_res = mCD_get_this_land_slot_no_nes(mgr); if (land_slot_res == mCD_RESULT_SUCCESS) { int chan = mgr->chan; if (chan != -1) { if (mCD_check_copyProtect((Save_t*)mgr->workArea, chan) == TRUE) { fileInfo->proc++; mgr->land_saved = Save_Get(save_exist); mgr->copy_protect = Common_Get(copy_protect); res = mCD_RESULT_SUCCESS; } else { mgr->cards[chan].game_result = mCD_TRANS_ERR_WRONG_LAND; mgr->land_saved = Save_Get(save_exist); mgr->copy_protect = Common_Get(copy_protect); res = mCD_RESULT_ERROR; } } else { res = mCD_RESULT_ERROR; } } else if (land_slot_res != mCD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_CheckPresentFile(char* filename, s32* fileNo, s32 chan, s32* result, void* workArea) { CARDStat stat; int file; int res = FALSE; if (mCD_check_card(result, mCD_MEMCARD_SECTORSIZE, (s32)chan) == mCD_RESULT_SUCCESS) { *result = CARDMount((s32)chan, workArea, NULL); if (*result == CARD_RESULT_READY || *result == CARD_RESULT_BROKEN) { *result = CARDCheck((s32)chan); if (*result == CARD_RESULT_READY) { for (file = *fileNo; file < 32; file++) { *result = CARDGetStatus((s32)chan, file, &stat); if (*result == CARD_RESULT_READY && mCD_CheckPresentFileStatus(&stat) == TRUE) { bcopy(stat.fileName, filename, CARD_FILENAME_MAX); res = TRUE; break; } } } /* @BUG - if CARDCheck fails, file will be undefined */ *fileNo = file; CARDUnmount((s32)chan); } else { if (*result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } *fileNo = 32; } } else { *fileNo = 32; } return res; } #include "../src/game/m_card_bti.c_inc" static int mCD_SaveHome_bg_read_send_present(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { static int icon_fileNo[mCD_PRESENT_TYPE_NUM] = { RESOURCE_TEGAMI, RESOURCE_TEGAMI2 }; static const char* comment_p_table[mCD_PRESENT_TYPE_NUM] = { l_comment_present_1_str, l_comment_gift_1_str }; static int comment_len_table[mCD_PRESENT_TYPE_NUM] = { 14, 13 }; void* workArea = mgr->workArea; mCD_file_entry_c* present_entry; mCD_memMgr_card_info_c* card_info; int type; PresentSaveFile_c* present_buf; int icon; icon = 0; type = mCD_PRESENT_TYPE_BONUS; present_entry = &l_mcd_file_table[mCD_FILE_PRESENT]; if (mgr->cards[0].workArea != NULL && mgr->cards[1].workArea != NULL && workArea != NULL) { mgr->chan = -1; card_info = &mgr->cards[fileInfo->chan]; /* Get info about the present save file */ if (mCD_CheckPresentFile(mgr->filename, &fileInfo->fileNo, fileInfo->chan, &card_info->result, card_info->workArea) == TRUE) { if (mCD_read_fg(workArea, mgr->filename, present_entry->entrysize, mCD_get_offset(mCD_FILE_PRESENT), fileInfo->chan, &card_info->result) == mCD_RESULT_SUCCESS) { present_buf = (PresentSaveFile_c*)workArea; /* Determine if this is a bonus gift file or a 'gift' present file */ if (mCD_CheckFilename(present_buf->header.comment + 32, l_comment_gift_1_str, 13) == TRUE) { type = mCD_PRESENT_TYPE_GIFT; } /* Try sending the presents */ if (mCD_send_present(present_buf, present_entry->entrysize) == TRUE) { mgr->loaded_file_type = mCD_FILE_PRESENT; mgr->workArea_size = mCD_get_size(mgr->loaded_file_type); mgr->chan = fileInfo->chan; mCD_get_present_comment1(present_buf->header.comment + 32, present_buf->save.present_count, comment_p_table[type], comment_len_table[type]); if (present_buf->save.present_count == 0) { icon = 1; } mCD_set_bti_data(present_buf->header.icon, icon_fileNo[icon], 0x400, 1, 0x200); present_buf->save.checksum = mFRm_GetFlatCheckSum((u16*)workArea, mgr->workArea_size, present_buf->save.checksum); fileInfo->proc++; } else if (present_buf->save.present_count != 0) { mgr->chan = -1; fileInfo->chan = CARD_NUM_CHANS; } else { fileInfo->fileNo++; mgr->chan = fileInfo->chan; } } else if (card_info->result == CARD_RESULT_WRONGDEVICE || card_info->result == CARD_RESULT_NOCARD || card_info->result == CARD_RESULT_IOERROR || card_info->result == CARD_RESULT_BROKEN || card_info->result == CARD_RESULT_FATAL_ERROR || card_info->result == CARD_RESULT_LIMIT || card_info->result == CARD_RESULT_ENCODING) { fileInfo->fileNo = 32; } } if (mgr->chan == -1 || fileInfo->fileNo >= 32) { fileInfo->proc = mCD_SAVEHOME_BG_PROC_READ_SEND_PRESENT; fileInfo->fileNo = 0; fileInfo->chan++; } if (fileInfo->chan >= CARD_NUM_CHANS) { fileInfo->proc = mCD_SAVEHOME_BG_PROC_GET_SLOT; mgr->chan = -1; } return mCD_RESULT_SUCCESS; } else { return mCD_RESULT_ERROR; } } static int mCD_write_common(mCD_memMgr_c* mgr) { int chan = mgr->chan; mCD_memMgr_card_info_c* card_info; int res; if (mgr->workArea != NULL && chan != -1) { card_info = &mgr->cards[chan]; res = mCD_save_file(mgr->workArea, mgr->loaded_file_type, mgr->chan, &card_info->result); card_info->game_result = mCD_TransErrorCode(card_info->result); } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_SaveHome_bg_write_present(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_file_entry_c* file_entry; int chan = mgr->chan; mCD_memMgr_card_info_c* card_info; int ofs; int ret; int write_res; if (chan != -1) { file_entry = &l_mcd_file_table[mgr->loaded_file_type]; ofs = mCD_get_offset(mgr->loaded_file_type); card_info = &mgr->cards[chan]; write_res = mCD_write_comp_bg(mgr->workArea, mgr->filename, mgr->workArea_size, file_entry->filesize, ofs, chan, &card_info->result); card_info->game_result = mCD_TransErrorCode(card_info->result); if (write_res != mCD_RESULT_BUSY) { if (card_info->result == CARD_RESULT_WRONGDEVICE || card_info->result == CARD_RESULT_NOCARD || card_info->result == CARD_RESULT_IOERROR || card_info->result == CARD_RESULT_BROKEN || card_info->result == CARD_RESULT_FATAL_ERROR || card_info->result == CARD_RESULT_LIMIT || card_info->result == CARD_RESULT_ENCODING) { fileInfo->chan++; fileInfo->fileNo = 0; } else { fileInfo->fileNo++; } if (fileInfo->fileNo >= 32) { fileInfo->chan++; } if (fileInfo->chan >= CARD_NUM_CHANS) { fileInfo->proc++; mgr->loaded_file_type = mCD_FILE_SAVE_MAIN; mgr->chan = -1; } else { fileInfo->proc = mCD_SAVEHOME_BG_PROC_READ_SEND_PRESENT; } } card_info->game_result = mCD_TransErrorCode(card_info->result); return mCD_RESULT_SUCCESS; } else { return mCD_RESULT_ERROR; } } static int mCD_SaveHome_bg_get_slot(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { int res = mCD_RESULT_BUSY; if (mgr->cards[0].workArea != NULL && mgr->cards[1].workArea != NULL && mgr->workArea != NULL) { if (Save_Get(save_exist) == FALSE) { if (mCD_CheckInitProtectCode(&l_keep_noLandCode) == FALSE && mCD_CheckProtectCode(l_keep_noLandCode.code) == TRUE) { int slot_res = mCD_GetNoLandSlot_bg(mgr); if (slot_res == mCD_RESULT_SUCCESS) { mgr->land_saved = Save_Get(save_exist); mgr->copy_protect = Common_Get(copy_protect); mgr->_0010 = 0b00; fileInfo->proc = mCD_SAVEHOME_BG_PROC_SET_FILE_PERMISSION; res = mCD_RESULT_SUCCESS; } else if (slot_res != mCD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } } else { int space_res = mCD_GetSpaceSlot_bg2(mgr, mCD_LAND_SAVE_SIZE); if (space_res == TRUE) { if (mgr->chan != -1) { fileInfo->proc++; mgr->land_saved = Save_Get(save_exist); mgr->copy_protect = Common_Get(copy_protect); mgr->_0010 = 0b00; res = mCD_RESULT_SUCCESS; } else { res = mCD_RESULT_ERROR; } } else if (space_res != mCD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } } } else { int land_slot_res = mCD_get_this_land_slot_no_nes(mgr); if (land_slot_res == mCD_RESULT_SUCCESS) { int chan = mgr->chan; if (chan != -1) { if (mCD_check_copyProtect((Save_t*)mgr->workArea, chan) == TRUE) { fileInfo->proc = mCD_SAVEHOME_BG_PROC_CHECK_REPAIR_LAND; mgr->land_saved = Save_Get(save_exist); mgr->copy_protect = Common_Get(copy_protect); res = mCD_RESULT_SUCCESS; } else { mgr->cards[chan].game_result = mCD_TRANS_ERR_WRONG_LAND; mgr->land_saved = Save_Get(save_exist); mgr->copy_protect = Common_Get(copy_protect); res = mCD_RESULT_ERROR; } } else { res = mCD_RESULT_ERROR; } } else if (land_slot_res != mCD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_SaveHome_bg_create_file(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { int chan = mgr->chan; mCD_memMgr_card_info_c* card_info; mCD_file_entry_c* entry = &l_mcd_file_table[mCD_FILE_SAVE_MISC]; int res; if (chan != -1) { card_info = &mgr->cards[chan]; mgr->_019C = 1; res = mCD_create_file_bg(l_mCD_land_file_name_dummy, CARD_ATTR_NO_MOVE | CARD_ATTR_NO_COPY, entry->filesize, chan, &card_info->result, &card_info->fileNo); card_info->game_result = mCD_TransErrorCode(card_info->result); if (res == mCD_RESULT_SUCCESS) { fileInfo->proc = mCD_SAVEHOME_BG_PROC_SET_FILE_PERMISSION; } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_check_broken_land(mCD_memMgr_c* mgr) { s32 chan = mgr->chan; Save_t* save = (Save_t*)mgr->workArea; int ok_save_idx = -1; int size; int res = FALSE; if (chan != -1 && save != NULL) { int i; size = mCD_get_size(mCD_FILE_SAVE_MAIN); for (i = 0; i < 2; i++) { s32 result; if (mCD_load_file(save, mCD_FILE_SAVE_MAIN + i, chan, &result) != mCD_RESULT_SUCCESS) { break; } if (mFRm_ReturnCheckSum((u16*)save, size) == 0 && mFRm_CheckSaveData_common(&save->save_check, save->land_info.id)) { ok_save_idx = i; } else { mgr->broken_file_idx = i; } } if (ok_save_idx != -1 && mgr->broken_file_idx != -1 && ok_save_idx != mgr->broken_file_idx) { res = TRUE; } } return res; } static int mCD_repair_load_land(mCD_memMgr_c* mgr) { s32 chan = mgr->chan; Save_t* save = (Save_t*)mgr->workArea; int res = FALSE; if (chan != -1 && save != NULL && mgr->broken_file_idx != -1) { s32 result; if (mCD_load_file(save, mCD_FILE_SAVE_MAIN + ((~mgr->broken_file_idx) & 1), chan, &result) == mCD_RESULT_SUCCESS) { int size = mCD_get_size(mCD_FILE_SAVE_MAIN); if (mFRm_ReturnCheckSum((u16*)save, size) == 0 && mFRm_CheckSaveData_common(&save->save_check, save->land_info.id)) { res = TRUE; } } } return res; } static int mCD_repair_land(mCD_memMgr_c* mgr) { int chan = mgr->chan; Save_t* save = (Save_t*)mgr->workArea; int broken_file_idx = mgr->broken_file_idx; if (chan != -1 && save != NULL && broken_file_idx != -1) { s32 result; /* The loaded file is the 'good' version of the save so we just write it back to the broken save */ return mCD_save_file(save, mCD_FILE_SAVE_MAIN + broken_file_idx, chan, &result); } else { return mCD_RESULT_ERROR; } } static int mCD_SaveHome_bg_check_repair_land(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { if (mCD_check_broken_land(mgr) == TRUE) { if (mCD_repair_load_land(mgr) == TRUE) { fileInfo->proc++; } else { fileInfo->proc = mCD_SAVEHOME_BG_PROC_SET_FILE_PERMISSION; } } else { fileInfo->proc = mCD_SAVEHOME_BG_PROC_SET_FILE_PERMISSION; } return mCD_RESULT_SUCCESS; } static int mCD_SaveHome_bg_repair_land(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { int res = mCD_RESULT_BUSY; if (mCD_repair_land(mgr)) { fileInfo->proc++; res = mCD_RESULT_SUCCESS; } return res; } // @unused mCD_SaveHome_bg_set_icon_data(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) static int mCD_SaveHome_bg_set_icon_data(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { // clang-format off static int icon_fileNo[] = { RESOURCE_EKI1, RESOURCE_EKI1_2, RESOURCE_EKI1_3, RESOURCE_EKI1_4, RESOURCE_EKI1_5, RESOURCE_EKI2, RESOURCE_EKI2_2, RESOURCE_EKI2_3, RESOURCE_EKI2_4, RESOURCE_EKI2_5, RESOURCE_EKI3, RESOURCE_EKI3_2, RESOURCE_EKI3_3, RESOURCE_EKI3_4, RESOURCE_EKI3_5, }; static int banner_fileNo[] = { RESOURCE_MURA_SPRING, RESOURCE_MURA_SUMMER, RESOURCE_MURA_FALL, RESOURCE_MURA_WINTER }; // clang-format on u8* buf = (u8*)mgr->workArea; if (buf != NULL) { mgr->loaded_file_type = mCD_FILE_SAVE_MISC; mgr->workArea_size = mCD_get_size(mgr->loaded_file_type); bzero(buf, mgr->workArea_size); bcopy(l_comment_0_str, buf, sizeof(l_comment_0_str)); mCD_get_land_comment1((char*)buf + sizeof(l_comment_0_str), Save_Get(land_info).name); buf = mCD_set_bti_data(buf, icon_fileNo[Save_Get(station_type)], 0xC00, 1, 0x200); buf = mCD_set_bti_data(buf, banner_fileNo[Common_Get(time.season)], 0x400, 1, 0x200); fileInfo->proc++; return mCD_RESULT_SUCCESS; } return mCD_RESULT_ERROR; } static int mCD_get_status_common(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo, const char* filename, u32 comment_addr, u32 icon_addr, int icon_fmt, int icon_speed, int icon_frames, int banner_fmt) { mCD_memMgr_card_info_c* card_info; s32 chan = mgr->chan; int res; if (chan != -1) { card_info = &mgr->cards[chan]; res = mCD_get_file_status_bg(&card_info->stat, filename, chan, &card_info->result); card_info->game_result = mCD_TransErrorCode(card_info->result); if (res == mCD_RESULT_SUCCESS) { int i; card_info->stat.commentAddr = comment_addr; card_info->stat.iconAddr = icon_addr; for (i = 0; i < icon_frames; i++) { card_info->stat.iconFormat = (card_info->stat.iconFormat & ~(CARD_STAT_ICON_MASK << (i * 2))) | (icon_fmt << (i * 2)); card_info->stat.iconSpeed = (card_info->stat.iconSpeed & ~(CARD_STAT_SPEED_MASK << (i * 2))) | (icon_speed << (i * 2)); } card_info->stat.bannerFormat = (card_info->stat.bannerFormat & ~CARD_STAT_BANNER_MASK) | banner_fmt; fileInfo->proc++; } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_SaveHome_bg_set_file_permission(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { s32 chan = mgr->chan; mCD_file_entry_c* entry = &l_mcd_file_table[mCD_FILE_SAVE_MISC]; const char* filename = entry->filename; mCD_memMgr_card_info_c* card_info; int res = mCD_RESULT_BUSY; if (chan != -1) { if (mgr->_019C == 1) { filename = l_mCD_land_file_name_dummy; } card_info = &mgr->cards[chan]; res = mCD_set_file_permission_bg(filename, CARD_ATTR_NO_MOVE | CARD_ATTR_NO_COPY, chan, &card_info->result, &card_info->fileNo); card_info->game_result = mCD_TransErrorCode(card_info->result); if (res == mCD_RESULT_SUCCESS) { fileInfo->proc++; } } else { res = mCD_RESULT_ERROR; } return res; } static void mCD_ClearResetCode(void) { bzero(&Now_Private->reset_code, sizeof(Now_Private->reset_code)); } static int mCD_CheckResetCode(Private_c* priv) { int res = TRUE; if ((priv->state_flags & mPr_FLAG_BIRTHDAY_ACTIVE) != 0) { priv->reset_code = 0; } if (priv->reset_code != 0) { res = FALSE; } return res; } static void mCD_SetResetCode(Private_c* priv) { priv->reset_code = (u32)RANDOM_F(USHT_MAX_S); priv->reset_code++; } static void mCD_SetResetInfo(Private_c* priv) { Common_Set(reset_flag, FALSE); if (mCD_CheckResetCode(priv) == FALSE) { /* No reset penalty if zurumode 2 is enabled */ if (!ZURUMODE2_ENABLED()) { Common_Set(reset_flag, TRUE); } priv->reset_count++; } } static int mCD_get_land_copyProtect(void) { return 1 + (u16)RANDOM(0xFFF0); } static int mCD_SaveHome_bg_set_data(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { Save_t* save = (Save_t*)mgr->workArea; Private_c* priv; int _04 = fileInfo->_04; int copy_protect; mActor_name_t* pockets_p; int i; if (save != NULL) { bzero(save, mgr->workArea_size); priv = Now_Private; mCkRh_SavePlayTime(Common_Get(player_no)); if (_04 == 0) { mCD_ClearResetCode(); mAGrw_ClearMoneyStoneShineGround(); } else if (mCD_CheckResetCode(priv) == TRUE) { mCD_SetResetCode(priv); } if (_04 == 0 && priv != NULL) { pockets_p = priv->inventory.pockets; /* Clear all Wisp spirits in the player's inventory */ for (i = 0; i < mPr_POCKETS_SLOT_COUNT; i++) { if (ITEM_IS_WISP(*pockets_p)) { mPr_SetPossessionItem(priv, i, EMPTY_NO, mPr_ITEM_COND_NORMAL); } pockets_p++; } } Save_Set(save_exist, TRUE); copy_protect = mCD_get_land_copyProtect(); Common_Set(copy_protect, copy_protect); Save_Set(copy_protect, copy_protect); Save_Set(travel_hard_time, lbRTC_HardTime()); bcopy(&Common_Get(save).save, save, sizeof(Save_t)); save->save_check.version = mFRm_VERSION; mFRm_SetSaveCheckData(&save->save_check); save->save_check.checksum = mFRm_GetFlatCheckSum((u16*)save, sizeof(Save), save->save_check.checksum); mgr->loaded_file_type = mCD_FILE_SAVE_MAIN; mgr->workArea_size = mCD_get_size(mgr->loaded_file_type); fileInfo->proc++; return mCD_RESULT_SUCCESS; } else { return mCD_RESULT_ERROR; } } static int mCD_SaveHome_bg_write_main_2(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { void* workArea = mgr->workArea; mCD_file_entry_c* file_entry = &l_mcd_file_table[mCD_FILE_SAVE_MAIN]; const char* filename = file_entry->filename; int chan = mgr->chan; int res; Save_t* save = (Save_t*)workArea; if (mgr->_019C == 1) { filename = l_mCD_land_file_name_dummy; } if (workArea != NULL && chan != -1) { mCD_memMgr_card_info_c* card_info; int ofs; mgr->loaded_file_type = mCD_FILE_SAVE_MAIN; ofs = mCD_get_offset(mgr->loaded_file_type); card_info = &mgr->cards[chan]; res = mCD_write_comp_bg(save, filename, mgr->workArea_size, file_entry->filesize, ofs, chan, &card_info->result); card_info->game_result = mCD_TransErrorCode(card_info->result); if (res == mCD_RESULT_SUCCESS) { mgr->loaded_file_type = mCD_FILE_SAVE_MAIN_BAK; fileInfo->proc++; } else if (res != mCD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_SaveHome_bg_write_bk(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { void* workArea = mgr->workArea; mCD_file_entry_c* file_entry = &l_mcd_file_table[mCD_FILE_SAVE_MAIN_BAK]; const char* filename = file_entry->filename; s32 chan = mgr->chan; mCD_memMgr_card_info_c* card_info; Private_c* priv = Now_Private; int res; Save_t* save = (Save_t*)workArea; int ofs; if (mgr->_019C == 1) { filename = l_mCD_land_file_name_dummy; } if (workArea != NULL && chan != -1) { mgr->loaded_file_type = mCD_FILE_SAVE_MAIN_BAK; ofs = mCD_get_offset(mgr->loaded_file_type); card_info = &mgr->cards[chan]; res = mCD_write_comp_bg(save, filename, mgr->workArea_size, file_entry->filesize, ofs, chan, &card_info->result); card_info->game_result = mCD_TransErrorCode(card_info->result); if (res == mCD_RESULT_SUCCESS) { if (fileInfo->_04 == 1) { if (Common_Get(player_decoy_flag) == TRUE && priv != NULL) { priv->exists = TRUE; } } else { Common_Set(player_decoy_flag, FALSE); } mgr->loaded_file_type = mCD_FILE_SAVE_MAIN_BAK; fileInfo->proc++; } else if (res != mCD_RESULT_BUSY) { res = mCD_RESULT_ERROR; } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_SaveHome_bg_set_others(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { // clang-format off static int icon_fileNo[] = { RESOURCE_EKI1, RESOURCE_EKI1_2, RESOURCE_EKI1_3, RESOURCE_EKI1_4, RESOURCE_EKI1_5, RESOURCE_EKI2, RESOURCE_EKI2_2, RESOURCE_EKI2_3, RESOURCE_EKI2_4, RESOURCE_EKI2_5, RESOURCE_EKI3, RESOURCE_EKI3_2, RESOURCE_EKI3_3, RESOURCE_EKI3_4, RESOURCE_EKI3_5, }; static int banner_fileNo[] = { RESOURCE_MURA_SPRING, RESOURCE_MURA_SUMMER, RESOURCE_MURA_FALL, RESOURCE_MURA_WINTER }; // clang-format on u8* data_p = (u8*)mgr->workArea; size_t data_size; if (data_p != NULL) { bzero(data_p, OTHERS_SIZE); bcopy(l_comment_0_str, data_p, sizeof(l_comment_0_str)); mCD_get_land_comment1((char*)data_p + sizeof(l_comment_0_str), Save_Get(land_info).name); data_p = mCD_set_bti_data(data_p + CARD_COMMENT_SIZE, banner_fileNo[Common_Get(time.season)], 0xC00, 1, 0x200); data_p = mCD_set_bti_data(data_p, icon_fileNo[Save_Get(station_type)], 0x400, 1, 0x200) + 32; { mCD_keep_mail_c* mail = (mCD_keep_mail_c*)data_p; mCD_save_data_aram_to_main(mail, l_aram_real_size_32_table[mCD_ARAM_DATA_MAIL], mCD_ARAM_DATA_MAIL); mail->landid = Save_Get(land_info).id; mail->checksum = mFRm_GetFlatCheckSum((u16*)mail, l_aram_real_size_32_table[mCD_ARAM_DATA_MAIL], mail->checksum); data_p += l_aram_real_size_32_table[mCD_ARAM_DATA_MAIL]; data_size = (sizeof(MemcardHeader_c) + 32) + l_aram_real_size_32_table[mCD_ARAM_DATA_MAIL]; } { mCD_keep_original_c* original = (mCD_keep_original_c*)data_p; mCD_save_data_aram_to_main(original, l_aram_real_size_32_table[mCD_ARAM_DATA_ORIGINAL], mCD_ARAM_DATA_ORIGINAL); original->landid = Save_Get(land_info).id; original->checksum = mFRm_GetFlatCheckSum((u16*)original, l_aram_real_size_32_table[mCD_ARAM_DATA_ORIGINAL], original->checksum); data_p += l_aram_real_size_32_table[mCD_ARAM_DATA_ORIGINAL]; data_size += l_aram_real_size_32_table[mCD_ARAM_DATA_ORIGINAL]; } { mCD_keep_diary_c* diary = (mCD_keep_diary_c*)data_p; mCD_save_data_aram_to_main(diary, l_aram_real_size_32_table[mCD_ARAM_DATA_DIARY], mCD_ARAM_DATA_DIARY); diary->checksum = mFRm_GetFlatCheckSum((u16*)diary, l_aram_real_size_32_table[mCD_ARAM_DATA_DIARY], diary->checksum); data_size += l_aram_real_size_32_table[mCD_ARAM_DATA_DIARY]; } data_size = mCD_ALIGN_SECTORSIZE(data_size); mgr->workArea_size = data_size; fileInfo->proc++; return mCD_RESULT_SUCCESS; } return mCD_RESULT_ERROR; } static int mCD_SaveHome_bg_write_others(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* card_info; int ret; void* workArea = mgr->workArea; mCD_file_entry_c* entry = &l_mcd_file_table[mCD_FILE_SAVE_MAIN]; const char* filename = entry->filename; int chan = mgr->chan; if (mgr->_019C == 1) { filename = l_mCD_land_file_name_dummy; } if (mgr->workArea != NULL && chan != -1) { card_info = &mgr->cards[chan]; ret = mCD_write_comp_bg(workArea, filename, mgr->workArea_size, OTHERS_SIZE + sizeof(Save) * 2, 0, chan, &card_info->result); card_info->game_result = mCD_TransErrorCode(card_info->result); if (ret == mCD_RESULT_SUCCESS) { fileInfo->proc++; } else if (ret != mCD_RESULT_BUSY) { ret = mCD_RESULT_ERROR; } } else { ret = mCD_RESULT_ERROR; } return ret; } static int mCD_SaveHome_bg_get_status_2(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_file_entry_c* entry = &l_mcd_file_table[mCD_FILE_SAVE_MAIN]; const char* filename = entry->filename; if (mgr->_019C == 1) { filename = l_mCD_land_file_name_dummy; } return mCD_get_status_common(mgr, fileInfo, filename, 0, CARD_COMMENT_SIZE, CARD_STAT_ICON_C8, CARD_STAT_SPEED_SLOW, 1, CARD_STAT_BANNER_C8); } static int mCD_SaveHome_bg_set_status_2(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* card_info; int ret; mCD_file_entry_c* entry = &l_mcd_file_table[mCD_FILE_SAVE_MAIN]; const char* filename = entry->filename; int chan = mgr->chan; if (mgr->_019C == 1) { filename = l_mCD_land_file_name_dummy; } if (chan != -1) { card_info = &mgr->cards[chan]; ret = mCD_set_file_status_bg(&card_info->stat, filename, chan, &card_info->result); if (ret == mCD_RESULT_SUCCESS) { fileInfo->proc++; } } else { ret = mCD_RESULT_ERROR; } return ret; } static int mCD_SaveHome_bg_rename(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* card_info; int ret = mCD_RESULT_ERROR; int chan = mgr->chan; if (mgr->_019C == 1) { if (chan != -1) { card_info = &mgr->cards[chan]; if (card_info->workArea != NULL) { if (mCD_rename_file_fg(l_mCD_land_file_name, l_mCD_land_file_name_dummy, chan, &card_info->result, card_info->workArea) == TRUE) { fileInfo->proc++; ret = mCD_RESULT_SUCCESS; } } } } else { fileInfo->proc++; ret = mCD_RESULT_SUCCESS; } return ret; } static int mCD_SaveHome_ChangeErrCode(int err_code) { switch (err_code) { default: break; case mCD_TRANS_ERR_TOWN_INVALID: case mCD_TRANS_ERR_16: case mCD_TRANS_ERR_GENERIC: err_code = mCD_TRANS_ERR_NONE; break; case mCD_TRANS_ERR_OTHER_TOWN: err_code = mCD_TRANS_ERR_NOCARD; break; } return err_code; } static void mCD_create_famicom_file(int chan) { if (mLd_PlayerManKindCheck() == FALSE) { famicom_internal_data_save(); } } static void mCD_load_famicom_file(void) { if (mLd_PlayerManKindCheck() == FALSE) { famicom_internal_data_load(); } } typedef int (*mCD_SAVEHOME_PROC)(mCD_memMgr_c*, mCD_memMgr_fileInfo_c*); extern int mCD_SaveHome_bg(int param_1, int* chan) { // clang-format off static mCD_SAVEHOME_PROC save_proc[] = { mCD_SaveHome_bg_get_area, mCD_SaveHome_bg_check_slot, mCD_SaveHome_bg_read_send_present, mCD_SaveHome_bg_write_present, mCD_SaveHome_bg_get_slot, mCD_SaveHome_bg_create_file, mCD_SaveHome_bg_check_repair_land, mCD_SaveHome_bg_repair_land, mCD_SaveHome_bg_set_file_permission, mCD_SaveHome_bg_set_data, mCD_SaveHome_bg_write_main_2, mCD_SaveHome_bg_write_bk, mCD_SaveHome_bg_set_others, mCD_SaveHome_bg_write_others, mCD_SaveHome_bg_get_status_2, mCD_SaveHome_bg_set_status_2, mCD_SaveHome_bg_rename, }; // clang-format on mCD_memMgr_card_info_c* cardInfo; mCD_memMgr_c* mgr = &l_memMgr; mCD_memMgr_fileInfo_c* fileInfo = &mgr->save_home_info; int ret = mCD_TRANS_ERR_BUSY; u8 proc = (u8)fileInfo->proc; mgr->_0188++; if (mgr->_018C == 0) { if (proc < 18) { int res; fileInfo->_04 = param_1; res = (*save_proc[proc])(mgr, fileInfo); if (res == mCD_RESULT_SUCCESS) { if (fileInfo->proc == 18) { *chan = mgr->chan; ret = mCD_TRANS_ERR_NONE; mCD_ClearNoLandProtectCode(&l_keep_noLandCode); } } else if (res != mCD_RESULT_BUSY) { int cur_chan = mgr->chan; if (cur_chan == 0 || cur_chan == 1) { *chan = cur_chan; cardInfo = &mgr->cards[mgr->chan]; ret = cardInfo->game_result; } else { ret = mCD_TRANS_ERR_NOCARD; } if (mgr->land_saved != -1) { Save_Set(save_exist, mgr->land_saved); } if (mgr->copy_protect != -1 && fileInfo->proc < 12) { Common_Set(copy_protect, mgr->copy_protect); } } if (res == mCD_RESULT_ERROR || (res == mCD_RESULT_SUCCESS && fileInfo->proc == 18)) { if (mgr->_0188 >= 112) { if (res == mCD_RESULT_SUCCESS) { mCD_create_famicom_file(mgr->chan); } sAdo_SysLevStop(NA_SE_47); mCD_ClearMemMgr_com2(mgr); } else { mgr->_018C = 1; mgr->_0190 = ret; mgr->_0194 = *chan; ret = mCD_TRANS_ERR_BUSY; if (mgr->_0190 == mCD_TRANS_ERR_BUSY) { mgr->_0190 = mCD_TRANS_ERR_NOCARD; } } } } else { ret = mCD_TRANS_ERR_NONE; mCD_ClearMemMgr_com2(mgr); } } else { if (mgr->_0188 >= 112) { ret = mgr->_0190; *chan = mgr->_0194; mCD_ClearMemMgr_com2(mgr); if (ret == mCD_TRANS_ERR_NONE) { mCD_create_famicom_file(*chan); } sAdo_SysLevStop(NA_SE_47); } } ret = mCD_SaveHome_ChangeErrCode(ret); if (ret != mCD_TRANS_ERR_BUSY) { SoftResetEnable = TRUE; } return ret; } static int mCD_TransErrCodeToCond(int err_code) { switch (err_code) { case mCD_TRANS_ERR_IOERROR: return 4; case mCD_TRANS_ERR_NOT_MEMCARD: return 6; case mCD_TRANS_ERR_BROKEN_WRONGENCODING: case mCD_TRANS_ERR_REPAIR: return 5; case mCD_TRANS_ERR_16: return 2; case mCD_TRANS_ERR_NO_SPACE: case mCD_TRANS_ERR_GENERIC: return 7; case mCD_TRANS_ERR_WRONGDEVICE: return 8; default: return 9; } } static void mCD_load_set_others_common(mCD_memMgr_c* mgr, mCD_memMgr_card_info_c* card_info, int chan, int diary_flag) { u8* data_p = (u8*)mgr->workArea; mCD_file_entry_c* entry; bzero(data_p, OTHERS_SIZE); entry = &l_mcd_file_table[mCD_FILE_SAVE_MISC]; if (mCD_read_fg(data_p, entry->filename, entry->entrysize, 0, chan, &card_info->result) == mCD_RESULT_SUCCESS) { data_p += sizeof(MemcardHeader_c) + 32; { mCD_keep_mail_c* mail = (mCD_keep_mail_c*)data_p; if (mFRm_ReturnCheckSum((u16*)mail, l_aram_real_size_32_table[mCD_ARAM_DATA_MAIL]) == 0) { mCD_save_data_main_to_aram(mail, l_aram_real_size_32_table[mCD_ARAM_DATA_MAIL], mCD_ARAM_DATA_MAIL); } data_p += l_aram_real_size_32_table[mCD_ARAM_DATA_MAIL]; } { mCD_keep_original_c* original = (mCD_keep_original_c*)data_p; if (mFRm_ReturnCheckSum((u16*)original, l_aram_real_size_32_table[mCD_ARAM_DATA_ORIGINAL]) == 0) { mCD_save_data_main_to_aram(original, l_aram_real_size_32_table[mCD_ARAM_DATA_ORIGINAL], mCD_ARAM_DATA_ORIGINAL); } data_p += l_aram_real_size_32_table[mCD_ARAM_DATA_ORIGINAL]; } if (diary_flag) { mCD_keep_diary_c* diary = (mCD_keep_diary_c*)data_p; if (mFRm_ReturnCheckSum((u16*)diary, l_aram_real_size_32_table[mCD_ARAM_DATA_DIARY]) == 0) { mCD_save_data_main_to_aram(diary, l_aram_real_size_32_table[mCD_ARAM_DATA_DIARY], mCD_ARAM_DATA_DIARY); } } } } extern void mCD_LoadLand(void) { static u16 noLand_code[2][8]; mCD_memMgr_c* mgr = &l_memMgr; mCD_memMgr_card_info_c* card_info = mgr->cards; Save_t* save; int noLand_info[2]; u8 cond[2]; int flashrom_cond = 9; int save_found = FALSE; mCD_memMgr_fileInfo_c* save_home_info = &mgr->save_home_info; int bad_save_chan; int save_chan = -1; int type; s32 chan; int res; res = mCD_bg_get_area_common(mgr, save_home_info, mCD_FILE_SAVE_MAIN, 2); save = (Save_t*)mgr->workArea; if (res == mCD_RESULT_SUCCESS) { for (chan = 0; chan < 2; chan++) { noLand_info[chan] = 0; cond[chan] = 9; bad_save_chan = 0; for (type = 0; type < 2; type++) { mgr->loaded_file_type = mCD_FILE_SAVE_MAIN + type; // main -> main backup mgr->workArea_size = mCD_get_size(mgr->loaded_file_type); bzero(save, mgr->workArea_size); if (mCD_load_file(save, mgr->loaded_file_type, chan, &card_info->result) == mCD_RESULT_SUCCESS) { if (mFRm_CheckSaveData_common(&save->save_check, save->land_info.id)) { if (mFRm_ReturnCheckSum((u16*)save, mgr->workArea_size) == 0 && (save->save_check.version == 6 || save->save_check.version == 5)) { bcopy(save, Common_GetPointer(save), sizeof(Save)); save_found = TRUE; Common_Set(copy_protect, Save_Get(copy_protect)); cond[chan] = 0; save_chan = chan; if (type == 1) { mCD_OnErrInfo(mCD_ERROR_OUTDATED); // loaded backup } else { mCD_OffErrInfo(mCD_ERROR_OUTDATED); // loaded main } break; } else { cond[chan] = 2; } } else if (cond[chan] == 9) { cond[chan] = 0; bad_save_chan++; } } else { if (card_info->result == CARD_RESULT_NOFILE) { if (mCD_find_fg(l_mCD_land_file_name_dummy, card_info->workArea, chan, &card_info->result) == TRUE) { cond[chan] = 0; } else { int res = mCD_RESULT_BUSY; while (res == mCD_RESULT_BUSY) { res = mCD_get_space_bg(&card_info->freeBlocks, chan, &card_info->result, card_info->workArea); } if (res == mCD_RESULT_SUCCESS) { if (card_info->freeBlocks >= mCD_LAND_SAVE_SIZE) { if (mCD_CheckPassportFile_slot(chan, card_info->workArea) == TRUE) { cond[chan] = 1; } else if (mCD_get_file_num(card_info->workArea, chan) >= CARD_MAX_FILE) { cond[chan] = 3; } else { cond[chan] = 0; } } else { cond[chan] = 7; } } else { cond[chan] = mCD_TransErrCodeToCond(mCD_TransErrorCode(card_info->result)); } } } else if (mCD_check_sector_size(mCD_MEMCARD_SECTORSIZE, chan) == FALSE) { cond[chan] = 6; } else { cond[chan] = mCD_TransErrCodeToCond(mCD_TransErrorCode_nes(card_info->result)); } break; } } if (save_found == TRUE) { break; } if (bad_save_chan == 1 && save_chan == -1) { noLand_info[chan] = mCD_check_noLand_file((mCD_LandProtectCode_c*)noLand_code[chan], (u8*)mgr->workArea, chan); save_chan = chan; } card_info++; } if (save_found == FALSE) { if (save_chan != -1) { if (noLand_info[save_chan] == TRUE) { bcopy(noLand_code[save_chan], &l_keep_noLandCode, sizeof(l_keep_noLandCode)); flashrom_cond = 0; mCD_load_set_others_common(mgr, &mgr->cards[save_chan], save_chan, FALSE); } else { flashrom_cond = 2; } } else { if (cond[0] > cond[1]) { flashrom_cond = cond[1]; save_chan = 1; } else { flashrom_cond = cond[0]; save_chan = 0; } } } else { flashrom_cond = cond[save_chan]; mCD_load_set_others_common(mgr, &mgr->cards[save_chan], save_chan, TRUE); } } Common_Set(save_error_type, flashrom_cond); if (save_chan != -1) { Common_Set(memcard_slot, save_chan); } else { Common_Set(memcard_slot, 0); } mCD_ClearMemMgr_com2(mgr); if (mFRm_CheckSaveData_common(Save_GetPointer(save_check), Save_Get(land_info).id) && Save_Get(save_check).version == 5) { bcopy(&Save_Get(save_check).time, Save_GetPointer(saved_auto_nwrite_time), sizeof(lbRTC_time_c)); } } extern void mCD_ReCheckLoadLand(GAME_PLAY* play) { int scene = Save_Get(scene_no); int bad; mCD_LoadLand(); Save_Set(scene_no, scene); switch (Common_Get(save_error_type)) { case 0: bad = TRUE; break; default: bad = FALSE; break; } if (bad == FALSE) { scene = SCENE_PLAYERSELECT_3; Common_Set(house_owner_name, RSV_NO); Common_Set(last_field_id, RSV_NO); } else { int res = mFRm_CheckSaveData(); if (res == FALSE) { scene = SCENE_PLAYERSELECT; Common_Set(house_owner_name, RSV_NO); Common_Set(last_field_id, RSV_NO); } else { int rtc_on = Common_Get(time.rtc_enabled); Common_Set(time.rtc_enabled, TRUE); mTM_rtcTime_limit_check(); scene = SCENE_PLAYERSELECT_2; Common_Set(time.rtc_enabled, rtc_on); mEv_ClearEventInfo(); } } play->next_scene_no = scene; } static int mCD_EraseLand_ChangeErrCode(int err_code) { switch (err_code) { case mCD_TRANS_ERR_BROKEN_WRONGENCODING: case mCD_TRANS_ERR_REPAIR: case mCD_TRANS_ERR_TOWN_INVALID: case mCD_TRANS_ERR_16: case mCD_TRANS_ERR_GENERIC: err_code = mCD_TRANS_ERR_IOERROR; break; case mCD_TRANS_ERR_NO_SPACE: case mCD_TRANS_ERR_OTHER_TOWN: err_code = mCD_TRANS_ERR_NOCARD; break; } return err_code; } static int mCD_EraseLand_bg_get_area(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { return mCD_bg_get_area_common(mgr, fileInfo, mCD_FILE_SAVE_MAIN, 1); } static int mCD_EraseLand_bg_get_slot(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* card_info = mgr->cards; int res = mCD_RESULT_BUSY; if (mgr->cards[0].workArea != NULL && mgr->cards[1].workArea != NULL && mgr->workArea != NULL) { if (Save_Get(save_exist) == FALSE) { res = mCD_RESULT_ERROR; } else { int slot = mCD_get_this_land_slot_no(mgr); if (slot == mCD_SLOT_B) { if (mgr->chan != -1) { res = mCD_RESULT_SUCCESS; fileInfo->proc++; } else { res = mCD_RESULT_ERROR; } } else if (slot != mCD_SLOT_A) { res = mCD_RESULT_ERROR; } } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_EraseLand_bg_set_data(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* card_info; u8* data_p = (u8*)mgr->workArea; int res; if (data_p != NULL && mgr->chan != -1) { bzero(data_p, CARD_WORKAREA_SIZE); bcopy(Common_GetPointer(save), data_p, CARD_WORKAREA_SIZE); mFRm_ClearSaveCheckData((mFRm_chk_t*)data_p); mgr->loaded_file_type = mCD_FILE_SAVE_MAIN; mgr->workArea_size = mCD_get_size(mCD_FILE_SAVE_MAIN); card_info = &mgr->cards[mgr->chan]; card_info->game_result = mCD_TRANS_ERR_NOCARD; fileInfo->proc++; res = mCD_RESULT_SUCCESS; } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_EraseLand_bg_write_main(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_file_entry_c* entry; mCD_memMgr_card_info_c* card_info; int res; int chan = mgr->chan; int ofs; if (chan != -1) { entry = &l_mcd_file_table[mgr->loaded_file_type]; ofs = mCD_get_offset(mgr->loaded_file_type); card_info = &mgr->cards[chan]; res = mCD_write_comp_bg(mgr->workArea, entry->filename, mgr->workArea_size, entry->filesize, ofs, chan, &card_info->result); card_info->game_result = mCD_TransErrorCode(card_info->result); if (res == mCD_RESULT_SUCCESS) { fileInfo->proc++; mgr->loaded_file_type = mCD_FILE_SAVE_MAIN_BAK; } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_EraseLand_bg_write_bk(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_file_entry_c* entry; mCD_memMgr_card_info_c* card_info; int res; int chan = mgr->chan; int ofs; if (chan != -1) { entry = &l_mcd_file_table[mgr->loaded_file_type]; ofs = mCD_get_offset(mgr->loaded_file_type); card_info = &mgr->cards[chan]; res = mCD_write_comp_bg(mgr->workArea, entry->filename, mgr->workArea_size, entry->filesize, ofs, chan, &card_info->result); card_info->game_result = mCD_TransErrorCode(card_info->result); if (res == mCD_RESULT_SUCCESS) { fileInfo->proc++; bzero(mgr->workArea, mgr->workArea_size); mgr->loaded_file_type = mCD_FILE_SAVE_MISC; mgr->workArea_size = mCD_get_size(mgr->loaded_file_type); } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_EraseLand_bg_load_icon(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* card_info; int res; int chan = mgr->chan; if (chan != -1) { card_info = &mgr->cards[chan]; res = mCD_load_file(mgr->workArea, mgr->loaded_file_type, chan, &card_info->result); if (res == mCD_RESULT_SUCCESS) { fileInfo->proc++; bcopy(l_comment_erase_land, (u8*)mgr->workArea + sizeof(l_comment_0_str), sizeof(l_comment_erase_land)); mCD_MakeProtectCode((mCD_LandProtectCode_c*)((u8*)mgr->workArea + sizeof(MemcardHeader_c))); } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_EraseLand_bg_write_icon(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { int res; res = mCD_write_common(mgr); if (res == mCD_RESULT_SUCCESS) { fileInfo->proc++; } return res; } extern int mCD_EraseLand_bg(int* slot) { // clang-format off static mCD_SAVEHOME_PROC erase_proc[] = { mCD_EraseLand_bg_get_area, mCD_EraseLand_bg_get_slot, mCD_EraseLand_bg_set_data, mCD_EraseLand_bg_write_main, mCD_EraseLand_bg_write_bk, mCD_EraseLand_bg_load_icon, mCD_EraseLand_bg_write_icon, }; // clang-format on mCD_memMgr_c* mgr = &l_memMgr; mCD_memMgr_fileInfo_c* fileInfo = &mgr->save_home_info; mCD_memMgr_card_info_c* card_info; int res; u8 proc = (u8)fileInfo->proc; int ret = mCD_TRANS_ERR_BUSY; mgr->_0188++; if (mgr->_018C == 0) { if (proc < 7) { res = (*erase_proc[proc])(mgr, fileInfo); if (res == mCD_RESULT_SUCCESS) { if (fileInfo->proc == 7) { *slot = mgr->chan; ret = mCD_TRANS_ERR_NONE; } } else if (res != mCD_RESULT_BUSY) { int cur_chan = mgr->chan; if (cur_chan == 0 || cur_chan == 1) { *slot = cur_chan; card_info = &mgr->cards[mgr->chan]; ret = card_info->game_result; } else { ret = mCD_TRANS_ERR_NOCARD; } } if (res == mCD_RESULT_ERROR || (res == mCD_RESULT_SUCCESS && fileInfo->proc == 7)) { if (mgr->_0188 >= 170) { sAdo_SysLevStop(NA_SE_53); mCD_ClearMemMgr_com2(mgr); } else { mgr->_018C = 1; mgr->_0190 = ret; mgr->_0194 = *slot; ret = mCD_TRANS_ERR_BUSY; if (mgr->_0190 == mCD_TRANS_ERR_BUSY) { mgr->_0190 = mCD_TRANS_ERR_NOCARD; } } } } else { ret = mCD_TRANS_ERR_NONE; mCD_ClearMemMgr_com2(mgr); } } else if (mgr->_0188 >= 170) { ret = mgr->_0190; *slot = mgr->_0194; mCD_ClearMemMgr_com2(mgr); sAdo_SysLevStop(NA_SE_53); } return mCD_EraseLand_ChangeErrCode(ret); } static int mCD_EraseBrokenLand_bg_get_slot(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* card_info; Save_t* save; int sel_chan; int i; s32 chan; int type; int ret; save = (Save_t*)mgr->workArea; card_info = mgr->cards; sel_chan = -1; if (mgr->cards[mCD_SLOT_A].workArea != NULL && mgr->cards[mCD_SLOT_B].workArea != NULL && mgr->workArea != NULL) { for (chan = 0; chan < 2; chan++) { card_info->game_result = mCD_TRANS_ERR_NOCARD; for (i = 0, type = 0; type < 2; type++) { int size; mgr->loaded_file_type = mCD_FILE_SAVE_MAIN + type; mgr->workArea_size = mCD_get_size(mgr->loaded_file_type); bzero(save, mgr->workArea_size); if (mCD_load_file(save, mgr->loaded_file_type, chan, &card_info->result) == mCD_RESULT_SUCCESS) { if (mFRm_CheckSaveData_common(&save->save_check, save->land_info.id)) { if (mFRm_ReturnCheckSum((u16*)save, mgr->workArea_size) == 0 && (save->save_check.version == 6 || save->save_check.version == 5)) { card_info->game_result = mCD_TRANS_ERR_15; sel_chan = chan; break; } else { i++; } } else { i++; } } else { card_info->game_result = mCD_TransErrorCode(card_info->result); break; } } if (i == 2) { mgr->chan = chan; break; } card_info++; } if (mgr->chan != -1) { fileInfo->proc++; ret = mCD_RESULT_SUCCESS; } else { if (sel_chan != -1) { mgr->chan = sel_chan; } else { mCD_GetHighPriority_common(mgr, mgr->cards[mCD_SLOT_A].game_result, mgr->cards[mCD_SLOT_B].game_result); } ret = mCD_RESULT_ERROR; } } else { ret = mCD_RESULT_ERROR; } return ret; } extern int mCD_EraseBrokenLand_bg(int* slot) { // clang-format off static mCD_SAVEHOME_PROC erase_proc[] = { mCD_EraseLand_bg_get_area, mCD_EraseBrokenLand_bg_get_slot, mCD_EraseLand_bg_set_data, mCD_EraseLand_bg_write_main, mCD_EraseLand_bg_write_bk, mCD_EraseLand_bg_load_icon, mCD_EraseLand_bg_write_icon, }; // clang-format on mCD_memMgr_c* mgr = &l_memMgr; mCD_memMgr_fileInfo_c* fileInfo = &mgr->save_home_info; mCD_memMgr_card_info_c* card_info; int res; u8 proc = (u8)fileInfo->proc; int ret = mCD_TRANS_ERR_BUSY; mgr->_0188++; if (mgr->_018C == 0) { if (proc < 7) { res = (*erase_proc[proc])(mgr, fileInfo); if (res == mCD_RESULT_SUCCESS) { if (fileInfo->proc == 7) { *slot = mgr->chan; ret = mCD_TRANS_ERR_NONE; } } else if (res != mCD_RESULT_BUSY) { int cur_chan = mgr->chan; if (cur_chan == 0 || cur_chan == 1) { *slot = cur_chan; card_info = &mgr->cards[mgr->chan]; ret = card_info->game_result; } else { ret = mCD_TRANS_ERR_NOCARD; } } if (res == mCD_RESULT_ERROR || (res == mCD_RESULT_SUCCESS && fileInfo->proc == 7)) { if (mgr->_0188 >= 170) { sAdo_SysLevStop(NA_SE_53); mCD_ClearMemMgr_com2(mgr); } else { mgr->_018C = 1; mgr->_0190 = ret; mgr->_0194 = *slot; ret = mCD_TRANS_ERR_BUSY; if (mgr->_0190 == mCD_TRANS_ERR_BUSY) { mgr->_0190 = mCD_TRANS_ERR_NOCARD; } } } } else { ret = mCD_TRANS_ERR_NONE; mCD_ClearMemMgr_com2(mgr); } } else if (mgr->_0188 >= 170) { ret = mgr->_0190; *slot = mgr->_0194; mCD_ClearMemMgr_com2(mgr); sAdo_SysLevStop(NA_SE_53); } return mCD_EraseLand_ChangeErrCode(ret); } extern int mCD_CheckPassportFile(void) { void* workArea; int ret; ret = -1; workArea = mCD_malloc_32(CARD_WORKAREA_SIZE); if (workArea != NULL) { int i; for (i = 0; i < 2; i++) { if (mCD_CheckPassportFile_slot(i, workArea) == TRUE) { ret = i; break; } } if (workArea != NULL) { zelda_free(workArea); } } return ret; } extern int mCD_CheckBrokenPassportFile(int slot) { ForeignerFile_c* foreigner_file; void* workArea; int i; int ret; s32 result; CARDStat stat; CARDFileInfo file_info; ret = FALSE; workArea = mCD_malloc_32(CARD_WORKAREA_SIZE); foreigner_file = (ForeignerFile_c*)mCD_malloc_32(mCD_PLAYER_SAVE_SIZE); if ((slot == mCD_SLOT_A || slot == mCD_SLOT_B) && workArea != NULL && foreigner_file != NULL && mCD_check_card(&result, mCD_MEMCARD_SECTORSIZE, slot) == TRUE) { result = CARDMount((s32)slot, workArea, NULL); if (result == CARD_RESULT_READY || result == CARD_RESULT_BROKEN) { result = CARDCheck((s32)slot); if (result == CARD_RESULT_READY) { for (i = 0; i < CARD_MAX_FILE; i++) { result = CARDGetStatus((s32)slot, i, &stat); if (result == CARD_RESULT_READY && mCD_CheckPassportFileStatus(&stat) == TRUE) { result = CARDOpen((s32)slot, stat.fileName, &file_info); if (result == CARD_RESULT_READY) { result = CARDRead(&file_info, foreigner_file, mCD_PLAYER_SAVE_SIZE, 0); if (result == CARD_RESULT_READY && (mFRm_ReturnCheckSum((u16*)&foreigner_file->file, sizeof(mCD_foreigner_c)) != 0 || mPr_NullCheckPersonalID(&foreigner_file->file.priv.player_ID) == TRUE)) { CARDClose(&file_info); ret = TRUE; break; } CARDClose(&file_info); } } } } CARDUnmount((s32)slot); } else if (result == CARD_RESULT_ENCODING) { CARDUnmount((s32)slot); } if (workArea != NULL) { zelda_free(workArea); } if (foreigner_file != NULL) { zelda_free(foreigner_file); } } return ret; } static int mCD_ErasePassport_bg_get_area(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { return mCD_bg_get_area_common(mgr, fileInfo, mCD_FILE_PLAYER, 1); } static int mCD_ErasePassport_bg_mount_card(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* card_info; int res; int chan = mgr->chan; if (chan != -1) { card_info = &mgr->cards[chan]; if (card_info->workArea != NULL && mCD_check_card(&card_info->result, mCD_MEMCARD_SECTORSIZE, chan) == TRUE) { card_info->result = CARDMount((s32)chan, card_info->workArea, NULL); if (card_info->result == CARD_RESULT_READY || card_info->result == CARD_RESULT_BROKEN) { card_info->result = CARDCheck((s32)chan); if (card_info->result == CARD_RESULT_READY) { res = mCD_RESULT_SUCCESS; fileInfo->proc++; } else { CARDUnmount((s32)chan); res = mCD_RESULT_ERROR; } } else { if (card_info->result == CARD_RESULT_ENCODING) { CARDUnmount((s32)chan); } res = mCD_RESULT_ERROR; } } else { res = mCD_RESULT_ERROR; } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_ErasePassportFile_bg_get_broken_Passport(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* card_info; ForeignerFile_c* foreigner_file; int ret; int i; CARDFileInfo file_info; int chan; int fileNo; CARDStat* stat; foreigner_file = (ForeignerFile_c*)mgr->workArea; chan = mgr->chan; fileNo = fileInfo->_04; ret = mCD_RESULT_BUSY; if (chan != -1 && foreigner_file != NULL) { card_info = &mgr->cards[chan]; stat = &card_info->stat; for (i = fileNo; i < CARD_MAX_FILE; i++) { card_info->result = CARDGetStatus((s32)chan, i, stat); if (card_info->result == CARD_RESULT_READY && mCD_CheckPassportFileStatus(stat) == TRUE) { card_info->result = CARDOpen((s32)chan, stat->fileName, &file_info); if (card_info->result == CARD_RESULT_READY) { card_info->result = CARDRead(&file_info, foreigner_file, mCD_PLAYER_SAVE_SIZE, 0); if (card_info->result == CARD_RESULT_READY && (mFRm_ReturnCheckSum((u16*)&foreigner_file->file, sizeof(mCD_foreigner_c)) != 0 || mPr_NullCheckPersonalID(&foreigner_file->file.priv.player_ID) == TRUE)) { fileInfo->_04 = i; CARDClose(&file_info); card_info->result = CARDDeleteAsync((s32)chan, stat->fileName, NULL); if (card_info->result == CARD_RESULT_READY) { ret = mCD_RESULT_SUCCESS; fileInfo->proc++; } else { ret = mCD_RESULT_ERROR; } break; } CARDClose(&file_info); } } } if (i == CARD_MAX_FILE) { CARDUnmount((s32)chan); ret = mCD_RESULT_SUCCESS; fileInfo->proc = 4; } else { if (ret == mCD_RESULT_ERROR) { CARDUnmount((s32)chan); } } } else { if (chan != -1) { CARDUnmount((s32)chan); } ret = mCD_RESULT_ERROR; } return ret; } static int mCD_ErasePassportFile_bg_erase(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { mCD_memMgr_card_info_c* info; int chan = mgr->chan; int _04 = fileInfo->_04; int ret = mCD_RESULT_BUSY; if (chan != -1 && _04 >= 0 && _04 < 127) { info = &mgr->cards[chan]; info->result = CARDGetResultCode(chan); if (info->result == CARD_RESULT_READY) { fileInfo->_04++; if (fileInfo->_04 >= 127) { CARDUnmount(chan); fileInfo->proc = 4; } else { fileInfo->proc = 2; } ret = mCD_RESULT_SUCCESS; } else if (info->result != CARD_RESULT_BUSY) { CARDUnmount(chan); ret = mCD_RESULT_ERROR; } } else { if (chan != -1) { CARDUnmount(chan); } ret = mCD_RESULT_ERROR; } return ret; } extern int mCD_ErasePassportFile_bg(int slot) { // clang-format off static mCD_SAVEHOME_PROC erase_proc[] = { mCD_ErasePassport_bg_get_area, mCD_ErasePassport_bg_mount_card, mCD_ErasePassportFile_bg_get_broken_Passport, mCD_ErasePassportFile_bg_erase, }; // clang-format on mCD_memMgr_c* mgr = &l_memMgr; mCD_memMgr_fileInfo_c* fileInfo = &mgr->save_home_info; mCD_memMgr_card_info_c* card_info; int res; u8 proc = (u8)fileInfo->proc; int ret = mCD_RESULT_BUSY; mgr->_0188++; mgr->chan = slot; if (mgr->_018C == 0) { if (proc < 4) { res = (*erase_proc[proc])(mgr, fileInfo); if (res == mCD_RESULT_SUCCESS) { if (fileInfo->proc == 4) { ret = mCD_RESULT_SUCCESS; } } else if (res != mCD_RESULT_BUSY) { ret = mCD_RESULT_ERROR; } if (res == mCD_RESULT_ERROR || (res == mCD_RESULT_SUCCESS && fileInfo->proc == 4)) { if (mgr->_0188 >= 170) { sAdo_SysLevStop(NA_SE_53); mCD_ClearMemMgr_com2(mgr); } else { mgr->_018C = 1; mgr->_0190 = ret; ret = mCD_RESULT_BUSY; } } } else { ret = mCD_RESULT_ERROR; mCD_ClearMemMgr_com2(mgr); } } else if (mgr->_0188 >= 170) { ret = l_memMgr._0190; mCD_ClearMemMgr_com2(mgr); sAdo_SysLevStop(NA_SE_53); } return ret; } static int mCD_GameStart_ChangeErrCode(int err_code) { switch (err_code) { case mCD_TRANS_ERR_BROKEN_WRONGENCODING: case mCD_TRANS_ERR_REPAIR: case mCD_TRANS_ERR_TOWN_INVALID: case mCD_TRANS_ERR_16: case mCD_TRANS_ERR_GENERIC: err_code = mCD_TRANS_ERR_IOERROR; break; case mCD_TRANS_ERR_NO_SPACE: case mCD_TRANS_ERR_OTHER_TOWN: err_code = mCD_TRANS_ERR_NOCARD; break; } return err_code; } static void mCD_SetCopyProtect(mCD_foreigner_c* passport) { f32 random = fqrand(); u16 code = (u16)(random * 0xFFFE); l_mcd_copy_protect = code; passport->copy_protect = code; passport->checksum = mFRm_GetFlatCheckSum((u16*)passport, sizeof(mCD_foreigner_c), passport->checksum); } static Private_c* mCD_GetSaveFilePrivateP(void) { return &l_mcd_foreigner_file.file.priv; } static int mCD_InitGameStart_bg_get_area(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { static int sound_mode[] = { 2, 0, 0, 0, 0 }; int soundm = 2; if (fileInfo->chan >= 0 && fileInfo->chan < 5) { soundm = sound_mode[fileInfo->chan]; } fileInfo->_10 = soundm; SoftResetEnable = FALSE; return mCD_bg_get_area_common(mgr, fileInfo, mCD_FILE_SAVE_MAIN, soundm); } static int mCD_InitGameStart_bg_get_slot(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { int _0C = fileInfo->chan; int res = mCD_RESULT_BUSY; if (mgr->cards[0].workArea != NULL && mgr->cards[1].workArea != NULL && mgr->workArea != NULL) { if (_0C == 0 || _0C == 2) { res = mCD_RESULT_SUCCESS; fileInfo->proc = 4; } else { int slot = mCD_get_this_land_slot_no_game_start(mgr); if (slot == mCD_SLOT_B) { int chan = mgr->chan; if (chan != -1) { if (mCD_check_copyProtect((Save_t*)mgr->workArea, chan) == TRUE) { res = mCD_RESULT_SUCCESS; fileInfo->proc++; } else { mCD_memMgr_card_info_c* card_info = mgr->cards; res = mCD_RESULT_ERROR; card_info[chan].game_result = mCD_TRANS_ERR_WRONG_LAND; } } else { res = mCD_RESULT_ERROR; } } else if (slot != mCD_SLOT_A) { res = mCD_RESULT_ERROR; } } } else { res = mCD_RESULT_ERROR; } return res; } static int mCD_InitGameStart_bg_check_repair_land(mCD_memMgr_c* mgr, mCD_memMgr_fileInfo_c* fileInfo) { if (mCD_check_broken_land(mgr) == TRUE) { if (mCD_repair_land(mgr) == TRUE) { fileInfo->proc++; } else { fileInfo->proc = 4; } } else { fileInfo->proc = 4; } return mCD_RESULT_SUCCESS; } static int mCD_LoadPrivate_idx(mCD_memMgr_c* mgr, Private_c* priv, Animal_c* animal, int idx) { ForeignerFile_c* file; mCD_foreigner_c* foreigner; void* workArea = mgr->workArea; mCD_cardPrivate_c* card_priv; int ret = FALSE; if (workArea != NULL && idx >= 0 && idx < ARRAY_SIZE(l_mcd_card_private_table, mCD_cardPrivate_c)) { card_priv = &l_mcd_card_private_table[idx]; if (!mPr_NullCheckPersonalID(&card_priv->pid)) { s32 result; int i; for (i = 0; i < mCD_SLOT_NUM; i++) { file = (ForeignerFile_c*)workArea; foreigner = &file->file; bzero(workArea, sizeof(ForeignerFile_c)); if (mCD_read_fg(file, card_priv->filename, sizeof(ForeignerFile_c), 0, i, &result) == mCD_RESULT_SUCCESS) { if (mFRm_ReturnCheckSum((u16*)foreigner, sizeof(mCD_foreigner_c)) == 0 && mPr_CheckCmpPersonalID(&foreigner->priv.player_ID, &card_priv->pid) == TRUE ) { mPr_CopyPrivateInfo(priv, &foreigner->priv); if (animal != NULL) { bcopy(&foreigner->remove_animal, animal, sizeof(Animal_c)); } bcopy(foreigner, &l_mcd_foreigner_file.file, sizeof(l_mcd_foreigner_file)); ret = TRUE; break; } } } } } return ret; }