Merge pull request #573 from mwpenny/save-deletion

Support save file deletion (#412)
This commit is contained in:
lambertjamesd 2023-12-26 09:42:27 -07:00 committed by GitHub
commit 61ed827764
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 596 additions and 46 deletions

View file

@ -0,0 +1,223 @@
#include "./confirmation_dialog.h"
#include "../font/dejavusans.h"
#include "../controls/controller.h"
#include "../audio/soundplayer.h"
#include "./translations.h"
#include "../build/assets/materials/ui.h"
#include "../build/src/audio/clips.h"
#include "../build/src/audio/subtitles.h"
#define DIALOG_LEFT 40
#define DIALOG_WIDTH (SCREEN_WD - (DIALOG_LEFT * 2))
#define DIALOG_PADDING 8
#define TEXT_MARGIN 4
#define CONTENT_LEFT (DIALOG_LEFT + DIALOG_PADDING)
#define CONTENT_WIDTH (DIALOG_WIDTH - (DIALOG_PADDING * 2))
#define CONTENT_CENTER_X (CONTENT_LEFT + (CONTENT_WIDTH / 2))
#define CONTENT_MARGIN 20
#define BUTTON_HEIGHT 16
#define BUTTON_MARGIN 8
static struct Coloru8 gDialogColor = {164, 164, 164, 255};
void confirmationDialogInit(struct ConfirmationDialog* confirmationDialog) {
confirmationDialog->menuOutline = menuBuildBorder(0, 0, 0, 0);
confirmationDialog->titleText = NULL;
confirmationDialog->messageText = NULL;
confirmationDialog->selectedButton = NULL;
confirmationDialog->closeCallback = NULL;
confirmationDialog->callbackData = NULL;
confirmationDialog->isShown = 0;
confirmationDialog->confirmButton = menuBuildButton(
&gDejaVuSansFont, "",
0,
0,
BUTTON_HEIGHT,
0
);
confirmationDialog->cancelButton = menuBuildButton(
&gDejaVuSansFont, "",
0,
0,
BUTTON_HEIGHT,
0
);
}
static void confirmationDialogLayout(struct ConfirmationDialog* confirmationDialog) {
int dialogHeight = CONTENT_MARGIN + confirmationDialog->messageText->height + BUTTON_MARGIN + BUTTON_HEIGHT + DIALOG_PADDING;
int dialogTop = (SCREEN_HT - dialogHeight) / 2;
menuRerenderBorder(
DIALOG_LEFT,
dialogTop,
DIALOG_WIDTH,
dialogHeight,
confirmationDialog->menuOutline
);
prerenderedTextRelocate(
confirmationDialog->titleText,
CONTENT_LEFT,
dialogTop + TEXT_MARGIN
);
prerenderedTextRelocate(
confirmationDialog->messageText,
CONTENT_LEFT,
dialogTop + CONTENT_MARGIN
);
int buttonsWidth = confirmationDialog->confirmButton.w + confirmationDialog->cancelButton.w + BUTTON_MARGIN;
int buttonsX = CONTENT_CENTER_X - (buttonsWidth / 2);
int buttonsY = confirmationDialog->messageText->y + confirmationDialog->messageText->height + BUTTON_MARGIN;
menuRelocateButton(
&confirmationDialog->confirmButton,
buttonsX,
buttonsY,
0
);
menuRelocateButton(
&confirmationDialog->cancelButton,
buttonsX + confirmationDialog->confirmButton.w + BUTTON_MARGIN,
buttonsY,
0
);
}
void confirmationDialogShow(struct ConfirmationDialog* confirmationDialog, struct ConfirmationDialogParams* params) {
if (confirmationDialog->titleText) {
prerenderedTextFree(confirmationDialog->titleText);
}
if (confirmationDialog->messageText) {
prerenderedTextFree(confirmationDialog->messageText);
}
confirmationDialog->titleText = menuBuildPrerenderedText(
&gDejaVuSansFont, params->title,
0,
0,
SCREEN_WD
);
confirmationDialog->messageText = menuBuildPrerenderedText(
&gDejaVuSansFont, params->message,
0,
0,
CONTENT_WIDTH
);
menuRebuildButtonText(
&confirmationDialog->confirmButton,
&gDejaVuSansFont,
params->confirmLabel,
0
);
menuRebuildButtonText(
&confirmationDialog->cancelButton,
&gDejaVuSansFont,
params->cancelLabel,
0
);
confirmationDialogLayout(confirmationDialog);
confirmationDialog->selectedButton = &confirmationDialog->cancelButton;
confirmationDialog->closeCallback = params->closeCallback;
confirmationDialog->callbackData = params->callbackData;
confirmationDialog->isShown = 1;
}
static void confirmationDialogClose(struct ConfirmationDialog* confirmationDialog, int isConfirmed) {
ConfirmationDialogCallback callback = confirmationDialog->closeCallback;
if (callback) {
callback(confirmationDialog->callbackData, isConfirmed);
}
confirmationDialog->isShown = 0;
}
enum InputCapture confirmationDialogUpdate(struct ConfirmationDialog* confirmationDialog) {
if (controllerGetButtonDown(0, B_BUTTON)) {
confirmationDialogClose(confirmationDialog, 0);
} else if (controllerGetButtonDown(0, A_BUTTON)) {
if (confirmationDialog->selectedButton == &confirmationDialog->confirmButton) {
confirmationDialogClose(confirmationDialog, 1);
} else {
confirmationDialogClose(confirmationDialog, 0);
}
soundPlayerPlay(SOUNDS_BUTTONCLICKRELEASE, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
}
int controllerDir = controllerGetDirectionDown(0);
if (controllerDir & (ControllerDirectionLeft | ControllerDirectionRight)) {
if (confirmationDialog->selectedButton == &confirmationDialog->confirmButton) {
confirmationDialog->selectedButton = &confirmationDialog->cancelButton;
} else {
confirmationDialog->selectedButton = &confirmationDialog->confirmButton;
}
soundPlayerPlay(SOUNDS_BUTTONROLLOVER, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
}
return InputCaptureGrab;
}
static void renderButtonText(struct ConfirmationDialog* confirmationDialog, struct MenuButton* button, struct PrerenderedTextBatch* batch) {
struct Coloru8* color = confirmationDialog->selectedButton == button ? &gColorBlack : &gColorWhite;
prerenderedBatchAdd(batch, button->text, color);
}
void confirmationDialogRender(struct ConfirmationDialog* confirmationDialog, struct RenderState* renderState) {
gSPDisplayList(renderState->dl++, ui_material_list[DEFAULT_UI_INDEX]);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WD, SCREEN_HT);
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_TRANSPARENT_OVERLAY_INDEX]);
gDPFillRectangle(renderState->dl++, 0, 0, SCREEN_WD, SCREEN_HT);
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_TRANSPARENT_OVERLAY_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[ROUNDED_CORNERS_INDEX]);
gDPPipeSync(renderState->dl++);
gDPSetEnvColor(renderState->dl++, gDialogColor.r, gDialogColor.g, gDialogColor.b, gDialogColor.a);
gSPDisplayList(renderState->dl++, confirmationDialog->menuOutline);
gSPDisplayList(renderState->dl++, ui_material_revert_list[ROUNDED_CORNERS_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_ENV_INDEX]);
if (confirmationDialog->selectedButton != NULL) {
gDPPipeSync(renderState->dl++);
gDPSetEnvColor(renderState->dl++, gSelectionOrange.r, gSelectionOrange.g, gSelectionOrange.b, gSelectionOrange.a);
gDPFillRectangle(
renderState->dl++,
confirmationDialog->selectedButton->x,
confirmationDialog->selectedButton->y,
confirmationDialog->selectedButton->x + confirmationDialog->selectedButton->w,
confirmationDialog->selectedButton->y + confirmationDialog->selectedButton->h
);
}
gSPDisplayList(renderState->dl++, confirmationDialog->confirmButton.outline);
gSPDisplayList(renderState->dl++, confirmationDialog->cancelButton.outline);
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_ENV_INDEX]);
struct PrerenderedTextBatch* batch = prerenderedBatchStart();
if (confirmationDialog->titleText) {
prerenderedBatchAdd(batch, confirmationDialog->titleText, NULL);
}
if (confirmationDialog->messageText) {
prerenderedBatchAdd(batch, confirmationDialog->messageText, NULL);
}
renderButtonText(confirmationDialog, &confirmationDialog->confirmButton, batch);
renderButtonText(confirmationDialog, &confirmationDialog->cancelButton, batch);
renderState->dl = prerenderedBatchFinish(batch, gDejaVuSansImages, renderState->dl);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WD, SCREEN_HT);
}

