mirror of
https://github.com/cxong/cdogs-sdl.git
synced 2025-07-23 07:23:01 +02:00
Loading screen (fixes #325 )
This commit is contained in:
BIN
graphics/bigpanel.png
Normal file
BIN
graphics/bigpanel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 603 B |
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -792,7 +792,7 @@ bail:
|
||||
LoopRunnerPush(
|
||||
l, ScreenLoading(
|
||||
"Starting game...", true,
|
||||
RunGame(&gCampaign, &gMission, &gMap)));
|
||||
RunGame(&gCampaign, &gMission, &gMap), true));
|
||||
}
|
||||
return UPDATE_RESULT_OK;
|
||||
}
|
||||
|
Reference in New Issue
Block a user