2009-08-21 20:21:05 +00:00
/*
* This file is part of OpenTTD .
* OpenTTD is free software ; you can redistribute it and / or modify it under the terms of the GNU General Public License as published by the Free Software Foundation , version 2.
* OpenTTD is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
* See the GNU General Public License for more details . You should have received a copy of the GNU General Public License along with OpenTTD . If not , see < http : //www.gnu.org/licenses/>.
*/
2009-08-09 16:54:03 +00:00
/** @file base_media_base.h Generic functions for replacing base data (graphics, sounds). */
# ifndef BASE_MEDIA_BASE_H
# define BASE_MEDIA_BASE_H
# include "fileio_func.h"
2009-12-22 21:40:29 +00:00
# include "gfx_type.h"
2012-03-17 15:45:37 +00:00
# include "textfile_type.h"
# include "textfile_gui.h"
2023-05-18 20:38:56 +00:00
# include "3rdparty/md5/md5.h"
2020-05-17 21:32:06 +00:00
# include <unordered_map>
2009-08-09 16:54:03 +00:00
2009-08-09 18:44:35 +00:00
/* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */
struct IniFile ;
struct ContentInfo ;
2009-08-09 16:54:03 +00:00
/** Structure holding filename and MD5 information about a single file */
struct MD5File {
2009-08-20 17:02:44 +00:00
/** The result of a checksum check */
enum ChecksumResult {
2018-06-07 19:34:24 +00:00
CR_UNKNOWN , ///< The file has not been checked yet
2009-08-20 17:02:44 +00:00
CR_MATCH , ///< The file did exist and the md5 checksum did match
CR_MISMATCH , ///< The file did exist, just the md5 checksum did not match
CR_NO_FILE , ///< The file did not exist
} ;
2023-04-18 20:21:17 +00:00
std : : string filename ; ///< filename
2023-05-18 20:38:56 +00:00
MD5Hash hash ; ///< md5 sum of the file
2023-04-18 20:21:17 +00:00
std : : string missing_warning ; ///< warning when this file is missing
2018-06-07 19:34:24 +00:00
ChecksumResult check_result ; ///< cached result of md5 check
2009-08-09 16:54:03 +00:00
2012-02-04 13:29:00 +00:00
ChecksumResult CheckMD5 ( Subdirectory subdir , size_t max_size ) const ;
2009-08-09 16:54:03 +00:00
} ;
/**
* Information about a single base set .
* @ tparam T the real class we ' re going to be
* @ tparam Tnum_files the number of files in the set
2011-11-14 19:24:22 +00:00
* @ tparam Tsearch_in_tars whether to search in the tars or not
2009-08-09 16:54:03 +00:00
*/
2011-11-14 19:24:22 +00:00
template < class T , size_t Tnum_files , bool Tsearch_in_tars >
2009-08-09 16:54:03 +00:00
struct BaseSet {
2020-05-17 21:32:06 +00:00
typedef std : : unordered_map < std : : string , std : : string > TranslatedStrings ;
2009-10-17 20:34:09 +00:00
2009-08-09 16:54:03 +00:00
/** Number of files in this set */
static const size_t NUM_FILES = Tnum_files ;
2011-11-14 19:24:22 +00:00
/** Whether to search in the tars or not. */
static const bool SEARCH_IN_TARS = Tsearch_in_tars ;
2009-12-22 21:40:29 +00:00
2009-08-09 16:54:03 +00:00
/** Internal names of the files in this set. */
2009-09-20 23:11:01 +00:00
static const char * const * file_names ;
2009-08-09 16:54:03 +00:00
2020-05-17 21:32:06 +00:00
std : : string name ; ///< The name of the base set
2023-11-28 21:07:30 +00:00
std : : string url ; ///< URL for information about the base set
2009-10-17 20:34:09 +00:00
TranslatedStrings description ; ///< Description of the base set
2023-05-08 17:01:06 +00:00
uint32_t shortname ; ///< Four letter short variant of the name
uint32_t version ; ///< The version of this base set
2010-02-22 16:24:23 +00:00
bool fallback ; ///< This set is a fallback set, i.e. it should be used only as last resort
2009-08-09 16:54:03 +00:00
2009-10-17 20:34:09 +00:00
MD5File files [ NUM_FILES ] ; ///< All files part of this set
uint found_files ; ///< Number of the files that could be found
uint valid_files ; ///< Number of the files that could be found and are valid
2009-08-09 16:54:03 +00:00
2009-10-17 20:34:09 +00:00
T * next ; ///< The next base set in this list
2009-08-09 16:54:03 +00:00
/** Free everything we allocated */
~ BaseSet ( )
{
delete this - > next ;
}
/**
* Get the number of missing files .
* @ return the number
*/
int GetNumMissing ( ) const
{
return Tnum_files - this - > found_files ;
}
2009-08-20 17:02:44 +00:00
/**
* Get the number of invalid files .
* @ note a missing file is invalid too !
* @ return the number
*/
int GetNumInvalid ( ) const
{
return Tnum_files - this - > valid_files ;
}
2023-10-10 23:38:57 +00:00
bool FillSetDetails ( const IniFile & ini , const std : : string & path , const std : : string & full_filename , bool allow_empty_filename = true ) ;
2023-10-02 12:37:43 +00:00
void CopyCompatibleConfig ( [ [ maybe_unused ] ] const T & src ) { }
2009-10-17 20:34:09 +00:00
/**
* Get the description for the given ISO code .
* It falls back to the first two characters of the ISO code in case
* no match could be made with the full ISO code . If even then the
* matching fails the default is returned .
* @ param isocode the isocode to search for
* @ return the description
*/
2023-11-10 00:17:36 +00:00
const std : : string & GetDescription ( const std : : string & isocode ) const
2009-10-17 20:34:09 +00:00
{
2020-05-17 21:32:06 +00:00
if ( ! isocode . empty ( ) ) {
2009-10-17 20:34:09 +00:00
/* First the full ISO code */
2020-05-17 21:32:06 +00:00
auto desc = this - > description . find ( isocode ) ;
2023-11-10 00:17:36 +00:00
if ( desc ! = this - > description . end ( ) ) return desc - > second ;
2020-05-17 21:32:06 +00:00
2009-10-17 20:34:09 +00:00
/* Then the first two characters */
2020-05-17 21:32:06 +00:00
desc = this - > description . find ( isocode . substr ( 0 , 2 ) ) ;
2023-11-10 00:17:36 +00:00
if ( desc ! = this - > description . end ( ) ) return desc - > second ;
2009-10-17 20:34:09 +00:00
}
/* Then fall back */
2023-11-10 00:17:36 +00:00
return this - > description . at ( std : : string { } ) ;
2009-10-17 20:34:09 +00:00
}
2012-02-04 13:29:00 +00:00
2023-11-10 12:25:56 +00:00
/**
* Get string to use when listing this set in the settings window .
* If there are no invalid files , then this is just the set name ,
* otherwise a string is formatted including the number of invalid files .
* @ return the string to display .
*/
std : : string GetListLabel ( ) const
{
if ( this - > GetNumInvalid ( ) = = 0 ) return this - > name ;
SetDParamStr ( 0 , this - > name ) ;
SetDParam ( 1 , this - > GetNumInvalid ( ) ) ;
return GetString ( STR_BASESET_STATUS ) ;
}
2012-02-04 13:29:00 +00:00
/**
* Calculate and check the MD5 hash of the supplied file .
* @ param file The file get the hash of .
* @ param subdir The sub directory to get the files from .
* @ return
* - # CR_MATCH if the MD5 hash matches
* - # CR_MISMATCH if the MD5 does not match
* - # CR_NO_FILE if the file misses
*/
static MD5File : : ChecksumResult CheckMD5 ( const MD5File * file , Subdirectory subdir )
{
return file - > CheckMD5 ( subdir , SIZE_MAX ) ;
}
2012-03-17 15:45:37 +00:00
/**
* Search a textfile file next to this base media .
* @ param type The type of the textfile to search for .
2023-05-04 22:04:52 +00:00
* @ return The filename for the textfile .
2012-03-17 15:45:37 +00:00
*/
2023-05-04 22:04:52 +00:00
std : : optional < std : : string > GetTextfile ( TextfileType type ) const
2012-03-17 15:45:37 +00:00
{
for ( uint i = 0 ; i < NUM_FILES ; i + + ) {
2023-05-04 22:04:52 +00:00
auto textfile = : : GetTextfile ( type , BASESET_DIR , this - > files [ i ] . filename ) ;
if ( textfile . has_value ( ) ) {
2012-03-17 15:45:37 +00:00
return textfile ;
}
}
2023-05-04 22:04:52 +00:00
return std : : nullopt ;
2012-03-17 15:45:37 +00:00
}
2009-08-09 16:54:03 +00:00
} ;
/**
2009-08-09 19:50:44 +00:00
* Base for all base media ( graphics , sounds )
2009-08-09 16:54:03 +00:00
* @ tparam Tbase_set the real set we ' re going to be
*/
template < class Tbase_set >
class BaseMedia : FileScanner {
protected :
static Tbase_set * available_sets ; ///< All available sets
2010-08-23 23:49:14 +00:00
static Tbase_set * duplicate_sets ; ///< All sets that aren't available, but needed for not downloading base sets when a newer version than the one on BaNaNaS is loaded.
2009-08-09 16:54:03 +00:00
static const Tbase_set * used_set ; ///< The currently used set
2020-12-06 20:11:50 +00:00
bool AddFile ( const std : : string & filename , size_t basepath_length , const std : : string & tar_filename ) override ;
2009-08-09 16:54:03 +00:00
/**
* Get the extension that is used to identify this set .
* @ return the extension
*/
static const char * GetExtension ( ) ;
public :
/**
* Determine the graphics pack that has to be used .
* The one with the most correct files wins .
* @ return true if a best set has been found .
*/
static bool DetermineBestSet ( ) ;
/** Do the scan for files. */
static uint FindSets ( )
{
BaseMedia < Tbase_set > fs ;
2011-11-14 21:34:27 +00:00
/* Searching in tars is only done in the old "data" directories basesets. */
uint num = fs . Scan ( GetExtension ( ) , Tbase_set : : SEARCH_IN_TARS ? OLD_DATA_DIR : OLD_GM_DIR , Tbase_set : : SEARCH_IN_TARS ) ;
return num + fs . Scan ( GetExtension ( ) , BASESET_DIR , Tbase_set : : SEARCH_IN_TARS ) ;
2009-08-09 16:54:03 +00:00
}
2012-08-20 21:01:40 +00:00
static Tbase_set * GetAvailableSets ( ) ;
2023-10-02 12:17:32 +00:00
static bool SetSet ( const Tbase_set * set ) ;
static bool SetSetByName ( const std : : string & name ) ;
static bool SetSetByShortname ( uint32_t shortname ) ;
2023-05-19 21:22:30 +00:00
static void GetSetsList ( std : : back_insert_iterator < std : : string > & output_iterator ) ;
2009-08-09 16:54:03 +00:00
static int GetNumSets ( ) ;
static int GetIndexOfUsedSet ( ) ;
static const Tbase_set * GetSet ( int index ) ;
static const Tbase_set * GetUsedSet ( ) ;
/**
* Check whether we have an set with the exact characteristics as ci .
* @ param ci the characteristics to search on ( shortname and md5sum )
* @ param md5sum whether to check the MD5 checksum
* @ return true iff we have an set matching .
*/
2009-08-09 18:44:35 +00:00
static bool HasSet ( const ContentInfo * ci , bool md5sum ) ;
2009-08-09 16:54:03 +00:00
} ;
2018-04-21 13:54:46 +00:00
template < class Tbase_set > /* static */ const Tbase_set * BaseMedia < Tbase_set > : : used_set ;
template < class Tbase_set > /* static */ Tbase_set * BaseMedia < Tbase_set > : : available_sets ;
template < class Tbase_set > /* static */ Tbase_set * BaseMedia < Tbase_set > : : duplicate_sets ;
2012-08-20 21:01:40 +00:00
/**
* Check whether there ' s a base set matching some information .
* @ param ci The content info to compare it to .
* @ param md5sum Should the MD5 checksum be tested as well ?
* @ param s The list with sets .
2019-04-10 21:07:06 +00:00
* @ return The filename of the first file of the base set , or \ c nullptr if there is no match .
2012-08-20 21:01:40 +00:00
*/
template < class Tbase_set >
const char * TryGetBaseSetFile ( const ContentInfo * ci , bool md5sum , const Tbase_set * s ) ;
2009-08-09 16:54:03 +00:00
/** Types of graphics in the base graphics set */
enum GraphicsFileType {
GFT_BASE , ///< Base sprites for all climates
GFT_LOGOS , ///< Logos, landscape icons and original terrain generator sprites
GFT_ARCTIC , ///< Landscape replacement sprites for arctic
GFT_TROPICAL , ///< Landscape replacement sprites for tropical
GFT_TOYLAND , ///< Landscape replacement sprites for toyland
GFT_EXTRA , ///< Extra sprites that were not part of the original sprites
2011-12-19 17:48:04 +00:00
MAX_GFT , ///< We are looking for this amount of GRFs
2009-08-09 16:54:03 +00:00
} ;
2011-10-04 21:35:47 +00:00
/** Blitter type for base graphics sets. */
enum BlitterType {
BLT_8BPP , ///< Base set has 8 bpp sprites only.
BLT_32BPP , ///< Base set has both 8 bpp and 32 bpp sprites.
} ;
2023-10-02 12:28:16 +00:00
struct GRFConfig ;
2009-08-09 16:54:03 +00:00
/** All data of a graphics set. */
2011-11-14 19:24:22 +00:00
struct GraphicsSet : BaseSet < GraphicsSet , MAX_GFT , true > {
2023-10-02 12:28:16 +00:00
private :
mutable std : : unique_ptr < GRFConfig > extra_cfg ; ///< Parameters for extra GRF
public :
2009-08-09 16:54:03 +00:00
PaletteType palette ; ///< Palette of this graphics set
2011-10-04 21:35:47 +00:00
BlitterType blitter ; ///< Blitter of this graphics set
2009-08-09 16:54:03 +00:00
2023-10-02 12:28:16 +00:00
GraphicsSet ( ) ;
~ GraphicsSet ( ) ;
2023-10-10 23:38:57 +00:00
bool FillSetDetails ( const IniFile & ini , const std : : string & path , const std : : string & full_filename ) ;
2023-10-02 12:28:16 +00:00
GRFConfig * GetExtraConfig ( ) const { return this - > extra_cfg . get ( ) ; }
GRFConfig & GetOrCreateExtraConfig ( ) const ;
2023-10-02 12:43:10 +00:00
bool IsConfigurable ( ) const ;
2023-10-02 12:37:43 +00:00
void CopyCompatibleConfig ( const GraphicsSet & src ) ;
2012-02-04 13:29:04 +00:00
static MD5File : : ChecksumResult CheckMD5 ( const MD5File * file , Subdirectory subdir ) ;
2009-08-09 16:54:03 +00:00
} ;
/** All data/functions related with replacing the base graphics. */
class BaseGraphics : public BaseMedia < GraphicsSet > {
public :
2023-10-02 11:29:32 +00:00
/** Values loaded from config file. */
struct Ini {
std : : string name ;
2023-10-02 12:17:32 +00:00
uint32_t shortname ; ///< unique key for base set
2023-10-02 12:37:43 +00:00
uint32_t extra_version ; ///< version of the extra GRF
std : : vector < uint32_t > extra_params ; ///< parameters for the extra GRF
2023-10-02 11:29:32 +00:00
} ;
static inline Ini ini_data ;
2009-08-09 16:54:03 +00:00
} ;
2009-08-09 19:50:44 +00:00
/** All data of a sounds set. */
2011-11-14 19:24:22 +00:00
struct SoundsSet : BaseSet < SoundsSet , 1 , true > {
2009-08-09 19:50:44 +00:00
} ;
/** All data/functions related with replacing the base sounds */
class BaseSounds : public BaseMedia < SoundsSet > {
public :
2023-10-02 11:29:32 +00:00
/** The set as saved in the config file. */
static inline std : : string ini_set ;
2009-08-09 19:50:44 +00:00
} ;
2009-12-22 21:40:29 +00:00
/** Maximum number of songs in the 'class' playlists. */
static const uint NUM_SONGS_CLASS = 10 ;
/** Number of classes for songs */
static const uint NUM_SONG_CLASSES = 3 ;
/** Maximum number of songs in the full playlist; theme song + the classes */
static const uint NUM_SONGS_AVAILABLE = 1 + NUM_SONG_CLASSES * NUM_SONGS_CLASS ;
/** Maximum number of songs in the (custom) playlist */
static const uint NUM_SONGS_PLAYLIST = 32 ;
2018-03-14 14:55:40 +00:00
/* Functions to read DOS music CAT files, similar to but not quite the same as sound effect CAT files */
2024-03-10 11:22:46 +00:00
std : : optional < std : : string > GetMusicCatEntryName ( const std : : string & filename , size_t entrynum ) ;
2024-03-16 22:59:32 +00:00
uint8_t * GetMusicCatEntryData ( const std : : string & filename , size_t entrynum , size_t & entrylen ) ;
2018-03-14 14:55:40 +00:00
2018-03-17 13:51:30 +00:00
enum MusicTrackType {
MTT_STANDARDMIDI , ///< Standard MIDI file
2018-03-14 14:55:40 +00:00
MTT_MPSMIDI , ///< MPS GM driver MIDI format (contained in a CAT file)
2018-03-17 13:51:30 +00:00
} ;
/** Metadata about a music track. */
struct MusicSongInfo {
2023-01-26 14:58:51 +00:00
std : : string songname ; ///< name of song displayed in UI
2024-03-16 22:59:32 +00:00
uint8_t tracknr ; ///< track number of song displayed in UI
2023-04-18 20:21:17 +00:00
std : : string filename ; ///< file on disk containing song (when used in MusicSet class)
2018-03-17 13:51:30 +00:00
MusicTrackType filetype ; ///< decoder required for song file
2018-03-14 14:55:40 +00:00
int cat_index ; ///< entry index in CAT file, for filetype==MTT_MPSMIDI
2018-06-06 18:58:06 +00:00
bool loop ; ///< song should play in a tight loop if possible, never ending
2018-03-04 22:34:02 +00:00
int override_start ; ///< MIDI ticks to skip over in beginning
int override_end ; ///< MIDI tick to end the song at (0 if no override)
2018-03-17 13:51:30 +00:00
} ;
2009-12-22 21:40:29 +00:00
/** All data of a music set. */
2011-11-14 19:24:22 +00:00
struct MusicSet : BaseSet < MusicSet , NUM_SONGS_AVAILABLE , false > {
2018-03-17 13:51:30 +00:00
/** Data about individual songs in set. */
MusicSongInfo songinfo [ NUM_SONGS_AVAILABLE ] ;
/** Number of valid songs in set. */
2024-03-16 22:59:32 +00:00
uint8_t num_available ;
2009-12-22 21:40:29 +00:00
2023-10-10 23:38:57 +00:00
bool FillSetDetails ( const IniFile & ini , const std : : string & path , const std : : string & full_filename ) ;
2009-12-22 21:40:29 +00:00
} ;
/** All data/functions related with replacing the base music */
class BaseMusic : public BaseMedia < MusicSet > {
public :
2023-10-02 11:29:32 +00:00
/** The set as saved in the config file. */
static inline std : : string ini_set ;
2009-12-22 21:40:29 +00:00
} ;
2009-08-09 16:54:03 +00:00
# endif /* BASE_MEDIA_BASE_H */