View file

@ -0,0 +1,35 @@
#ifndef __MENU_CONFIRMATION_DIALOG_H__
#define __MENU_CONFIRMATION_DIALOG_H__
#include "./menu.h"
#include "../graphics/graphics.h"
typedef void (*ConfirmationDialogCallback)(void* data, int isConfirmed);
struct ConfirmationDialogParams {
char* title;
char* message;
char* confirmLabel;
char* cancelLabel;
ConfirmationDialogCallback closeCallback;
void* callbackData;
};
struct ConfirmationDialog {
Gfx* menuOutline;
struct PrerenderedText* titleText;
struct PrerenderedText* messageText;
struct MenuButton confirmButton;
struct MenuButton cancelButton;
struct MenuButton* selectedButton;
ConfirmationDialogCallback closeCallback;
void* callbackData;
int isShown;
};
void confirmationDialogInit(struct ConfirmationDialog* confirmationDialog);
void confirmationDialogShow(struct ConfirmationDialog* confirmationDialog, struct ConfirmationDialogParams* params);
enum InputCapture confirmationDialogUpdate(struct ConfirmationDialog* confirmationDialog);
void confirmationDialogRender(struct ConfirmationDialog* confirmationDialog, struct RenderState* renderState);
#endif

View file

@ -159,7 +159,7 @@ int controlsMeasureIcons(enum ControllerAction action) {
return result; return result;
} }
Gfx* controlsRenderIcons(Gfx* dl, enum ControllerAction action, int x, int y) { Gfx* controlsRenderActionIcons(Gfx* dl, enum ControllerAction action, int x, int y) {
struct ControllerSourceWithController sources[MAX_SOURCES_PER_ACTION]; struct ControllerSourceWithController sources[MAX_SOURCES_PER_ACTION];
int sourceCount = controllerSourcesForAction(action, sources, MAX_SOURCES_PER_ACTION); int sourceCount = controllerSourcesForAction(action, sources, MAX_SOURCES_PER_ACTION);
@ -192,12 +192,31 @@ Gfx* controlsRenderIcons(Gfx* dl, enum ControllerAction action, int x, int y) {
return dl; return dl;
} }
void controlsRenderButtonIcon(enum ControllerActionSource source, int x, int y, struct RenderState* renderState) {
struct ControllerIcon icon;
source = controllerSourceMapAction(source);
if (!IS_VALID_SOURCE(source)) {
return;
}
icon = gControllerButtonIcons[(int)gControllerActionToButtonIcon[(int)source]];
gSPTextureRectangle(
renderState->dl++,
x << 2, y << 2,
(x + icon.w) << 2, (y + icon.h) << 2,
G_TX_RENDERTILE,
icon.x << 5, icon.y << 5,
0x400, 0x400
);
}
void controlsLayoutRow(struct ControlsMenuRow* row, struct ControlActionDataRow* data, int x, int y) { void controlsLayoutRow(struct ControlsMenuRow* row, struct ControlActionDataRow* data, int x, int y) {
struct PrerenderedText* copy = prerenderedTextCopy(row->actionText); struct PrerenderedText* copy = prerenderedTextCopy(row->actionText);
menuFreePrerenderedDeferred(row->actionText); menuFreePrerenderedDeferred(row->actionText);
row->actionText = copy; row->actionText = copy;
prerenderedTextRelocate(row->actionText, x + ROW_PADDING, y); prerenderedTextRelocate(row->actionText, x + ROW_PADDING, y);
Gfx* dl = controlsRenderIcons(row->sourceIcons, data->action, CONTROLS_X + CONTROLS_WIDTH - ROW_PADDING * 2, y); Gfx* dl = controlsRenderActionIcons(row->sourceIcons, data->action, CONTROLS_X + CONTROLS_WIDTH - ROW_PADDING * 2, y);
gSPEndDisplayList(dl++); gSPEndDisplayList(dl++);
row->y = y; row->y = y;
} }
@ -521,7 +540,7 @@ void controlsRenderPrompt(enum ControllerAction action, char* message, float opa
gSPDisplayList(renderState->dl++, ui_material_list[BUTTON_ICONS_INDEX]); gSPDisplayList(renderState->dl++, ui_material_list[BUTTON_ICONS_INDEX]);
gDPSetEnvColor(renderState->dl++, 232, 206, 80, opacityAsInt); gDPSetEnvColor(renderState->dl++, 232, 206, 80, opacityAsInt);
renderState->dl = controlsRenderIcons(renderState->dl, action, textPositionX - CONTROL_PROMPT_PADDING, textPositionY); renderState->dl = controlsRenderActionIcons(renderState->dl, action, textPositionX - CONTROL_PROMPT_PADDING, textPositionY);
gSPDisplayList(renderState->dl++, ui_material_revert_list[BUTTON_ICONS_INDEX]); gSPDisplayList(renderState->dl++, ui_material_revert_list[BUTTON_ICONS_INDEX]);
stackMallocFree(fontRender); stackMallocFree(fontRender);

View file

@ -46,5 +46,6 @@ void controlsMenuRender(struct ControlsMenu* controlsMenu, struct RenderState* r
void controlsRenderPrompt(enum ControllerAction action, char* message, float opacity, struct RenderState* renderState); void controlsRenderPrompt(enum ControllerAction action, char* message, float opacity, struct RenderState* renderState);
void controlsRenderSubtitle(char* message, float textOpacity, float backgroundOpacity, struct RenderState* renderState, enum SubtitleType subtitleType); void controlsRenderSubtitle(char* message, float textOpacity, float backgroundOpacity, struct RenderState* renderState, enum SubtitleType subtitleType);
void controlsRenderButtonIcon(enum ControllerActionSource source, int x, int y, struct RenderState* renderState);
#endif #endif

View file

@ -25,28 +25,64 @@ void loadGamePopulate(struct LoadGameMenu* loadGame) {
savefileInfo[i].testchamberDisplayNumber = saveSlots[i].testChamber; savefileInfo[i].testchamberDisplayNumber = saveSlots[i].testChamber;
savefileInfo[i].savefileName = saveSlots[i].saveSlot == 0 ? translationsGet(GAMEUI_AUTOSAVE) : NULL; savefileInfo[i].savefileName = saveSlots[i].saveSlot == 0 ? translationsGet(GAMEUI_AUTOSAVE) : NULL;
savefileInfo[i].screenshot = (u16*)SCREEN_SHOT_SRAM(saveSlots[i].saveSlot); savefileInfo[i].screenshot = (u16*)SCREEN_SHOT_SRAM(saveSlots[i].saveSlot);
savefileInfo[i].isFree = 0;
} }
savefileUseList(loadGame->savefileList, translationsGet(GAMEUI_LOADGAME), savefileInfo, numberOfSaves); savefileUseList(
loadGame->savefileList,
translationsGet(GAMEUI_LOADGAME),
translationsGet(GAMEUI_LOAD),
savefileInfo,
numberOfSaves
);
}
static void loadGameConfirmDeletionClosed(struct LoadGameMenu* loadGame, int isConfirmed) {
if (isConfirmed) {
short selectedSaveIndex = loadGame->savefileList->selectedSave;
struct SavefileInfo* selectedSave = &loadGame->savefileList->savefileInfo[selectedSaveIndex];
savefileDeleteGame(selectedSave->slotIndex);
loadGamePopulate(loadGame);
if (selectedSaveIndex >= loadGame->savefileList->numberOfSaves) {
--selectedSaveIndex;
}
loadGame->savefileList->selectedSave = selectedSaveIndex;
}
} }
enum InputCapture loadGameUpdate(struct LoadGameMenu* loadGame) { enum InputCapture loadGameUpdate(struct LoadGameMenu* loadGame) {
if (controllerGetButtonDown(0, A_BUTTON) && loadGame->savefileList->numberOfSaves) { enum InputCapture capture = savefileListUpdate(loadGame->savefileList);
Checkpoint* save = stackMalloc(MAX_CHECKPOINT_SIZE); if (capture != InputCapturePass) {
int testChamber; return capture;
int testSubject;
savefileLoadGame(savefileGetSlot(loadGame->savefileList), save, &testChamber, &testSubject);
gCurrentTestSubject = testSubject;
levelQueueLoad(getLevelIndexFromChamberDisplayNumber(testChamber), NULL, NULL);
checkpointUse(save);
stackMallocFree(save);
soundPlayerPlay(SOUNDS_BUTTONCLICKRELEASE, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
} }
return savefileListUpdate(loadGame->savefileList); if (loadGame->savefileList->numberOfSaves) {
if (controllerGetButtonDown(0, A_BUTTON)) {
Checkpoint* save = stackMalloc(MAX_CHECKPOINT_SIZE);
int testChamber;
int testSubject;
savefileLoadGame(savefileGetSlot(loadGame->savefileList), save, &testChamber, &testSubject);
gCurrentTestSubject = testSubject;
levelQueueLoad(getLevelIndexFromChamberDisplayNumber(testChamber), NULL, NULL);
checkpointUse(save);
stackMallocFree(save);
soundPlayerPlay(SOUNDS_BUTTONCLICKRELEASE, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
} else if (controllerGetButtonDown(0, Z_TRIG)) {
savefileListConfirmDeletion(
loadGame->savefileList,
(ConfirmationDialogCallback)&loadGameConfirmDeletionClosed,
loadGame
);
soundPlayerPlay(SOUNDS_BUTTONCLICKRELEASE, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
}
}
return InputCapturePass;
} }
void loadGameRender(struct LoadGameMenu* loadGame, struct RenderState* renderState, struct GraphicsTask* task) { void loadGameRender(struct LoadGameMenu* loadGame, struct RenderState* renderState, struct GraphicsTask* task) {

View file

@ -16,10 +16,7 @@ struct PrerenderedText* menuBuildPrerenderedText(struct Font* font, char* messag
return result; return result;
} }
Gfx* menuBuildBorder(int x, int y, int width, int height) { Gfx* menuRerenderBorder(int x, int y, int width, int height, Gfx* dl) {
Gfx* result = malloc(sizeof(Gfx) * 7 * 3 + 1);
Gfx* dl = result;
gSPTextureRectangle( gSPTextureRectangle(
dl++, dl++,
x << 2, y << 2, x << 2, y << 2,
@ -83,6 +80,13 @@ Gfx* menuBuildBorder(int x, int y, int width, int height) {
0x400, 0x400 0x400, 0x400
); );
return dl;
}
Gfx* menuBuildBorder(int x, int y, int width, int height) {
Gfx* result = malloc(sizeof(Gfx) * 7 * 3 + 1);
Gfx* dl = menuRerenderBorder(x, y, width, height, result);
gSPEndDisplayList(dl++); gSPEndDisplayList(dl++);
return result; return result;
@ -193,6 +197,18 @@ void menuRebuildButtonText(struct MenuButton* button, struct Font* font, char* m
menuRenderOutline(button->x, button->y, button->w, button->h, 0, button->outline); menuRenderOutline(button->x, button->y, button->w, button->h, 0, button->outline);
} }
void menuRelocateButton(struct MenuButton* button, int x, int y, int rightAlign) {
if (rightAlign) {
x -= button->w;
}
menuRenderOutline(x, y, button->w, button->h, 0, button->outline);
prerenderedTextRelocate(button->text, x + BUTTON_LEFT_PADDING, y + BUTTON_TOP_PADDING);
button->x = x;
button->y = y;
}
void menuSetRenderColor(struct RenderState* renderState, int isSelected, struct Coloru8* selected, struct Coloru8* defaultColor) { void menuSetRenderColor(struct RenderState* renderState, int isSelected, struct Coloru8* selected, struct Coloru8* defaultColor) {
if (isSelected) { if (isSelected) {
gDPSetEnvColor(renderState->dl++, selected->r, selected->g, selected->b, selected->a); gDPSetEnvColor(renderState->dl++, selected->r, selected->g, selected->b, selected->a);

View file

@ -47,6 +47,7 @@ extern struct Coloru8 gBorderDark;
struct PrerenderedText* menuBuildPrerenderedText(struct Font* font, char* message, int x, int y, int maxWidth); struct PrerenderedText* menuBuildPrerenderedText(struct Font* font, char* message, int x, int y, int maxWidth);
Gfx* menuRerenderBorder(int x, int y, int width, int height, Gfx* dl);
Gfx* menuBuildBorder(int x, int y, int width, int height); Gfx* menuBuildBorder(int x, int y, int width, int height);
Gfx* menuBuildHorizontalLine(int x, int y, int width); Gfx* menuBuildHorizontalLine(int x, int y, int width);
Gfx* menuRerenderSolidBorder(int x, int y, int w, int h, int nx, int ny, int nw, int nh, Gfx* dl); Gfx* menuRerenderSolidBorder(int x, int y, int w, int h, int nx, int ny, int nw, int nh, Gfx* dl);
@ -56,6 +57,7 @@ Gfx* menuBuildOutline(int x, int y, int width, int height, int invert);
struct MenuButton menuBuildButton(struct Font* font, char* message, int x, int y, int height, int rightAlign); struct MenuButton menuBuildButton(struct Font* font, char* message, int x, int y, int height, int rightAlign);
void menuSetRenderColor(struct RenderState* renderState, int isSelected, struct Coloru8* selected, struct Coloru8* defaultColor); void menuSetRenderColor(struct RenderState* renderState, int isSelected, struct Coloru8* selected, struct Coloru8* defaultColor);
void menuRebuildButtonText(struct MenuButton* button, struct Font* font, char* message, int rightAlign); void menuRebuildButtonText(struct MenuButton* button, struct Font* font, char* message, int rightAlign);
void menuRelocateButton(struct MenuButton* button, int x, int y, int rightAlign);
struct MenuCheckbox menuBuildCheckbox(struct Font* font, char* message, int x, int y); struct MenuCheckbox menuBuildCheckbox(struct Font* font, char* message, int x, int y);
Gfx* menuCheckboxRender(struct MenuCheckbox* checkbox, Gfx* dl); Gfx* menuCheckboxRender(struct MenuCheckbox* checkbox, Gfx* dl);

View file

@ -28,6 +28,7 @@ void saveGamePopulate(struct SaveGameMenu* saveGame, int includeNew) {
savefileInfo[i].testchamberDisplayNumber = saveSlots[i].testChamber; savefileInfo[i].testchamberDisplayNumber = saveSlots[i].testChamber;
savefileInfo[i].savefileName = NULL; savefileInfo[i].savefileName = NULL;
savefileInfo[i].screenshot = (u16*)SCREEN_SHOT_SRAM(saveSlots[i].saveSlot); savefileInfo[i].screenshot = (u16*)SCREEN_SHOT_SRAM(saveSlots[i].saveSlot);
savefileInfo[i].isFree = 0;
if (suggestedSlot == saveSlots[i].saveSlot) { if (suggestedSlot == saveSlots[i].saveSlot) {
startSelection = i; startSelection = i;
@ -41,6 +42,7 @@ void saveGamePopulate(struct SaveGameMenu* saveGame, int includeNew) {
savefileInfo[numberOfSaves].savefileName = translationsGet(GAMEUI_NEWSAVEGAME); savefileInfo[numberOfSaves].savefileName = translationsGet(GAMEUI_NEWSAVEGAME);
savefileInfo[numberOfSaves].testchamberDisplayNumber = getChamberDisplayNumberFromLevelIndex(gCurrentLevelIndex, gScene.player.body.currentRoom); savefileInfo[numberOfSaves].testchamberDisplayNumber = getChamberDisplayNumberFromLevelIndex(gCurrentLevelIndex, gScene.player.body.currentRoom);
savefileInfo[numberOfSaves].screenshot = gScreenGrabBuffer; savefileInfo[numberOfSaves].screenshot = gScreenGrabBuffer;
savefileInfo[numberOfSaves].isFree = 1;
if (suggestedSlot == 0) { if (suggestedSlot == 0) {
startSelection = numberOfSaves; startSelection = numberOfSaves;
@ -49,7 +51,13 @@ void saveGamePopulate(struct SaveGameMenu* saveGame, int includeNew) {
++numberOfSaves; ++numberOfSaves;
} }
savefileUseList(saveGame->savefileList, translationsGet(GAMEUI_SAVEGAME), savefileInfo, numberOfSaves); savefileUseList(
saveGame->savefileList,
translationsGet(GAMEUI_SAVEGAME),
translationsGet(GAMEUI_SAVE),
savefileInfo,
numberOfSaves
);
if (startSelection == -1) { if (startSelection == -1) {
saveGame->savefileList->selectedSave = numberOfSaves - 1; saveGame->savefileList->selectedSave = numberOfSaves - 1;
@ -58,20 +66,83 @@ void saveGamePopulate(struct SaveGameMenu* saveGame, int includeNew) {
} }
} }
enum InputCapture saveGameUpdate(struct SaveGameMenu* saveGame) { static void saveGameSaveInSelectedSlot(struct SaveGameMenu* saveGame) {
if (controllerGetButtonDown(0, A_BUTTON) && saveGame->savefileList->numberOfSaves) { Checkpoint* save = stackMalloc(MAX_CHECKPOINT_SIZE);
Checkpoint* save = stackMalloc(MAX_CHECKPOINT_SIZE); if (checkpointSaveInto(&gScene, save)) {
if (checkpointSaveInto(&gScene, save)) { savefileSaveGame(
savefileSaveGame(save, gScreenGrabBuffer, getChamberDisplayNumberFromLevelIndex(gCurrentLevelIndex, gScene.player.body.currentRoom), gCurrentTestSubject, savefileGetSlot(saveGame->savefileList)); save,
saveGamePopulate(saveGame, 0); gScreenGrabBuffer,
soundPlayerPlay(SOUNDS_BUTTONCLICKRELEASE, 1.0f, 0.5f, NULL, NULL, SoundTypeAll); getChamberDisplayNumberFromLevelIndex(gCurrentLevelIndex, gScene.player.body.currentRoom),
}else{ gCurrentTestSubject,
soundPlayerPlay(SOUNDS_WPN_DENYSELECT, 1.0f, 0.5f, NULL, NULL, SoundTypeAll); savefileGetSlot(saveGame->savefileList)
);
saveGamePopulate(saveGame, 1);
soundPlayerPlay(SOUNDS_BUTTONCLICKRELEASE, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
} else {
soundPlayerPlay(SOUNDS_WPN_DENYSELECT, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
}
stackMallocFree(save);
}
static void saveGameConfirmDeletionClosed(struct SaveGameMenu* saveGame, int isConfirmed) {
if (isConfirmed) {
short selectedSaveIndex = saveGame->savefileList->selectedSave;
struct SavefileInfo* selectedSave = &saveGame->savefileList->savefileInfo[selectedSaveIndex];
savefileDeleteGame(selectedSave->slotIndex);
saveGamePopulate(saveGame, 1);
if (selectedSaveIndex >= saveGame->savefileList->numberOfSaves) {
--selectedSaveIndex;
} }
stackMallocFree(save); saveGame->savefileList->selectedSave = selectedSaveIndex;
}
}
static void saveGameConfirmOverwriteClosed(void* saveGame, int isConfirmed) {
if (isConfirmed) {
saveGameSaveInSelectedSlot(saveGame);
}
}
enum InputCapture saveGameUpdate(struct SaveGameMenu* saveGame) {
enum InputCapture capture = savefileListUpdate(saveGame->savefileList);
if (capture != InputCapturePass) {
return capture;
} }
return savefileListUpdate(saveGame->savefileList); if (saveGame->savefileList->numberOfSaves) {
if (controllerGetButtonDown(0, A_BUTTON)) {
short selectedSaveIndex = saveGame->savefileList->selectedSave;
struct SavefileInfo* selectedSave = &saveGame->savefileList->savefileInfo[selectedSaveIndex];
if (selectedSave->isFree) {
saveGameSaveInSelectedSlot(saveGame);
} else {
savefileListConfirmOverwrite(
saveGame->savefileList,
(ConfirmationDialogCallback)&saveGameConfirmOverwriteClosed,
saveGame
);
soundPlayerPlay(SOUNDS_BUTTONCLICKRELEASE, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
}
} else if (controllerGetButtonDown(0, Z_TRIG)) {
short selectedSaveIndex = saveGame->savefileList->selectedSave;
struct SavefileInfo* selectedSave = &saveGame->savefileList->savefileInfo[selectedSaveIndex];
if (!selectedSave->isFree) {
savefileListConfirmDeletion(
saveGame->savefileList,
(ConfirmationDialogCallback)&saveGameConfirmDeletionClosed,
saveGame
);
soundPlayerPlay(SOUNDS_BUTTONCLICKRELEASE, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
}
}
}
return InputCapturePass;
} }
void saveGameRender(struct SaveGameMenu* saveGame, struct RenderState* renderState, struct GraphicsTask* task) { void saveGameRender(struct SaveGameMenu* saveGame, struct RenderState* renderState, struct GraphicsTask* task) {

View file

@ -6,6 +6,8 @@
#include "../graphics/image.h" #include "../graphics/image.h"
#include "../audio/soundplayer.h" #include "../audio/soundplayer.h"
#include "./text_manipulation.h" #include "./text_manipulation.h"
#include "./controls.h"
#include "./translations.h"
#include <string.h> #include <string.h>
#include "../build/assets/materials/ui.h" #include "../build/assets/materials/ui.h"
@ -72,15 +74,19 @@ void savefileListSlotInit(struct SavefileListSlot* savefileListSlot, int x, int
} }
#define LOAD_GAME_LEFT 40 #define LOAD_GAME_LEFT 40
#define LOAD_GAME_TOP 20 #define LOAD_GAME_TOP 15
#define FILE_OFFSET_X 16 #define FILE_OFFSET_X 16
#define FILE_OFFSET_Y 28 #define FILE_OFFSET_Y 28
#define CONTROLS_HEIGHT 10
#define CONTROL_TEXT_PADDING 12
#define CONTROL_TEXT_MARGIN 2
#define CONTENT_X (LOAD_GAME_LEFT + 8) #define CONTENT_X (LOAD_GAME_LEFT + 8)
#define CONTENT_Y (LOAD_GAME_TOP + FILE_OFFSET_Y - 8) #define CONTENT_Y (LOAD_GAME_TOP + FILE_OFFSET_Y - 8)
#define CONTENT_WIDTH (SCREEN_WD - CONTENT_X * 2) #define CONTENT_WIDTH (SCREEN_WD - CONTENT_X * 2)
#define CONTENT_HEIGHT (SCREEN_HT - CONTENT_Y - LOAD_GAME_TOP - 8) #define CONTENT_HEIGHT (SCREEN_HT - CONTENT_Y - LOAD_GAME_TOP - CONTROLS_HEIGHT - 8)
#define SCROLLED_ROW_Y(rowIndex, scrollOffset) (LOAD_GAME_TOP + (rowIndex) * ROW_HEIGHT + FILE_OFFSET_Y + (scrollOffset)) #define SCROLLED_ROW_Y(rowIndex, scrollOffset) (LOAD_GAME_TOP + (rowIndex) * ROW_HEIGHT + FILE_OFFSET_Y + (scrollOffset))
@ -117,6 +123,8 @@ void savefileListMenuSetScroll(struct SavefileListMenu* savefileList, int amount
void savefileListMenuInit(struct SavefileListMenu* savefileList) { void savefileListMenuInit(struct SavefileListMenu* savefileList) {
savefileList->menuOutline = menuBuildBorder(LOAD_GAME_LEFT, LOAD_GAME_TOP, SCREEN_WD - LOAD_GAME_LEFT * 2, SCREEN_HT - LOAD_GAME_TOP * 2); savefileList->menuOutline = menuBuildBorder(LOAD_GAME_LEFT, LOAD_GAME_TOP, SCREEN_WD - LOAD_GAME_LEFT * 2, SCREEN_HT - LOAD_GAME_TOP * 2);
savefileList->savefileListTitleText = NULL; savefileList->savefileListTitleText = NULL;
savefileList->deleteText = NULL;
savefileList->confirmText = NULL;
savefileList->numberOfSaves = 3; savefileList->numberOfSaves = 3;
savefileList->scrollOffset = 0; savefileList->scrollOffset = 0;
@ -128,14 +136,46 @@ void savefileListMenuInit(struct SavefileListMenu* savefileList) {
LOAD_GAME_TOP + i * ROW_HEIGHT + FILE_OFFSET_Y LOAD_GAME_TOP + i * ROW_HEIGHT + FILE_OFFSET_Y
); );
} }
confirmationDialogInit(&savefileList->confirmationDialog);
} }
void savefileUseList(struct SavefileListMenu* savefileList, char* title, struct SavefileInfo* savefileInfo, int slotCount) { void savefileUseList(struct SavefileListMenu* savefileList, char* title, char* confirmLabel, struct SavefileInfo* savefileInfo, int slotCount) {
if (savefileList->savefileListTitleText) { if (savefileList->savefileListTitleText) {
prerenderedTextFree(savefileList->savefileListTitleText); prerenderedTextFree(savefileList->savefileListTitleText);
} }
if (savefileList->deleteText) {
prerenderedTextFree(savefileList->deleteText);
}
if (savefileList->confirmText) {
prerenderedTextFree(savefileList->confirmText);
}
savefileList->savefileListTitleText = menuBuildPrerenderedText(&gDejaVuSansFont, title, 48, LOAD_GAME_TOP + 4, SCREEN_WD); savefileList->savefileListTitleText = menuBuildPrerenderedText(
&gDejaVuSansFont,
title,
CONTENT_X,
LOAD_GAME_TOP + 4,
SCREEN_WD
);
savefileList->deleteText = menuBuildPrerenderedText(&gDejaVuSansFont,
translationsGet(GAMEUI_DELETE),
CONTENT_X + CONTROL_TEXT_PADDING,
CONTENT_Y + CONTENT_HEIGHT + CONTROL_TEXT_MARGIN,
120
);
savefileList->confirmText = menuBuildPrerenderedText(
&gDejaVuSansFont,
confirmLabel,
0,
CONTENT_Y + CONTENT_HEIGHT + CONTROL_TEXT_MARGIN,
120
);
prerenderedTextRelocate(
savefileList->confirmText,
CONTENT_X + CONTENT_WIDTH - savefileList->confirmText->width - 1,
savefileList->confirmText->y
);
for (int i = 0; i < slotCount; ++i) { for (int i = 0; i < slotCount; ++i) {
savefileList->savefileInfo[i] = savefileInfo[i]; savefileList->savefileInfo[i] = savefileInfo[i];
@ -148,6 +188,10 @@ void savefileUseList(struct SavefileListMenu* savefileList, char* title, struct
} }
enum InputCapture savefileListUpdate(struct SavefileListMenu* savefileList) { enum InputCapture savefileListUpdate(struct SavefileListMenu* savefileList) {
if (savefileList->confirmationDialog.isShown) {
return confirmationDialogUpdate(&savefileList->confirmationDialog);
}
if (controllerGetButtonDown(0, B_BUTTON)) { if (controllerGetButtonDown(0, B_BUTTON)) {
return InputCaptureExit; return InputCaptureExit;
} }
@ -185,6 +229,40 @@ enum InputCapture savefileListUpdate(struct SavefileListMenu* savefileList) {
return InputCapturePass; return InputCapturePass;
} }
static void savefileListRenderControls(struct SavefileListMenu* savefileList, struct RenderState* renderState) {
if (savefileList->numberOfSaves == 0) {
return;
}
struct SavefileInfo* selectedSave = &savefileList->savefileInfo[savefileList->selectedSave];
struct PrerenderedTextBatch* batch = prerenderedBatchStart();
gSPDisplayList(renderState->dl++, ui_material_list[BUTTON_ICONS_INDEX]);
if (savefileList->confirmText) {
controlsRenderButtonIcon(
ControllerActionSourceAButton,
savefileList->confirmText->x - CONTROL_TEXT_PADDING - 2,
savefileList->confirmText->y,
renderState
);
prerenderedBatchAdd(batch, savefileList->confirmText, NULL);
}
if (savefileList->deleteText && !selectedSave->isFree) {
controlsRenderButtonIcon(
ControllerActionSourceZTrig,
savefileList->deleteText->x - CONTROL_TEXT_PADDING - 1,
savefileList->deleteText->y,
renderState
);
prerenderedBatchAdd(batch, savefileList->deleteText, NULL);
}
gSPDisplayList(renderState->dl++, ui_material_revert_list[BUTTON_ICONS_INDEX]);
renderState->dl = prerenderedBatchFinish(batch, gDejaVuSansImages, renderState->dl);
}
void savefileListRender(struct SavefileListMenu* savefileList, struct RenderState* renderState, struct GraphicsTask* task) { void savefileListRender(struct SavefileListMenu* savefileList, struct RenderState* renderState, struct GraphicsTask* task) {
gSPDisplayList(renderState->dl++, ui_material_list[DEFAULT_UI_INDEX]); gSPDisplayList(renderState->dl++, ui_material_list[DEFAULT_UI_INDEX]);
@ -229,6 +307,8 @@ void savefileListRender(struct SavefileListMenu* savefileList, struct RenderStat
renderState->dl = prerenderedBatchFinish(batch, gDejaVuSansImages, renderState->dl); renderState->dl = prerenderedBatchFinish(batch, gDejaVuSansImages, renderState->dl);
savefileListRenderControls(savefileList, renderState);
gDPPipeSync(renderState->dl++); gDPPipeSync(renderState->dl++);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, CONTENT_X, CONTENT_Y, CONTENT_X + CONTENT_WIDTH, CONTENT_Y + CONTENT_HEIGHT); gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, CONTENT_X, CONTENT_Y, CONTENT_X + CONTENT_WIDTH, CONTENT_Y + CONTENT_HEIGHT);
@ -252,6 +332,7 @@ void savefileListRender(struct SavefileListMenu* savefileList, struct RenderStat
renderState->dl = prerenderedBatchFinish(batch, gDejaVuSansImages, renderState->dl); renderState->dl = prerenderedBatchFinish(batch, gDejaVuSansImages, renderState->dl);
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_0_INDEX]); gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_0_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[IMAGE_COPY_INDEX]); gSPDisplayList(renderState->dl++, ui_material_list[IMAGE_COPY_INDEX]);
@ -289,10 +370,40 @@ void savefileListRender(struct SavefileListMenu* savefileList, struct RenderStat
gSPDisplayList(renderState->dl++, ui_material_revert_list[IMAGE_COPY_INDEX]); gSPDisplayList(renderState->dl++, ui_material_revert_list[IMAGE_COPY_INDEX]);
if (savefileList->confirmationDialog.isShown) {
confirmationDialogRender(&savefileList->confirmationDialog, renderState);
}
gDPPipeSync(renderState->dl++); gDPPipeSync(renderState->dl++);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WD, SCREEN_HT); gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WD, SCREEN_HT);
} }
int savefileGetSlot(struct SavefileListMenu* savefileList) { int savefileGetSlot(struct SavefileListMenu* savefileList) {
return savefileList->savefileInfo[savefileList->selectedSave].slotIndex; return savefileList->savefileInfo[savefileList->selectedSave].slotIndex;
} }
void savefileListConfirmDeletion(struct SavefileListMenu* savefileList, ConfirmationDialogCallback callback, void* callbackData) {
struct ConfirmationDialogParams dialogParams = {
translationsGet(GAMEUI_CONFIRMDELETESAVEGAME_TITLE),
translationsGet(GAMEUI_CONFIRMDELETESAVEGAME_INFO),
translationsGet(GAMEUI_CONFIRMDELETESAVEGAME_OK),
translationsGet(GAMEUI_CANCEL),
callback,
callbackData
};
confirmationDialogShow(&savefileList->confirmationDialog, &dialogParams);
}
void savefileListConfirmOverwrite(struct SavefileListMenu* savefileList, ConfirmationDialogCallback callback, void* callbackData) {
struct ConfirmationDialogParams dialogParams = {
translationsGet(GAMEUI_CONFIRMOVERWRITESAVEGAME_TITLE),
translationsGet(GAMEUI_CONFIRMOVERWRITESAVEGAME_INFO),
translationsGet(GAMEUI_CONFIRMOVERWRITESAVEGAME_OK),
translationsGet(GAMEUI_CANCEL),
callback,
callbackData
};
confirmationDialogShow(&savefileList->confirmationDialog, &dialogParams);
}

View file

@ -6,12 +6,14 @@
#include "../graphics/graphics.h" #include "../graphics/graphics.h"
#include "../savefile/savefile.h" #include "../savefile/savefile.h"
#include "./new_game_menu.h" #include "./new_game_menu.h"
#include "./confirmation_dialog.h"
struct SavefileInfo { struct SavefileInfo {
short slotIndex; short slotIndex;
short testchamberDisplayNumber; short testchamberDisplayNumber;
char* savefileName; char* savefileName;
u16* screenshot; u16* screenshot;
int isFree;
}; };
struct SavefileListSlot { struct SavefileListSlot {
@ -28,6 +30,9 @@ struct SavefileListSlot {
struct SavefileListMenu { struct SavefileListMenu {
Gfx* menuOutline; Gfx* menuOutline;
struct PrerenderedText* savefileListTitleText; struct PrerenderedText* savefileListTitleText;
struct PrerenderedText* deleteText;
struct PrerenderedText* confirmText;
struct ConfirmationDialog confirmationDialog;
struct SavefileInfo savefileInfo[MAX_SAVE_SLOTS]; struct SavefileInfo savefileInfo[MAX_SAVE_SLOTS];
struct SavefileListSlot slots[MAX_VISIBLE_SLOTS]; struct SavefileListSlot slots[MAX_VISIBLE_SLOTS];
short numberOfSaves; short numberOfSaves;
@ -37,9 +42,11 @@ struct SavefileListMenu {
}; };
void savefileListMenuInit(struct SavefileListMenu* savefileList); void savefileListMenuInit(struct SavefileListMenu* savefileList);
void savefileUseList(struct SavefileListMenu* savefileList, char* title, struct SavefileInfo* savefileInfo, int slotCount); void savefileUseList(struct SavefileListMenu* savefileList, char* title, char* confirmLabel, struct SavefileInfo* savefileInfo, int slotCount);
enum InputCapture savefileListUpdate(struct SavefileListMenu* savefileList); enum InputCapture savefileListUpdate(struct SavefileListMenu* savefileList);
void savefileListRender(struct SavefileListMenu* savefileList, struct RenderState* renderState, struct GraphicsTask* task); void savefileListRender(struct SavefileListMenu* savefileList, struct RenderState* renderState, struct GraphicsTask* task);
int savefileGetSlot(struct SavefileListMenu* savefileList); int savefileGetSlot(struct SavefileListMenu* savefileList);
void savefileListConfirmDeletion(struct SavefileListMenu* savefileList, ConfirmationDialogCallback callback, void* callbackData);
void savefileListConfirmOverwrite(struct SavefileListMenu* savefileList, ConfirmationDialogCallback callback, void* callbackData);
#endif #endif

View file

@ -85,9 +85,7 @@ void savefileNew() {
gSaveData.header.flags = 0; gSaveData.header.flags = 0;
for (int i = 0; i < MAX_SAVE_SLOTS; ++i) { for (int i = 0; i < MAX_SAVE_SLOTS; ++i) {
gSaveData.saveSlotMetadata[i].testChamber = NO_TEST_CHAMBER; savefileDeleteGame(i);
gSaveData.saveSlotMetadata[i].testSubjectNumber = 0xFF;
gSaveData.saveSlotMetadata[i].saveSlotOrder = 0xFF;
} }
controllerSetDefaultSource(); controllerSetDefaultSource();
@ -152,6 +150,25 @@ void savefileSave() {
savefileSramSave((void*)SRAM_ADDR, &gSaveData, sizeof(gSaveData)); savefileSramSave((void*)SRAM_ADDR, &gSaveData, sizeof(gSaveData));
} }
void savefileDeleteGame(int slotIndex) {
unsigned char prevSortOrder = gSaveData.saveSlotMetadata[slotIndex].saveSlotOrder;
// shift existing slot sort orders
for (int i = 0; i < MAX_SAVE_SLOTS; ++i) {
unsigned char currSlotOrder = gSaveData.saveSlotMetadata[i].saveSlotOrder;
if (currSlotOrder > prevSortOrder && currSlotOrder < 0xFF) {
--gSaveData.saveSlotMetadata[i].saveSlotOrder;
}
}
gSaveData.saveSlotMetadata[slotIndex].testChamber = NO_TEST_CHAMBER;
gSaveData.saveSlotMetadata[slotIndex].testSubjectNumber = 0xFF;
gSaveData.saveSlotMetadata[slotIndex].saveSlotOrder = 0xFF;
savefileSave();
}
#define SAVE_SLOT_SRAM_ADDRESS(index) (SRAM_ADDR + (1 + (index)) * SAVE_SLOT_SIZE) #define SAVE_SLOT_SRAM_ADDRESS(index) (SRAM_ADDR + (1 + (index)) * SAVE_SLOT_SIZE)
void savefileSaveGame(Checkpoint checkpoint, u16* screenshot, int testChamberDisplayNumber, int subjectNumber, int slotIndex) { void savefileSaveGame(Checkpoint checkpoint, u16* screenshot, int testChamberDisplayNumber, int subjectNumber, int slotIndex) {

View file

@ -90,6 +90,8 @@ extern int gCurrentTestSubject;
void savefileLoad(); void savefileLoad();
void savefileSave(); void savefileSave();
void savefileDeleteGame(int slotIndex);
void savefileSaveGame(Checkpoint checkpoint, u16* screenshot, int testChamberIndex, int subjectNumber, int slotIndex); void savefileSaveGame(Checkpoint checkpoint, u16* screenshot, int testChamberIndex, int subjectNumber, int slotIndex);
int savefileListSaves(struct SaveSlotInfo* slots, int includeAuto); int savefileListSaves(struct SaveSlotInfo* slots, int includeAuto);
int savefileNextTestSubject(); int savefileNextTestSubject();

View file

@ -9,11 +9,20 @@ hl_gameui_whitelist = {
"GAMEUI_ASPECTWIDE", "GAMEUI_ASPECTWIDE",
"GAMEUI_AUDIO", "GAMEUI_AUDIO",
"GAMEUI_AUTOSAVE", "GAMEUI_AUTOSAVE",
"GAMEUI_CANCEL",
"GAMEUI_CAPTIONING", "GAMEUI_CAPTIONING",
"GAMEUI_CHAPTER", "GAMEUI_CHAPTER",
"GAMEUI_CONFIRMDELETESAVEGAME_INFO",
"GAMEUI_CONFIRMDELETESAVEGAME_OK",
"GAMEUI_CONFIRMDELETESAVEGAME_TITLE",
"GAMEUI_CONFIRMOVERWRITESAVEGAME_INFO",
"GAMEUI_CONFIRMOVERWRITESAVEGAME_OK",
"GAMEUI_CONFIRMOVERWRITESAVEGAME_TITLE",
"GAMEUI_DELETE",
"GAMEUI_GAMEMENU_QUIT", "GAMEUI_GAMEMENU_QUIT",
"GAMEUI_GAMEMENU_RESUMEGAME", "GAMEUI_GAMEMENU_RESUMEGAME",
"GAMEUI_JOYSTICKINVERTED", "GAMEUI_JOYSTICKINVERTED",
"GAMEUI_LOAD",
"GAMEUI_LOADGAME", "GAMEUI_LOADGAME",
"GAMEUI_MUSICVOLUME", "GAMEUI_MUSICVOLUME",
"GAMEUI_NEWGAME", "GAMEUI_NEWGAME",
@ -23,6 +32,7 @@ hl_gameui_whitelist = {
"GAMEUI_PORTAL", "GAMEUI_PORTAL",
"GAMEUI_PORTALDEPTHLABEL", "GAMEUI_PORTALDEPTHLABEL",
"GAMEUI_PORTALFUNNEL", "GAMEUI_PORTALFUNNEL",
"GAMEUI_SAVE",
"GAMEUI_SAVEGAME", "GAMEUI_SAVEGAME",
"GAMEUI_SOUNDEFFECTVOLUME", "GAMEUI_SOUNDEFFECTVOLUME",
"GAMEUI_SUBTITLES", "GAMEUI_SUBTITLES",
@ -139,7 +149,7 @@ def get_caption_keys_values_language(lines):
keyval[1] = keyval[1].replace("[$WIN32]", "") keyval[1] = keyval[1].replace("[$WIN32]", "")
key = keyval[0].replace('"', "").replace(".", "_").replace("-", "_").replace('\\', "_").replace('#', "").upper() key = keyval[0].replace('"', "").replace(".", "_").replace("-", "_").replace('\\', "_").replace('#', "").upper()
val = keyval[1].replace('"', "").replace("\n", "").replace("\\", "").strip() val = keyval[1].replace('"', "").replace("\n", "").replace("\\n", " ").replace("\\", "").strip()
val = re.sub(r'\<clr.+\>','',val) val = re.sub(r'\<clr.+\>','',val)
val = re.sub(r'\<norepeat.+\>','',val) val = re.sub(r'\<norepeat.+\>','',val)
val = val.replace("<sfx>", "") val = val.replace("<sfx>", "")