raze/source/core/mapinfo.h
2023-12-05 22:39:27 +01:00

346 lines
7 KiB
C++

#pragma once
#include "gstrings.h"
#include "cmdlib.h"
#include "quotemgr.h"
#include "palentry.h"
#include "vectors.h"
#include "screenjob.h"
#include "maptypes.h"
#include "d_net.h"
#ifdef GetMessage
#undef GetMessage // Windows strikes...
#endif
enum EMax
{
MAXSKILLS = 7,
MAXMENUGAMEPLAYENTRIES = 7,
};
enum EVolFlags
{
VF_HIDEFROMSP = 1,
VF_OPTIONAL = 2,
VF_SHAREWARELOCK = 4, // show in shareware but lock access.
VF_NOSKILL = 8,
};
enum EMapFlags
{
LEVEL_NOINTERMISSION = 1,
LEVEL_SECRETEXITOVERRIDE = 2, // when given an explicit level number, override with secret exit in the map, mainly for compiling episodes out of single levels.
LEVEL_CLEARINVENTORY = 4,
LEVEL_CLEARWEAPONS = 8,
LEVEL_FORCENOEOG = 16, // RR E1L7 needs this to override its boss's death ending the game.
};
enum EMapGameFlags
{
LEVEL_RR_HULKSPAWN = 1,
LEVEL_RR_CLEARMOONSHINE = 2,
LEVEL_EX_COUNTDOWN = 4,
LEVEL_EX_TRAINING = 8,
LEVEL_EX_ALTSOUND = 16,
LEVEL_EX_MULTI = 32,
LEVEL_SW_SPAWNMINES = 64,
LEVEL_SW_BOSSMETER_SERPENT = 128,
LEVEL_SW_BOSSMETER_SUMO = 256,
LEVEL_SW_BOSSMETER_ZILLA = 512,
LEVEL_SW_DEATHEXIT_SERPENT = 1024,
LEVEL_SW_DEATHEXIT_SUMO = 2048,
LEVEL_SW_DEATHEXIT_ZILLA = 4096,
LEVEL_SW_DEATHEXIT_SERPENT_NEXT = 8192,
LEVEL_WT_BOSSSPAWN = 16384,
LEVEL_BOSSONLYCUTSCENE = 32768,
};
// These get filled in by the map definition parsers of the front ends.
extern FString gSkillNames[MAXSKILLS];
extern int gDefaultVolume, gDefaultSkill;
// Localization capable replacement of the game specific solutions.
enum
{
MI_FORCEEOG = 1,
MI_USERMAP = 2,
};
enum {
MAX_MESSAGES = 32
};
class DObject;
struct MapRecord;
struct GlobalCutscenes
{
CutsceneDef Intro;
CutsceneDef DefaultMapIntro;
CutsceneDef DefaultMapOutro;
CutsceneDef DefaultGameover;
CutsceneDef SharewareEnd;
CutsceneDef LoadingScreen;
FString MPSummaryScreen;
FString SummaryScreen;
FString StatusBarClass;
};
struct ClusterDef
{
FString name; // What gets displayed for this cluster. In Duke this is normally the corresponding volume name but does not have to be.
CutsceneDef intro; // plays when entering this cluster
CutsceneDef outro; // plays when leaving this cluster
CutsceneDef gameover; // when defined, plays when the player dies in this cluster
FString InterBackground;
int index = -1;
int flags = 0; // engine and common flags
};
struct VolumeRecord // episodes
{
FString startmap;
FString name;
FString subtitle;
int index = -1;
int flags = 0;
int shortcut = 0;
};
struct MapRecord
{
int parTime = 0;
int designerTime = 0;
FString fileName;
FString labelName;
FString name;
FString music;
FString Author;
FString NextMap;
FString NextSecret;
int cdSongId = -1;
int musicorder = -1;
CutsceneDef intro;
CutsceneDef outro;
int flags = 0;
int gameflags = 0;
int levelNumber = -1;
int cluster = -1;
PalEntry fadeto = 0;
int fogdensity = 0;
int skyfog = 0;
FString BorderTexture;
FString InterBackground;
TArray<FString> PrecacheTextures;
FVector4 skyrotatevector;
// The rest is only used by Blood
FString messages[MAX_MESSAGES];
int8_t fog = -1, weather = -1; // Blood defines these but they aren't used.
// game specific stuff
int rr_startsound = 0;
int rr_mamaspawn = 15;
DAngle ex_ramses_horiz = maphoriz(-11);
int ex_ramses_cdtrack = -1; // this is not music, it is the actual dialogue!
FString ex_ramses_pup;
FString ex_ramses_text;
const char* LabelName() const
{
if (flags & MI_USERMAP) return GStrings("MNU_USERMAP");
return labelName.GetChars();
}
const char *DisplayName() const
{
if (name.IsEmpty()) return labelName.GetChars();
return GStrings.localize(name.GetChars());
}
void SetName(const char *n)
{
name = n;
name.StripRight();
name = FStringTable::MakeMacro(name.GetChars());
}
void SetFileName(const char* n)
{
if (*n == '/' || *n == '\\') n++;
fileName = n;
FixPathSeperator(fileName);
labelName = ExtractFileBase(n);
}
const char* GetMessage(int num)
{
if (num < 0 || num>= MAX_MESSAGES) return "";
return GStrings(messages[num]);
}
void AddMessage(int num, const FString &msg)
{
messages[num] = msg;
}
};
struct StatRecord
{
int max;
int got;
int player[MAXPLAYERS];
void addTotal(int amount = 1)
{
max += amount;
if (amount < 0 && max < 0) max = 0;
}
void add(int playerno, int amount = 1)
{
got += amount;
if (amount < 0 && got < 0) got = 0;
if (playerno >= 0 && playerno < MAXPLAYERS)
{
player[playerno] += amount;
if (amount < 0 && player[playerno] < 0) player[playerno] = 0;
}
}
void clear()
{
memset(this, 0, sizeof(*this));
}
};
struct SummaryInfo
{
int kills;
int maxkills;
int secrets;
int maxsecrets;
int supersecrets;
int time;
int totaltime;
int playercount;
bool cheated;
bool endofgame;
};
struct MapLocals
{
StatRecord kills, secrets, superSecrets;
void fillSummary(SummaryInfo& sum);
void clearStats()
{
kills.clear();
secrets.clear();
superSecrets.clear();
}
void setKills(int num)
{
kills.clear();
kills.max = num;
}
void setSecrets(int num, int supernum = 0)
{
secrets.clear();
secrets.max = num;
superSecrets.clear();
superSecrets.max = supernum;
}
void addKillCount(int amount = 1)
{
kills.addTotal(amount);
}
void addSecretCount(int amount = 1)
{
secrets.addTotal(amount);
}
void addKill(int playerno, int amount = 1)
{
kills.add(playerno, amount);
}
void addSecret(int playerno, int amount = 1)
{
secrets.add(playerno, amount);
}
void addSuperSecret(int playerno, int amount = 1)
{
superSecrets.add(playerno, amount);
}
void addFrags(int playerno, int amount)
{
// todo
}
};
extern GlobalCutscenes globalCutscenes;
extern MapRecord* currentLevel; // level that is currently played.
extern MapLocals Level;
void SetMusicReplacement(const char *mapname, const char *music);
void ReplaceMusics(bool namehack = false);
bool SetMusicForMap(const char* mapname, const char* music, bool namehack = false);
MapRecord *FindMapByName(const char *nm);
MapRecord *FindMapByLevelNum(int num);
MapRecord* FindMapByIndexOnly(int clst, int num); // this is for map setup where fallbacks are undesirable.
MapRecord* FindMapByIndex(int clst, int num);
MapRecord *FindNextMap(MapRecord *thismap);
MapRecord* FindNextSecretMap(MapRecord* thismap);
MapRecord* SetupUserMap(const char* boardfilename, const char *defaultmusic = nullptr);
MapRecord* AllocateMap();
VolumeRecord* FindVolume(int index);
ClusterDef* FindCluster(int index);
ClusterDef* AllocateCluster();
VolumeRecord* AllocateVolume();
void SetLevelNum(MapRecord* info, int num);
inline VolumeRecord* MustFindVolume(int index)
{
auto r = FindVolume(index);
if (r) return r;
r = AllocateVolume();
r->index = index;
return r;
}
inline ClusterDef* MustFindCluster(int index)
{
auto r = FindCluster(index);
if (r) return r;
r = AllocateCluster();
r->index = index;
return r;
}
// These should be the only places converting between level numbers and volume/map pairs
constexpr inline int makelevelnum(int vol, int map)
{
return vol * 1000 + map;
}
enum
{
RRENDSLOT = 127
};