Loading screen (fixes #325 )

This commit is contained in:
Cong
2022-04-11 20:03:48 +10:00
parent 5ba64aee77
commit 689bf3d83a
12 changed files with 148 additions and 171 deletions

BIN
graphics/bigpanel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

View File

@@ -14,6 +14,7 @@ beam_8x8.png
beam_yellow_8x8.png
bench.png
bench_wreck.png
bigpanel.png
bloodstain.png
blueprint.png
bone_blood.png

View File

@@ -31,6 +31,7 @@
#include <cdogs/files.h>
#include <cdogs/font.h>
#include <cdogs/grafx_bg.h>
#include <cdogs/log.h>
#include <cdogs/music.h>
#include <cdogs/objective.h>
@@ -50,6 +51,8 @@ typedef struct
{
EventWaitResult waitResult;
CampaignSetting *c;
GameMode gameMode;
const CampaignEntry *entry;
} ScreenCampaignIntroData;
static void CampaignIntroTerminate(GameLoopData *data);
static void CampaignIntroOnEnter(GameLoopData *data);
@@ -57,11 +60,13 @@ static void CampaignIntroOnExit(GameLoopData *data);
static void CampaignIntroInput(GameLoopData *data);
static GameLoopResult CampaignIntroUpdate(GameLoopData *data, LoopRunner *l);
static void CampaignIntroDraw(GameLoopData *data);
GameLoopData *ScreenCampaignIntro(CampaignSetting *c)
GameLoopData *ScreenCampaignIntro(CampaignSetting *c, const GameMode gameMode, const CampaignEntry *entry)
{
ScreenCampaignIntroData *data;
CMALLOC(data, sizeof *data);
data->c = c;
data->gameMode = gameMode;
data->entry = entry;
return GameLoopDataNew(
data, CampaignIntroTerminate, CampaignIntroOnEnter,
CampaignIntroOnExit, CampaignIntroInput, CampaignIntroUpdate,
@@ -74,18 +79,23 @@ static void CampaignIntroTerminate(GameLoopData *data)
}
static void CampaignIntroOnEnter(GameLoopData *data)
{
ScreenCampaignIntroData *mData = data->Data;
MusicPlayFromChunk(
&gSoundDevice.music, MUSIC_MENU, &mData->c->CustomSongs[MUSIC_MENU]);
ScreenCampaignIntroData *sData = data->Data;
gCampaign.Entry.Mode = sData->gameMode;
if (!gCampaign.IsLoaded && !CampaignLoad(&gCampaign, sData->entry))
{
// Failed to load
LOG(LM_MAIN, LL_ERROR, "cannot load campaign %s", sData->entry->Info);
}
else
{
MusicPlayFromChunk(
&gSoundDevice.music, MUSIC_MENU, &sData->c->CustomSongs[MUSIC_MENU]);
}
}
static void CampaignIntroOnExit(GameLoopData *data)
{
const ScreenCampaignIntroData *sData = data->Data;
if (sData->waitResult != EVENT_WAIT_CANCEL)
{
MenuPlaySound(MENU_SOUND_ENTER);
}
else
if (sData->waitResult == EVENT_WAIT_CANCEL)
{
CampaignUnload(&gCampaign);
}
@@ -94,23 +104,27 @@ static void CampaignIntroInput(GameLoopData *data)
{
ScreenCampaignIntroData *sData = data->Data;
sData->waitResult = EventWaitForAnyKeyOrButton();
if (sData->waitResult == EVENT_WAIT_OK)
{
MenuPlaySound(MENU_SOUND_ENTER);
}
}
static GameLoopResult CampaignIntroUpdate(GameLoopData *data, LoopRunner *l)
{
const ScreenCampaignIntroData *sData = data->Data;
if (!IsIntroNeeded(gCampaign.Entry.Mode) ||
if (!gCampaign.IsLoaded || sData->waitResult == EVENT_WAIT_CANCEL)
{
LoopRunnerPop(l);
}
else if (!IsIntroNeeded(gCampaign.Entry.Mode) ||
sData->waitResult == EVENT_WAIT_OK)
{
// Switch to num players selection
LoopRunnerPush(
l, ScreenLoading(
"Loading campaign...", true,
NumPlayersSelection(&gGraphicsDevice, &gEventHandlers)));
}
else if (sData->waitResult == EVENT_WAIT_CANCEL)
{
LoopRunnerPop(l);
NumPlayersSelection(&gGraphicsDevice, &gEventHandlers), true));
}
return UPDATE_RESULT_OK;
}
@@ -246,11 +260,7 @@ static void MissionBriefingOnExit(GameLoopData *data)
{
const MissionBriefingData *mData = data->Data;
if (mData->waitResult == EVENT_WAIT_OK)
{
MenuPlaySound(MENU_SOUND_ENTER);
}
else
if (mData->waitResult != EVENT_WAIT_OK)
{
CampaignUnload(&gCampaign);
}
@@ -278,6 +288,7 @@ static void MissionBriefingInput(GameLoopData *data)
}
// Otherwise, exit out of loop
mData->waitResult = EVENT_WAIT_OK;
MenuPlaySound(MENU_SOUND_ENTER);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2014-2017, 2021 Cong Xu
Copyright (c) 2014-2017, 2021-2022 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
#include "game_loop.h"
GameLoopData *ScreenCampaignIntro(CampaignSetting *c);
GameLoopData *ScreenCampaignIntro(CampaignSetting *c, const GameMode gameMode, const CampaignEntry *entry);
GameLoopData *ScreenMissionBriefing(
CampaignSetting *c, const struct MissionOptions *m);
// Display a summary page at the end of a mission

View File

@@ -247,9 +247,9 @@ int main(int argc, char *argv[])
PlayerDataInit(&gPlayerDatas);
LoadingScreenDraw(&gLoadingScreen, "Loading main menu...", 1.0f);
LoopRunner l = LoopRunnerNew(NULL);
LoopRunner l = LoopRunnerNew();
LoopRunnerPush(&l, MainMenu(&gGraphicsDevice, &l));
LoopRunnerPush(&l, ScreenLoading("Loading main menu...", false, NULL));
LoopRunnerPush(&l, ScreenLoading("Loading main menu...", false, NULL, false));
if (connectAddr.host != 0)
{
if (NetClientTryScanAndConnect(&gNetClient, connectAddr.host))
@@ -295,8 +295,6 @@ int main(int argc, char *argv[])
LoopRunnerTerminate(&l);
bail:
LoadingScreenReload(&gLoadingScreen);
LoadingScreenDraw(&gLoadingScreen, "Quitting...", 1.0f);
NetServerTerminate(&gNetServer);
PlayerDataTerminate(&gPlayerDatas);
MapObjectsTerminate(&gMapObjects);

View File

@@ -611,7 +611,7 @@ static void NextLoop(RunGameData *rData, LoopRunner *l)
{
nextScreen = HighScoresScreen(rData->co, &gGraphicsDevice);
}
LoopRunnerPush(l, ScreenLoading("Debriefing...", true, nextScreen));
LoopRunnerPush(l, ScreenLoading("Debriefing...", true, nextScreen, true));
if (!HasRounds(rData->co->Entry.Mode) && !rData->co->IsComplete)
{
rData->co->MissionIndex = rData->m->NextMission;

View File

@@ -155,14 +155,10 @@ GameLoopData *GameLoopDataNew(
static GameLoopData *GetCurrentLoop(LoopRunner *l);
static GameLoopData *GetParentLoop(LoopRunner *l);
LoopRunner LoopRunnerNew(GameLoopData *newData)
LoopRunner LoopRunnerNew(void)
{
LoopRunner l;
CArrayInit(&l.Loops, sizeof(GameLoopData *));
if (newData != NULL)
{
LoopRunnerPush(&l, newData);
}
return l;
}
static void GameLoopTerminate(GameLoopData *data);
@@ -229,8 +225,19 @@ bool LoopRunnerRunInner(LoopRunInnerData *ctx)
}
else if (newData != ctx->data)
{
// State change; restart loop
GameLoopOnExit(ctx->data);
GameLoopData *parent = GetParentLoop(ctx->l);
CA_FOREACH(GameLoopData *, data, ctx->l->Loops)
if (*data == newData)
{
continue;
}
// Don't exit the parent yet if we need to draw it
if (*data == parent && newData->DrawParent && (*data)->DrawFunc)
{
continue;
}
GameLoopOnExit(*data);
CA_FOREACH_END()
ctx->data = newData;
GameLoopOnEnter(ctx->data);
ctx->p = LoopRunParamsNew(ctx->data);
@@ -275,6 +282,7 @@ bool LoopRunnerRunInner(LoopRunInnerData *ctx)
GameLoopData *parent = GetParentLoop(ctx->l);
if (parent && parent->DrawFunc)
{
GameLoopOnEnter(parent);
parent->DrawFunc(parent);
}
}
@@ -382,6 +390,7 @@ void LoopRunnerPush(LoopRunner *l, GameLoopData *newData)
void LoopRunnerPop(LoopRunner *l)
{
GameLoopData *data = GetCurrentLoop(l);
GameLoopOnExit(data);
data->IsUsed = false;
CArrayDelete(&l->Loops, l->Loops.size - 1);
}
@@ -397,15 +406,17 @@ static void GameLoopTerminate(GameLoopData *data)
static void GameLoopOnEnter(GameLoopData *data)
{
if (data->OnEnter)
if (!data->HasEntered && data->OnEnter)
{
data->OnEnter(data);
}
EventReset(&gEventHandlers);
data->HasEntered = true;
data->HasExited = false;
}
static void GameLoopOnExit(GameLoopData *data)
{
if (data->OnExit)
if (!data->HasExited && data->OnExit)
{
data->OnExit(data);
}
@@ -413,6 +424,8 @@ static void GameLoopOnExit(GameLoopData *data)
{
GameLoopTerminate(data);
}
data->HasExited = true;
data->HasEntered = false;
}
static GameLoopData *GetCurrentLoop(LoopRunner *l)

View File

@@ -60,6 +60,8 @@ typedef struct sGameLoopData
bool InputEverySecondFrame;
bool SkipNextFrame;
int Frames; // total frames looped
bool HasEntered;
bool HasExited;
bool HasDrawnFirst;
bool IsUsed;
bool DrawParent;
@@ -72,7 +74,7 @@ GameLoopData *GameLoopDataNew(
GameLoopResult (*updateFunc)(GameLoopData *, LoopRunner *),
void (*drawFunc)(GameLoopData *));
LoopRunner LoopRunnerNew(GameLoopData *newData);
LoopRunner LoopRunnerNew(void);
void LoopRunnerTerminate(LoopRunner *l);
void LoopRunnerRun(LoopRunner *l);

View File

@@ -44,104 +44,61 @@ void LoadingScreenInit(LoadingScreen *l, GraphicsDevice *g)
}
void LoadingScreenTerminate(LoadingScreen *l)
{
MapTerminate(&l->m);
DrawBufferTerminate(&l->db);
CArrayTerminate(&l->tileIndices);
CArrayTerminate(&l->panelIndices);
}
static void LazyLoad(LoadingScreen *l, const float showPct)
static void LazyLoad(LoadingScreen *l)
{
if (l->logo == NULL)
{
l->logo = PicManagerGetPic(&gPicManager, "logo");
}
bool mapCreated = false;
// Create map large enough to cover the entire screen
const struct vec2i mapSize = svec2i(X_TILES, Y_TILES);
if (gPicManager.tileStyleNames.size > 0 &&
(l->m.Size.x < mapSize.x || l->m.Size.y < mapSize.y))
if (l->panel == NULL)
{
// Map with floors only
Mission m;
MissionInit(&m);
m.Type = MAPTYPE_CAVE;
m.Size = mapSize;
m.u.Cave.Repeat = 1;
m.u.Cave.R1 = 9;
m.u.Cave.R2 = -1;
TileClassInit(
&m.u.Cave.TileClasses.Floor, &gPicManager, &gTileFloor,
IntFloorStyle(rand() % FLOOR_STYLE_COUNT),
TileClassBaseStyleType(TILE_CLASS_FLOOR),
RangeToColor(rand() % COLORRANGE_COUNT),
RangeToColor(rand() % COLORRANGE_COUNT));
m.u.Cave.ExitEnabled = false;
MapBuild(&l->m, &m, false, 0, GAME_MODE_NORMAL, NULL);
MapMarkAllAsVisited(&l->m);
DrawBufferInit(&l->db, mapSize, l->g);
mapCreated = true;
l->panel = PicManagerGetPic(&gPicManager, "bigpanel");
}
if (mapCreated || l->showPct != showPct)
// Init panel array large enough to cover the entire screen
if (l->panel)
{
// Show a random percent of tiles
l->showPct = showPct;
if (mapSize.x * mapSize.y != (int)l->tileIndices.size)
const struct vec2i panelsSize = svec2i_add(svec2i_divide(l->g->cachedConfig.Res, l->panel->size), svec2i_one());
if (panelsSize.x * panelsSize.y != (int)l->panelIndices.size)
{
CArrayTerminate(&l->tileIndices);
CArrayInit(&l->tileIndices, sizeof(int));
for (int i = 0; i < mapSize.x * mapSize.y; i++)
CArrayTerminate(&l->panelIndices);
CArrayInit(&l->panelIndices, sizeof(int));
for (int i = 0; i < panelsSize.x * panelsSize.y; i++)
{
CArrayPushBack(&l->tileIndices, &i);
CArrayPushBack(&l->panelIndices, &i);
}
CArrayShuffle(&l->tileIndices);
CArrayShuffle(&l->panelIndices);
}
const int nTiles = (int)(mapSize.x * mapSize.y * showPct);
CA_FOREACH(const int, tileIdx, l->tileIndices)
const int y = *tileIdx / mapSize.x;
const int x = *tileIdx - y * mapSize.x;
Tile *t = MapGetTile(&l->m, svec2i(x, y));
t->isVisited = _ca_index < nTiles;
CA_FOREACH_END()
}
if (gSoundDevice.isInitialised &&
(l->sndTick == NULL || l->sndComplete == NULL))
if (gSoundDevice.isInitialised && l->sndTick == NULL)
{
l->sndTick = StrSound("click");
l->sndComplete = StrSound("explosion_small");
}
}
static int ReloadTileClass(any_t data, any_t item)
{
PicManager *pm = data;
TileClass *t = item;
TileClassReloadPic(t, pm);
return MAP_OK;
}
void LoadingScreenReload(LoadingScreen *l)
{
if (hashmap_iterate(l->m.TileClasses, ReloadTileClass, &gPicManager) !=
MAP_OK)
{
CASSERT(false, "failed to reload tile classes");
}
}
static void LoadingScreenDrawInner(
LoadingScreen *l, const char *loadingText, const float showPct)
{
LazyLoad(l, showPct);
LazyLoad(l);
if (!svec2i_is_zero(l->m.Size))
if (l->panel)
{
DrawBufferSetFromMap(
&l->db, &l->m, Vec2CenterOfTile(svec2i_scale_divide(l->m.Size, 2)),
X_TILES);
DrawBufferArgs args;
memset(&args, 0, sizeof args);
DrawBufferDraw(&l->db, svec2i_zero(), &args);
const int stride = l->g->cachedConfig.Res.x / l->panel->size.x + 1;
CA_FOREACH(const int, panelIdx, l->panelIndices)
if (_ca_index > (int)(l->panelIndices.size * showPct))
{
break;
}
const int y = *panelIdx / stride;
const int x = *panelIdx - (y * stride);
PicRender(
l->panel, l->g->gameWindow.renderer, svec2i_multiply(svec2i(x, y), l->panel->size), colorWhite, 0,
svec2_one(), SDL_FLIP_NONE, Rect2iZero());
CA_FOREACH_END()
}
if (l->logo)
@@ -171,11 +128,7 @@ void LoadingScreenDraw(
WindowContextPostRender(&l->g->gameWindow);
Mix_Chunk *sound = showPct < 1.0f ? l->sndTick : l->sndComplete;
if (sound)
{
SoundPlay(&gSoundDevice, sound);
}
SoundPlayAtPlusDistance(&gSoundDevice, l->sndTick, gSoundDevice.earLeft1, 255);
SDL_Delay(70);
}
@@ -187,23 +140,28 @@ typedef struct
const char *loadingText;
float showPct;
GameLoopData *nextLoop;
bool removeParent;
int count;
} ScreenLoadingData;
static void LoopTerminate(GameLoopData *data);
static GameLoopResult LoopUpdate(GameLoopData *data, LoopRunner *l);
static void LoopDraw(GameLoopData *data);
GameLoopData *ScreenLoading(
const char *loadingText, const bool ascending, GameLoopData *nextLoop)
const char *loadingText, const bool ascending, GameLoopData *nextLoop, const bool removeParent)
{
ScreenLoadingData *sData;
CCALLOC(sData, sizeof *sData);
sData->l = &gLoadingScreen;
sData->loadingText = loadingText;
sData->ascending = ascending;
sData->removeParent = removeParent;
sData->showPct = ascending ? 0.0f : 1.0f;
sData->nextLoop = nextLoop;
return GameLoopDataNew(
GameLoopData *data = GameLoopDataNew(
sData, LoopTerminate, NULL, NULL, NULL, LoopUpdate, LoopDraw);
data->DrawParent = true;
return data;
}
static void LoopTerminate(GameLoopData *data)
@@ -215,26 +173,30 @@ static GameLoopResult LoopUpdate(GameLoopData *data, LoopRunner *l)
{
ScreenLoadingData *sData = data->Data;
const bool complete = sData->showPct == (sData->ascending ? 1.0f : 0.0f);
Mix_Chunk *sound = complete ? sData->l->sndTick : sData->l->sndComplete;
if (sound)
if ((sData->count % 2) == 0)
{
SoundPlay(&gSoundDevice, sound);
SoundPlayAtPlusDistance(&gSoundDevice, sData->l->sndTick, gSoundDevice.earLeft1, 255);
}
sData->count++;
if (complete)
{
LoopRunnerPop(l);
if (sData->ascending)
{
if (sData->removeParent)
{
LoopRunnerPop(l);
}
if (sData->nextLoop)
{
LoopRunnerChange(l, sData->nextLoop);
LoopRunnerPush(l, sData->nextLoop);
// Show a loading screen with tiles animating out
LoopRunnerPush(l, ScreenLoading(sData->loadingText, false, NULL, false));
}
// Show a loading screen with tiles animating out
LoopRunnerPush(l, ScreenLoading(sData->loadingText, false, NULL));
}
return UPDATE_RESULT_OK;
}
sData->showPct += sData->ascending ? 0.1f : -0.1f;
sData->showPct += sData->ascending ? 0.04f : -0.06f;
sData->showPct = CLAMP(sData->showPct, 0.0f, 1.0f);
return UPDATE_RESULT_DRAW;
}

View File

@@ -36,13 +36,10 @@
typedef struct
{
const Pic *logo;
const Pic *panel;
GraphicsDevice *g;
Map m;
float showPct;
CArray tileIndices;
DrawBuffer db;
CArray panelIndices; // of int
Mix_Chunk *sndTick;
Mix_Chunk *sndComplete;
} LoadingScreen;
extern LoadingScreen gLoadingScreen;
@@ -50,10 +47,8 @@ extern LoadingScreen gLoadingScreen;
void LoadingScreenInit(LoadingScreen *l, GraphicsDevice *g);
void LoadingScreenTerminate(LoadingScreen *l);
// Reload tile textures, required when the map changes
void LoadingScreenReload(LoadingScreen *l);
void LoadingScreenDraw(
LoadingScreen *l, const char *loadingText, const float showPct);
GameLoopData *ScreenLoading(
const char *loadingText, const bool ascending, GameLoopData *nextLoop);
const char *loadingText, const bool ascending, GameLoopData *nextLoop, const bool removeParent);

View File

@@ -62,6 +62,8 @@ typedef struct
DrawBuffer buffer;
HSV bgTint;
RunGameData rData;
GameMode gameMode;
const CampaignEntry *entry;
} MainMenuData;
static void MenuResetSize(MenuSystem *ms);
static void MenuCreateAll(
@@ -128,6 +130,8 @@ static void MainMenuReset(MainMenuData *data)
GenerateLiveBackground(data);
MenuResetSize(&data->ms);
data->entry = NULL;
}
static void MainMenuTerminate(GameLoopData *data)
{
@@ -213,7 +217,7 @@ static GameLoopResult MainMenuUpdate(GameLoopData *data, LoopRunner *l)
if (gCampaign.IsLoaded)
{
// Loaded game already; skip menus and go straight to game
LoopRunnerPush(l, ScreenCampaignIntro(&gCampaign.Setting));
LoopRunnerPush(l, ScreenCampaignIntro(&gCampaign.Setting, gCampaign.Entry.Mode, &gCampaign.Entry));
return UPDATE_RESULT_OK;
}
@@ -223,13 +227,13 @@ static GameLoopResult MainMenuUpdate(GameLoopData *data, LoopRunner *l)
const GameLoopResult result = MenuUpdate(&mData->ms);
if (result == UPDATE_RESULT_OK)
{
if (gCampaign.IsLoaded)
if (mData->entry)
{
LoopRunnerPush(l, ScreenCampaignIntro(&gCampaign.Setting));
LoopRunnerPush(l, ScreenLoading("Loading game...", true, ScreenCampaignIntro(&gCampaign.Setting, mData->gameMode, mData->entry), false));
}
else
{
LoopRunnerPop(l);
LoopRunnerPush(l, ScreenLoading("Quitting...", true, NULL, true));
}
}
if (gEventHandlers.HasResolutionChanged)
@@ -251,8 +255,7 @@ static void MainMenuDraw(GameLoopData *data)
}
static menu_t *MenuCreateStart(
const char *name, MenuSystem *ms, LoopRunner *l,
CustomCampaigns *campaigns);
const char *name, MainMenuData *mainMenu, LoopRunner *l);
static menu_t *MenuCreateOptions(const char *name, MainMenuData *data);
menu_t *MenuCreateQuit(const char *name);
@@ -267,7 +270,7 @@ static void MenuCreateAll(
MENU_DISPLAY_ITEMS_CREDITS | MENU_DISPLAY_ITEMS_AUTHORS);
MenuAddSubmenu(
data->ms.root,
MenuCreateStart("Start", &data->ms, l, &data->campaigns));
MenuCreateStart("Start", data, l));
MenuAddSubmenu(data->ms.root, MenuCreateOptions("Options...", data));
#ifndef __EMSCRIPTEN__
MenuAddSubmenu(data->ms.root, MenuCreateQuit("Quit"));
@@ -282,39 +285,38 @@ typedef struct
// so we can enable it if LAN servers are found
int MenuJoinIndex;
} CheckLANServerData;
static menu_t *MenuCreateContinue(const char *name, const CampaignEntry *entry);
static menu_t *MenuCreateQuickPlay(const char *name, const CampaignEntry *entry);
static menu_t *MenuCreateContinue(const char *name, MainMenuData *mainMenu, const CampaignEntry *entry);
static menu_t *MenuCreateQuickPlay(const char *name, MainMenuData *mainMenu);
static menu_t *MenuCreateCampaigns(
const char *name, const char *title, CampaignList *list,
const char *name, const char *title, MainMenuData *mainMenu, CampaignList *list,
const GameMode mode);
static menu_t *CreateJoinLANGame(
const char *name, const char *title, MenuSystem *ms, LoopRunner *l);
static void CheckLANServers(menu_t *menu, void *data);
static menu_t *MenuCreateStart(
const char *name, MenuSystem *ms, LoopRunner *l,
CustomCampaigns *campaigns)
const char *name, MainMenuData *mainMenu, LoopRunner *l)
{
menu_t *menu = MenuCreateNormal(name, "Start:", MENU_TYPE_NORMAL, 0);
const CampaignSave *cs = AutosaveGetLastCampaign(&gAutosave);
MenuAddSubmenu(
menu, MenuCreateContinue("Continue", &cs->Campaign));
menu, MenuCreateContinue("Continue", mainMenu, &cs->Campaign));
const int menuContinueIndex = (int)menu->u.normal.subMenus.size - 1;
MenuAddSubmenu(
menu, MenuCreateCampaigns(
"Campaign", "Select a campaign:", &campaigns->campaignList,
"Campaign", "Select a campaign:", mainMenu, &mainMenu->campaigns.campaignList,
GAME_MODE_NORMAL));
MenuAddSubmenu(
menu, MenuCreateQuickPlay("Quick Play", &campaigns->quickPlayEntry));
menu, MenuCreateQuickPlay("Quick Play", mainMenu));
MenuAddSubmenu(
menu, MenuCreateCampaigns(
"Dogfight", "Select a dogfight scenario:",
&campaigns->dogfightList, GAME_MODE_DOGFIGHT));
mainMenu, &mainMenu->campaigns.dogfightList, GAME_MODE_DOGFIGHT));
MenuAddSubmenu(
menu, MenuCreateCampaigns(
"Deathmatch", "Select a deathmatch scenario:",
&campaigns->dogfightList, GAME_MODE_DEATHMATCH));
mainMenu, &mainMenu->campaigns.dogfightList, GAME_MODE_DEATHMATCH));
MenuAddSubmenu(
menu, CreateJoinLANGame("Join LAN game", "Choose LAN server", ms, l));
menu, CreateJoinLANGame("Join LAN game", "Choose LAN server", &mainMenu->ms, l));
CheckLANServerData *cdata;
CMALLOC(cdata, sizeof *cdata);
cdata->MenuJoinIndex = (int)menu->u.normal.subMenus.size - 1;
@@ -337,11 +339,11 @@ typedef struct
{
GameMode GameMode;
const CampaignEntry *Entry;
MainMenuData *MainMenu;
} StartGameModeData;
static void StartGameMode(menu_t *menu, void *data);
static menu_t *CreateStartGameMode(
const char *name, GameMode mode, const CampaignEntry *entry)
const char *name, MainMenuData *mainMenu, GameMode mode, const CampaignEntry *entry)
{
menu_t *menu = MenuCreate(name, MENU_TYPE_RETURN);
menu->enterSound = MENU_SOUND_START;
@@ -349,33 +351,27 @@ static menu_t *CreateStartGameMode(
CCALLOC(data, sizeof *data);
data->GameMode = mode;
data->Entry = entry;
data->MainMenu = mainMenu;
MenuSetPostEnterFunc(menu, StartGameMode, data, true);
return menu;
}
static void StartGameMode(menu_t *menu, void *data)
{
LoadingScreenReload(&gLoadingScreen);
LoadingScreenDraw(&gLoadingScreen, "Loading game...", 1.0f);
UNUSED(menu);
StartGameModeData *mData = data;
gCampaign.Entry.Mode = mData->GameMode;
if (!CampaignLoad(&gCampaign, mData->Entry))
{
// Failed to load
printf("Error: cannot load campaign %s\n", mData->Entry->Info);
}
mData->MainMenu->gameMode = mData->GameMode;
mData->MainMenu->entry = mData->Entry;
}
static menu_t *MenuCreateContinue(const char *name, const CampaignEntry *entry)
static menu_t *MenuCreateContinue(const char *name, MainMenuData *mainMenu, const CampaignEntry *entry)
{
return CreateStartGameMode(name, GAME_MODE_NORMAL, entry);
return CreateStartGameMode(name, mainMenu, GAME_MODE_NORMAL, entry);
}
static menu_t *MenuCreateQuickPlay(const char *name, const CampaignEntry *entry)
static menu_t *MenuCreateQuickPlay(const char *name, MainMenuData *mainMenu)
{
return CreateStartGameMode(name, GAME_MODE_QUICK_PLAY, entry);
return CreateStartGameMode(name, mainMenu, GAME_MODE_QUICK_PLAY, &mainMenu->campaigns.quickPlayEntry);
}
static menu_t *MenuCreateCampaignItem(
CampaignEntry *entry, const GameMode mode);
static menu_t *MenuCreateCampaignItem(MainMenuData *mainMenu, CampaignEntry *entry, const GameMode mode);
static void CampaignsDisplayFilename(
const menu_t *menu, GraphicsDevice *g, const struct vec2i pos,
@@ -406,7 +402,7 @@ static void CampaignsDisplayFilename(
FontStrOpt(s, pos, opts);
}
static menu_t *MenuCreateCampaigns(
const char *name, const char *title, CampaignList *list,
const char *name, const char *title, MainMenuData *mainMenu, CampaignList *list,
const GameMode mode)
{
menu_t *menu = MenuCreateNormal(name, title, MENU_TYPE_NORMAL, 0);
@@ -416,19 +412,18 @@ static menu_t *MenuCreateCampaigns(
char folderName[CDOGS_FILENAME_MAX];
sprintf(folderName, "%s/", subList->Name);
MenuAddSubmenu(
menu, MenuCreateCampaigns(folderName, title, subList, mode));
menu, MenuCreateCampaigns(folderName, title, mainMenu, subList, mode));
CA_FOREACH_END()
CA_FOREACH(CampaignEntry, e, list->list)
MenuAddSubmenu(menu, MenuCreateCampaignItem(e, mode));
MenuAddSubmenu(menu, MenuCreateCampaignItem(mainMenu, e, mode));
CA_FOREACH_END()
MenuSetCustomDisplay(menu, CampaignsDisplayFilename, NULL);
return menu;
}
static menu_t *MenuCreateCampaignItem(
CampaignEntry *entry, const GameMode mode)
static menu_t *MenuCreateCampaignItem(MainMenuData *mainMenu, CampaignEntry *entry, const GameMode mode)
{
menu_t *menu = CreateStartGameMode(entry->Info, mode, entry);
menu_t *menu = CreateStartGameMode(entry->Info, mainMenu, mode, entry);
// Special colors:
// - Green for new campaigns
// - White (normal) for in-progress campaigns

View File

@@ -792,7 +792,7 @@ bail:
LoopRunnerPush(
l, ScreenLoading(
"Starting game...", true,
RunGame(&gCampaign, &gMission, &gMap)));
RunGame(&gCampaign, &gMission, &gMap), true));
}
return UPDATE_RESULT_OK;
}