2019-12-09 23:01:45 +00:00
# pragma once
# include "gstrings.h"
2019-12-10 16:35:28 +00:00
# include "cmdlib.h"
2019-12-10 23:57:53 +00:00
# include "quotemgr.h"
2021-05-01 20:52:28 +00:00
# include "palentry.h"
# include "vectors.h"
2019-12-10 23:57:53 +00:00
# ifdef GetMessage
# undef GetMessage // Windows strikes...
# endif
2019-12-09 23:01:45 +00:00
2020-10-04 16:31:48 +00:00
enum EMax
{
MAXSKILLS = 7 ,
MAXMENUGAMEPLAYENTRIES = 7 ,
} ;
2020-10-06 23:31:41 +00:00
enum EVolFlags
{
2021-05-01 20:52:28 +00:00
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 ,
2021-05-02 08:55:22 +00:00
LEVEL_FORCENOEOG = 16 , // RR E1L7 needs this to override its boss's death ending the game.
2021-05-01 20:52:28 +00:00
} ;
enum EMapGameFlags
{
LEVEL_RR_HULKSPAWN = 1 ,
LEVEL_RR_CLEARMOONSHINE = 2 ,
2020-10-06 23:31:41 +00:00
} ;
2020-10-04 16:31:48 +00:00
// These get filled in by the map definition parsers of the front ends.
extern FString gSkillNames [ MAXSKILLS ] ;
extern int gDefaultVolume , gDefaultSkill ;
2019-12-09 23:01:45 +00:00
// Localization capable replacement of the game specific solutions.
inline void MakeStringLocalizable ( FString & quote )
{
// Only prepend a quote if the string is localizable.
if ( quote . Len ( ) > 0 & & quote [ 0 ] ! = ' $ ' & & GStrings [ quote ] ) quote . Insert ( 0 , " $ " ) ;
}
2019-12-10 21:22:59 +00:00
enum
{
MI_FORCEEOG = 1 ,
2020-07-07 11:19:09 +00:00
MI_USERMAP = 2 ,
2019-12-10 21:22:59 +00:00
} ;
2020-08-03 18:12:33 +00:00
enum {
MAX_MESSAGES = 32
} ;
2021-04-25 23:45:16 +00:00
class DObject ;
2021-04-27 22:51:28 +00:00
struct MapRecord ;
2021-04-25 23:45:16 +00:00
struct CutsceneDef
{
FString video ;
FString function ;
2021-05-01 20:52:28 +00:00
FString soundName ;
int soundID ; // ResID not SoundID!
2021-04-25 23:45:16 +00:00
int sound = 0 ;
int framespersec = 0 ; // only relevant for ANM.
2021-04-27 23:15:15 +00:00
bool transitiononly = false ; // only play when transitioning between maps, but not when starting on a map or ending a game.
2021-04-25 23:45:16 +00:00
void Create ( DObject * runner ) ;
2021-04-27 23:15:15 +00:00
bool Create ( DObject * runner , MapRecord * map , bool transition ) ;
2021-05-01 20:52:28 +00:00
bool isdefined ( ) { return video . IsNotEmpty ( ) | | function . IsNotEmpty ( ) ; }
int GetSound ( ) ;
2021-04-25 23:45:16 +00:00
} ;
struct GlobalCutscenes
{
CutsceneDef Intro ;
CutsceneDef DefaultMapIntro ;
CutsceneDef DefaultMapOutro ;
2021-05-02 10:22:40 +00:00
CutsceneDef DefaultGameover ;
2021-04-27 22:51:28 +00:00
CutsceneDef SharewareEnd ;
2021-04-27 23:12:07 +00:00
CutsceneDef LoadingScreen ;
2021-04-25 23:45:16 +00:00
FString MPSummaryScreen ;
FString SummaryScreen ;
} ;
2021-05-01 20:52:28 +00:00
struct ClusterDef
2021-04-25 23:45:16 +00:00
{
2021-05-01 20:52:28 +00:00
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
int gameflags = 0 ; // game specific flags.
} ;
struct VolumeRecord // episodes
{
FString startmap ;
2021-04-25 23:45:16 +00:00
FString name ;
FString subtitle ;
2021-05-01 20:52:28 +00:00
int index = - 1 ;
int flags = 0 ;
int shortcut = 0 ;
2021-04-25 23:45:16 +00:00
} ;
2019-12-09 23:01:45 +00:00
struct MapRecord
{
2020-07-01 18:31:29 +00:00
int parTime = 0 ;
int designerTime = 0 ;
2019-12-09 23:01:45 +00:00
FString fileName ;
2019-12-10 16:35:28 +00:00
FString labelName ;
2019-12-09 23:01:45 +00:00
FString name ;
FString music ;
2021-05-01 20:52:28 +00:00
FString Author ;
FString NextMap ;
FString NextSecret ;
int cdSongId = - 1 ;
int musicorder = - 1 ;
2021-04-25 23:45:16 +00:00
CutsceneDef intro ;
CutsceneDef outro ;
2019-12-11 22:41:05 +00:00
int flags = 0 ;
2021-05-01 20:52:28 +00:00
int gameflags = 0 ;
2020-07-01 18:31:29 +00:00
int levelNumber = - 1 ;
2021-05-01 20:52:28 +00:00
int mapindex = - 1 ; // index in the episode. This only for finding the next map in the progression when nothing explicit is defined.
2021-04-27 18:04:11 +00:00
int cluster = - 1 ;
2019-12-09 23:01:45 +00:00
2021-05-01 20:52:28 +00:00
PalEntry fadeto = 0 ;
int fogdensity = 0 ;
int skyfog = 0 ;
FString BorderTexture ;
FString InterBackground ;
TArray < FString > PrecacheTextures ;
FVector4 skyrotatevector ;
2019-12-09 23:01:45 +00:00
// The rest is only used by Blood
2020-08-03 18:12:33 +00:00
FString messages [ MAX_MESSAGES ] ;
2019-12-10 23:57:53 +00:00
int8_t fog = - 1 , weather = - 1 ; // Blood defines these but they aren't used.
2021-05-01 20:52:28 +00:00
// game specific stuff
int rr_startsound = 0 ;
2019-12-09 23:01:45 +00:00
2020-07-07 11:19:09 +00:00
const char * LabelName ( ) const
{
if ( flags & MI_USERMAP ) return GStrings ( " TXT_USERMAP " ) ;
return labelName ;
}
const char * DisplayName ( ) const
2019-12-09 23:01:45 +00:00
{
2019-12-10 16:35:28 +00:00
if ( name . IsEmpty ( ) ) return labelName ;
2019-12-09 23:01:45 +00:00
return GStrings . localize ( name ) ;
}
void SetName ( const char * n )
{
name = n ;
MakeStringLocalizable ( name ) ;
}
2019-12-10 16:35:28 +00:00
void SetFileName ( const char * n )
{
2020-09-03 21:10:28 +00:00
if ( * n = = ' / ' | | * n = = ' \\ ' ) n + + ;
2019-12-10 16:35:28 +00:00
fileName = n ;
2020-03-01 06:28:40 +00:00
FixPathSeperator ( fileName ) ;
2019-12-10 16:35:28 +00:00
labelName = ExtractFileBase ( n ) ;
}
2019-12-10 23:57:53 +00:00
const char * GetMessage ( int num )
{
2020-08-03 18:12:33 +00:00
if ( num < 0 | | num > = MAX_MESSAGES ) return " " ;
return GStrings ( messages [ num ] ) ;
}
void AddMessage ( int num , const FString & msg )
{
messages [ num ] = msg ;
2019-12-10 23:57:53 +00:00
}
2019-12-09 23:01:45 +00:00
} ;
2021-04-26 00:00:40 +00:00
struct SummaryInfo
{
int kills ;
int maxkills ;
int secrets ;
int maxsecrets ;
int supersecrets ;
int time ;
2021-04-26 19:13:11 +00:00
int playercount ;
2021-04-26 00:00:40 +00:00
bool cheated ;
bool endofgame ;
} ;
2021-04-25 23:45:16 +00:00
extern GlobalCutscenes globalCutscenes ;
2019-12-10 21:22:59 +00:00
extern MapRecord * currentLevel ;
2020-06-23 22:40:22 +00:00
2020-07-07 11:19:09 +00:00
bool SetMusicForMap ( const char * mapname , const char * music , bool namehack = false ) ;
2020-06-23 22:40:22 +00:00
2020-07-07 11:19:09 +00:00
MapRecord * FindMapByName ( const char * nm ) ;
MapRecord * FindMapByLevelNum ( int num ) ;
2021-05-02 07:08:57 +00:00
MapRecord * FindMapByIndexOnly ( int clst , int num ) ; // this is for map setup where fallbacks are undesirable.
MapRecord * FindMapByIndex ( int clst , int num ) ;
2020-07-07 11:19:09 +00:00
MapRecord * FindNextMap ( MapRecord * thismap ) ;
2021-05-02 07:08:57 +00:00
MapRecord * FindNextSecretMap ( MapRecord * thismap ) ;
2020-07-07 18:27:21 +00:00
MapRecord * SetupUserMap ( const char * boardfilename , const char * defaultmusic = nullptr ) ;
MapRecord * AllocateMap ( ) ;
2019-12-10 21:22:59 +00:00
2021-05-01 22:35:56 +00:00
VolumeRecord * FindVolume ( int index ) ;
ClusterDef * FindCluster ( int index ) ;
ClusterDef * AllocateCluster ( ) ;
VolumeRecord * AllocateVolume ( ) ;
2021-05-01 20:52:28 +00:00
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 ;
}
2020-08-03 18:11:30 +00:00
// These should be the only places converting between level numbers and volume/map pairs
2021-05-01 20:52:28 +00:00
constexpr inline int makelevelnum ( int vol , int map )
2020-08-03 18:11:30 +00:00
{
return vol * 1000 + map ;
}
2019-12-10 21:22:59 +00:00
enum
{
RRENDSLOT = 127
2020-08-03 18:11:30 +00:00
} ;