mirror of
https://github.com/DrBeef/Raze.git
synced 2024-12-15 15:11:01 +00:00
235 lines
No EOL
5 KiB
C++
235 lines
No EOL
5 KiB
C++
#include "zstring.h"
|
|
#include "gameconfigfile.h"
|
|
#include "gamecontrol.h"
|
|
#include "resourcefile.h"
|
|
#include "sc_man.h"
|
|
#include "i_specialpaths.h"
|
|
#include "inputstate.h"
|
|
#include "c_cvars.h"
|
|
#include "../../glbackend/glbackend.h"
|
|
|
|
|
|
// Currently there is no global state for the current game. This is a temporary workaround because the video init code needs to do a few things based on the active game.
|
|
|
|
FString currentGame;
|
|
|
|
namespace Duke
|
|
{
|
|
extern GameInterface Interface;
|
|
}
|
|
namespace Redneck
|
|
{
|
|
extern GameInterface Interface;
|
|
}
|
|
namespace Blood
|
|
{
|
|
extern GameInterface Interface;
|
|
}
|
|
namespace ShadowWarrior
|
|
{
|
|
extern GameInterface Interface;
|
|
}
|
|
|
|
GameInterface *CheckFrontend()
|
|
{
|
|
FILE* f = fopen("blood.rff", "rb");
|
|
if (f)
|
|
{
|
|
currentGame = "Blood";
|
|
fclose(f);
|
|
return &Blood::Interface;
|
|
}
|
|
else
|
|
{
|
|
f = fopen("redneck.grp", "rb");
|
|
if (f)
|
|
{
|
|
currentGame = "Redneck";
|
|
fseek(f, 0, SEEK_END);
|
|
auto pos = ftell(f);
|
|
// Quick hack to distinguish these two. This won't survive until production but for testing it's sufficient.
|
|
if (pos > 190'000'000) currentGame = "RedneckRides";
|
|
fclose(f);
|
|
return &Redneck::Interface;
|
|
}
|
|
else
|
|
{
|
|
f = fopen("sw.grp", "rb");
|
|
if (f)
|
|
{
|
|
currentGame = "ShadowWarrior";
|
|
fclose(f);
|
|
return &ShadowWarrior::Interface;
|
|
}
|
|
f = fopen("fury.grp", "rb");
|
|
if (f)
|
|
{
|
|
currentGame = "IonFury";
|
|
fclose(f);
|
|
return &Duke::Interface;
|
|
}
|
|
f = fopen("nam.grp", "rb");
|
|
if (f)
|
|
{
|
|
currentGame = "Nam";
|
|
fclose(f);
|
|
return &Duke::Interface;
|
|
}
|
|
f = fopen("ww2gi.grp", "rb");
|
|
if (f)
|
|
{
|
|
currentGame = "WW2GI";
|
|
fclose(f);
|
|
return &Duke::Interface;
|
|
}
|
|
else
|
|
{
|
|
currentGame = "Duke";
|
|
}
|
|
return &Duke::Interface;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChooseGame()
|
|
{
|
|
auto dir = Args->CheckValue("-game");
|
|
if (dir && !chdir(dir))
|
|
{
|
|
gi = CheckFrontend();
|
|
return;
|
|
}
|
|
|
|
TArray<FString> paths;
|
|
std::vector<std::wstring> wgames;
|
|
TArray<TASKDIALOG_BUTTON> buttons;
|
|
char* token;
|
|
|
|
FileReader fr;
|
|
if (fr.OpenFile("./games.list"))
|
|
{
|
|
auto filedata = fr.ReadPadded(1);
|
|
|
|
auto script = scriptfile_fromstring((char*)filedata.Data());
|
|
int id = 1000;
|
|
while (!scriptfile_eof(script))
|
|
{
|
|
scriptfile_getstring(script, &token);
|
|
if (scriptfile_eof(script))
|
|
{
|
|
break;
|
|
}
|
|
FString game = token;
|
|
scriptfile_getstring(script, &token);
|
|
paths.Push(token);
|
|
FStringf display("%s\n%s", game.GetChars(), token);
|
|
wgames.push_back(display.WideString());
|
|
buttons.Push({ id++, wgames.back().c_str() });
|
|
}
|
|
}
|
|
if (paths.Size() == 0)
|
|
{
|
|
exit(1);
|
|
}
|
|
|
|
int nResult = 0;
|
|
|
|
TASKDIALOGCONFIG stTaskConfig;
|
|
ZeroMemory(&stTaskConfig, sizeof(stTaskConfig));
|
|
|
|
stTaskConfig.cbSize = sizeof(TASKDIALOGCONFIG);
|
|
stTaskConfig.hwndParent = NULL;
|
|
stTaskConfig.hInstance = NULL;
|
|
|
|
stTaskConfig.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION| TDF_USE_COMMAND_LINKS;
|
|
|
|
if (!gi)
|
|
{
|
|
// Open a popup to select the game.
|
|
// The entire startup code just doesn't work right if this isn't checked as the very first thing.
|
|
stTaskConfig.pszWindowTitle = L"Demolition";
|
|
stTaskConfig.pszMainInstruction = L"Choose your game";
|
|
stTaskConfig.pszContent = L"";
|
|
stTaskConfig.cButtons = buttons.Size();
|
|
|
|
stTaskConfig.pButtons = buttons.Data();
|
|
stTaskConfig.nDefaultButton = 1000;
|
|
|
|
if (SUCCEEDED(TaskDialogIndirect(&stTaskConfig, &nResult, NULL, NULL)))
|
|
{
|
|
if (nResult >= 1000 && nResult < 1000 +(int)buttons.Size())
|
|
{
|
|
nResult -= 1000;
|
|
chdir(paths[nResult]);
|
|
gi = CheckFrontend();
|
|
}
|
|
}
|
|
if (gi == nullptr) exit(1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<FResourceFile> engine_res;
|
|
|
|
// The resourge manager in cache1d is far too broken to add some arbitrary file without some adjustment.
|
|
// For now, keep this file here, until the resource management can be redone in a more workable fashion.
|
|
extern FString progdir;
|
|
|
|
void InitBaseRes()
|
|
{
|
|
if (!engine_res)
|
|
{
|
|
// If we get here for the first time, load the engine-internal data.
|
|
FString baseres = progdir + "demolition.pk3";
|
|
engine_res.reset(FResourceFile::OpenResourceFile(baseres, true, true));
|
|
if (!engine_res)
|
|
{
|
|
I_Error("Engine resources (%s) not found", baseres.GetChars());
|
|
}
|
|
}
|
|
}
|
|
|
|
FileReader openFromBaseResource(const char* fn)
|
|
{
|
|
InitBaseRes();
|
|
auto lump = engine_res->FindLump(fn);
|
|
if (lump) return lump->NewReader();
|
|
// Also look in game filtered directories.
|
|
FStringf filtername("filter/game-%s/%s", currentGame.GetChars(), fn);
|
|
lump = engine_res->FindLump(filtername);
|
|
if (lump) return lump->NewReader();
|
|
return FileReader(nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
int GameMain()
|
|
{
|
|
try
|
|
{
|
|
// Write to the DOCUMENTS directory, not the game directory
|
|
|
|
FString logpath = M_GetDocumentsPath() + "demolition.log";
|
|
OSD_SetLogFile(logpath);
|
|
CONFIG_ReadCombatMacros();
|
|
|
|
// Startup dialog must be presented here so that everything can be set up before reading the keybinds.
|
|
G_LoadConfig(currentGame);
|
|
CONFIG_Init();
|
|
r = gi->app_main(buildargc, (const char**)buildargv);
|
|
}
|
|
catch (const std::runtime_error & err)
|
|
{
|
|
wm_msgbox("Error", "%s", err.what());
|
|
return 3;
|
|
}
|
|
catch (const ExitEvent & exit)
|
|
{
|
|
// Just let the rest of the function execute.
|
|
r = exit.Reason();
|
|
}
|
|
} |