Add: Draw network password indicator lock in company drop down list. (#7079)
[openttd-github.git] / src / music.cpp
blob3d0e40bf9bdd32cd8473f23e1679feb7abe68a86
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file music.cpp The songs that OpenTTD knows. */
12 #include "stdafx.h"
15 /** The type of set we're replacing */
16 #define SET_TYPE "music"
17 #include "base_media_func.h"
19 #include "safeguards.h"
20 #include "fios.h"
23 /**
24 * Read the name of a music CAT file entry.
25 * @param filename Name of CAT file to read from
26 * @param entrynum Index of entry whose name to read
27 * @return Pointer to string, caller is responsible for freeing memory,
28 * NULL if entrynum does not exist.
30 char *GetMusicCatEntryName(const char *filename, size_t entrynum)
32 if (!FioCheckFileExists(filename, BASESET_DIR)) return NULL;
34 FioOpenFile(CONFIG_SLOT, filename, BASESET_DIR);
35 uint32 ofs = FioReadDword();
36 size_t entry_count = ofs / 8;
37 if (entrynum < entry_count) {
38 FioSeekTo(entrynum * 8, SEEK_SET);
39 FioSeekTo(FioReadDword(), SEEK_SET);
40 byte namelen = FioReadByte();
41 char *name = MallocT<char>(namelen + 1);
42 FioReadBlock(name, namelen);
43 name[namelen] = '\0';
44 return name;
46 return NULL;
49 /**
50 * Read the full data of a music CAT file entry.
51 * @param filename Name of CAT file to read from.
52 * @param entrynum Index of entry to read
53 * @param[out] entrylen Receives length of data read
54 * @return Pointer to buffer with data read, caller is responsible for freeind memory,
55 * NULL if entrynum does not exist.
57 byte *GetMusicCatEntryData(const char *filename, size_t entrynum, size_t &entrylen)
59 entrylen = 0;
60 if (!FioCheckFileExists(filename, BASESET_DIR)) return NULL;
62 FioOpenFile(CONFIG_SLOT, filename, BASESET_DIR);
63 uint32 ofs = FioReadDword();
64 size_t entry_count = ofs / 8;
65 if (entrynum < entry_count) {
66 FioSeekTo(entrynum * 8, SEEK_SET);
67 size_t entrypos = FioReadDword();
68 entrylen = FioReadDword();
69 FioSeekTo(entrypos, SEEK_SET);
70 FioSkipBytes(FioReadByte());
71 byte *data = MallocT<byte>(entrylen);
72 FioReadBlock(data, entrylen);
73 return data;
75 return NULL;
78 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<MusicSet>, MusicSet)
80 /** Names corresponding to the music set's files */
81 static const char * const _music_file_names[] = {
82 "theme",
83 "old_0", "old_1", "old_2", "old_3", "old_4", "old_5", "old_6", "old_7", "old_8", "old_9",
84 "new_0", "new_1", "new_2", "new_3", "new_4", "new_5", "new_6", "new_7", "new_8", "new_9",
85 "ezy_0", "ezy_1", "ezy_2", "ezy_3", "ezy_4", "ezy_5", "ezy_6", "ezy_7", "ezy_8", "ezy_9",
87 /** Make sure we aren't messing things up. */
88 assert_compile(lengthof(_music_file_names) == NUM_SONGS_AVAILABLE);
90 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
91 /* static */ const char * const *BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names = _music_file_names;
93 template <class Tbase_set>
94 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
96 return ".obm"; // OpenTTD Base Music
99 template <class Tbase_set>
100 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
102 if (BaseMedia<Tbase_set>::used_set != NULL) return true;
104 const Tbase_set *best = NULL;
105 for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
106 if (c->GetNumMissing() != 0) continue;
108 if (best == NULL ||
109 (best->fallback && !c->fallback) ||
110 best->valid_files < c->valid_files ||
111 (best->valid_files == c->valid_files &&
112 (best->shortname == c->shortname && best->version < c->version))) {
113 best = c;
117 BaseMedia<Tbase_set>::used_set = best;
118 return BaseMedia<Tbase_set>::used_set != NULL;
121 bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_filename)
123 bool ret = this->BaseSet<MusicSet, NUM_SONGS_AVAILABLE, false>::FillSetDetails(ini, path, full_filename);
124 if (ret) {
125 this->num_available = 0;
126 IniGroup *names = ini->GetGroup("names");
127 IniGroup *catindex = ini->GetGroup("catindex");
128 IniGroup *timingtrim = ini->GetGroup("timingtrim");
129 uint tracknr = 1;
130 for (uint i = 0; i < lengthof(this->songinfo); i++) {
131 const char *filename = this->files[i].filename;
132 if (names == NULL || StrEmpty(filename) || this->files[i].check_result == MD5File::CR_NO_FILE) {
133 this->songinfo[i].songname[0] = '\0';
134 continue;
137 this->songinfo[i].filename = filename; // non-owned pointer
139 IniItem *item = catindex->GetItem(_music_file_names[i], false);
140 if (item != NULL && !StrEmpty(item->value)) {
141 /* Song has a CAT file index, assume it's MPS MIDI format */
142 this->songinfo[i].filetype = MTT_MPSMIDI;
143 this->songinfo[i].cat_index = atoi(item->value);
144 char *songname = GetMusicCatEntryName(filename, this->songinfo[i].cat_index);
145 if (songname == NULL) {
146 DEBUG(grf, 0, "Base music set song missing from CAT file: %s/%d", filename, this->songinfo[i].cat_index);
147 this->songinfo[i].songname[0] = '\0';
148 continue;
150 strecpy(this->songinfo[i].songname, songname, lastof(this->songinfo[i].songname));
151 free(songname);
152 } else {
153 this->songinfo[i].filetype = MTT_STANDARDMIDI;
156 const char *trimmed_filename = filename;
157 /* As we possibly add a path to the filename and we compare
158 * on the filename with the path as in the .obm, we need to
159 * keep stripping path elements until we find a match. */
160 for (; trimmed_filename != NULL; trimmed_filename = strchr(trimmed_filename, PATHSEPCHAR)) {
161 /* Remove possible double path separator characters from
162 * the beginning, so we don't start reading e.g. root. */
163 while (*trimmed_filename == PATHSEPCHAR) trimmed_filename++;
165 item = names->GetItem(trimmed_filename, false);
166 if (item != NULL && !StrEmpty(item->value)) break;
169 if (this->songinfo[i].filetype == MTT_STANDARDMIDI) {
170 if (item != NULL && !StrEmpty(item->value)) {
171 strecpy(this->songinfo[i].songname, item->value, lastof(this->songinfo[i].songname));
172 } else {
173 DEBUG(grf, 0, "Base music set song name missing: %s", filename);
174 return false;
177 this->num_available++;
179 /* Number the theme song (if any) track 0, rest are normal */
180 if (i == 0) {
181 this->songinfo[i].tracknr = 0;
182 } else {
183 this->songinfo[i].tracknr = tracknr++;
186 item = timingtrim->GetItem(trimmed_filename, false);
187 if (item != NULL && !StrEmpty(item->value)) {
188 const char *endpos = strchr(item->value, ':');
189 if (endpos != NULL) {
190 this->songinfo[i].override_start = atoi(item->value);
191 this->songinfo[i].override_end = atoi(endpos + 1);
196 return ret;