2016-03-11 14:57:17 +01:00
|
|
|
/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
|
|
|
|
|
2016-03-29 03:03:54 +02:00
|
|
|
#include "SeriousSam/StdH.h"
|
2016-03-11 14:57:17 +01:00
|
|
|
#include "LevelInfo.h"
|
2016-03-29 03:03:54 +02:00
|
|
|
|
|
|
|
#ifdef PLATFORM_WIN32
|
2016-03-11 14:57:17 +01:00
|
|
|
#include <io.h>
|
2016-03-29 03:03:54 +02:00
|
|
|
#endif
|
2016-03-11 14:57:17 +01:00
|
|
|
|
|
|
|
CListHead _lhAutoDemos;
|
|
|
|
CListHead _lhAllLevels;
|
|
|
|
CListHead _lhFilteredLevels;
|
|
|
|
extern INDEX sam_bShowAllLevels;
|
|
|
|
|
|
|
|
|
|
|
|
CLevelInfo::CLevelInfo(void)
|
|
|
|
{
|
|
|
|
li_fnLevel = CTString("Levels\\Default.wld");
|
|
|
|
li_strName = TRANS("<invalid level>");
|
|
|
|
li_ulSpawnFlags = 0x0;
|
|
|
|
}
|
|
|
|
CLevelInfo::CLevelInfo(const CLevelInfo &li)
|
|
|
|
{
|
|
|
|
li_fnLevel = li.li_fnLevel;
|
|
|
|
li_strName = li.li_strName;
|
|
|
|
li_ulSpawnFlags = li.li_ulSpawnFlags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLevelInfo::operator=(const CLevelInfo &li)
|
|
|
|
{
|
|
|
|
li_fnLevel = li.li_fnLevel;
|
|
|
|
li_strName = li.li_strName;
|
|
|
|
li_ulSpawnFlags = li.li_ulSpawnFlags;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get level info for given filename
|
|
|
|
BOOL GetLevelInfo(CLevelInfo &li, const CTFileName &fnm)
|
|
|
|
{
|
|
|
|
// try to
|
|
|
|
try {
|
|
|
|
// open the world file
|
|
|
|
CTFileStream strm;
|
|
|
|
strm.Open_t(fnm);
|
|
|
|
// skip initial chunk ids
|
|
|
|
strm.ExpectID_t("BUIV"); // 'build version'
|
|
|
|
INDEX iDummy;
|
|
|
|
strm>>iDummy; // the version number
|
|
|
|
strm.ExpectID_t("WRLD"); // 'world'
|
|
|
|
strm.ExpectID_t("WLIF"); // 'world info'
|
|
|
|
if (strm.PeekID_t()==CChunkID("DTRS")) {
|
|
|
|
strm.ExpectID_t("DTRS"); // 'world info'
|
|
|
|
}
|
|
|
|
// read the name
|
|
|
|
strm>>li.li_strName;
|
|
|
|
// read the flags
|
|
|
|
strm>>li.li_ulSpawnFlags;
|
|
|
|
|
|
|
|
// translate name
|
|
|
|
li.li_strName = TranslateConst(li.li_strName, 0);
|
|
|
|
|
|
|
|
// if dummy name
|
|
|
|
if (li.li_strName=="") {
|
|
|
|
// use filename
|
|
|
|
li.li_strName = fnm.FileName();
|
|
|
|
}
|
|
|
|
|
|
|
|
// remember filename
|
|
|
|
li.li_fnLevel = fnm;
|
|
|
|
|
|
|
|
// succeed
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
// if failed
|
|
|
|
} catch (char *strError) {
|
|
|
|
(void) strError;
|
|
|
|
//CPrintF("Invalid world file '%s': %s\n", (const char*) fnm, strError);
|
|
|
|
// set dummy info
|
|
|
|
li = CLevelInfo();
|
|
|
|
// fail
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int qsort_CompareLevels(const void *elem1, const void *elem2 )
|
|
|
|
{
|
|
|
|
const CLevelInfo &li1 = **(CLevelInfo **)elem1;
|
|
|
|
const CLevelInfo &li2 = **(CLevelInfo **)elem2;
|
|
|
|
return strcmp(li1.li_fnLevel, li2.li_fnLevel);
|
|
|
|
}
|
|
|
|
|
|
|
|
// init level-info subsystem
|
|
|
|
void LoadLevelsList(void)
|
|
|
|
{
|
|
|
|
CPrintF(TRANS("Reading levels directory...\n"));
|
|
|
|
|
|
|
|
// list the levels directory with subdirs
|
|
|
|
CDynamicStackArray<CTFileName> afnmDir;
|
2016-03-29 03:03:54 +02:00
|
|
|
MakeDirList(afnmDir, CTString("Levels\\"), CTString("*.wld"), DLI_RECURSIVE|DLI_SEARCHCD);
|
2016-03-11 14:57:17 +01:00
|
|
|
|
|
|
|
// for each file in the directory
|
|
|
|
for (INDEX i=0; i<afnmDir.Count(); i++) {
|
|
|
|
CTFileName fnm = afnmDir[i];
|
|
|
|
|
|
|
|
CPrintF(TRANS(" file '%s' : "), (const char *)fnm);
|
|
|
|
// try to load its info, and if valid
|
|
|
|
CLevelInfo li;
|
|
|
|
if (GetLevelInfo(li, fnm)) {
|
2016-03-29 03:03:54 +02:00
|
|
|
CPrintF(TRANS("'%s' spawn=0x%08x\n"), (const char *) li.li_strName, li.li_ulSpawnFlags);
|
2016-03-11 14:57:17 +01:00
|
|
|
|
|
|
|
// create new info for that file
|
|
|
|
CLevelInfo *pliNew = new CLevelInfo;
|
|
|
|
*pliNew = li;
|
|
|
|
// add it to list of all levels
|
|
|
|
_lhAllLevels.AddTail(pliNew->li_lnNode);
|
|
|
|
} else {
|
|
|
|
CPrintF(TRANS("invalid level\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// sort the list
|
2016-03-29 03:03:54 +02:00
|
|
|
_lhAllLevels.Sort(qsort_CompareLevels, _offsetof(CLevelInfo, li_lnNode));
|
2016-03-11 14:57:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// cleanup level-info subsystem
|
|
|
|
void ClearLevelsList(void)
|
|
|
|
{
|
|
|
|
// delete list of levels
|
|
|
|
FORDELETELIST(CLevelInfo, li_lnNode, _lhAllLevels, itli) {
|
|
|
|
delete &itli.Current();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// find all levels that match given flags
|
|
|
|
void FilterLevels(ULONG ulSpawnFlags)
|
|
|
|
{
|
|
|
|
// delete list of filtered levels
|
|
|
|
{FORDELETELIST(CLevelInfo, li_lnNode, _lhFilteredLevels, itli) {
|
|
|
|
delete &itli.Current();
|
|
|
|
}}
|
|
|
|
|
|
|
|
// for each level in main list
|
|
|
|
FOREACHINLIST(CLevelInfo, li_lnNode, _lhAllLevels, itli) {
|
|
|
|
CLevelInfo &li = *itli;
|
|
|
|
|
|
|
|
// initially, the level is not visible in list
|
|
|
|
BOOL bVisible = FALSE;
|
|
|
|
// if all levels are shown, it is visible
|
|
|
|
if (sam_bShowAllLevels) {
|
|
|
|
bVisible = TRUE;
|
|
|
|
// if it satisfies the spawn flags
|
|
|
|
} else if (li.li_ulSpawnFlags&ulSpawnFlags) {
|
|
|
|
// if spawn flags include single player
|
|
|
|
if (ulSpawnFlags&SPF_SINGLEPLAYER) {
|
|
|
|
// visibile only if visited already
|
|
|
|
bVisible = FileExists(li.li_fnLevel.NoExt()+".vis");
|
|
|
|
// if not single player
|
|
|
|
} else {
|
|
|
|
// it is visibile
|
|
|
|
bVisible = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if visible
|
|
|
|
if (bVisible) {
|
|
|
|
// make a copy
|
|
|
|
CLevelInfo *pliNew = new CLevelInfo;
|
|
|
|
*pliNew = li;
|
|
|
|
// add it to the list of filtered levels
|
|
|
|
_lhFilteredLevels.AddTail(pliNew->li_lnNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if level doesn't support given flags, find one that does
|
|
|
|
void ValidateLevelForFlags(CTString &fnm, ULONG ulSpawnFlags)
|
|
|
|
{
|
|
|
|
// for each level in main list
|
|
|
|
{FOREACHINLIST(CLevelInfo, li_lnNode, _lhAllLevels, itli) {
|
|
|
|
CLevelInfo &li = *itli;
|
|
|
|
// if found
|
|
|
|
if (li.li_fnLevel == fnm) {
|
|
|
|
// if it satisfies the flags
|
|
|
|
if (li.li_ulSpawnFlags&ulSpawnFlags) {
|
|
|
|
// all ok
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
|
|
|
|
// for each level in main list
|
|
|
|
{FOREACHINLIST(CLevelInfo, li_lnNode, _lhAllLevels, itli) {
|
|
|
|
CLevelInfo &li = *itli;
|
|
|
|
// if it satisfies the flags
|
|
|
|
if (li.li_ulSpawnFlags&ulSpawnFlags) {
|
|
|
|
// use that one
|
|
|
|
fnm = li.li_fnLevel;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
|
|
|
|
// if nothing found, use default invalid level
|
|
|
|
fnm = CLevelInfo().li_fnLevel;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get level info for its filename
|
|
|
|
CLevelInfo FindLevelByFileName(const CTFileName &fnm)
|
|
|
|
{
|
|
|
|
// for each level in main list
|
|
|
|
FOREACHINLIST(CLevelInfo, li_lnNode, _lhAllLevels, itli) {
|
|
|
|
CLevelInfo &li = *itli;
|
|
|
|
// if found
|
|
|
|
if (li.li_fnLevel == fnm) {
|
|
|
|
// return it
|
|
|
|
return li;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if none found, return dummy
|
|
|
|
return CLevelInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
int qsort_CompareDemos(const void *elem1, const void *elem2 )
|
|
|
|
{
|
|
|
|
const CLevelInfo &li1 = **(CLevelInfo **)elem1;
|
|
|
|
const CLevelInfo &li2 = **(CLevelInfo **)elem2;
|
|
|
|
return strcmp(li1.li_fnLevel, li2.li_fnLevel);
|
|
|
|
}
|
|
|
|
|
|
|
|
// init list of autoplay demos
|
|
|
|
void LoadDemosList(void)
|
|
|
|
{
|
|
|
|
CPrintF(TRANS("Reading demos directory...\n"));
|
|
|
|
|
|
|
|
// list the levels directory with subdirs
|
|
|
|
CDynamicStackArray<CTFileName> afnmDir;
|
2016-03-29 03:03:54 +02:00
|
|
|
MakeDirList(afnmDir, CTString("Demos\\"), CTString("Demos\\auto-*.dem"), DLI_RECURSIVE);
|
2016-03-11 14:57:17 +01:00
|
|
|
|
|
|
|
// for each file in the directory
|
|
|
|
for (INDEX i=0; i<afnmDir.Count(); i++) {
|
|
|
|
CTFileName fnm = afnmDir[i];
|
|
|
|
// create new info for that file
|
|
|
|
CLevelInfo *pli = new CLevelInfo;
|
|
|
|
pli->li_fnLevel = fnm;
|
|
|
|
CPrintF(" %s\n", (const char *)pli->li_fnLevel);
|
|
|
|
// add it to list
|
|
|
|
_lhAutoDemos.AddTail(pli->li_lnNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
// sort the list
|
2016-03-29 03:03:54 +02:00
|
|
|
_lhAutoDemos.Sort(qsort_CompareDemos, _offsetof(CLevelInfo, li_lnNode));
|
2016-03-11 14:57:17 +01:00
|
|
|
|
|
|
|
// add the intro to the start
|
|
|
|
extern CTString sam_strIntroLevel;
|
|
|
|
if (sam_strIntroLevel!="") {
|
|
|
|
CLevelInfo *pli = new CLevelInfo;
|
|
|
|
pli->li_fnLevel = sam_strIntroLevel;
|
|
|
|
CPrintF(" %s\n", (const char *)pli->li_fnLevel);
|
|
|
|
_lhAutoDemos.AddHead(pli->li_lnNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear list of autoplay demos
|
|
|
|
void ClearDemosList(void)
|
|
|
|
{
|
|
|
|
// delete list of levels
|
|
|
|
FORDELETELIST(CLevelInfo, li_lnNode, _lhAllLevels, itli) {
|
|
|
|
delete &itli.Current();
|
|
|
|
}
|
|
|
|
}
|