From a49970ac3f2ddcb48379f233b937a4af27053b1d Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Tue, 7 Jun 2022 23:18:59 +0300 Subject: [PATCH] Decompile editor options window --- src/character_editor.cc | 307 +++++++++++---- src/db.cc | 7 +- src/dbox.cc | 855 +++++++++++++++++++++++++++++++++++++--- src/dbox.h | 26 +- src/xfile.cc | 2 +- 5 files changed, 1060 insertions(+), 137 deletions(-) diff --git a/src/character_editor.cc b/src/character_editor.cc index 021f5f7..02cc4e5 100644 --- a/src/character_editor.cc +++ b/src/character_editor.cc @@ -722,7 +722,7 @@ int _editor_design(bool isCreationMode) windowRefresh(characterEditorWindowHandle); } else if ((gCharacterEditorIsCreationMode && (keyCode == 501 || keyCode == KEY_UPPERCASE_O || keyCode == KEY_LOWERCASE_O)) || (!gCharacterEditorIsCreationMode && (keyCode == 501 || keyCode == KEY_UPPERCASE_P || keyCode == KEY_LOWERCASE_P))) { - // _OptionWindow(); + _OptionWindow(); windowRefresh(characterEditorWindowHandle); } else if (keyCode >= 525 && keyCode < 535) { _InfoButton(keyCode); @@ -3536,8 +3536,31 @@ int _OptionWindow() int width = _GInfo[43].width; int height = _GInfo[43].height; + // NOTE: The following is a block of general purpose string buffers used in + // this function. They are either store path, or strings from .msg files. I + // don't know if such usage was intentional in the original code or it's a + // result of some kind of compiler optimization. + char string1[512]; + char string2[512]; + char string3[512]; + char string4[512]; + char string5[512]; + + // Only two of the these blocks are used as a dialog body. Depending on the + // dialog either 1 or 2 strings used from this array. + const char* dialogBody[2] = { + string5, + string2, + }; + if (gCharacterEditorIsCreationMode) { - int win = windowCreate(238, 90, _GInfo[41].width, _GInfo[41].height, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02); + int optionsWindowX = (screenGetWidth() != 640) + ? (screenGetWidth() - _GInfo[41].width) / 2 + : 238; + int optionsWindowY = (screenGetHeight() != 480) + ? (screenGetHeight() - _GInfo[41].height) / 2 + : 90; + int win = windowCreate(optionsWindowX, optionsWindowY, _GInfo[41].width, _GInfo[41].height, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02); if (win == -1) { return -1; } @@ -3575,15 +3598,11 @@ int _OptionWindow() memcpy(down[index], _grphbmp[43], size); memcpy(up[index], _grphbmp[42], size); - const char* msg = getmsg(&editorMessageList, &editorMessageListItem, 600 + index); + strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 600 + index)); - char dest[512]; - strcpy(dest, msg); - - int length = fontGetStringWidth(dest); - int v60 = width / 2 - length / 2; - fontDrawText(up[index] + v60, dest, width, width, _colorTable[18979]); - fontDrawText(down[index] + v60, dest, width, width, _colorTable[14723]); + int offset = width * 7 + width / 2 - fontGetStringWidth(string4) / 2; + fontDrawText(up[index] + offset, string4, width, width, _colorTable[18979]); + fontDrawText(down[index] + offset, string4, width, width, _colorTable[14723]); int btn = buttonCreate(win, 13, y, width, height, -1, -1, -1, 500 + index, up[index], down[index], NULL, BUTTON_FLAG_TRANSPARENT); if (btn != -1) { @@ -3610,7 +3629,7 @@ int _OptionWindow() fontSetCurrent(101); int rc = 0; - while (rc != 0) { + while (rc == 0) { int keyCode = _get_input(); if (_game_user_wants_to_quit != 0) { @@ -3625,84 +3644,74 @@ int _OptionWindow() rc = 2; } else if (keyCode == 503 || keyCode == KEY_UPPERCASE_E || keyCode == KEY_LOWERCASE_E) { // ERASE - char line1[512]; - strcpy(line1, getmsg(&editorMessageList, &editorMessageListItem, 605)); + strcpy(string5, getmsg(&editorMessageList, &editorMessageListItem, 605)); + strcpy(string2, getmsg(&editorMessageList, &editorMessageListItem, 606)); - char line2[512]; - strcpy(line2, getmsg(&editorMessageList, &editorMessageListItem, 606)); - - const char* lines[] = { line1, line2 }; - if (showDialogBox(NULL, lines, 2, 169, 126, _colorTable[992], NULL, _colorTable[992], 0x10) != 0) { + if (showDialogBox(NULL, dialogBody, 2, 169, 126, _colorTable[992], NULL, _colorTable[992], DIALOG_BOX_YES_NO) != 0) { _ResetPlayer(); skillsGetTagged(_temp_tag_skill, NUM_TAGGED_SKILLS); - int v224 = 3; - int v225 = 0; - do { - if (_temp_tag_skill[v224] != -1) { + int taggedSkillCount = 0; + for (int index = 3; index >= 0; index--) { + if (_temp_tag_skill[index] != -1) { break; } - --v224; - ++v225; - } while (v224 > -1); - - if (gCharacterEditorIsCreationMode) { - v225--; + taggedSkillCount++; } - _tagskill_count = v225; + if (gCharacterEditorIsCreationMode) { + taggedSkillCount--; + } + + _tagskill_count = taggedSkillCount; traitsGetSelected(&_temp_trait[0], &_temp_trait[1]); - int v226 = 1; - int v227 = 0; - do { - if (_temp_trait[v226] != -1) { + int traitCount = 0; + for (int index = 1; index >= 0; index--) { + if (_temp_trait[index] != -1) { break; } - --v226; - ++v227; - } while (v226 > -1); + traitCount++; + } - _trait_count = v227; + _trait_count = traitCount; critterUpdateDerivedStats(gDude); _ResetScreen(); } } else if (keyCode == 502 || keyCode == KEY_UPPERCASE_P || keyCode == KEY_LOWERCASE_P) { // PRINT TO FILE - char dest[512]; - dest[0] = '\0'; + string4[0] = '\0'; - strcat(dest, "*.TXT"); + strcat(string4, "*."); + strcat(string4, "TXT"); char** fileList; - int fileListLength = fileNameListInit(dest, &fileList, 0, 0); + int fileListLength = fileNameListInit(string4, &fileList, 0, 0); if (fileListLength != -1) { - char v236[512]; - // PRINT - strcpy(v236, getmsg(&editorMessageList, &editorMessageListItem, 616)); + strcpy(string1, getmsg(&editorMessageList, &editorMessageListItem, 616)); // PRINT TO FILE - strcpy(dest, getmsg(&editorMessageList, &editorMessageListItem, 602)); + strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 602)); - if (_save_file_dialog(dest, fileList, v236, fileListLength, 168, 80, 0) == 0) { - strcat(v236, ".TXT"); + if (showSaveFileDialog(string4, fileList, string1, fileListLength, 168, 80, 0) == 0) { + strcat(string1, "."); + strcat(string1, "TXT"); - dest[0] = '\0'; + string4[0] = '\0'; + strcat(string4, string1); - if (!characterFileExists(dest)) { + if (!characterFileExists(string4)) { // already exists - sprintf(dest, + sprintf(string4, "%s %s", - compat_strupr(v236), + strupr(string1), getmsg(&editorMessageList, &editorMessageListItem, 609)); - char v240[512]; - strcpy(v240, getmsg(&editorMessageList, &editorMessageListItem, 610)); + strcpy(string5, getmsg(&editorMessageList, &editorMessageListItem, 610)); - const char* lines[] = { v240 }; - if (showDialogBox(dest, lines, 1, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0x10) != 0) { + if (showDialogBox(string4, dialogBody, 1, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0x10) != 0) { rc = 1; } else { rc = 0; @@ -3712,24 +3721,24 @@ int _OptionWindow() } if (rc != 0) { - dest[0] = '\0'; - strcat(dest, v236); + string4[0] = '\0'; + strcat(string4, string1); - if (characterPrintToFile(dest) == 0) { - sprintf(dest, + if (characterPrintToFile(string4) == 0) { + sprintf(string4, "%s%s", - compat_strupr(v236), + strupr(string1), getmsg(&editorMessageList, &editorMessageListItem, 607)); - showDialogBox(dest, NULL, 0, 169, 126, _colorTable[992], NULL, _colorTable[992], 0); + showDialogBox(string4, NULL, 0, 169, 126, _colorTable[992], NULL, _colorTable[992], 0); } else { soundPlayFile("iisxxxx1"); - sprintf(dest, + sprintf(string4, "%s%s%s", getmsg(&editorMessageList, &editorMessageListItem, 611), - compat_strupr(v236), + strupr(string1), "!"); - showDialogBox(dest, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[992], 0x01); + showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[992], 0x01); } } } @@ -3738,33 +3747,173 @@ int _OptionWindow() } else { soundPlayFile("iisxxxx1"); - strcpy(dest, getmsg(&editorMessageList, &editorMessageListItem, 615)); - showDialogBox(dest, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0); + strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 615)); + showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0); rc = 0; } } else if (keyCode == 501 || keyCode == KEY_UPPERCASE_L || keyCode == KEY_LOWERCASE_L) { // LOAD - char path[COMPAT_MAX_PATH]; - path[0] = '\0'; - strcat(path, "*."); - strcat(path, "GCD"); + string4[0] = '\0'; + strcat(string4, "*."); + strcat(string4, "GCD"); - char** fileNames; - int filesCount = fileNameListInit(path, &fileNames, 0, 0); - if (filesCount != -1) { + char** fileNameList; + int fileNameListLength = fileNameListInit(string4, &fileNameList, 0, 0); + if (fileNameListLength != -1) { + // NOTE: This value is not copied as in save dialog. + char* title = getmsg(&editorMessageList, &editorMessageListItem, 601); + int loadFileDialogRc = showLoadFileDialog(title, fileNameList, string3, fileNameListLength, 168, 80, 0); + if (loadFileDialogRc == -1) { + fileNameListFree(&fileNameList, 0); + // FIXME: This branch ignores cleanup at the end of the loop. + return -1; + } + if (loadFileDialogRc == 0) { + string4[0] = '\0'; + strcat(string4, string3); + + int oldRemainingCharacterPoints = characterEditorRemainingCharacterPoints; + + _ResetPlayer(); + + if (gcdLoad(string4) == 0) { + critterUpdateDerivedStats(gDude); + pcStatsReset(); + for (int stat = 0; stat < SAVEABLE_STAT_COUNT; stat++) { + critterSetBonusStat(gDude, stat, 0); + } + perksReset(); + critterUpdateDerivedStats(gDude); + skillsGetTagged(_temp_tag_skill, 4); + + int taggedSkillCount = 0; + for (int index = 3; index >= 0; index--) { + if (_temp_tag_skill[index] != -1) { + break; + } + taggedSkillCount++; + } + + if (gCharacterEditorIsCreationMode) { + taggedSkillCount--; + } + + _tagskill_count = taggedSkillCount; + + traitsGetSelected(&(_temp_trait[0]), &(_temp_trait[1])); + + int traitCount = 0; + for (int index = 1; index >= 0; index--) { + if (_temp_trait[index] != -1) { + break; + } + traitCount++; + } + + _trait_count = traitCount; + + critterUpdateDerivedStats(gDude); + + critterAdjustHitPoints(gDude, 1000); + + rc = 1; + } else { + _RestorePlayer(); + characterEditorRemainingCharacterPoints = oldRemainingCharacterPoints; + critterAdjustHitPoints(gDude, 1000); + soundPlayFile("iisxxxx1"); + + strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 612)); + strcat(string4, string3); + strcat(string4, "!"); + + showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0); + } + + _ResetScreen(); + } + + fileNameListFree(&fileNameList, 0); } else { soundPlayFile("iisxxxx1"); // Error reading file list! - strcpy(path, getmsg(&editorMessageList, &editorMessageListItem, 615)); + strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 615)); rc = 0; - showDialogBox(path, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0); + showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0); } } else if (keyCode == 500 || keyCode == KEY_UPPERCASE_S || keyCode == KEY_LOWERCASE_S) { - // TODO: Incomplete. + // SAVE + string4[0] = '\0'; + strcat(string4, "*."); + strcat(string4, "GCD"); + + char** fileNameList; + int fileNameListLength = fileNameListInit(string4, &fileNameList, 0, 0); + if (fileNameListLength != -1) { + strcpy(string1, getmsg(&editorMessageList, &editorMessageListItem, 617)); + strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 600)); + + if (showSaveFileDialog(string4, fileNameList, string1, fileNameListLength, 168, 80, 0) == 0) { + strcat(string1, "."); + strcat(string1, "GCD"); + + string4[0] = '\0'; + strcat(string4, string1); + + bool shouldSave; + if (characterFileExists(string4)) { + sprintf(string4, "%s %s", + strupr(string1), + getmsg(&editorMessageList, &editorMessageListItem, 609)); + strcpy(string5, getmsg(&editorMessageList, &editorMessageListItem, 610)); + + if (showDialogBox(string4, dialogBody, 1, 169, 126, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_YES_NO) != 0) { + shouldSave = true; + } else { + shouldSave = false; + } + } else { + shouldSave = true; + } + + if (shouldSave) { + skillsSetTagged(_temp_tag_skill, 4); + traitsSetSelected(_temp_trait[0], _temp_trait[1]); + + string4[0] = '\0'; + strcat(string4, string1); + + if (gcdSave(string4) != 0) { + soundPlayFile("iisxxxx1"); + sprintf(string4, "%s%s!", + strupr(string1), + getmsg(&editorMessageList, &editorMessageListItem, 611)); + showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE); + rc = 0; + } else { + sprintf(string4, "%s%s", + strupr(string1), + getmsg(&editorMessageList, &editorMessageListItem, 607)); + showDialogBox(string4, NULL, 0, 169, 126, _colorTable[992], NULL, _colorTable[992], DIALOG_BOX_LARGE); + rc = 1; + } + } + } + + fileNameListFree(&fileNameList, 0); + } else { + soundPlayFile("iisxxxx1"); + + // Error reading file list! + char* msg = getmsg(&editorMessageList, &editorMessageListItem, 615); + showDialogBox(msg, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0); + + rc = 0; + } } windowRefresh(win); @@ -3804,7 +3953,7 @@ int _OptionWindow() char title[512]; strcpy(title, getmsg(&editorMessageList, &editorMessageListItem, 602)); - if (_save_file_dialog(title, fileNames, fileName, filesCount, 168, 80, 0) == 0) { + if (showSaveFileDialog(title, fileNames, fileName, filesCount, 168, 80, 0) == 0) { strcat(fileName, ".TXT"); title[0] = '\0'; @@ -3814,7 +3963,7 @@ int _OptionWindow() if (characterFileExists(title)) { sprintf(title, "%s %s", - compat_strupr(fileName), + strupr(fileName), getmsg(&editorMessageList, &editorMessageListItem, 609)); char line2[512]; @@ -3839,7 +3988,7 @@ int _OptionWindow() sprintf(title, "%s%s%s", getmsg(&editorMessageList, &editorMessageListItem, 611), - compat_strupr(fileName), + strupr(fileName), "!"); showDialogBox(title, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 1); } diff --git a/src/db.cc b/src/db.cc index b00d767..734cc37 100644 --- a/src/db.cc +++ b/src/db.cc @@ -650,7 +650,12 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a } if (!v2) { - sprintf(xlist->fileNames[index], "%s%s", fileName, extension); + // NOTE: Quick and dirty fix to buffer overflow. See RE to + // understand the problem. + char path[COMPAT_MAX_PATH]; + sprintf(path, "%s%s", fileName, extension); + free(xlist->fileNames[length]); + xlist->fileNames[length] = strdup(path); length++; } } diff --git a/src/dbox.cc b/src/dbox.cc index 6600724..56ce9ca 100644 --- a/src/dbox.cc +++ b/src/dbox.cc @@ -1,6 +1,7 @@ #include "dbox.h" #include "art.h" +#include "character_editor.h" #include "color.h" #include "core.h" #include "debug.h" @@ -18,6 +19,45 @@ #include +#define FILE_DIALOG_LINE_COUNT 12 + +#define FILE_DIALOG_DOUBLE_CLICK_DELAY 32 + +#define LOAD_FILE_DIALOG_DONE_BUTTON_X 58 +#define LOAD_FILE_DIALOG_DONE_BUTTON_Y 187 + +#define LOAD_FILE_DIALOG_DONE_LABEL_X 79 +#define LOAD_FILE_DIALOG_DONE_LABEL_Y 187 + +#define LOAD_FILE_DIALOG_CANCEL_BUTTON_X 163 +#define LOAD_FILE_DIALOG_CANCEL_BUTTON_Y 187 + +#define LOAD_FILE_DIALOG_CANCEL_LABEL_X 182 +#define LOAD_FILE_DIALOG_CANCEL_LABEL_Y 187 + +#define SAVE_FILE_DIALOG_DONE_BUTTON_X 58 +#define SAVE_FILE_DIALOG_DONE_BUTTON_Y 214 + +#define SAVE_FILE_DIALOG_DONE_LABEL_X 79 +#define SAVE_FILE_DIALOG_DONE_LABEL_Y 213 + +#define SAVE_FILE_DIALOG_CANCEL_BUTTON_X 163 +#define SAVE_FILE_DIALOG_CANCEL_BUTTON_Y 214 + +#define SAVE_FILE_DIALOG_CANCEL_LABEL_X 182 +#define SAVE_FILE_DIALOG_CANCEL_LABEL_Y 213 + +#define FILE_DIALOG_TITLE_X 49 +#define FILE_DIALOG_TITLE_Y 16 + +#define FILE_DIALOG_SCROLL_BUTTON_X 36 +#define FILE_DIALOG_SCROLL_BUTTON_Y 44 + +#define FILE_DIALOG_FILE_LIST_X 55 +#define FILE_DIALOG_FILE_LIST_Y 49 +#define FILE_DIALOG_FILE_LIST_WIDTH 190 +#define FILE_DIALOG_FILE_LIST_HEIGHT 124 + // 0x5108C8 const int gDialogBoxBackgroundFrmIds[DIALOG_TYPE_COUNT] = { 218, // MEDIALOG.FRM - Medium generic dialog box @@ -55,7 +95,7 @@ const int _dblines[DIALOG_TYPE_COUNT] = { }; // 0x510900 -int _flgids[7] = { +int gLoadFileDialogFrmIds[FILE_DIALOG_FRM_COUNT] = { 224, // loadbox.frm - character editor 8, // lilredup.frm - little red button up 9, // lilreddn.frm - little red button down @@ -66,7 +106,7 @@ int _flgids[7] = { }; // 0x51091C -int _flgids2[7] = { +int gSaveFileDialogFrmIds[FILE_DIALOG_FRM_COUNT] = { 225, // savebox.frm - character editor 8, // lilredup.frm - little red button up 9, // lilreddn.frm - little red button down @@ -451,17 +491,32 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i return rc; } -// 0x41EA78 -int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLength, int x, int y, int flags) +// 0x41DE90 +int showLoadFileDialog(char *title, char** fileList, char* dest, int fileListLength, int x, int y, int flags) { int oldFont = fontGetCurrent(); - unsigned char* frmBuffers[7]; - CacheEntry* frmHandles[7]; - Size frmSizes[7]; + bool isScrollable = false; + if (fileListLength > FILE_DIALOG_LINE_COUNT) { + isScrollable = true; + } - for (int index = 0; index < 7; index++) { - int fid = buildFid(6, _flgids2[index], 0, 0, 0); + int selectedFileIndex = 0; + int pageOffset = 0; + int maxPageOffset = fileListLength - (FILE_DIALOG_LINE_COUNT + 1); + if (maxPageOffset < 0) { + maxPageOffset = fileListLength - 1; + if (maxPageOffset < 0) { + maxPageOffset = 0; + } + } + + unsigned char* frmBuffers[FILE_DIALOG_FRM_COUNT]; + CacheEntry* frmHandles[FILE_DIALOG_FRM_COUNT]; + Size frmSizes[FILE_DIALOG_FRM_COUNT]; + + for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { + int fid = buildFid(6, gLoadFileDialogFrmIds[index], 0, 0, 0); frmBuffers[index] = artLockFrameDataReturningSize(fid, &(frmHandles[index]), &(frmSizes[index].width), &(frmSizes[index].height)); if (frmBuffers[index] == NULL) { while (--index >= 0) { @@ -471,16 +526,23 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen } } - int win = windowCreate(x, y, frmSizes[0].width, frmSizes[0].height, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04); + + int backgroundWidth = frmSizes[FILE_DIALOG_FRM_BACKGROUND].width; + int backgroundHeight = frmSizes[FILE_DIALOG_FRM_BACKGROUND].height; + + // Maintain original position in original resolution, otherwise center it. + if (screenGetWidth() != 640) x = (screenGetWidth() - backgroundWidth) / 2; + if (screenGetHeight() != 480) y = (screenGetHeight() - backgroundHeight) / 2; + int win = windowCreate(x, y, backgroundWidth, backgroundHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04); if (win == -1) { - for (int index = 0; index < 7; index++) { + for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { artUnlock(frmHandles[index]); } return -1; } unsigned char* windowBuffer = windowGetBuffer(win); - memcpy(windowBuffer, frmBuffers[0], frmSizes[0].width * frmSizes[0].height); + memcpy(windowBuffer, frmBuffers[FILE_DIALOG_FRM_BACKGROUND], backgroundWidth * backgroundHeight); MessageList messageList; MessageListItem messageListItem; @@ -488,7 +550,7 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen if (!messageListInit(&messageList)) { windowDestroy(win); - for (int index = 0; index < 7; index++) { + for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { artUnlock(frmHandles[index]); } @@ -501,7 +563,7 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen if (!messageListLoad(&messageList, path)) { windowDestroy(win); - for (int index = 0; index < 7; index++) { + for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { artUnlock(frmHandles[index]); } @@ -512,23 +574,23 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen // DONE const char* done = getmsg(&messageList, &messageListItem, 100); - fontDrawText(windowBuffer + frmSizes[0].width * 213 + 79, done, frmSizes[0].width, frmSizes[0].width, _colorTable[18979]); + fontDrawText(windowBuffer + LOAD_FILE_DIALOG_DONE_LABEL_Y * backgroundWidth + LOAD_FILE_DIALOG_DONE_LABEL_X, done, backgroundWidth, backgroundWidth, _colorTable[18979]); // CANCEL const char* cancel = getmsg(&messageList, &messageListItem, 103); - fontDrawText(windowBuffer + frmSizes[0].width * 213 + 182, cancel, frmSizes[0].width, frmSizes[0].width, _colorTable[18979]); + fontDrawText(windowBuffer + LOAD_FILE_DIALOG_CANCEL_LABEL_Y * backgroundWidth + LOAD_FILE_DIALOG_CANCEL_LABEL_X, cancel, backgroundWidth, backgroundWidth, _colorTable[18979]); int doneBtn = buttonCreate(win, - 58, - 214, - frmSizes[2].width, - frmSizes[2].height, + LOAD_FILE_DIALOG_DONE_BUTTON_X, + LOAD_FILE_DIALOG_DONE_BUTTON_Y, + frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width, + frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height, -1, -1, -1, 500, - frmBuffers[1], - frmBuffers[2], + frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL], + frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED], NULL, BUTTON_FLAG_TRANSPARENT); if (doneBtn != -1) { @@ -536,16 +598,16 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen } int cancelBtn = buttonCreate(win, - 163, - 214, - frmSizes[2].width, - frmSizes[2].height, + LOAD_FILE_DIALOG_CANCEL_BUTTON_X, + LOAD_FILE_DIALOG_CANCEL_BUTTON_Y, + frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width, + frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height, -1, -1, -1, 501, - frmBuffers[1], - frmBuffers[2], + frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL], + frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED], NULL, BUTTON_FLAG_TRANSPARENT); if (cancelBtn != -1) { @@ -553,16 +615,16 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen } int scrollUpBtn = buttonCreate(win, - 36, - 44, - frmSizes[6].width, - frmSizes[6].height, + FILE_DIALOG_SCROLL_BUTTON_X, + FILE_DIALOG_SCROLL_BUTTON_Y, + frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].width, + frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height, -1, 505, 506, 505, - frmBuffers[5], - frmBuffers[6], + frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_NORMAL], + frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED], NULL, BUTTON_FLAG_TRANSPARENT); if (scrollUpBtn != -1) { @@ -570,16 +632,16 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen } int scrollDownButton = buttonCreate(win, - 36, - 44 + frmSizes[6].height, - frmSizes[4].width, - frmSizes[4].height, + FILE_DIALOG_SCROLL_BUTTON_X, + FILE_DIALOG_SCROLL_BUTTON_Y + frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height, + frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].width, + frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].height, -1, 503, 504, 503, - frmBuffers[3], - frmBuffers[4], + frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_NORMAL], + frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED], NULL, BUTTON_FLAG_TRANSPARENT); if (scrollUpBtn != -1) { @@ -588,10 +650,10 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen buttonCreate( win, - 55, - 49, - 190, - 124, + FILE_DIALOG_FILE_LIST_X, + FILE_DIALOG_FILE_LIST_Y, + FILE_DIALOG_FILE_LIST_WIDTH, + FILE_DIALOG_FILE_LIST_HEIGHT, -1, -1, -1, @@ -601,25 +663,714 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen NULL, 0); - if (a1 != NULL) { - fontDrawText(windowBuffer + frmSizes[0].width * 16 + 49, a1, frmSizes[0].width, frmSizes[0].width, _colorTable[18979]); + if (title != NULL) { + fontDrawText(windowBuffer + backgroundWidth * FILE_DIALOG_TITLE_Y + FILE_DIALOG_TITLE_X, title, backgroundWidth, backgroundWidth, _colorTable[18979]); } + + fontSetCurrent(101); + + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + windowRefresh(win); + + int doubleClickSelectedFileIndex = -2; + int doubleClickTimer = FILE_DIALOG_DOUBLE_CLICK_DELAY; + + int rc = -1; + while (rc == -1) { + unsigned int tick = _get_time(); + int keyCode = _get_input(); + int scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_NONE; + int scrollCounter = 0; + bool isScrolling = false; + + if (keyCode == 500) { + if (fileListLength != 0) { + strncpy(dest, fileList[selectedFileIndex + pageOffset], 16); + rc = 0; + } else { + rc = 1; + } + } else if (keyCode == 501 || keyCode == KEY_ESCAPE) { + rc = 1; + } else if (keyCode == 502 && fileListLength != 0) { + int mouseX; + int mouseY; + mouseGetPosition(&mouseX, &mouseY); + + int selectedLine = (mouseY - y - FILE_DIALOG_FILE_LIST_Y) / fontGetLineHeight(); + if (selectedLine - 1 < 0) { + selectedLine = 0; + } + + if (isScrollable || selectedLine < fileListLength) { + if (selectedLine >= FILE_DIALOG_LINE_COUNT) { + selectedLine = FILE_DIALOG_LINE_COUNT - 1; + } + } else { + selectedLine = fileListLength - 1; + } + + selectedFileIndex = selectedLine; + if (selectedFileIndex == doubleClickSelectedFileIndex) { + soundPlayFile("ib1p1xx1"); + strncpy(dest, fileList[selectedFileIndex + pageOffset], 16); + rc = 0; + } + + doubleClickSelectedFileIndex = selectedFileIndex; + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + } else if (keyCode == 506) { + scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_UP; + } else if (keyCode == 504) { + scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_DOWN; + } else { + switch (keyCode) { + case KEY_ARROW_UP: + pageOffset--; + if (pageOffset < 0) { + selectedFileIndex--; + if (selectedFileIndex < 0) { + selectedFileIndex = 0; + } + pageOffset = 0; + } + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + doubleClickSelectedFileIndex = -2; + break; + case KEY_ARROW_DOWN: + if (isScrollable) { + pageOffset++; + // FIXME: Should be >= maxPageOffset (as in save dialog). + // Otherwise out of bounds index is considered selected. + if (pageOffset > maxPageOffset) { + selectedFileIndex++; + // FIXME: Should be >= FILE_DIALOG_LINE_COUNT (as in + // save dialog). Otherwise out of bounds index is + // considered selected. + if (selectedFileIndex > FILE_DIALOG_LINE_COUNT) { + selectedFileIndex = FILE_DIALOG_LINE_COUNT - 1; + } + pageOffset = maxPageOffset; + } + } else { + selectedFileIndex++; + if (selectedFileIndex > maxPageOffset) { + selectedFileIndex = maxPageOffset; + } + } + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + doubleClickSelectedFileIndex = -2; + break; + case KEY_HOME: + selectedFileIndex = 0; + pageOffset = 0; + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + doubleClickSelectedFileIndex = -2; + break; + case KEY_END: + if (isScrollable) { + selectedFileIndex = FILE_DIALOG_LINE_COUNT - 1; + pageOffset = maxPageOffset; + } else { + selectedFileIndex = maxPageOffset; + pageOffset = 0; + } + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + doubleClickSelectedFileIndex = -2; + break; + } + } + + if (scrollDirection != FILE_DIALOG_SCROLL_DIRECTION_NONE) { + unsigned int scrollDelay = 4; + doubleClickSelectedFileIndex = -2; + while (1) { + unsigned int scrollTick = _get_time(); + scrollCounter += 1; + if ((!isScrolling && scrollCounter == 1) || (isScrolling && scrollCounter > 14.4)) { + isScrolling = true; + + if (scrollCounter > 14.4) { + scrollDelay += 1; + if (scrollDelay > 24) { + scrollDelay = 24; + } + } + + if (scrollDirection == FILE_DIALOG_SCROLL_DIRECTION_UP) { + pageOffset--; + if (pageOffset < 0) { + selectedFileIndex--; + if (selectedFileIndex < 0) { + selectedFileIndex = 0; + } + pageOffset = 0; + } + } else { + if (isScrollable) { + pageOffset++; + if (pageOffset > maxPageOffset) { + selectedFileIndex++; + if (selectedFileIndex >= FILE_DIALOG_LINE_COUNT) { + selectedFileIndex = FILE_DIALOG_LINE_COUNT - 1; + } + pageOffset = maxPageOffset; + } + } else { + selectedFileIndex++; + if (selectedFileIndex > maxPageOffset) { + selectedFileIndex = maxPageOffset; + } + } + } + + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + windowRefresh(win); + } + + unsigned int delay = (scrollCounter > 14.4) ? 1000 / scrollDelay : 1000 / 24; + while (getTicksSince(scrollTick) < delay) { + } + + if (_game_user_wants_to_quit != 0) { + rc = 1; + break; + } + + int keyCode = _get_input(); + if (keyCode == 505 || keyCode == 503) { + break; + } + } + } else { + windowRefresh(win); + + doubleClickTimer--; + if (doubleClickTimer == 0) { + doubleClickTimer = FILE_DIALOG_DOUBLE_CLICK_DELAY; + doubleClickSelectedFileIndex = -2; + } + + while (getTicksSince(tick) < (1000 / 24)) { + } + } + + if (_game_user_wants_to_quit) { + rc = 1; + } + } + + windowDestroy(win); + + for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { + artUnlock(frmHandles[index]); + } + + messageListFree(&messageList); + fontSetCurrent(oldFont); + + return rc; +} + +// 0x41EA78 +int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags) +{ + int oldFont = fontGetCurrent(); + + bool isScrollable = false; + if (fileListLength > FILE_DIALOG_LINE_COUNT) { + isScrollable = true; + } + + int selectedFileIndex = 0; + int pageOffset = 0; + int maxPageOffset = fileListLength - (FILE_DIALOG_LINE_COUNT + 1); + if (maxPageOffset < 0) { + maxPageOffset = fileListLength - 1; + if (maxPageOffset < 0) { + maxPageOffset = 0; + } + } + + unsigned char* frmBuffers[FILE_DIALOG_FRM_COUNT]; + CacheEntry* frmHandles[FILE_DIALOG_FRM_COUNT]; + Size frmSizes[FILE_DIALOG_FRM_COUNT]; + + for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { + int fid = buildFid(6, gSaveFileDialogFrmIds[index], 0, 0, 0); + frmBuffers[index] = artLockFrameDataReturningSize(fid, &(frmHandles[index]), &(frmSizes[index].width), &(frmSizes[index].height)); + if (frmBuffers[index] == NULL) { + while (--index >= 0) { + artUnlock(frmHandles[index]); + } + return -1; + } + } + + int backgroundWidth = frmSizes[FILE_DIALOG_FRM_BACKGROUND].width; + int backgroundHeight = frmSizes[FILE_DIALOG_FRM_BACKGROUND].height; + + // Maintain original position in original resolution, otherwise center it. + if (screenGetWidth() != 640) x = (screenGetWidth() - backgroundWidth) / 2; + if (screenGetHeight() != 480) y = (screenGetHeight() - backgroundHeight) / 2; + int win = windowCreate(x, y, backgroundWidth, backgroundHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04); + if (win == -1) { + for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { + artUnlock(frmHandles[index]); + } + return -1; + } + + unsigned char* windowBuffer = windowGetBuffer(win); + memcpy(windowBuffer, frmBuffers[FILE_DIALOG_FRM_BACKGROUND], backgroundWidth * backgroundHeight); + + MessageList messageList; + MessageListItem messageListItem; + + if (!messageListInit(&messageList)) { + windowDestroy(win); + + for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { + artUnlock(frmHandles[index]); + } + + return -1; + } + + char path[COMPAT_MAX_PATH]; + sprintf(path, "%s%s", asc_5186C8, "DBOX.MSG"); + + if (!messageListLoad(&messageList, path)) { + windowDestroy(win); + + for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { + artUnlock(frmHandles[index]); + } + + return -1; + } + + fontSetCurrent(103); + + // DONE + const char* done = getmsg(&messageList, &messageListItem, 100); + fontDrawText(windowBuffer + backgroundWidth * SAVE_FILE_DIALOG_DONE_LABEL_Y + SAVE_FILE_DIALOG_DONE_LABEL_X, done, backgroundWidth, backgroundWidth, _colorTable[18979]); + + // CANCEL + const char* cancel = getmsg(&messageList, &messageListItem, 103); + fontDrawText(windowBuffer + backgroundWidth * SAVE_FILE_DIALOG_CANCEL_LABEL_Y + SAVE_FILE_DIALOG_CANCEL_LABEL_X, cancel, backgroundWidth, backgroundWidth, _colorTable[18979]); + + int doneBtn = buttonCreate(win, + SAVE_FILE_DIALOG_DONE_BUTTON_X, + SAVE_FILE_DIALOG_DONE_BUTTON_Y, + frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width, + frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height, + -1, + -1, + -1, + 500, + frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL], + frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED], + NULL, + BUTTON_FLAG_TRANSPARENT); + if (doneBtn != -1) { + buttonSetCallbacks(doneBtn, _gsound_red_butt_press, _gsound_red_butt_release); + } + + int cancelBtn = buttonCreate(win, + SAVE_FILE_DIALOG_CANCEL_BUTTON_X, + SAVE_FILE_DIALOG_CANCEL_BUTTON_Y, + frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width, + frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height, + -1, + -1, + -1, + 501, + frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL], + frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED], + NULL, + BUTTON_FLAG_TRANSPARENT); + if (cancelBtn != -1) { + buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release); + } + + int scrollUpBtn = buttonCreate(win, + FILE_DIALOG_SCROLL_BUTTON_X, + FILE_DIALOG_SCROLL_BUTTON_Y, + frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].width, + frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height, + -1, + 505, + 506, + 505, + frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_NORMAL], + frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED], + NULL, + BUTTON_FLAG_TRANSPARENT); + if (scrollUpBtn != -1) { + buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release); + } + + int scrollDownButton = buttonCreate(win, + FILE_DIALOG_SCROLL_BUTTON_X, + FILE_DIALOG_SCROLL_BUTTON_Y + frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height, + frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].width, + frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].height, + -1, + 503, + 504, + 503, + frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_NORMAL], + frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED], + NULL, + BUTTON_FLAG_TRANSPARENT); + if (scrollUpBtn != -1) { + buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release); + } + + buttonCreate( + win, + FILE_DIALOG_FILE_LIST_X, + FILE_DIALOG_FILE_LIST_Y, + FILE_DIALOG_FILE_LIST_WIDTH, + FILE_DIALOG_FILE_LIST_HEIGHT, + -1, + -1, + -1, + 502, + NULL, + NULL, + NULL, + 0); + + if (title != NULL) { + fontDrawText(windowBuffer + backgroundWidth * FILE_DIALOG_TITLE_Y + FILE_DIALOG_TITLE_X, title, backgroundWidth, backgroundWidth, _colorTable[18979]); + } + + fontSetCurrent(101); + + int cursorHeight = fontGetLineHeight(); + int cursorWidth = fontGetStringWidth("_") - 4; + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + + int fileNameLength = 0; + char* pch = dest; + while (*pch != '\0' && *pch != '.') { + fileNameLength++; + if (fileNameLength >= 12) { + break; + } + } + dest[fileNameLength] = '\0'; + + char fileNameCopy[32]; + strncpy(fileNameCopy, dest, 32); + + int fileNameCopyLength = strlen(fileNameCopy); + fileNameCopy[fileNameCopyLength + 1] = '\0'; + fileNameCopy[fileNameCopyLength] = ' '; + + unsigned char* fileNameBufferPtr = windowBuffer + backgroundWidth * 190 + 57; + + bufferFill(fileNameBufferPtr, fontGetStringWidth(fileNameCopy), cursorHeight, backgroundWidth, 100); + fontDrawText(fileNameBufferPtr, fileNameCopy, backgroundWidth, backgroundWidth, _colorTable[992]); + + windowRefresh(win); + + int blinkingCounter = 3; + bool blink = false; + + int doubleClickSelectedFileIndex = -2; + int doubleClickTimer = FILE_DIALOG_DOUBLE_CLICK_DELAY; + + int rc = -1; + while (rc == -1) { + unsigned int tick = _get_time(); + int keyCode = _get_input(); + int scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_NONE; + int scrollCounter = 0; + bool isScrolling = false; + + if (keyCode == 500) { + rc = 0; + } else if (keyCode == KEY_RETURN) { + soundPlayFile("ib1p1xx1"); + rc = 0; + } else if (keyCode == 501 || keyCode == KEY_ESCAPE) { + rc = 1; + } else if ((keyCode == KEY_DELETE || keyCode == KEY_BACKSPACE) && fileNameCopyLength > 0) { + bufferFill(fileNameBufferPtr, fontGetStringWidth(fileNameCopy), cursorHeight, backgroundWidth, 100); + fileNameCopy[fileNameCopyLength - 1] = ' '; + fileNameCopy[fileNameCopyLength] = '\0'; + fontDrawText(fileNameBufferPtr, fileNameCopy, backgroundWidth, backgroundWidth, _colorTable[992]); + fileNameCopyLength--; + windowRefresh(win); + } else if (keyCode < KEY_FIRST_INPUT_CHARACTER || keyCode > KEY_LAST_INPUT_CHARACTER || fileNameCopyLength >= 8) { + if (keyCode == 502 && fileListLength != 0) { + int mouseX; + int mouseY; + mouseGetPosition(&mouseX, &mouseY); + + int selectedLine = (mouseY - y - FILE_DIALOG_FILE_LIST_Y) / fontGetLineHeight(); + if (selectedLine - 1 < 0) { + selectedLine = 0; + } + + if (isScrollable || selectedLine < fileListLength) { + if (selectedLine >= FILE_DIALOG_LINE_COUNT) { + selectedLine = FILE_DIALOG_LINE_COUNT - 1; + } + } else { + selectedLine = fileListLength - 1; + } + + selectedFileIndex = selectedLine; + if (selectedFileIndex == doubleClickSelectedFileIndex) { + soundPlayFile("ib1p1xx1"); + strncpy(dest, fileList[selectedFileIndex + pageOffset], 16); + + int index; + for (index = 0; index < 12; index++) { + if (dest[index] == '.' || dest[index] == '\0') { + break; + } + } + + dest[index] = '\0'; + rc = 2; + } else { + doubleClickSelectedFileIndex = selectedFileIndex; + bufferFill(fileNameBufferPtr, fontGetStringWidth(fileNameCopy), cursorHeight, backgroundWidth, 100); + strncpy(fileNameCopy, fileList[selectedFileIndex + pageOffset], 16); + + int index; + for (index = 0; index < 12; index++) { + if (fileNameCopy[index] == '.' || fileNameCopy[index] == '\0') { + break; + } + } + + fileNameCopy[index] = '\0'; + fileNameCopyLength = strlen(fileNameCopy); + fileNameCopy[fileNameCopyLength] = ' '; + fileNameCopy[fileNameCopyLength + 1] = '\0'; + + fontDrawText(fileNameBufferPtr, fileNameCopy, backgroundWidth, backgroundWidth, _colorTable[992]); + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + } + } else if (keyCode == 506) { + scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_UP; + } else if (keyCode == 504) { + scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_DOWN; + } else { + switch (keyCode) { + case KEY_ARROW_UP: + pageOffset--; + if (pageOffset < 0) { + selectedFileIndex--; + if (selectedFileIndex < 0) { + selectedFileIndex = 0; + } + pageOffset = 0; + } + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + doubleClickSelectedFileIndex = -2; + break; + case KEY_ARROW_DOWN: + if (isScrollable) { + pageOffset++; + if (pageOffset >= maxPageOffset) { + selectedFileIndex++; + if (selectedFileIndex >= FILE_DIALOG_LINE_COUNT) { + selectedFileIndex = FILE_DIALOG_LINE_COUNT - 1; + } + pageOffset = maxPageOffset; + } + } else { + selectedFileIndex++; + if (selectedFileIndex > maxPageOffset) { + selectedFileIndex = maxPageOffset; + } + } + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + doubleClickSelectedFileIndex = -2; + break; + case KEY_HOME: + selectedFileIndex = 0; + pageOffset = 0; + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + doubleClickSelectedFileIndex = -2; + break; + case KEY_END: + if (isScrollable) { + selectedFileIndex = 11; + pageOffset = maxPageOffset; + } else { + selectedFileIndex = maxPageOffset; + pageOffset = 0; + } + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + doubleClickSelectedFileIndex = -2; + break; + } + } + } else if (_isdoschar(keyCode)) { + bufferFill(fileNameBufferPtr, fontGetStringWidth(fileNameCopy), cursorHeight, backgroundWidth, 100); + + fileNameCopy[fileNameCopyLength] = keyCode & 0xFF; + fileNameCopy[fileNameCopyLength + 1] = ' '; + fileNameCopy[fileNameCopyLength + 2] = '\0'; + fontDrawText(fileNameBufferPtr, fileNameCopy, backgroundWidth, backgroundWidth, _colorTable[992]); + fileNameCopyLength++; + + windowRefresh(win); + } + + if (scrollDirection != FILE_DIALOG_SCROLL_DIRECTION_NONE) { + unsigned int scrollDelay = 4; + doubleClickSelectedFileIndex = -2; + while (1) { + unsigned int scrollTick = _get_time(); + scrollCounter += 1; + if ((!isScrolling && scrollCounter == 1) || (isScrolling && scrollCounter > 14.4)) { + isScrolling = true; + + if (scrollCounter > 14.4) { + scrollDelay += 1; + if (scrollDelay > 24) { + scrollDelay = 24; + } + } + + if (scrollDirection == FILE_DIALOG_SCROLL_DIRECTION_UP) { + pageOffset--; + if (pageOffset < 0) { + selectedFileIndex--; + if (selectedFileIndex < 0) { + selectedFileIndex = 0; + } + pageOffset = 0; + } + } else { + if (isScrollable) { + pageOffset++; + if (pageOffset > maxPageOffset) { + selectedFileIndex++; + if (selectedFileIndex >= FILE_DIALOG_LINE_COUNT) { + selectedFileIndex = FILE_DIALOG_LINE_COUNT - 1; + } + pageOffset = maxPageOffset; + } + } else { + selectedFileIndex++; + if (selectedFileIndex > maxPageOffset) { + selectedFileIndex = maxPageOffset; + } + } + } + + fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth); + windowRefresh(win); + } + + // NOTE: Original code is slightly different. For unknown reason + // entire blinking stuff is placed into two different branches, + // which only differs by amount of delay. Probably result of + // using large blinking macro as there are no traces of inlined + // function. + blinkingCounter -= 1; + if (blinkingCounter == 0) { + blinkingCounter = 3; + + int color = blink ? 100 : _colorTable[992]; + blink = !blink; + + bufferFill(fileNameBufferPtr + fontGetStringWidth(fileNameCopy) - cursorWidth, cursorWidth, cursorHeight - 2, backgroundWidth, color); + } + + // FIXME: Missing windowRefresh makes blinking useless. + + unsigned int delay = (scrollCounter > 14.4) ? 1000 / scrollDelay : 1000 / 24; + while (getTicksSince(scrollTick) < delay) { + } + + if (_game_user_wants_to_quit != 0) { + rc = 1; + break; + } + + int key = _get_input(); + if (key == 505 || key == 503) { + break; + } + } + } else { + blinkingCounter -= 1; + if (blinkingCounter == 0) { + blinkingCounter = 3; + + int color = blink ? 100 : _colorTable[992]; + blink = !blink; + + bufferFill(fileNameBufferPtr + fontGetStringWidth(fileNameCopy) - cursorWidth, cursorWidth, cursorHeight - 2, backgroundWidth, color); + } + + windowRefresh(win); + + doubleClickTimer--; + if (doubleClickTimer == 0) { + doubleClickTimer = FILE_DIALOG_DOUBLE_CLICK_DELAY; + doubleClickSelectedFileIndex = -2; + } + + while (getTicksSince(tick) < (1000 / 24)) { + } + } + + if (_game_user_wants_to_quit != 0) { + rc = 1; + } + } + + if (rc == 0) { + if (fileNameCopyLength != 0) { + fileNameCopy[fileNameCopyLength] = '\0'; + strcpy(dest, fileNameCopy); + } else { + rc = 1; + } + } else { + if (rc == 2) { + rc = 0; + } + } + + windowDestroy(win); + + for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) { + artUnlock(frmHandles[index]); + } + + messageListFree(&messageList); + fontSetCurrent(oldFont); + + return rc; } // 0x41FBDC -void _PrntFlist(unsigned char* buffer, char** fileList, int pageOffset, int fileListLength, int selectedIndex, int pitch) +void fileDialogRenderFileList(unsigned char* buffer, char** fileList, int pageOffset, int fileListLength, int selectedIndex, int pitch) { int lineHeight = fontGetLineHeight(); - int y = 49; - bufferFill(buffer + y * pitch + 55, 190, 124, pitch, 100); + int y = FILE_DIALOG_FILE_LIST_Y; + bufferFill(buffer + y * pitch + FILE_DIALOG_FILE_LIST_X, FILE_DIALOG_FILE_LIST_WIDTH, FILE_DIALOG_FILE_LIST_HEIGHT, pitch, 100); if (fileListLength != 0) { - if (fileListLength - pageOffset > 12) { - fileListLength = 12; + if (fileListLength - pageOffset > FILE_DIALOG_LINE_COUNT) { + fileListLength = FILE_DIALOG_LINE_COUNT; } for (int index = 0; index < fileListLength; index++) { int color = index == selectedIndex ? _colorTable[32747] : _colorTable[992]; - fontDrawText(buffer + y * index + 55, fileList[index], pitch, pitch, color); + fontDrawText(buffer + pitch * y + FILE_DIALOG_FILE_LIST_X, fileList[pageOffset + index], pitch, pitch, color); y += lineHeight; } } diff --git a/src/dbox.h b/src/dbox.h index 50196e4..f6bc916 100644 --- a/src/dbox.h +++ b/src/dbox.h @@ -16,17 +16,35 @@ typedef enum DialogType { DIALOG_TYPE_COUNT, } DialogType; +typedef enum FileDialogFrm { + FILE_DIALOG_FRM_BACKGROUND, + FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL, + FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED, + FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_NORMAL, + FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED, + FILE_DIALOG_FRM_SCROLL_UP_ARROW_NORMAL, + FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED, + FILE_DIALOG_FRM_COUNT, +} FileDialogFrm; + +typedef enum FileDialogScrollDirection { + FILE_DIALOG_SCROLL_DIRECTION_NONE, + FILE_DIALOG_SCROLL_DIRECTION_UP, + FILE_DIALOG_SCROLL_DIRECTION_DOWN, +} FileDialogScrollDirection; + extern const int gDialogBoxBackgroundFrmIds[DIALOG_TYPE_COUNT]; extern const int _ytable[DIALOG_TYPE_COUNT]; extern const int _xtable[DIALOG_TYPE_COUNT]; extern const int _doneY[DIALOG_TYPE_COUNT]; extern const int _doneX[DIALOG_TYPE_COUNT]; extern const int _dblines[DIALOG_TYPE_COUNT]; -extern int _flgids[7]; -extern int _flgids2[7]; +extern int gLoadFileDialogFrmIds[FILE_DIALOG_FRM_COUNT]; +extern int gSaveFileDialogFrmIds[FILE_DIALOG_FRM_COUNT]; int showDialogBox(const char* title, const char** body, int bodyLength, int x, int y, int titleColor, const char* a8, int bodyColor, int flags); -int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLength, int x, int y, int flags); -void _PrntFlist(unsigned char* buffer, char** fileList, int pageOffset, int fileListLength, int selectedIndex, int pitch); +int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags); +int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags); +void fileDialogRenderFileList(unsigned char* buffer, char** fileList, int pageOffset, int fileListLength, int selectedIndex, int pitch); #endif /* DBOX_H */ diff --git a/src/xfile.cc b/src/xfile.cc index c4096aa..27589db 100644 --- a/src/xfile.cc +++ b/src/xfile.cc @@ -617,7 +617,7 @@ bool xlistEnumerate(const char* pattern, XListEnumerationHandler* handler, XList } } while (fileFindNext(&directoryFileFindData)); } - return findFindClose(&directoryFileFindData); + findFindClose(&directoryFileFindData); } xbase = xbase->next; }