Start work on load game menu

This commit is contained in:
James Lambert 2023-04-29 21:32:25 -06:00
parent f1ca5ae1e4
commit 4adbef10b4
16 changed files with 269 additions and 48 deletions

View file

@ -245,6 +245,8 @@ build/src/menu/main_menu.o: build/src/audio/clips.h build/assets/materials/ui.h
build/src/menu/new_game_menu.o: build/src/audio/clips.h build/assets/materials/ui.h build/assets/materials/images.h build/assets/test_chambers/test_chamber_00/test_chamber_00.h
build/src/menu/load_game.o: build/assets/materials/ui.h
build/src/menu/landing_menu.o: build/assets/materials/ui.h
build/src/menu/options_menu.o: build/assets/materials/ui.h

View file

@ -5,7 +5,7 @@
#include "../math/mathf.h"
#include "../savefile/savefile.h"
enum ControllerAction gDefaultControllerSettings[ControllerActionSourceCount] = {
unsigned char gDefaultControllerSettings[ControllerActionSourceCount] = {
[ControllerActionSourceAButton] = ControllerActionJump,
[ControllerActionSourceBButton] = ControllerActionUseItem,
[ControllerActionSourceCUpButton] = ControllerActionMove,

View file

@ -72,7 +72,9 @@ enum MainMenuState landingMenuUpdate(struct LandingMenu* landingMenu) {
case 0:
return MainMenuStateNewGame;
break;
case 1:
return MainMenuStateLoadGame;
break;
case 2:
return MainMenuStateOptions;
break;

166
src/menu/load_game.c Normal file
View file

@ -0,0 +1,166 @@
#include "load_game.h"
#include "../font/dejavusans.h"
#include "../controls/controller.h"
#include "../util/rom.h"
#include "../graphics/image.h"
#include "../build/assets/materials/ui.h"
#define BORDER_WIDTH 92
#define BORDER_HEIGHT 58
void loadGameSlotUseSlot(struct LoadGameSlot* loadGameSlot, struct SaveSlotInfo slotInfo) {
loadGameSlot->saveSlot = slotInfo.saveSlot;
struct Chapter* chapter = chapterFindForChamber(slotInfo.testChamber);
romCopy(chapter->imageData, loadGameSlot->imageData, CHAPTER_IMAGE_SIZE);
}
void loadGameSlotInit(struct LoadGameSlot* loadGameSlot, int x, int y) {
loadGameSlot->testChamberText = menuBuildText(&gDejaVuSansFont, "Testchamber 00", x + BORDER_WIDTH + 8, y);
loadGameSlot->border = menuBuildSolidBorder(
x, y, BORDER_WIDTH, BORDER_HEIGHT,
x + 5, y + 5, 82, 48
);
loadGameSlot->x = x;
loadGameSlot->y = y;
loadGameSlot->imageData = malloc(CHAPTER_IMAGE_SIZE);
loadGameSlot->saveSlot = 0;
}
#define LOAD_GAME_LEFT 40
#define LOAD_GAME_TOP 20
#define FILE_OFFSET_X 16
#define FILE_OFFSET_Y 28
#define CONTENT_X (LOAD_GAME_LEFT + 8)
#define CONTENT_Y (LOAD_GAME_TOP + FILE_OFFSET_Y - 8)
#define CONTENT_WIDTH (SCREEN_WD - CONTENT_X * 2)
#define CONTENT_HEIGHT (SCREEN_HT - CONTENT_Y - LOAD_GAME_TOP - 8)
void loadGameMenuReread(struct LoadGameMenu* loadGame) {
loadGame->numberOfSaves = savefileListSaves(loadGame->slotInfo);
loadGame->scrollOffset = 0;
loadGame->selectedSave = 0;
loadGame->slotInfo[0].saveSlot = 0;
loadGame->slotInfo[0].testChamber = 0;
loadGame->numberOfSaves = 1;
int i;
for (i = 0; i < loadGame->numberOfSaves && i < MAX_VISIBLE_SLOTS; ++i) {
loadGameSlotUseSlot(&loadGame->slots[i], loadGame->slotInfo[i]);
}
for (; i < MAX_VISIBLE_SLOTS; ++i) {
loadGame->slots[i].saveSlot = -1;
}
}
void loadGameMenuInit(struct LoadGameMenu* loadGame) {
loadGame->menuOutline = menuBuildBorder(LOAD_GAME_LEFT, LOAD_GAME_TOP, SCREEN_WD - LOAD_GAME_LEFT * 2, SCREEN_HT - LOAD_GAME_TOP * 2);
loadGame->loadGameText = menuBuildText(&gDejaVuSansFont, "LOAD GAME", 48, LOAD_GAME_TOP + 4);
loadGame->numberOfSaves = 3;
loadGame->scrollOffset = 0;
for (int i = 0; i < MAX_VISIBLE_SLOTS; ++i) {
loadGameSlotInit(
&loadGame->slots[i],
LOAD_GAME_LEFT + FILE_OFFSET_X,
LOAD_GAME_TOP + i * (BORDER_HEIGHT + 8) + FILE_OFFSET_Y
);
}
loadGameMenuReread(loadGame);
}
enum MenuDirection loadGameUpdate(struct LoadGameMenu* loadGame) {
if (controllerGetButtonDown(0, B_BUTTON)) {
return MenuDirectionUp;
}
return MenuDirectionStay;
}
void loadGameRender(struct LoadGameMenu* loadGame, struct RenderState* renderState, struct GraphicsTask* task) {
gSPDisplayList(renderState->dl++, ui_material_list[DEFAULT_UI_INDEX]);
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]);
gSPDisplayList(renderState->dl++, loadGame->menuOutline);
gSPDisplayList(renderState->dl++, ui_material_revert_list[ROUNDED_CORNERS_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_TRANSPARENT_OVERLAY_INDEX]);
gDPFillRectangle(renderState->dl++, CONTENT_X, CONTENT_Y, CONTENT_X + CONTENT_WIDTH, CONTENT_Y + CONTENT_HEIGHT);
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_TRANSPARENT_OVERLAY_INDEX]);
gDPPipeSync(renderState->dl++);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, CONTENT_X, CONTENT_Y, CONTENT_X + CONTENT_WIDTH, CONTENT_Y + CONTENT_HEIGHT);
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_ENV_INDEX]);
for (int i = 0; i < MAX_VISIBLE_SLOTS; ++i) {
struct LoadGameSlot* slot = &loadGame->slots[i];
if (slot->saveSlot < 0) {
continue;
}
menuSetRenderColor(renderState, loadGame->scrollOffset + i == loadGame->selectedSave, &gSelectionOrange, &gColorBlack);
gSPDisplayList(renderState->dl++, slot->border);
}
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_ENV_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[DEJAVU_SANS_INDEX]);
gDPPipeSync(renderState->dl++);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WD, SCREEN_HT);
gSPDisplayList(renderState->dl++, loadGame->loadGameText);
gDPPipeSync(renderState->dl++);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, CONTENT_X, CONTENT_Y, CONTENT_X + CONTENT_WIDTH, CONTENT_Y + CONTENT_HEIGHT);
for (int i = 0; i < MAX_VISIBLE_SLOTS; ++i) {
struct LoadGameSlot* slot = &loadGame->slots[i];
if (slot->saveSlot < 0) {
continue;
}
menuSetRenderColor(renderState, loadGame->scrollOffset + i == loadGame->selectedSave, &gSelectionOrange, &gColorWhite);
gSPDisplayList(renderState->dl++, slot->testChamberText);
}
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_INDEX]);
for (int i = 0; i < MAX_VISIBLE_SLOTS; ++i) {
struct LoadGameSlot* slot = &loadGame->slots[i];
if (slot->saveSlot < 0) {
continue;
}
graphicsCopyImage(
renderState,
slot->imageData,
CHAPTER_IMAGE_WIDTH, CHAPTER_IMAGE_HEIGHT,
0, 0,
slot->x + 5, slot->y + 5,
CHAPTER_IMAGE_WIDTH, CHAPTER_IMAGE_HEIGHT,
gColorWhite
);
}
gDPPipeSync(renderState->dl++);
gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WD, SCREEN_HT);
}

