- added support for ZDoom-style GAMEINFO.

This commit is contained in:
Christoph Oelckers 2020-01-11 17:05:25 +01:00
parent af80e64ecf
commit 3b955b7c94
6 changed files with 285 additions and 20 deletions

View file

@ -51,6 +51,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "st_start.h"
#include "s_music.h"
#include "i_video.h"
#include "v_text.h"
#include "resourcefile.h"
#include "c_dispatch.h"
#include "glbackend/glbackend.h"
#ifndef NETCODE_DISABLE
@ -62,6 +64,7 @@ MapRecord *currentLevel; // level that is currently played. (The real level, not
MapRecord* lastLevel; // Same here, for the last level.
MapRecord userMapRecord; // stand-in for the user map.
FStartupInfo RazeStartupInfo;
FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown.
FString progdir;
@ -70,7 +73,9 @@ void C_CON_SetAliases();
InputState inputState;
void SetClipshapes();
int ShowStartupWindow(TArray<GrpEntry> &);
FString GetGameFronUserFiles();
void InitFileSystem(TArray<GrpEntry>&);
void I_SetWindowTitle(const char* caption);
bool gHaveNetworking;
bool AppActive;
@ -86,6 +91,7 @@ CVAR(Bool, disableautoload, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALC
//CVAR(Bool, autoloadbrightmaps, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG) // hopefully this is an option for later
//CVAR(Bool, autoloadlights, false, CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOBALCONFIG)
//==========================================================================
//
//
@ -443,6 +449,12 @@ static TArray<GrpEntry> SetupGame()
// If the user has specified a file name, let's see if we know it.
//
FString game = GetGameFronUserFiles();
if (userConfig.gamegrp.IsEmpty())
{
userConfig.gamegrp = game;
}
if (userConfig.gamegrp.Len())
{
FString gamegrplower = "/" + userConfig.gamegrp.MakeLower();
@ -461,7 +473,6 @@ static TArray<GrpEntry> SetupGame()
}
}
if (groupno == -1)
{
int pick = 0;
@ -510,6 +521,9 @@ static TArray<GrpEntry> SetupGame()
if (groupno == -1) return TArray<GrpEntry>();
auto& group = groups[groupno];
if (RazeStartupInfo.Name.IsNotEmpty()) I_SetWindowTitle(RazeStartupInfo.Name);
else I_SetWindowTitle(group.FileInfo.name);
// Now filter out the data we actually need and delete the rest.
usedgroups.Push(group);

View file

@ -157,3 +157,17 @@ void S_SetSoundPaused(int state);
void G_HandleMemErr(int32_t lineNum, const char* fileName, const char* funcName);
void G_FatalEngineError(void);
struct FStartupInfo
{
FString Name;
uint32_t FgColor; // Foreground color for title banner
uint32_t BkColor; // Background color for title banner
//FString Song;
//int Type;
//int LoadLights = -1;
//int LoadBrightmaps = -1;
};
extern FStartupInfo RazeStartupInfo;

View file

@ -42,6 +42,9 @@
#include "printf.h"
#include "m_argv.h"
#include "version.h"
#include "sc_man.h"
#include "v_video.h"
#include "v_text.h"
#include "../platform/win32/i_findfile.h" // This is a temporary direct path. Needs to be fixed when stuff gets cleaned up.
#ifndef PATH_MAX
@ -268,7 +271,7 @@ static void D_AddDirectory (TArray<FString> &wadfiles, const char *dir)
{
skindir[stuffstart++] = '/';
int savedstart = stuffstart;
static const char* validexts[] = { "*.grp", "*.zip", "*.pk3", "*.pk4", "*.7z", "*.pk7", "*.dat" };
static const char* validexts[] = { "*.grp", "*.zip", "*.pk3", "*.pk4", "*.7z", "*.pk7", "*.dat", "*.rff" };
for (auto ext : validexts)
{
stuffstart = savedstart;
@ -290,6 +293,186 @@ static void D_AddDirectory (TArray<FString> &wadfiles, const char *dir)
}
}
//==========================================================================
//
//
//
//==========================================================================
static FString ParseGameInfo(TArray<FString>& pwads, const char* fn, const char* data, int size)
{
FScanner sc;
FString iwad;
int pos = 0;
const char* lastSlash = strrchr(fn, '/');
sc.OpenMem("GAMEINFO", data, size);
sc.SetCMode(true);
while (sc.GetToken())
{
sc.TokenMustBe(TK_Identifier);
FString nextKey = sc.String;
sc.MustGetToken('=');
if (!nextKey.CompareNoCase("GAME"))
{
sc.MustGetString();
iwad = sc.String;
}
else if (!nextKey.CompareNoCase("LOAD"))
{
do
{
sc.MustGetString();
// Try looking for the wad in the same directory as the .wad
// before looking for it in the current directory.
FString checkpath;
if (lastSlash != NULL)
{
checkpath = FString(fn, (lastSlash - fn) + 1);
checkpath += sc.String;
}
else
{
checkpath = sc.String;
}
if (!FileExists(checkpath))
{
pos += D_AddFile(pwads, sc.String, true, pos);
}
else
{
pos += D_AddFile(pwads, checkpath, true, pos);
}
} while (sc.CheckToken(','));
}
else if (!nextKey.CompareNoCase("STARTUPTITLE"))
{
sc.MustGetString();
RazeStartupInfo.Name = sc.String;
}
else if (!nextKey.CompareNoCase("STARTUPCOLORS"))
{
sc.MustGetString();
RazeStartupInfo.FgColor = V_GetColor(NULL, sc);
sc.MustGetStringName(",");
sc.MustGetString();
RazeStartupInfo.BkColor = V_GetColor(NULL, sc);
}
else
{
// Silently ignore unknown properties
do
{
sc.MustGetAnyToken();
} while (sc.CheckToken(','));
}
}
return iwad;
}
//==========================================================================
//
//
//
//==========================================================================
static FString CheckGameInfo(TArray<FString>& pwads)
{
// scan the list of WADs backwards to find the last one that contains a GAMEINFO lump
for (int i = pwads.Size() - 1; i >= 0; i--)
{
bool isdir = false;
FResourceFile* resfile;
const char* filename = pwads[i];
// Does this exist? If so, is it a directory?
if (!DirEntryExists(pwads[i], &isdir))
{
Printf(TEXTCOLOR_RED "Could not find %s\n", filename);
continue;
}
if (!isdir)
{
FileReader fr;
if (!fr.OpenFile(filename))
{
// Didn't find file
continue;
}
resfile = FResourceFile::OpenResourceFile(filename, fr, true);
}
else
resfile = FResourceFile::OpenDirectory(filename, true);
FName gameinfo = "GAMEINFO.TXT";
if (resfile != NULL)
{
uint32_t cnt = resfile->LumpCount();
for (int i = cnt - 1; i >= 0; i--)
{
FResourceLump* lmp = resfile->GetLump(i);
if (lmp->LumpName[0] == gameinfo)
{
// Found one!
FString iwad = ParseGameInfo(pwads, resfile->FileName, (const char*)lmp->Lock(), lmp->LumpSize);
delete resfile;
return iwad;
}
}
delete resfile;
}
}
return "";
}
//==========================================================================
//
//
//
//==========================================================================
FString GetGameFronUserFiles()
{
TArray<FString> Files;
if (userConfig.AddFilesPre) for (auto& file : *userConfig.AddFilesPre)
{
D_AddFile(Files, file);
}
if (userConfig.AddFiles)
{
for (auto& file : *userConfig.AddFiles)
{
D_AddFile(Files, file);
}
// Finally, if the last entry in the chain is a directory, it's being considered the mod directory, and all GRPs inside need to be loaded, too.
if (userConfig.AddFiles->NumArgs() > 0)
{
auto fn = (*userConfig.AddFiles)[userConfig.AddFiles->NumArgs() - 1];
bool isdir = false;
if (DirEntryExists(fn, &isdir) && isdir)
{
// Insert the GRPs before this entry itself.
FString lastfn;
Files.Pop(lastfn);
D_AddDirectory(Files, fn);
Files.Push(lastfn);
}
}
}
return CheckGameInfo(Files);
}
//==========================================================================
//
//
//
//==========================================================================
void InitFileSystem(TArray<GrpEntry>& groups)
{
@ -338,6 +521,20 @@ void InitFileSystem(TArray<GrpEntry>& groups)
i--;
}
const char* key;
const char* value;
if (GameConfig->SetSection("global.Autoload"))
{
while (GameConfig->NextInSection(key, value))
{
if (stricmp(key, "Path") == 0)
{
FString nice = NicePath(value);
D_AddFile(Files, nice);
}
}
}
if (!insertdirectoriesafter && userConfig.AddFilesPre) for (auto& file : *userConfig.AddFilesPre)
{
D_AddFile(Files, file);
@ -364,19 +561,7 @@ void InitFileSystem(TArray<GrpEntry>& groups)
}
}
}
const char* key;
const char* value;
if (GameConfig->SetSection("global.Autoload"))
{
while (GameConfig->NextInSection(key, value))
{
if (stricmp(key, "Path") == 0)
{
FString nice = NicePath(value);
D_AddFile(Files, nice);
}
}
}
TArray<FString> todelete;
for (auto& g : groups)

