raze/source/core/mapinfo.h
Christoph Oelckers 9340f39053 use the actor's metadata in PickupAmmo
This allows removing the AmmoItemData array.
Also make some tweaks to handle the nnext extension for customizable ammo amount given. Instead of tying it to gModernMap this now also uses a feature flag that will later be exposed to RMAPINFO.
2023-10-08 09:41:11 +02:00

347 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 featureflags = 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
};