Merge branch 'master' into newrenderer2

This commit is contained in:
Christoph Oelckers 2021-04-14 22:37:59 +02:00
commit 9a58299bee
14 changed files with 166 additions and 61 deletions

View file

@ -9,11 +9,11 @@ struct FStartupInfo
uint32_t FgColor; // Foreground color for title banner
uint32_t BkColor; // Background color for title banner
FString Song;
FString con;
int Type;
int LoadLights = -1;
int LoadBrightmaps = -1;
int LoadWidescreen = -1;
int modern = 0;
enum
{
DefaultStartup,

View file

@ -154,13 +154,28 @@ int FDirectory::AddDirectory(const char *dirpath)
}
else
{
if (strstr(fi, ".orig") || strstr(fi, ".bak"))
if (strstr(fi, ".orig") || strstr(fi, ".bak") || strstr(fi, ".cache"))
{
// We shouldn't add backup files to the file system
continue;
}
size_t size = 0;
FString fn = FString(dirpath) + fi;
// The next one is courtesy of EDuke32. :(
// Putting cache files in the application directory is very bad style.
// Unfortunately, having a garbage file named "texture" present will cause serious problems down the line.
if (!stricmp(fi, "textures"))
{
FILE* f = fopen(fn, "rb");
if (f)
{
char check[3]{};
fread(check, 1, 3, f);
if (!memcmp(check, "LZ4", 3)) continue;
}
}
if (GetFileInfo(fn, &size, nullptr))
{
AddEntry(fn, (int)size);

View file

@ -427,9 +427,12 @@ void drawredlines(int cposx, int cposy, int czoom, int cang)
for (j = startwall, wal = &wall[startwall]; j < endwall; j++, wal++)
{
int k = wal->nextwall;
if (k < 0 || k >= MAXWALLS) continue;
if (k < 0 || k >= numwalls) continue;
if (sector[wal->nextsector].ceilingz == z1 && sector[wal->nextsector].floorz == z2)
int s = wal->nextsector;
if (s < 0 || s >= numsectors) continue;
if (sector[s].ceilingz == z1 && sector[s].floorz == z2)
if (((wal->cstat | wall[wal->nextwall].cstat) & (16 + 32)) == 0) continue;
if (ShowRedLine(j, i))

View file

@ -126,7 +126,7 @@ FMemArena dump; // this is for memory blocks than cannot be deallocated without
InputState inputState;
int ShowStartupWindow(TArray<GrpEntry> &);
FString GetGameFronUserFiles();
TArray<FString> GetGameFronUserFiles();
void InitFileSystem(TArray<GrpEntry>&);
void I_SetWindowTitle(const char* caption);
void S_ParseSndInfo();
@ -654,14 +654,25 @@ static TArray<GrpEntry> SetupGame()
int groupno = -1;
// If the user has specified a file name, let's see if we know it.
//
FString game = GetGameFronUserFiles();
auto game = GetGameFronUserFiles();
if (userConfig.gamegrp.IsEmpty())
{
userConfig.gamegrp = game;
for (auto& str : game)
{
for (auto& grp : groups)
{
if (grp.FileInfo.gameid.CompareNoCase(str) == 0)
{
userConfig.gamegrp = grp.FileName;
goto foundit;
}
}
}
}
foundit:
// If the user has specified a file name, let's see if we know it.
//
if (userConfig.gamegrp.Len())
{
FString gamegrplower = "/" + userConfig.gamegrp.MakeLower();
@ -757,7 +768,7 @@ static TArray<GrpEntry> SetupGame()
if (ugroup.FileInfo.gamefilter.IsNotEmpty()) LumpFilter = ugroup.FileInfo.gamefilter;
g_gameType |= ugroup.FileInfo.flags;
}
if (userConfig.DefaultCon.IsEmpty()) userConfig.DefaultCon = selectedScript;
if (userConfig.DefaultCon.IsEmpty()) userConfig.DefaultCon = GameStartupInfo.con.IsNotEmpty()? GameStartupInfo.con : selectedScript;
if (userConfig.DefaultDef.IsEmpty()) userConfig.DefaultDef = selectedDef;
// This can only happen with a custom game that does not define any filter.

View file

@ -139,6 +139,7 @@ struct GrpInfo
FString defname;
FString rtsname;
FString gamefilter;
FString gameid;
uint32_t CRC = 0;
uint32_t dependencyCRC = 0;
size_t size = 0;

View file

@ -60,10 +60,10 @@ static const char* validexts[] = { "*.grp", "*.zip", "*.pk3", "*.pk4", "*.7z", "
//
//==========================================================================
static FString ParseGameInfo(TArray<FString>& pwads, const char* fn, const char* data, int size)
static TArray<FString> ParseGameInfo(TArray<FString>& pwads, const char* fn, const char* data, int size)
{
FScanner sc;
FString iwad;
TArray<FString> bases;
int pos = 0;
const char* lastSlash = strrchr(fn, '/');
@ -78,7 +78,7 @@ static FString ParseGameInfo(TArray<FString>& pwads, const char* fn, const char*
if (!nextKey.CompareNoCase("GAME"))
{
sc.MustGetString();
iwad = sc.String;
bases.Push(sc.String);
}
else if (!nextKey.CompareNoCase("LOAD"))
{
@ -122,10 +122,10 @@ static FString ParseGameInfo(TArray<FString>& pwads, const char* fn, const char*
sc.MustGetString();
GameStartupInfo.BkColor = V_GetColor(NULL, sc);
}
else if (!nextKey.CompareNoCase("MODERN"))
else if (!nextKey.CompareNoCase("CON"))
{
sc.MustGetNumber();
GameStartupInfo.modern = sc.Number ? 1 : -1;
sc.MustGetString();
GameStartupInfo.con = sc.String;;
}
else
{
@ -136,7 +136,7 @@ static FString ParseGameInfo(TArray<FString>& pwads, const char* fn, const char*
} while (sc.CheckToken(','));
}
}
return iwad;
return bases;
}
//==========================================================================
//
@ -144,7 +144,7 @@ static FString ParseGameInfo(TArray<FString>& pwads, const char* fn, const char*
//
//==========================================================================
static FString CheckGameInfo(TArray<FString>& pwads)
static TArray<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--)
@ -184,15 +184,15 @@ static FString CheckGameInfo(TArray<FString>& pwads)
if (FName(lmp->getName(), true) == gameinfo)
{
// Found one!
FString iwad = ParseGameInfo(pwads, resfile->FileName, (const char*)lmp->Lock(), lmp->LumpSize);
auto bases = ParseGameInfo(pwads, resfile->FileName, (const char*)lmp->Lock(), lmp->LumpSize);
delete resfile;
return iwad;
return bases;
}
}
delete resfile;
}
}
return "";
return TArray<FString>();
}
//==========================================================================
@ -201,7 +201,7 @@ static FString CheckGameInfo(TArray<FString>& pwads)
//
//==========================================================================
FString GetGameFronUserFiles()
TArray<FString> GetGameFronUserFiles()
{
TArray<FString> Files;

View file

@ -437,7 +437,7 @@ static void BuildEpisodeMenu()
{
ld->mItems.Pop(popped);
}
if (isBlood()) gDefaultSkill = 2;
ld->mSelectedItem = gDefaultSkill + ld->mItems.Size(); // account for pre-added items
int y = ld->mYpos;

View file

@ -460,6 +460,11 @@ static TArray<GrpInfo> ParseGrpInfo(const char *fn, FileReader &fr, TMap<FString
sc.MustGetToken(TK_StringConst);
grp.gamefilter = sc.String;
}
else if (sc.Compare("gameid"))
{
sc.MustGetToken(TK_StringConst);
grp.gameid = sc.String;
}
else if (sc.Compare("fgcolor"))
{
sc.MustGetToken(TK_IntConst);

View file

@ -599,13 +599,14 @@ void artClearMapArt(void)
void artSetupMapArt(const char* filename)
{
if (currentMapArt.CompareNoCase(filename)) return;
currentMapArt = filename;
artClearMapArt();
FString lcfilename = filename;
FString lcfilename = StripExtension(filename);
lcfilename.MakeLower();
if (currentMapArt.CompareNoCase(lcfilename) == 0) return;
artClearMapArt();
currentMapArt = lcfilename;
// Re-get from the texture manager if this map's tiles have already been created.
if (TileFiles.maptilesadded.Find(lcfilename) < TileFiles.maptilesadded.Size())
{
@ -635,7 +636,7 @@ void artSetupMapArt(const char* filename)
for (int i = 0; i < MAXARTFILES_TOTAL - MAXARTFILES_BASE; i++)
{
FStringf fullname("%s_%02d.art", filename, i);
FStringf fullname("%s_%02d.art", lcfilename.GetChars(), i);
TileFiles.LoadArtFile(fullname, filename);
}
}

View file

@ -126,6 +126,11 @@ void GameInterface::GetInput(InputPacket* packet, ControlInfo* const hidInput)
{
applylook(&pPlayer->angle, input.avel, &sPlayerInput[nLocalPlayer].actions, scaleAdjust);
sethorizon(&pPlayer->horizon, input.horz, &sPlayerInput[nLocalPlayer].actions, scaleAdjust);
if (input.horz)
{
pPlayer->bPlayerPan = pPlayer->bLockPan = true;
}
}
pPlayer->angle.processhelpers(scaleAdjust);

View file

@ -436,7 +436,7 @@ void RestartPlayer(short nPlayer)
nYDamage[nPlayer] = 0;
nXDamage[nPlayer] = 0;
plr->horizon.ohoriz = plr->horizon.horiz = q16horiz(0);
plr->nDestVertPan = plr->horizon.ohoriz = plr->horizon.horiz = q16horiz(0);
nBreathTimer[nPlayer] = 90;
nTauntTimer[nPlayer] = RandomSize(3) + 3;
@ -456,6 +456,8 @@ void RestartPlayer(short nPlayer)
SetMagicFrame();
RestoreGreenPal();
plr->bPlayerPan = plr->bLockPan = false;
}
ototalvel[nPlayer] = totalvel[nPlayer] = 0;
@ -1030,13 +1032,14 @@ void FuncPlayer(int a, int nDamage, int nRun)
StopLocalSound();
InitSpiritHead();
PlayerList[nPlayer].nDestVertPan = q16horiz(0);
if (currentLevel->levelNumber == 11)
{
PlayerList[nPlayer].horizon.settarget(46);
PlayerList[nPlayer].nDestVertPan = q16horiz(46);
}
else
{
PlayerList[nPlayer].horizon.settarget(11);
PlayerList[nPlayer].nDestVertPan = q16horiz(11);
}
}
}
@ -1064,7 +1067,7 @@ void FuncPlayer(int a, int nDamage, int nRun)
zVelB = -zVelB;
}
if (zVelB > 512 && PlayerList[nPlayer].horizon.horiz.asq16() != 0 && (sPlayerInput[nPlayer].actions & (SB_AIMMODE))) {
if (zVelB > 512 && !PlayerList[nPlayer].horizon.horiz.asq16() && !(sPlayerInput[nPlayer].actions & SB_AIMMODE)) {
sPlayerInput[nPlayer].actions |= SB_CENTERVIEW;
}
}
@ -1163,29 +1166,9 @@ void FuncPlayer(int a, int nDamage, int nRun)
}
sectdone:
if (!PlayerList[nPlayer].horizon.horiz.asbuild() || PlayerList[nPlayer].bIsFalling)
if (!PlayerList[nPlayer].bPlayerPan && !PlayerList[nPlayer].bLockPan)
{
// Calculate base pan amount based on how much the player is falling.
fixed_t dVertPan = (spr_z - sprite[nPlayerSprite].z) << 9;
if (!bUnderwater && dVertPan != 0)
{
fixed_t adjustment;
if (dVertPan >= IntToFixed(4))
adjustment = 4;
else if (dVertPan <= -IntToFixed(4))
adjustment = -4;
else
adjustment = dVertPan << 1;
PlayerList[nPlayer].horizon.addadjustment(adjustment);
PlayerList[nPlayer].bIsFalling = true;
}
else
{
sPlayerInput[nPlayer].actions |= SB_CENTERVIEW;
PlayerList[nPlayer].bIsFalling = false;
}
PlayerList[nPlayer].nDestVertPan = q16horiz(clamp((spr_z - sprite[nPlayerSprite].z) << 9, gi->playerHorizMin(), gi->playerHorizMax()));
}
playerX -= sprite[nPlayerSprite].x;
@ -2653,11 +2636,40 @@ loc_1BD2E:
PlayerList[nPlayer].field_2 = 0;
}
Player* pPlayer = &PlayerList[nPlayer];
if (actions & (SB_LOOK_UP | SB_LOOK_DOWN))
{
pPlayer->nDestVertPan = pPlayer->horizon.horiz;
pPlayer->bPlayerPan = pPlayer->bLockPan = true;
}
else if (actions & (SB_AIM_UP | SB_AIM_DOWN | SB_CENTERVIEW))
{
pPlayer->nDestVertPan = pPlayer->horizon.horiz;
pPlayer->bPlayerPan = pPlayer->bLockPan = false;
}
if (SyncInput())
{
Player* pPlayer = &PlayerList[nPlayer];
sethorizon(&pPlayer->horizon, sPlayerInput[nPlayer].pan, &sPlayerInput[nLocalPlayer].actions);
}
if (sPlayerInput[nPlayer].pan)
{
pPlayer->nDestVertPan = pPlayer->horizon.horiz;
pPlayer->bPlayerPan = pPlayer->bLockPan = true;
}
if (totalvel[nPlayer] > 20)
{
pPlayer->bPlayerPan = false;
}
double nVertPan = (pPlayer->nDestVertPan - pPlayer->horizon.horiz).asq16() * (1. / (FRACUNIT << 2));
if (nVertPan != 0)
{
pPlayer->horizon.addadjustment(abs(nVertPan) >= 4 ? clamp(nVertPan, -4, 4) : nVertPan * 2.);
}
}
else // else, player's health is less than 0
{
@ -2849,7 +2861,6 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, Player& w, Player*
("field38", w.field_38)
("field3a", w.field_3A)
("field3c", w.field_3C)
("bIsFalling", w.bIsFalling)
("seq", w.nSeq)
("horizon", w.horizon)
("angle", w.angle)

View file

@ -71,7 +71,8 @@ struct Player
short field_3A;
short field_3C;
short nRun;
bool bIsFalling;
bool bPlayerPan, bLockPan;
fixedhoriz nDestVertPan;
PlayerHorizon horizon;
PlayerAngle angle;

View file

@ -4,7 +4,7 @@ CRC
DUKEKR_CRC 0xAA4F6A40
DUKE15_CRC 0xFD3DCFF1
DUKEPP_CRC 0xF514A6AC
DUKEWT_CRC 0x982AFE4A
DukeWorldTour_CRC 0x982AFE4A
DUKE099_CRC 0x02F18900
DUKE10_CRC 0xA28AA589
DUKE11_CRC 0x912E1E8D
@ -54,6 +54,7 @@ grpinfo
dependency 0
FgColor 0xffff00
BkColor 0xff6f00
GameID "Duke13"
}
grpinfo
@ -66,6 +67,7 @@ grpinfo
dependency 0
FgColor 0xffff00
BkColor 0xff6f00
GameID "Duke13"
}
grpinfo
@ -78,18 +80,20 @@ grpinfo
dependency 0
FgColor 0xffff00
BkColor 0xff6f00
GameID "Duke3D"
}
grpinfo
{
name "Duke Nukem 3D: Atomic Edition (WT)"
size 44356548
crc DUKEWT_CRC
crc DukeWorldTour_CRC
flags GAMEFLAG_DUKE
gamefilter "Duke.Duke"
dependency 0
FgColor 0xffff00
BkColor 0xff6f00
GameID "DukeWorldTour"
}
grpinfo // another variant? I got this one, dated 2016-10-12
@ -102,6 +106,7 @@ grpinfo // another variant? I got this one, dated 2016-10-12
dependency 0
FgColor 0xffff00
BkColor 0xff6f00
GameID "DukeWorldTour"
}
grpinfo
@ -114,6 +119,7 @@ grpinfo
dependency 0
FgColor 0xffff00
BkColor 0xff6f00
GameID "Duke3D"
}
grpinfo
@ -196,6 +202,7 @@ grpinfo
flags GAMEFLAG_DUKE|GAMEFLAG_ADDON|GAMEFLAG_DUKEDC
dependency DUKE13_CRC
gamefilter "Duke.DukeDC"
GameID "DukeDC13"
}
grpinfo
@ -206,6 +213,7 @@ grpinfo
flags GAMEFLAG_DUKE|GAMEFLAG_ADDON|GAMEFLAG_DUKEDC
dependency DUKE15_CRC
gamefilter "Duke.DukeDC"
GameID "DukeDC"
}
grpinfo
@ -216,6 +224,7 @@ grpinfo
flags GAMEFLAG_DUKE|GAMEFLAG_ADDON|GAMEFLAG_DUKEDC
dependency DUKE15_CRC
gamefilter "Duke.DukeDC"
GameID "DukeDC"
}
grpinfo
@ -227,6 +236,7 @@ grpinfo
flags GAMEFLAG_DUKE|GAMEFLAG_ADDON|GAMEFLAG_DUKEDC
dependency DUKE15_CRC
gamefilter "Duke.DukeDC"
GameID "DukeDC"
}
// These are a bit strange but without anything to check I do not know in what way.
@ -244,6 +254,7 @@ grpinfo
gamefilter "Duke.Vacation"
FgColor 0x00004f
BkColor 0x8f8fff
GameID "DukeVacation"
}
grpinfo
@ -257,6 +268,7 @@ grpinfo
gamefilter "Duke.Vacation"
FgColor 0x00004f
BkColor 0x8f8fff
GameID "DukeVacation"
}
grpinfo
@ -270,6 +282,7 @@ grpinfo
gamefilter "Duke.NWinter"
FgColor 0
BkColor 0x8f8f8f
GameID "NuclearWinter"
}
grpinfo
@ -291,6 +304,7 @@ grpinfo
dependency DUKE15_CRC
mustcontain "FIREFLYTROOPER.CON", "FLAMETHROWER.CON", "music/E5L1_BulletDam.ogg", "sound/VO_E5L1_Duke_CreamAndSugar.ogg"
gamefilter "Duke.Worldtour"
GameID "DukeWorldTour"
}
grpinfo
@ -339,6 +353,7 @@ grpinfo
gamefilter "Blood.Blood"
FgColor 0
BkColor 0x7f003f
GameID "Blood10"
}
grpinfo
@ -354,6 +369,7 @@ grpinfo
gamefilter "Blood.Blood"
FgColor 0
BkColor 0xaf0024
GameID "Blood11"
}
grpinfo
@ -369,6 +385,7 @@ grpinfo
gamefilter "Blood.Blood"
FgColor 0
BkColor 0xaf0024
GameID "Blood"
}
grpinfo
@ -384,6 +401,7 @@ grpinfo
gamefilter "Blood.Blood"
FgColor 0
BkColor 0x7f002f
GameID "Blood"
}
/* this doesn't work with the current setup.
@ -411,6 +429,7 @@ grpinfo
dependency BLOOD_CRC
loadart "CPART07.AR_", "CPART15.AR_"
gamefilter "Blood.Cryptic"
GameID "CyrpticPassage"
}
addon
@ -423,6 +442,7 @@ addon
dependency BLOOD_CRC
loadart "CPART07.AR_", "CPART15.AR_"
gamefilter "Blood.Cryptic"
GameID "CyrpticPassage"
}
addon
@ -436,6 +456,7 @@ addon
dependency BLOOD_CRC
loadart "CPART07.AR_", "CPART15.AR_"
gamefilter "Blood.Cryptic"
GameID "CyrpticPassage"
}
addon
@ -448,6 +469,7 @@ addon
flags GAMEFLAG_BLOOD|GAMEFLAG_ADDON
dependency BLOOD_CRC
gamefilter "Blood.Cryptic"
GameID "CyrpticPassage"
}
grpinfo
@ -460,6 +482,7 @@ grpinfo
gamefilter "ShadowWarrior.ShadowWarrior"
FgColor 0
BkColor 0xaf0000
GameID "ShadowWarrior"
}
grpinfo
@ -472,6 +495,7 @@ grpinfo
gamefilter "ShadowWarrior.ShadowWarrior"
FgColor 0
BkColor 0xaf0000
GameID "ShadowWarrior"
}
grpinfo
@ -484,6 +508,7 @@ grpinfo
gamefilter "ShadowWarrior.ShadowWarrior"
FgColor 0
BkColor 0xaf0000
GameID "ShadowWarrior"
}
grpinfo
@ -496,6 +521,7 @@ grpinfo
gamefilter "ShadowWarrior.ShadowWarrior"
FgColor 0
BkColor 0xaf0000
GameID "ShadowWarrior"
}
grpinfo
@ -555,6 +581,7 @@ grpinfo
defname "sw.def"
dependency SWREG12_CRC
gamefilter "ShadowWarrior.Wanton"
GameID "WantonDestruction"
}
grpinfo
@ -566,6 +593,7 @@ grpinfo
defname "sw.def"
dependency SWREG12_CRC
gamefilter "ShadowWarrior.Wanton"
GameID "WantonDestruction"
}
grpinfo
@ -578,6 +606,7 @@ grpinfo
dependency SWREG12_CRC
gamefilter "ShadowWarrior.Wanton"
deletecontent "swcustom.txt" // not localizable and also not present in the alternative packages.
GameID "WantonDestruction"
}
grpinfo
@ -590,6 +619,7 @@ grpinfo
dependency SWREG12_CRC
gamefilter "ShadowWarrior.TwinDragon"
deletecontent "swcustom.txt" // not localizable and also not present in the alternative package.
GameID "TwinDragon"
}
grpinfo
@ -601,6 +631,7 @@ grpinfo
defname "twindrag.def"
dependency SWREG12_CRC
gamefilter "ShadowWarrior.TwinDragon"
GameID "TwinDragon"
}
grpinfo
@ -612,6 +643,7 @@ grpinfo
defname "twindrag.def"
dependency SWREG12_CRC
gamefilter "ShadowWarrior.TwinDragon"
GameID "TwinDragon"
}
grpinfo
@ -625,6 +657,7 @@ grpinfo
gamefilter "Redneck.Redneck"
FgColor 0xbc9e89
BkColor 0x7f3300
GameID "Redneck"
}
grpinfo
@ -638,6 +671,7 @@ grpinfo
gamefilter "Redneck.RidesAgain"
FgColor 0xbc9e89
BkColor 0x7f3300
GameID "RedneckRides"
}
grpinfo
@ -651,6 +685,7 @@ grpinfo
loadart "TILESA66.ART", "TILESB66.ART" // replaces TILES009 and TILES023.
gamefilter "Redneck.Route66"
deletecontent "turd66.anm*turdmov.anm", "turd66.voc*turdmov.voc", "end66.anm*rr_outro.anm", "end66.voc*rr_outro.voc" // This renames instead of deleting
GameID "Route66"
}
addon
@ -664,6 +699,7 @@ addon
loadart "TILESA66.ART", "TILESB66.ART" // replaces TILES009 and TILES023.
gamefilter "Redneck.Route66"
deletecontent "turd66.anm*turdmov.anm", "turd66.voc*turdmov.voc", "end66.anm*rr_outro.anm", "end66.voc*rr_outro.voc" // This renames instead of deleting
GameID "Route66"
}
grpinfo
@ -676,6 +712,7 @@ grpinfo
gamefilter "Nam.Nam"
FgColor 0
BkColor 0x78720d
GameID "Nam"
}
grpinfo
@ -688,6 +725,7 @@ grpinfo
gamefilter "Nam.Napalm"
FgColor 0
BkColor 0x78720d
GameID "Nam"
}
grpinfo
@ -700,6 +738,7 @@ grpinfo
gamefilter "WW2GI.WW2GI"
FgColor 0
BkColor 0x78720d
GameID "WW2GI"
}
grpinfo
@ -711,6 +750,7 @@ grpinfo
flags GAMEFLAG_WW2GI|GAMEFLAG_ADDON
dependency WW2GI_CRC
gamefilter "WW2GI.Platoon"
GameID "PlatoonLeader"
}
grpinfo
@ -723,6 +763,7 @@ grpinfo
gamefilter "Exhumed.Powerslave"
FgColor 0xff0000
BkColor 0xffff33
GameID "Exhumed"
}
grpinfo
@ -735,6 +776,7 @@ grpinfo
gamefilter "Exhumed.Exhumed"
FgColor 0xff0000
BkColor 0xffff33
GameID "Exhumed"
}
grpinfo

View file

@ -1888,7 +1888,7 @@ OptionMenu "EngineCredits2"
OptionMenu "EngineCredits2a"
{
title "$MNU_CREDITS"
Submenu " ---->", "EngineCredits3"
Submenu " ---->", "EngineCredits2b"
StaticText "RedNukem / NBlood", 1
StaticText "Alexey \"Nuke.YKT\" Skrybykin", 0
StaticText ""
@ -1900,6 +1900,16 @@ OptionMenu "EngineCredits2a"
StaticText "sirlemonhead", 0
}
OptionMenu "EngineCredits2b"
{
title "$MNU_CREDITS"
Submenu " ---->", "EngineCredits3"
StaticText "Widescreen graphics", 1
StaticText "James Manning   fgsfds            ", 0
StaticText "Dzierzan    Phredreeke      ", 0
StaticText "MaxED        Kinsie   ", 0
}
OptionMenu "EngineCredits3"
{
title "$MNU_CREDITS"