View file

@ -102,6 +102,7 @@ public:
FString TakeValue(const char *check);
int NumArgs() const;
void FlushArgs();
TArray<FString>& Array() { return Argv; }
private:
TArray<FString> Argv;

View file

@ -336,17 +336,17 @@ void FConsoleWindow::SetTitleText()
// It's used in graphical startup screen, with Hexen style in particular
// Native OS X backend doesn't implement this yet
if (DoomStartupInfo.FgColor == DoomStartupInfo.BkColor)
if (RazeStartupInfo.FgColor == RazeStartupInfo.BkColor)
{
DoomStartupInfo.FgColor = ~DoomStartupInfo.FgColor;
RazeStartupInfo.FgColor = ~RazeStartupInfo.FgColor;
}
NSTextField* titleText = [[NSTextField alloc] initWithFrame:titleTextRect];
[titleText setStringValue:[NSString stringWithCString:DoomStartupInfo.Name
[titleText setStringValue:[NSString stringWithCString:RazeStartupInfo.Name
encoding:NSISOLatin1StringEncoding]];
[titleText setAlignment:NSCenterTextAlignment];
[titleText setTextColor:RGB(DoomStartupInfo.FgColor)];
[titleText setBackgroundColor:RGB(DoomStartupInfo.BkColor)];
[titleText setTextColor:RGB(RazeStartupInfo.FgColor)];
[titleText setBackgroundColor:RGB(RazeStartupInfo.BkColor)];
[titleText setFont:[NSFont fontWithName:@"Trebuchet MS Bold" size:18.0f]];
[titleText setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
[titleText setSelectable:NO];

View file

@ -426,6 +426,57 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
return 0;
case WM_DRAWITEM:
// Draw title banner.
if (wParam == IDC_STATIC_TITLE && RazeStartupInfo.Name.IsNotEmpty())
{
const PalEntry *c;
// Draw the game title strip at the top of the window.
auto drawitem = (LPDRAWITEMSTRUCT)lParam;
SIZE size;
// Draw the background.
auto rect = drawitem->rcItem;
rect.bottom -= 1;
c = (const PalEntry *)&RazeStartupInfo.BkColor;
auto hbr = CreateSolidBrush (RGB(c->r,c->g,c->b));
FillRect (drawitem->hDC, &drawitem->rcItem, hbr);
DeleteObject (hbr);
// Calculate width of the title string.
SetTextAlign (drawitem->hDC, TA_TOP);
oldfont = SelectObject (drawitem->hDC, GameTitleFont != NULL ? GameTitleFont : (HFONT)GetStockObject (DEFAULT_GUI_FONT));
auto widename = RazeStartupInfo.Name.WideString();
GetTextExtentPoint32W (drawitem->hDC, widename.c_str(), (int)widename.length(), &size);
// Draw the title.
c = (const PalEntry *)&RazeStartupInfo.FgColor;
SetTextColor (drawitem->hDC, RGB(c->r,c->g,c->b));
SetBkMode (drawitem->hDC, TRANSPARENT);
TextOutW (drawitem->hDC, rect.left + (rect.right - rect.left - size.cx) / 2, 2, widename.c_str(), (int)widename.length());
SelectObject (drawitem->hDC, oldfont);
return TRUE;
}
// Draw stop icon.
else if (wParam == IDC_ICONPIC)
{
HICON icon;
POINTL char_pos;
auto drawitem = (LPDRAWITEMSTRUCT)lParam;
// This background color should match the edit control's.
auto hbr = CreateSolidBrush (RGB(70,70,70));
FillRect (drawitem->hDC, &drawitem->rcItem, hbr);
DeleteObject (hbr);
// Draw the icon aligned with the first line of error text.
SendMessage (ConWindow, EM_POSFROMCHAR, (WPARAM)&char_pos, ErrorIconChar);
icon = (HICON)LoadImage (0, IDI_ERROR, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
DrawIcon (drawitem->hDC, 6, char_pos.y, icon);
return TRUE;
}
return FALSE;
case WM_COMMAND:
if (ErrorIcon != NULL && (HWND)lParam == ConWindow && HIWORD(wParam) == EN_UPDATE)