#include "gui.h" #include #include #include "datatypes.h" #include "stage.h" #include "delays.h" #include "util.h" /* Copyright (c) 2013-2021 Devine Lu Linvega 2018 web port by rezmason 2021 C89 port by rezmason Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ #define PATH_LENGTH 64 #define NODE_RENDER_PATH "graphics/node_render/%s.%i" #define CURSOR_BORDER 32 #define NUDGE_MULT 0.025 #define loadCursor(cursor, path) success &= Loader_LoadCursor(&cursor, "graphics/cursor/" path) #define loadImage(asset, path) success &= Loader_LoadImage(Loader_CreateImage(&asset, LOADTYPE_MANUAL, "graphics/interface/" path)) #define lazyLoadImage(asset, path) Loader_CreateImage(&asset, LOADTYPE_LAZY, "graphics/interface/" path) #define lazierLoadImage(asset, path) Loader_CreateImage(&asset, LOADTYPE_LAZIER, "graphics/interface/" path) #define loadLogo(asset, path) Loader_CreateImage(&asset, LOADTYPE_LAZIER, "graphics/logos/" path) static const char *modifierNames[] = { "", ".filled", ".empty", ".on", ".open", ".secret", ".seal.1", ".seal.2", ".unlocked", ".seal.1", ".seal.2", ".seal.both", ".exit"}; static SDL_Cursor *cursorsByType[NumberOfCursorTypes][2]; static CursorType currentCursorType = CURSORTYPE_FORWARD; static int cursorPressed = 0; static CursorType actionCursorType = CURSORTYPE_FORWARD; static int actionTriggerActive; static SDL_Color red = {0xFF, 0x0, 0x0, 0xFF}; static SDL_Color cyan = {0x72, 0xDE, 0xC2, 0xFF}; static Image *iconsByType[NumberOfIconTypes]; static Image *clocksByType[NumberOfClockTypes]; static Image *mazeIconsByAxisAndInstruction[NumberOfMazeAxes][NumberOfMazeInstructions]; static Image *progressPanesByChapter[NumberOfChapters]; static Image *sealsByZone[NumberOfZones]; static Image *ententeProgressPane; static Image *menuControls; static Image *menuLogo; static Image *vignette; static Image *black; static Image *logos[5]; static int nodeImageIndex = 0; static Image *nodeImages[2]; static char nodeImagePaths[2][PATH_LENGTH]; static int logoDelays[10]; static char *creditURLs[5] = { "https://xxiivv.com", "https://rezmason.net", "https://aliceffekt.bandcamp.com", "https://100r.co", "https://git.sr.ht/~rabbits/hiversaires"}; static int creditIndex; static int showedURL = 0; int GUI_PreloadAssets(void) { int success = 1; /* Cursors get loaded immediately */ loadCursor(cursorsByType[CURSORTYPE_FUSE][0], "fuse.png"); loadCursor(cursorsByType[CURSORTYPE_FUSE][1], "fuse.png"); loadCursor(cursorsByType[CURSORTYPE_FORWARD][0], "pointer.up.png"); loadCursor(cursorsByType[CURSORTYPE_FORWARD][1], "pointer.up.pressed.png"); loadCursor(cursorsByType[CURSORTYPE_LEFT][0], "pointer.left.png"); loadCursor(cursorsByType[CURSORTYPE_LEFT][1], "pointer.left.pressed.png"); loadCursor(cursorsByType[CURSORTYPE_RIGHT][0], "pointer.right.png"); loadCursor(cursorsByType[CURSORTYPE_RIGHT][1], "pointer.right.pressed.png"); cursorsByType[CURSORTYPE_SYSTEM][0] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); cursorsByType[CURSORTYPE_SYSTEM][1] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); /* HUD images get loaded immediately */ loadImage(iconsByType[ICONTYPE_ALERT], "alert.svg"); loadImage(iconsByType[ICONTYPE_CLOCK_0], "clock.0.svg"); loadImage(iconsByType[ICONTYPE_CLOCK_1], "clock.1.svg"); loadImage(iconsByType[ICONTYPE_CLOCK_2], "clock.2.svg"); loadImage(iconsByType[ICONTYPE_FOOTSTEP], "footstep.svg"); loadImage(iconsByType[ICONTYPE_FUSE_0], "fuse.0.svg"); loadImage(iconsByType[ICONTYPE_FUSE_1], "fuse.1.svg"); loadImage(iconsByType[ICONTYPE_FUSE_2], "fuse.2.svg"); loadImage(iconsByType[ICONTYPE_FUSE_3], "fuse.3.svg"); loadImage(iconsByType[ICONTYPE_MUSIC_OFF], "music.off.svg"); loadImage(iconsByType[ICONTYPE_MUSIC_ON], "music.on.svg"); loadImage(iconsByType[ICONTYPE_SAVE], "save.svg"); loadImage(sealsByZone[ZONE_ANTECHANNEL], "seal.antechannel.svg"); loadImage(sealsByZone[ZONE_CAPSULE], "seal.capsule.svg"); loadImage(sealsByZone[ZONE_CIRCULAR], "seal.circular.svg"); loadImage(sealsByZone[ZONE_ENTENTE], "seal.entente.svg"); loadImage(sealsByZone[ZONE_FOREST], "seal.forest.svg"); loadImage(sealsByZone[ZONE_METAMONDST], "seal.metamondst.svg"); loadImage(sealsByZone[ZONE_NATANIEV], "seal.nataniev.svg"); loadImage(sealsByZone[ZONE_NETHER], "seal.nether.svg"); loadImage(sealsByZone[ZONE_NONE], "seal.none.svg"); loadImage(sealsByZone[ZONE_RAINRE], "seal.rainre.svg"); loadImage(sealsByZone[ZONE_STONES], "seal.stones.svg"); loadImage(sealsByZone[ZONE_STUDIO], "seal.studio.svg"); loadImage(sealsByZone[ZONE_TERMINAL], "seal.terminal.svg"); /* Clock, maze and progress images can be loaded once they're needed */ lazyLoadImage(clocksByType[CLOCKTYPE_SHADOW], "dimclock.shadow.svg"); lazyLoadImage(clocksByType[CLOCKTYPE_STATE_0], "dimclock.state0.svg"); lazyLoadImage(clocksByType[CLOCKTYPE_STATE_1], "dimclock.state1.svg"); lazyLoadImage(clocksByType[CLOCKTYPE_STATE_2], "dimclock.state2.svg"); lazyLoadImage(mazeIconsByAxisAndInstruction[MAZEAXIS_X][MAZEINSTRUCTION_LEFT], "entente.x.left.svg"); lazyLoadImage(mazeIconsByAxisAndInstruction[MAZEAXIS_X][MAZEINSTRUCTION_RIGHT], "entente.x.right.svg"); lazyLoadImage(mazeIconsByAxisAndInstruction[MAZEAXIS_X][MAZEINSTRUCTION_STRAIGHT], "entente.x.straight.svg"); lazyLoadImage(mazeIconsByAxisAndInstruction[MAZEAXIS_Y][MAZEINSTRUCTION_LEFT], "entente.y.left.svg"); lazyLoadImage(mazeIconsByAxisAndInstruction[MAZEAXIS_Y][MAZEINSTRUCTION_RIGHT], "entente.y.right.svg"); lazyLoadImage(mazeIconsByAxisAndInstruction[MAZEAXIS_Y][MAZEINSTRUCTION_STRAIGHT], "entente.y.straight.svg"); lazyLoadImage(progressPanesByChapter[CHAPTER_ACT1], "progress.act1.svg"); lazyLoadImage(progressPanesByChapter[CHAPTER_ACT2], "progress.act2.svg"); lazyLoadImage(progressPanesByChapter[CHAPTER_ACT3], "progress.act3.svg"); lazyLoadImage(progressPanesByChapter[CHAPTER_ACT4], "progress.act4.svg"); lazyLoadImage(progressPanesByChapter[CHAPTER_ACT5], "progress.act5.svg"); lazyLoadImage(ententeProgressPane, "progress.entente.svg"); /* The full-screen menus are huge and rarely needed */ lazierLoadImage(menuControls, "menu.controls.svg"); lazierLoadImage(menuLogo, "menu.logo.svg"); /* The splash screen images only show up once */ loadLogo(logos[0], "100R.svg"); loadLogo(logos[1], "xxiivv.svg"); loadLogo(logos[2], "rm.svg"); loadLogo(logos[3], "aliceffekt.svg"); loadLogo(logos[4], "hiversaires_source.svg"); /* This one's interesting: the vignette is a full-screen radial gradient that flashes almost every time the player performs an action. So it's loaded when the game initializes, but it's a very small SVG that's rendered very large. */ loadImage(vignette, "vignette.svg"); loadImage(black, "black.svg"); return success; } void GUI_Init(void) { Stage_SetAlpha(BILLBOARD_HUD_STEP_RIGHT, 0); Stage_SetAlpha(BILLBOARD_HUD_STEP_FORWARD, 0); Stage_SetAlpha(BILLBOARD_HUD_STEP_LEFT, 0); Stage_SetAlpha(BILLBOARD_HUD_CLOCK_ALERT, 0); Stage_SetAlpha(BILLBOARD_HUD_SEAL_ALERT, 0); Stage_SetAlpha(BILLBOARD_HUD_FUSE_ALERT, 0); Stage_SetAlpha(BILLBOARD_HUD_SAVE, 0); Stage_SetAlpha(BILLBOARD_CLOCK_SHADOW, 0); Stage_SetAlpha(BILLBOARD_VIGNETTE, 0); Stage_SetAlpha(BILLBOARD_HIVERSAIRES_LOGO, 0); Stage_SetAlpha(BILLBOARD_CONTROLS, 0); Stage_SetAlpha(BILLBOARD_LOGO, 0); /* Most HUD elements occupy a Stage region for the whole game */ nodeImageIndex = 0; Stage_SetImage(BILLBOARD_NODE, nodeImages[0]); Stage_SetImage(BILLBOARD_LAST_NODE_FADE, nodeImages[1]); Stage_SetImage(BILLBOARD_HUD_STEP_RIGHT, iconsByType[ICONTYPE_FOOTSTEP]); Stage_SetImage(BILLBOARD_HUD_STEP_FORWARD, iconsByType[ICONTYPE_FOOTSTEP]); Stage_SetImage(BILLBOARD_HUD_STEP_LEFT, iconsByType[ICONTYPE_FOOTSTEP]); Stage_SetImage(BILLBOARD_HUD_CLOCK_ALERT, iconsByType[ICONTYPE_ALERT]); Stage_SetImage(BILLBOARD_HUD_SEAL_ALERT, iconsByType[ICONTYPE_ALERT]); Stage_SetImage(BILLBOARD_HUD_FUSE_ALERT, iconsByType[ICONTYPE_ALERT]); Stage_SetImage(BILLBOARD_HUD_SAVE, iconsByType[ICONTYPE_SAVE]); Stage_SetImage(BILLBOARD_CLOCK_SHADOW, clocksByType[CLOCKTYPE_SHADOW]); Stage_SetImage(BILLBOARD_VIGNETTE, vignette); Stage_SetImage(BILLBOARD_BLACK, black); Stage_SetImage(BILLBOARD_HIVERSAIRES_LOGO, menuLogo); Stage_SetImage(BILLBOARD_CONTROLS, menuControls); SDL_SetCursor(cursorsByType[currentCursorType][cursorPressed]); Loader_CreateImage(&nodeImages[0], LOADTYPE_LAZIER, nodeImagePaths[0]); Loader_CreateImage(&nodeImages[1], LOADTYPE_LAZIER, nodeImagePaths[1]); } void GUI_Quit(void) { int i, j; for(i = 0; i < NumberOfCursorTypes; i++) { SDL_FreeCursor(cursorsByType[i][0]); SDL_FreeCursor(cursorsByType[i][1]); cursorsByType[i][0] = NULL; cursorsByType[i][1] = NULL; } for(i = 0; i < NumberOfIconTypes; i++) { Loader_DestroyImage(iconsByType[i]); iconsByType[i] = NULL; } for(i = 0; i < NumberOfClockTypes; i++) { Loader_DestroyImage(clocksByType[i]); clocksByType[i] = NULL; } for(i = 0; i < NumberOfMazeAxes; i++) { for(j = 0; j < NumberOfMazeInstructions; j++) { Loader_DestroyImage(mazeIconsByAxisAndInstruction[i][j]); mazeIconsByAxisAndInstruction[i][j] = NULL; } } for(i = 0; i < NumberOfChapters; i++) { Loader_DestroyImage(progressPanesByChapter[i]); progressPanesByChapter[i] = NULL; } for(i = 0; i < NumberOfZones; i++) { Loader_DestroyImage(sealsByZone[i]); sealsByZone[i] = NULL; } Loader_DestroyImage(ententeProgressPane); ententeProgressPane = NULL; Loader_DestroyImage(menuControls); menuControls = NULL; Loader_DestroyImage(menuLogo); menuLogo = NULL; Loader_DestroyImage(vignette); vignette = NULL; Loader_DestroyImage(black); black = NULL; for(i = 0; i < 5; i++) { Loader_DestroyImage(logos[i]); logos[i] = NULL; } Loader_DestroyImage(nodeImages[0]); Loader_DestroyImage(nodeImages[1]); } void GUI_SetActionTrigger(int active) { actionTriggerActive = active; } void GUI_HideCursor(void) { SDL_ShowCursor(0); } void GUI_UpdateCursor(int mouseX, int mouseY, int pressed) { CursorType type; RegionName regionUnderMouse = GUI_GetRegionNameAt(mouseX, mouseY); if(Stage_PointNearBorder(mouseX, mouseY, CURSOR_BORDER)) { /* The system cursor is shown near the edge of the window, so that the game's cursors don't obstruct the player's view of their cursor while they resize or move the window. */ type = CURSORTYPE_SYSTEM; } else { switch(regionUnderMouse) { case TRIGGER_ACTION: type = actionCursorType; break; case TRIGGER_MOVE_FORWARD: type = CURSORTYPE_FORWARD; break; case TRIGGER_MOVE_LEFT: type = CURSORTYPE_LEFT; break; case TRIGGER_MOVE_RIGHT: type = CURSORTYPE_RIGHT; break; default: type = CURSORTYPE_FORWARD; break; } } SDL_ShowCursor(1); if(currentCursorType != type || cursorPressed != pressed) { currentCursorType = type; cursorPressed = pressed; SDL_SetCursor(cursorsByType[currentCursorType][cursorPressed]); } } void GUI_EnableFuseCursor(int enable) { int currentCursorIsActionCursor = currentCursorType == actionCursorType; actionCursorType = enable ? CURSORTYPE_FUSE : CURSORTYPE_FORWARD; if(currentCursorIsActionCursor) { currentCursorType = actionCursorType; SDL_SetCursor(cursorsByType[currentCursorType][cursorPressed]); } } RegionName GUI_GetRegionNameAt(int mouseX, int mouseY) { int i = actionTriggerActive ? TRIGGER_ACTION : TRIGGER_MOVE_FORWARD; for(; i <= TRIGGER_MOVE_RIGHT; i++) { if(Stage_HitTest(i, mouseX, mouseY)) { return i; } } return TRIGGER_MOVE_FORWARD; } void GUI_Reset(void) { GUI_HideMenu(); Stage_SetAlpha(BILLBOARD_LAST_NODE_FADE, 0); Stage_SetAlpha(BILLBOARD_CLOCK, 0); Stage_SetAlpha(BILLBOARD_CLOCK_SHADOW, 0); Stage_SetAlpha(BILLBOARD_PROGRESS_PANE, 0); Stage_SetAlpha(BILLBOARD_ENTENTE_SCREEN, 0); } void GUI_ShowClockFace(int state, int refresh) { Stage_SetImage(BILLBOARD_CLOCK, clocksByType[CLOCKTYPE_STATE_0 + state]); if(!refresh) { Stage_Fade(BILLBOARD_CLOCK_SHADOW, 0, 0.23, 1.5, 0.5); Stage_Fade(BILLBOARD_CLOCK, 0, 1, 0.5, 0.5); } else { Stage_SetAlpha(BILLBOARD_CLOCK_SHADOW, 0.23); Stage_SetAlpha(BILLBOARD_CLOCK, 1); } } void GUI_ShowClock(int state) { Stage_SetImage(BILLBOARD_HUD_CLOCK, iconsByType[ICONTYPE_CLOCK_0 + state]); Stage_Fade(BILLBOARD_HUD_CLOCK, 1, 0, 0.5, 3); } void GUI_ShowClockAlert(void) { Stage_Fade(BILLBOARD_HUD_CLOCK_ALERT, 1, 0, 0.5, 0.5); } void GUI_ShowSeals(Zone zoneP, Zone zoneQ) { /* For aesthetic reasons, seals are always presented in a particular order. */ Zone zone1, zone2; if((zoneP > ZONE_NONE && zoneP < zoneQ) || zoneQ == ZONE_NONE) { zone1 = zoneP; zone2 = zoneQ; } else { zone1 = zoneQ; zone2 = zoneP; } Stage_SetImage(BILLBOARD_HUD_SEAL_1, sealsByZone[zone1]); Stage_SetImage(BILLBOARD_HUD_SEAL_2, sealsByZone[zone2]); Stage_Fade(BILLBOARD_HUD_SEAL_1, 1, 0, 0.5, 3); Stage_Fade(BILLBOARD_HUD_SEAL_2, 1, 0, 0.5, 3); } void GUI_ShowSealAlert(void) { Stage_Fade(BILLBOARD_HUD_SEAL_ALERT, 1, 0, 0.5, 0.5); } void GUI_ShowEnergy(int level) { Stage_SetImage(BILLBOARD_HUD_FUSE, iconsByType[ICONTYPE_FUSE_0 + level]); Stage_Fade(BILLBOARD_HUD_FUSE, 1, 0, 0.5, 3); } void GUI_ShowEnergyAlert(void) { Stage_Fade(BILLBOARD_HUD_FUSE_ALERT, 1, 0, 1.5, 0.5); } void GUI_ShowAudio(int enabled) { Stage_SetImage(BILLBOARD_HUD_AUDIO, iconsByType[ICONTYPE_MUSIC_OFF + enabled]); Stage_Fade(BILLBOARD_HUD_AUDIO, 1, 0, 0.5, 3); } void GUI_HideMenu(void) { Stage_SetAlpha(BILLBOARD_BLACK, 0.); Stage_SetAlpha(BILLBOARD_HIVERSAIRES_LOGO, 0.); Stage_SetAlpha(BILLBOARD_CONTROLS, 0.); Stage_SetAlpha(BILLBOARD_LOGO, 0.); } void GUI_ShowHomeMenu(void) { Stage_SetAlpha(BILLBOARD_HUD_SEAL_1, 0); Stage_SetAlpha(BILLBOARD_HUD_SEAL_2, 0); Stage_SetAlpha(BILLBOARD_HUD_FUSE, 0); Stage_SetAlpha(BILLBOARD_HUD_SAVE, 0); Stage_SetAlpha(BILLBOARD_NODE, 1); Stage_Fade(BILLBOARD_BLACK, 1, 0, 2, 0); Stage_Fade(BILLBOARD_HIVERSAIRES_LOGO, 1, 0, 2, 3); Stage_Fade(BILLBOARD_CONTROLS, 1, 0, 1, 8); } void GUI_ShowMovement(int nudgeX, int nudgeY) { Stage_Nudge(nudgeX * NUDGE_MULT, nudgeY * NUDGE_MULT, 0.2); Stage_Fade(BILLBOARD_NODE, 0.5, 1, 0.2, 0); Stage_SetAlpha(BILLBOARD_LAST_NODE_FADE, 0); } void GUI_ShowNode(char *nodeName, Orientation orientation, NodeModifier modifier, double fadeDuration, double fadeDelay) { /* The main visual information in Hiversaires comes from the images loaded here. The previous node image often cross-fades into the current one. To accomplish this effect, Hiversaires takes the old image, swaps its region with LAST_NODE_FADE, and fades out on top of the new image. The last and current images are reused in alternating roles, similar to a double buffering game. */ char path[PATH_LENGTH]; int nextIndex = !nodeImageIndex; snprintf(path, PATH_LENGTH, NODE_RENDER_PATH "%s.jpg", nodeName, orientation, modifierNames[modifier]); if(strcmp(nodeImagePaths[nodeImageIndex], path) == 0) { return; } nodeImageIndex = nextIndex; strcpy(nodeImagePaths[nextIndex], path); Stage_SwapImages(BILLBOARD_LAST_NODE_FADE, BILLBOARD_NODE); Stage_SetImage(BILLBOARD_NODE, nodeImages[nodeImageIndex]); Stage_SetAlpha(BILLBOARD_NODE, 1); Stage_Fade(BILLBOARD_LAST_NODE_FADE, 1, 0, fadeDuration, fadeDelay); } static void splashNext(void *data) { Image *image = data; Stage_SetImage(BILLBOARD_LOGO, image); Stage_Fade(BILLBOARD_LOGO, 1, 0, 0.125, 0.675); } static void splashEnd(void *data) { FuncWrapper *wrapper = data; Stage_SetAlpha(BILLBOARD_LOGO, 0); wrapper->f(); free(wrapper); } void GUI_RunSplash(void (*onComplete)(void)) { Stage_SetAlpha(BILLBOARD_BLACK, 1); Stage_SetAlpha(BILLBOARD_LOGO, 1); Delays_Add(&logoDelays[0], 0.5 + 0.8 * 0, splashNext, logos[0]); Delays_Add(&logoDelays[1], 0.5 + 0.8 * 1, splashNext, logos[1]); Delays_Add(&logoDelays[2], 0.5 + 0.8 * 2, splashNext, logos[2]); Delays_Add(&logoDelays[3], 0.5 + 0.8 * 3, splashEnd, wrapFunction(onComplete)); } void GUI_SkipSplash(void) { Stage_SetAlpha(BILLBOARD_BLACK, 1); Stage_SetAlpha(BILLBOARD_LOGO, 0); Delays_Cancel(&logoDelays[0], 0); Delays_Cancel(&logoDelays[1], 0); Delays_Cancel(&logoDelays[2], 0); Delays_Cancel(&logoDelays[3], 1); } static void creditIn(void *data) { Image *image = data; creditIndex++; showedURL = 0; Stage_SetImage(BILLBOARD_LOGO, image); Stage_Fade(BILLBOARD_LOGO, 0, 1, 0.5, 0); } static void creditOut(void *data) { (void)data; Stage_Fade(BILLBOARD_LOGO, 1, 0, 0.5, 0); } void GUI_ShowCredits(int showSecret) { creditIndex = -1; Stage_Fade(BILLBOARD_BLACK, 0, 1, 3, 0); Delays_Add(&logoDelays[0], 3 + (0.5 + 5) * 0 + 0.5 * 0, creditIn, logos[1]); Delays_Add(&logoDelays[1], 3 + (0.5 + 5) * 1 + 0.5 * 0, creditOut, logos[1]); Delays_Add(&logoDelays[2], 3 + (0.5 + 5) * 1 + 0.5 * 1, creditIn, logos[2]); Delays_Add(&logoDelays[3], 3 + (0.5 + 5) * 2 + 0.5 * 1, creditOut, logos[2]); Delays_Add(&logoDelays[4], 3 + (0.5 + 5) * 2 + 0.5 * 2, creditIn, logos[3]); Delays_Add(&logoDelays[5], 3 + (0.5 + 5) * 3 + 0.5 * 2, creditOut, logos[3]); Delays_Add(&logoDelays[6], 3 + (0.5 + 5) * 3 + 0.5 * 3, creditIn, logos[0]); if(showSecret) { Delays_Add(&logoDelays[7], 3 + (0.5 + 5) * 4 + 0.5 * 3, creditOut, logos[0]); Delays_Add(&logoDelays[8], 3 + (0.5 + 5) * 4 + 0.5 * 4, creditIn, logos[4]); } } void GUI_LaunchCreditURL(void) { if(showedURL) { return; } showedURL = 1; SDL_OpenURL(creditURLs[creditIndex]); } void GUI_FlashVignette(void) { Stage_Fade(BILLBOARD_VIGNETTE, 1., 0., 1., 0.); } void GUI_ShowSave(void) { Stage_Fade(BILLBOARD_HUD_SAVE, 1, 0, 0.5, 3); } void GUI_ShowProgressScreen(Chapter chapter) { Stage_SetImage(BILLBOARD_PROGRESS_PANE, progressPanesByChapter[chapter]); Stage_Fade(BILLBOARD_PROGRESS_PANE, 0, 1, 0.5, 0.3); } void GUI_ShowEntenteScreen(void) { Stage_SetImage(BILLBOARD_ENTENTE_SCREEN, ententeProgressPane); Stage_Fade(BILLBOARD_PROGRESS_PANE, 0, 1, 0.5, 0.3); } void GUI_ShowMazeInstruction(MazeAxis axis, MazeInstruction instruction) { Stage_SetImage(BILLBOARD_ENTENTE_SCREEN, mazeIconsByAxisAndInstruction[axis][instruction]); Stage_Fade(BILLBOARD_ENTENTE_SCREEN, 0, 1, 1, 0); } void GUI_ShowFootstep(Footstep step) { RegionName name; switch(step) { case FOOTSTEP_LEFT: name = BILLBOARD_HUD_STEP_LEFT; break; case FOOTSTEP_RIGHT: name = BILLBOARD_HUD_STEP_RIGHT; break; default: name = BILLBOARD_HUD_STEP_FORWARD; break; } Stage_Fade(name, 1, 0, 0.5, 0); } void GUI_TintRed(void) { Stage_Tint(red, 2.1, -0.1); } void GUI_TintCyan(void) { Stage_Tint(cyan, 2.1, -0.1); } void GUI_StopTint(void) { Stage_StopTint(); }