34
src/menu/load_game.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef __MENU_LOAD_GAME_H__
#define __MENU_LOAD_GAME_H__
#include "./menu.h"
#include "../graphics/graphics.h"
#include "../savefile/savefile.h"
#include "./new_game_menu.h"
struct LoadGameSlot {
Gfx* testChamberText;
Gfx* border;
Gfx* gameId;
short x, y;
short saveSlot;
void* imageData;
};
#define MAX_VISIBLE_SLOTS 3
struct LoadGameMenu {
Gfx* menuOutline;
Gfx* loadGameText;
struct SaveSlotInfo slotInfo[MAX_SAVE_SLOTS];
struct LoadGameSlot slots[MAX_VISIBLE_SLOTS];
short numberOfSaves;
short scrollOffset;
short selectedSave;
};
void loadGameMenuInit(struct LoadGameMenu* loadGame);
enum MenuDirection loadGameUpdate(struct LoadGameMenu* loadGame);
void loadGameRender(struct LoadGameMenu* loadGame, struct RenderState* renderState, struct GraphicsTask* task);
#endif

View file

@ -22,6 +22,7 @@ void mainMenuInit(struct MainMenu* mainMenu) {
landingMenuInit(&mainMenu->landingMenu);
newGameInit(&mainMenu->newGameMenu);
loadGameMenuInit(&mainMenu->loadGameMenu);
optionsMenuInit(&mainMenu->optionsMenu);
mainMenu->state = MainMenuStateLanding;
@ -31,6 +32,14 @@ void mainMenuInit(struct MainMenu* mainMenu) {
gScene.camera.fov = 56.0f;
}
enum MainMenuState mainMenuDirectionToState(enum MenuDirection direction, enum MainMenuState currentState) {
if (direction == MenuDirectionUp) {
return MainMenuStateLanding;
}
return currentState;
}
void mainMenuUpdate(struct MainMenu* mainMenu) {
if (!skAnimatorIsRunning(&gScene.animator.animators[TEST_CHAMBER_00_TEST_CHAMBER_00_ARMATURE_CAMERA])) {
sceneAnimatorPlay(
@ -50,10 +59,13 @@ void mainMenuUpdate(struct MainMenu* mainMenu) {
mainMenu->state = landingMenuUpdate(&mainMenu->landingMenu);
break;
case MainMenuStateNewGame:
mainMenu->state = newGameUpdate(&mainMenu->newGameMenu);
mainMenu->state = mainMenuDirectionToState(newGameUpdate(&mainMenu->newGameMenu), mainMenu->state);
break;
case MainMenuStateLoadGame:
mainMenu->state = mainMenuDirectionToState(loadGameUpdate(&mainMenu->loadGameMenu), mainMenu->state);
break;
case MainMenuStateOptions:
mainMenu->state = optionsMenuUpdate(&mainMenu->optionsMenu);
mainMenu->state = mainMenuDirectionToState(optionsMenuUpdate(&mainMenu->optionsMenu), mainMenu->state);
break;
}
}
@ -88,6 +100,9 @@ void mainMenuRender(struct MainMenu* mainMenu, struct RenderState* renderState,
case MainMenuStateNewGame:
newGameRender(&mainMenu->newGameMenu, renderState, task);
break;
case MainMenuStateLoadGame:
loadGameRender(&mainMenu->loadGameMenu, renderState, task);
break;
case MainMenuStateOptions:
optionsMenuRender(&mainMenu->optionsMenu, renderState, task);
break;

View file

@ -8,11 +8,13 @@
#include "./landing_menu.h"
#include "./new_game_menu.h"
#include "./options_menu.h"
#include "./load_game.h"
struct MainMenu {
enum MainMenuState state;
struct LandingMenu landingMenu;
struct NewGameMenu newGameMenu;
struct LoadGameMenu loadGameMenu;
struct OptionsMenu optionsMenu;
};

View file

@ -4,6 +4,7 @@
enum MainMenuState {
MainMenuStateLanding,
MainMenuStateNewGame,
MainMenuStateLoadGame,
MainMenuStateOptions,
};

View file

@ -28,9 +28,17 @@ struct Chapter gChapters[] = {
{NULL, NULL, NULL},
};
#define CHAPTER_COUNT (sizeof(gChapters) / sizeof(*gChapters))
#define CHAPTER_COUNT ((sizeof(gChapters) / sizeof(*gChapters)) - 1)
#define CHAPTER_IMAGE_SIZE (84 * 48 * 2)
struct Chapter* chapterFindForChamber(int chamberIndex) {
for (int i = 1; i < CHAPTER_COUNT; ++i) {
if (gChapters[i].testChamberNumber > chamberIndex) {
return &gChapters[i - 1];
}
}
return &gChapters[CHAPTER_COUNT - 1];
}
void chapterMenuInit(struct ChapterMenu* chapterMenu, int x, int y) {
chapterMenu->chapterText = malloc(sizeof(Gfx) * GFX_ENTRIES_PER_IMAGE * 10 + GFX_ENTRIES_PER_END_DL);
@ -39,7 +47,7 @@ void chapterMenuInit(struct ChapterMenu* chapterMenu, int x, int y) {
x, y + 27,
92, 58,
x + 5, y + 32,
84, 48
CHAPTER_IMAGE_WIDTH, CHAPTER_IMAGE_HEIGHT
);
chapterMenu->imageBuffer = malloc(CHAPTER_IMAGE_SIZE);
@ -110,9 +118,9 @@ void newGameInit(struct NewGameMenu* newGameMenu) {
newGameMenu->selectedChapter = 0;
}
enum MainMenuState newGameUpdate(struct NewGameMenu* newGameMenu) {
enum MenuDirection newGameUpdate(struct NewGameMenu* newGameMenu) {
if (controllerGetButtonDown(0, B_BUTTON)) {
return MainMenuStateLanding;
return MenuDirectionUp;
}
if (controllerGetButtonDown(0, A_BUTTON) && gChapters[newGameMenu->selectedChapter + 1].testChamberNumber >= 0) {
@ -124,7 +132,7 @@ enum MainMenuState newGameUpdate(struct NewGameMenu* newGameMenu) {
}
if ((controllerGetDirectionDown(0) & ControllerDirectionRight) != 0 &&
newGameMenu->selectedChapter + 1 < CHAPTER_COUNT &&
newGameMenu->selectedChapter < CHAPTER_COUNT &&
gChapters[newGameMenu->selectedChapter + 1].imageData) {
newGameMenu->selectedChapter = newGameMenu->selectedChapter + 1;
}
@ -142,7 +150,7 @@ enum MainMenuState newGameUpdate(struct NewGameMenu* newGameMenu) {
chapterMenuSetChapter(&newGameMenu->chapter1, &gChapters[newGameMenu->chapterOffset + 1]);
}
return MainMenuStateNewGame;
return MenuDirectionStay;
}
void newGameRender(struct NewGameMenu* newGameMenu, struct RenderState* renderState, struct GraphicsTask* task) {

View file

@ -5,6 +5,11 @@
#include "./menu.h"
#include "./menu_state.h"
#define CHAPTER_IMAGE_WIDTH 84
#define CHAPTER_IMAGE_HEIGHT 48
#define CHAPTER_IMAGE_SIZE (CHAPTER_IMAGE_WIDTH * CHAPTER_IMAGE_HEIGHT * 2)
struct Chapter {
char* chapter;
char* testChamber;
@ -22,6 +27,8 @@ struct ChapterMenu {
int y;
};
struct Chapter* chapterFindForChamber(int chamberIndex);
void chapterMenuInit(struct ChapterMenu* chapterMenu, int x, int y);
void chapterMenuSetChapter(struct ChapterMenu* chapterMenu, struct Chapter* chapter);
@ -38,7 +45,7 @@ struct NewGameMenu {
};
void newGameInit(struct NewGameMenu* newGameMenu);
enum MainMenuState newGameUpdate(struct NewGameMenu* newGameMenu);
enum MenuDirection newGameUpdate(struct NewGameMenu* newGameMenu);
void newGameRender(struct NewGameMenu* newGameMenu, struct RenderState* renderState, struct GraphicsTask* task);
#endif

View file

@ -3,6 +3,8 @@
#include "../font/font.h"
#include "../font/dejavusans.h"
#include "../savefile/savefile.h"
#include "../build/assets/materials/ui.h"
#include "../controls/controller.h"
@ -43,7 +45,7 @@ void optionsMenuInit(struct OptionsMenu* options) {
audioOptionsInit(&options->audioOptions);
}
enum MainMenuState optionsMenuUpdate(struct OptionsMenu* options) {
enum MenuDirection optionsMenuUpdate(struct OptionsMenu* options) {
enum MenuDirection menuDirection = MenuDirectionStay;
switch (options->tabs.selectedTab) {
@ -56,7 +58,8 @@ enum MainMenuState optionsMenuUpdate(struct OptionsMenu* options) {
}
if (menuDirection == MenuDirectionUp) {
return MainMenuStateLanding;
savefileSave();
return MenuDirectionUp;
}
if (menuDirection == MenuDirectionLeft) {
@ -78,7 +81,7 @@ enum MainMenuState optionsMenuUpdate(struct OptionsMenu* options) {
}
return MainMenuStateOptions;
return MenuDirectionStay;
}
void optionsMenuRender(struct OptionsMenu* options, struct RenderState* renderState, struct GraphicsTask* task) {

View file

@ -26,7 +26,7 @@ struct OptionsMenu {
};
void optionsMenuInit(struct OptionsMenu* options);
enum MainMenuState optionsMenuUpdate(struct OptionsMenu* options);
enum MenuDirection optionsMenuUpdate(struct OptionsMenu* options);
void optionsMenuRender(struct OptionsMenu* options, struct RenderState* renderState, struct GraphicsTask* task);
#endif

View file

@ -40,9 +40,6 @@ int checkpointCutsceneCount() {
int checkpointEstimateSize(struct Scene* scene) {
int result = 0;
// test chamber index
result += sizeof(char);
int binCount = SIGNAL_BIN_COUNT(gSignalCount);
result += sizeof(unsigned long long) * binCount * 2;
@ -67,10 +64,6 @@ int checkpointExists() {
return 0;
}
int checkpointLevelIndex(Checkpoint checkpoint) {
return *((unsigned char*)checkpoint);
}
void checkpointSave(struct Scene* scene) {
int size = checkpointEstimateSize(scene);
@ -81,10 +74,6 @@ void checkpointSave(struct Scene* scene) {
void* curr = gCheckpoint;
char testChamberIndex = gCurrentLevelIndex;
curr = checkpointWrite(curr, 1, &testChamberIndex);
int binCount = SIGNAL_BIN_COUNT(gSignalCount);
curr = checkpointWrite(curr, sizeof(unsigned long long) * binCount, gSignals);
curr = checkpointWrite(curr, sizeof(unsigned long long) * binCount, gDefaultSignals);
@ -116,10 +105,6 @@ void checkpointLoadLast(struct Scene* scene) {
void* curr = gCheckpoint;
char testChamberIndex;
curr = checkpointRead(curr, sizeof(char), &testChamberIndex);
int binCount = SIGNAL_BIN_COUNT(gSignalCount);
curr = checkpointRead(curr, sizeof(unsigned long long) * binCount, gSignals);
curr = checkpointRead(curr, sizeof(unsigned long long) * binCount, gDefaultSignals);

View file

@ -16,6 +16,5 @@ void checkpointClear();
void checkpointSave(struct Scene* scene);
void checkpointLoadLast(struct Scene* scene);
int checkpointExists();
int checkpointLevelIndex(Checkpoint checkpoint);
#endif

View file

@ -135,7 +135,7 @@ int savefileReadFlags(enum SavefileFlags flags) {
#define SAVE_SLOT_SRAM_ADDRESS(index) (SRAM_ADDR + (1 + (index)) * MAX_CHECKPOINT_SIZE)
void savefileSaveGame(Checkpoint checkpoint, int isAutosave) {
void savefileSaveGame(Checkpoint checkpoint, int testChamberIndex, int isAutosave) {
int slotIndex = 0;
if (!isAutosave) {
@ -162,27 +162,24 @@ void savefileSaveGame(Checkpoint checkpoint, int isAutosave) {
osSetTimer(&timer, SRAM_CHUNK_DELAY, 0, &timerQueue, 0);
(void) osRecvMesg(&timerQueue, NULL, OS_MESG_BLOCK);
gSaveData.saveSlotTestChamber[slotIndex] = checkpointLevelIndex(checkpoint);
gSaveData.saveSlotTestChamber[slotIndex] = testChamberIndex;
if (isAutosave) {
if (!(gSaveData.header.flags & SavefileFlagsHasAutosave)) {
gSaveData.header.flags |= SavefileFlagsHasAutosave;
savefileSave();
}
} else {
gSaveData.header.nextSaveSlot = slotIndex + 1;
if (gSaveData.header.nextSaveSlot >= MAX_SAVE_SLOTS) {
gSaveData.header.nextSaveSlot = 1;
}
return;
}
++gSaveData.header.saveSlotCount;
gSaveData.header.nextSaveSlot = slotIndex + 1;
if (gSaveData.header.nextSaveSlot >= MAX_SAVE_SLOTS) {
gSaveData.header.nextSaveSlot = 1;
}
++gSaveData.header.saveSlotCount;
if (gSaveData.header.saveSlotCount >= MAX_USER_SAVE_SLOTS) {
gSaveData.header.saveSlotCount = MAX_USER_SAVE_SLOTS;
if (gSaveData.header.saveSlotCount >= MAX_USER_SAVE_SLOTS) {
gSaveData.header.saveSlotCount = MAX_USER_SAVE_SLOTS;
}
}
savefileSave();

View file

@ -56,7 +56,7 @@ void savefileSetFlags(enum SavefileFlags flags);
void savefileUnsetFlags(enum SavefileFlags flags);
int savefileReadFlags(enum SavefileFlags flags);
void savefileSaveGame(Checkpoint checkpoint, int isAutosave);
void savefileSaveGame(Checkpoint checkpoint, int testChamberIndex, int isAutosave);
int savefileListSaves(struct SaveSlotInfo* slots);
void savefileLoadGame(int slot, Checkpoint checkpoint);