mirror of
https://github.com/DrBeef/Raze.git
synced 2024-12-04 01:51:55 +00:00
aabbbcb2ff
This includes loading a level and busy-waiting for a sound to play. Also block these loops and the sounds they wait for in network games to avoid problems from longer delays here. The problem seems to be directly inherited from ZDoom which shows the same issue with screen wipes. Fixes #297
308 lines
7.9 KiB
C++
308 lines
7.9 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
Copyright (C) 2019 sirlemonhead, Nuke.YKT
|
|
This file is part of PCExhumed.
|
|
PCExhumed is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License version 2
|
|
as published by the Free Software Foundation.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
See the GNU General Public License for more details.
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
#include "ns.h"
|
|
#include "compat.h"
|
|
#include "common.h"
|
|
#include "engine.h"
|
|
#include "exhumed.h"
|
|
#include "sequence.h"
|
|
#include "names.h"
|
|
#include "player.h"
|
|
#include "ps_input.h"
|
|
#include "sound.h"
|
|
#include "view.h"
|
|
#include "status.h"
|
|
#include "version.h"
|
|
#include "aistuff.h"
|
|
#include "mapinfo.h"
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <ctype.h>
|
|
#include <time.h>
|
|
#include <assert.h>
|
|
#include "gamecvars.h"
|
|
#include "savegamehelp.h"
|
|
#include "c_dispatch.h"
|
|
#include "raze_sound.h"
|
|
#include "gamestate.h"
|
|
#include "screenjob.h"
|
|
#include "c_console.h"
|
|
#include "cheathandler.h"
|
|
#include "statistics.h"
|
|
#include "g_input.h"
|
|
#include "core/menu/menu.h"
|
|
#include "d_net.h"
|
|
|
|
BEGIN_PS_NS
|
|
|
|
short nBestLevel;
|
|
static int32_t nonsharedtimer;
|
|
|
|
int GameAction=-1;
|
|
|
|
extern uint8_t nCinemaSeen;
|
|
|
|
void RunCinemaScene(int num);
|
|
void GameMove(void);
|
|
void DrawClock();
|
|
double calc_smoothratio();
|
|
void DoTitle(CompletionFunc completion);
|
|
|
|
static int FinishLevel(TArray<JobDesc> &jobs)
|
|
{
|
|
int lnum = currentLevel->levelNumber;
|
|
if (lnum > nBestLevel) {
|
|
nBestLevel = lnum - 1;
|
|
}
|
|
|
|
|
|
StopAllSounds();
|
|
|
|
bCamera = false;
|
|
automapMode = am_off;
|
|
|
|
STAT_Update(lnum == kMap20);
|
|
if (lnum != kMap20)
|
|
{
|
|
if (EndLevel != 2 && !netgame)
|
|
{
|
|
// There's really no choice but to enter an active wait loop here to make the sound play out.
|
|
PlayLocalSound(StaticSound[59], 0, true, CHANF_UI);
|
|
int nTicks = I_msTime() + 100;
|
|
while (nTicks > I_msTime())
|
|
{
|
|
I_GetEvent();
|
|
soundEngine->UpdateSounds(I_GetTime());
|
|
}
|
|
Net_ClearFifo();
|
|
}
|
|
}
|
|
else nPlayerLives[0] = 0;
|
|
|
|
DoAfterCinemaScene(lnum, jobs);
|
|
return lnum == kMap20? -1 : lnum + 1;
|
|
}
|
|
|
|
|
|
static void showmap(short nLevel, short nLevelNew, short nLevelBest, TArray<JobDesc> &jobs)
|
|
{
|
|
if (nLevelNew == 5 && !(nCinemaSeen & 1)) {
|
|
nCinemaSeen |= 1;
|
|
DoBeforeCinemaScene(5, jobs);
|
|
}
|
|
|
|
menu_DrawTheMap(nLevel, nLevelNew, nLevelBest, jobs);
|
|
|
|
if (nLevelNew == 11 && !(nCinemaSeen & 2)) {
|
|
DoBeforeCinemaScene(11, jobs);
|
|
}
|
|
}
|
|
|
|
|
|
static void GameDisplay(void)
|
|
{
|
|
drawtime.Reset();
|
|
drawtime.Clock();
|
|
|
|
if (currentLevel && currentLevel->levelNumber == kMap20)
|
|
{
|
|
DoEnergyTile();
|
|
DrawClock();
|
|
}
|
|
|
|
DrawView(calc_smoothratio());
|
|
DrawStatusBar();
|
|
if (paused && !M_Active())
|
|
{
|
|
auto tex = GStrings("TXTB_PAUSED");
|
|
int nStringWidth = SmallFont->StringWidth(tex);
|
|
DrawText(twod, SmallFont, CR_UNTRANSLATED, 160 - nStringWidth / 2, 100, tex, DTA_FullscreenScale, FSMode_Fit320x200, TAG_DONE);
|
|
}
|
|
|
|
drawtime.Unclock();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void drawmenubackground()
|
|
{
|
|
auto nLogoTile = EXHUMED ? kExhumedLogo : kPowerslaveLogo;
|
|
int dword_9AB5F = (I_GetBuildTime() / 16) & 3;
|
|
|
|
twod->ClearScreen();
|
|
|
|
DrawRel(kSkullHead, 160, 100, 32);
|
|
DrawRel(kSkullJaw, 161, 130, 32);
|
|
DrawRel(nLogoTile, 160, 40, 32);
|
|
|
|
// draw the fire urn/lamp thingies
|
|
DrawRel(kTile3512 + dword_9AB5F, 50, 150, 32);
|
|
DrawRel(kTile3512 + ((dword_9AB5F + 2) & 3), 270, 150, 32);
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void CheckProgression()
|
|
{
|
|
TArray<JobDesc> jobs;
|
|
bool startlevel = false;
|
|
int mylevelnew = -1;
|
|
|
|
if (GameAction >= 0)
|
|
{
|
|
if (GameAction < 1000)
|
|
{
|
|
// start a new game on the given level
|
|
currentLevel = nullptr;
|
|
mylevelnew = GameAction;
|
|
currentLevel = FindMapByLevelNum(mylevelnew);
|
|
GameAction = -1;
|
|
InitNewGame();
|
|
if (mylevelnew > 0) STAT_StartNewGame("Exhumed", 1);
|
|
if (mylevelnew != 0) nBestLevel = mylevelnew - 1;
|
|
}
|
|
else
|
|
{
|
|
// A savegame was loaded. Just start the level without any further actions.
|
|
GameAction = -1;
|
|
gamestate = GS_LEVEL;
|
|
return;
|
|
}
|
|
}
|
|
else if (EndLevel)
|
|
{
|
|
if (currentLevel->levelNumber == 0) startmainmenu();
|
|
else mylevelnew = FinishLevel(jobs);
|
|
EndLevel = false;
|
|
}
|
|
if (mylevelnew > -1 && mylevelnew < kMap20)
|
|
{
|
|
startlevel = true;
|
|
// start a new game at the given level
|
|
if (!nNetPlayerCount && mylevelnew > 0)
|
|
{
|
|
showmap(currentLevel? currentLevel->levelNumber : -1, mylevelnew, nBestLevel, jobs);
|
|
}
|
|
else
|
|
jobs.Push({ Create<DScreenJob>() }); // we need something in here even in the multiplayer case.
|
|
}
|
|
if (jobs.Size() > 0)
|
|
{
|
|
selectedlevelnew = mylevelnew;
|
|
RunScreenJob(jobs.Data(), jobs.Size(), [=](bool)
|
|
{
|
|
if (!startlevel) gamestate = GS_STARTUP;
|
|
else
|
|
{
|
|
gamestate = GS_LEVEL;
|
|
|
|
InitLevel(selectedlevelnew);
|
|
#if 0
|
|
// this would be the place to autosave upon level start
|
|
if (!bInDemo && selectedlevelnew > nBestLevel && selectedlevelnew != 0 && selectedlevelnew <= kMap20) {
|
|
menu_GameSave(SavePosition);
|
|
}
|
|
#endif
|
|
if (selectedlevelnew > nBestLevel)
|
|
{
|
|
nBestLevel = selectedlevelnew;
|
|
}
|
|
|
|
if (selectedlevelnew == 11) nCinemaSeen |= 2;
|
|
if (mylevelnew != selectedlevelnew) STAT_Cancel();
|
|
else STAT_NewLevel(currentLevel->labelName);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void GameLoop()
|
|
{
|
|
GameTicker();
|
|
PlayerInterruptKeys(true);
|
|
gi->UpdateSounds();
|
|
CheckKeys2();
|
|
}
|
|
|
|
|
|
void GameInterface::RunGameFrame()
|
|
{
|
|
again:
|
|
CheckProgression();
|
|
switch (gamestate)
|
|
{
|
|
default:
|
|
case GS_STARTUP:
|
|
resettiming();
|
|
GameAction = -1;
|
|
EndLevel = false;
|
|
|
|
if (userConfig.CommandMap.IsNotEmpty())
|
|
{
|
|
auto map = FindMapByName(userConfig.CommandMap);
|
|
if (map) GameAction = map->levelNumber;
|
|
userConfig.CommandMap = "";
|
|
goto again;
|
|
}
|
|
else
|
|
{
|
|
DoTitle([](bool) { startmainmenu(); });
|
|
}
|
|
break;
|
|
|
|
case GS_MENUSCREEN:
|
|
case GS_FULLCONSOLE:
|
|
drawmenubackground();
|
|
break;
|
|
|
|
case GS_LEVEL:
|
|
GameLoop();
|
|
GameDisplay();
|
|
break;
|
|
|
|
case GS_INTERMISSION:
|
|
case GS_INTRO:
|
|
RunScreenJobFrame(); // This handles continuation through its completion callback.
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
void GameInterface::ErrorCleanup()
|
|
{
|
|
// Clear all progression sensitive variables here.
|
|
GameAction = -1;
|
|
EndLevel = false;
|
|
}
|
|
|
|
END_PS_NS
|