diff --git a/bin/data/orig_dos.obs b/bin/data/orig_dos.obs index ced0628a2a..b342e314d9 100644 --- a/bin/data/orig_dos.obs +++ b/bin/data/orig_dos.obs @@ -5,7 +5,7 @@ ; [metadata] name = original_dos -shortname = TTDD +shortname = TTDO version = 0 description = Original Transport Tycoon Deluxe DOS edition sounds diff --git a/bin/data/orig_win.obs b/bin/data/orig_win.obs index 5f57880346..71e3299629 100644 --- a/bin/data/orig_win.obs +++ b/bin/data/orig_win.obs @@ -5,7 +5,7 @@ ; [metadata] name = original_windows -shortname = TTDW +shortname = TTDO version = 0 description = Original Transport Tycoon Deluxe Windows edition sounds diff --git a/src/base_media_base.h b/src/base_media_base.h index a13b77d581..0e52bbc7ab 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -13,11 +13,18 @@ struct ContentInfo; /** Structure holding filename and MD5 information about a single file */ struct MD5File { + /** The result of a checksum check */ + enum ChecksumResult { + 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 + }; + const char *filename; ///< filename uint8 hash[16]; ///< md5 sum of the file const char *missing_warning; ///< warning when this file is missing - bool CheckMD5() const; + ChecksumResult CheckMD5() const; }; /** @@ -40,6 +47,7 @@ struct BaseSet { 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 T *next; ///< The next base set in this list @@ -65,6 +73,16 @@ struct BaseSet { return Tnum_files - this->found_files; } + /** + * 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; + } + /** * Read the set information from a loaded ini. * @param ini the ini to read from @@ -172,16 +190,6 @@ enum GraphicsFileType { struct GraphicsSet : BaseSet { PaletteType palette; ///< Palette of this graphics set - /** - * Is this set useable? Are enough files found to think it exists. - * @return true if it's useable. - */ - bool IsUseable() const - { - /* Do not find 'only' openttd[dw].grf */ - return this->found_files > 1; - } - bool FillSetDetails(struct IniFile *ini, const char *path); }; @@ -196,14 +204,6 @@ public: /** All data of a sounds set. */ struct SoundsSet : BaseSet { - /** - * Is this set useable? Are enough files found to think it exists. - * @return true if it's useable. - */ - bool IsUseable() const - { - return this->found_files > 0; - } }; /** All data/functions related with replacing the base sounds */ diff --git a/src/base_media_func.h b/src/base_media_func.h index ba09259522..ea3e413661 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -95,7 +95,17 @@ bool BaseSet::FillSetDetails(IniFile *ini, const char *path) file->missing_warning = strdup(item->value); } - if (file->CheckMD5()) this->found_files++; + switch (file->CheckMD5()) { + case MD5File::CR_MATCH: + this->valid_files++; + /* FALL THROUGH */ + case MD5File::CR_MISMATCH: + this->found_files++; + break; + + case MD5File::CR_NO_FILE: + break; + } } return true; @@ -129,8 +139,8 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length) } if (duplicate != NULL) { /* The more complete set takes precedence over the version number. */ - if ((duplicate->found_files == set->found_files && duplicate->version >= set->version) || - duplicate->found_files > set->found_files) { + if ((duplicate->valid_files == set->valid_files && duplicate->version >= set->version) || + duplicate->valid_files > set->valid_files) { DEBUG(grf, 1, "Not adding %s (%i) as base " SET_TYPE " set (duplicate)", set->name, set->version); delete set; } else { @@ -191,12 +201,15 @@ template { p += seprintf(p, last, "List of " SET_TYPE " sets:\n"); for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { - if (!s->IsUseable()) continue; - p += seprintf(p, last, "%18s: %s", s->name, s->description); - int missing = s->GetNumMissing(); - if (missing != 0) { - p += seprintf(p, last, " (missing %i file%s)\n", missing, missing == 1 ? "" : "s"); + int invalid = s->GetNumInvalid(); + if (invalid != 0) { + int missing = s->GetNumMissing(); + if (missing == 0) { + p += seprintf(p, last, " (%i corrupt file%s)\n", invalid, invalid == 1 ? "" : "s"); + } else { + p += seprintf(p, last, " (unuseable: %i missing file%s)\n", missing, missing == 1 ? "" : "s"); + } } else { p += seprintf(p, last, "\n"); } @@ -213,7 +226,7 @@ template /* static */ bool BaseMedia::HasSet(const ContentInfo *ci, bool md5sum) { for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { - if (!s->IsUseable()) continue; + if (s->GetNumMissing() != 0) continue; if (s->shortname != ci->unique_id) continue; if (!md5sum) return true; @@ -246,7 +259,7 @@ template { int n = 0; for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { - if (s != BaseMedia::used_set && !s->IsUseable()) continue; + if (s != BaseMedia::used_set && s->GetNumMissing() != 0) continue; n++; } return n; @@ -258,7 +271,7 @@ template int n = 0; for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { if (s == BaseMedia::used_set) return n; - if (!s->IsUseable()) continue; + if (s->GetNumMissing() != 0) continue; n++; } return -1; @@ -268,7 +281,7 @@ template /* static */ const Tbase_set *BaseMedia::GetSet(int index) { for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { - if (s != BaseMedia::used_set && !s->IsUseable()) continue; + if (s != BaseMedia::used_set && s->GetNumMissing() != 0) continue; if (index == 0) return s; index--; } diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 4bf4c8fa31..1f8bf089f6 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -85,7 +85,6 @@ static void LoadGrfIndexed(const char *filename, const SpriteID *index_tbl, int LoadSpritesIndexed(file_index, &sprite_id, index_tbl); } - /** * Checks whether the MD5 checksums of the files are correct. * @@ -111,25 +110,24 @@ void CheckExternalFiles() char *add_pos = error_msg; const char *last = lastof(error_msg); - if (used_set->GetNumMissing() != 0) { + if (used_set->GetNumInvalid() != 0) { /* Not all files were loaded succesfully, see which ones */ add_pos += seprintf(add_pos, last, "Trying to load graphics set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one.\n\nThe following files are corrupted or missing:\n", used_set->name); for (uint i = 0; i < GraphicsSet::NUM_FILES; i++) { - if (!used_set->files[i].CheckMD5()) { - add_pos += seprintf(add_pos, last, "\t%s (%s)\n", used_set->files[i].filename, used_set->files[i].missing_warning); - } + MD5File::ChecksumResult res = used_set->files[i].CheckMD5(); + if (res != MD5File::CR_MATCH) add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", used_set->files[i].filename, res == MD5File::CR_MISMATCH ? "corrupt" : "missing", used_set->files[i].missing_warning); } add_pos += seprintf(add_pos, last, "\n"); } const SoundsSet *sounds_set = BaseSounds::GetUsedSet(); - if (sounds_set->GetNumMissing() != 0) { + if (sounds_set->GetNumInvalid() != 0) { add_pos += seprintf(add_pos, last, "Trying to load sound set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one.\n\nThe following files are corrupted or missing:\n", sounds_set->name); assert_compile(SoundsSet::NUM_FILES == 1); /* No need to loop each file, as long as there is only a single * sound file. */ - add_pos += seprintf(add_pos, last, "\t%s (%s)\n", sounds_set->files->filename, sounds_set->files->missing_warning); + add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", sounds_set->files->filename, sounds_set->files->CheckMD5() == MD5File::CR_MISMATCH ? "corrupt" : "missing", sounds_set->files->missing_warning); } if (add_pos != error_msg) ShowInfoF("%s", error_msg); @@ -218,31 +216,32 @@ bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path) /** * Calculate and check the MD5 hash of the supplied filename. - * @return true if the checksum is correct. + * @return + * CR_MATCH if the MD5 hash matches + * CR_MISMATCH if the MD5 does not match + * CR_NO_FILE if the file misses */ -bool MD5File::CheckMD5() const +MD5File::ChecksumResult MD5File::CheckMD5() const { size_t size; FILE *f = FioFOpenFile(this->filename, "rb", DATA_DIR, &size); - if (f != NULL) { - Md5 checksum; - uint8 buffer[1024]; - uint8 digest[16]; - size_t len; - - while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { - size -= len; - checksum.Append(buffer, len); - } + if (f == NULL) return CR_NO_FILE; - FioFCloseFile(f); + Md5 checksum; + uint8 buffer[1024]; + uint8 digest[16]; + size_t len; - checksum.Finish(digest); - return memcmp(this->hash, digest, sizeof(this->hash)) == 0; - } else { // file not found - return false; + while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { + size -= len; + checksum.Append(buffer, len); } + + FioFCloseFile(f); + + checksum.Finish(digest); + return memcmp(this->hash, digest, sizeof(this->hash)) == 0 ? CR_MATCH : CR_MISMATCH; } /** Names corresponding to the GraphicsFileType */ @@ -287,10 +286,14 @@ template { if (BaseMedia::used_set != NULL) return true; - const Tbase_set *best = BaseMedia::available_sets; + const Tbase_set *best = NULL; for (const Tbase_set *c = BaseMedia::available_sets; c != NULL; c = c->next) { - if (best->found_files < c->found_files || - (best->found_files == c->found_files && ( + /* Skip unuseable sets */ + if (c->GetNumMissing() != 0) continue; + + if (best == NULL || + best->valid_files < c->valid_files || + (best->valid_files == c->valid_files && ( (best->shortname == c->shortname && best->version < c->version) || (best->palette != _use_palette && c->palette == _use_palette)))) { best = c; diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 18b06c575a..e18c08ad19 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -199,7 +199,7 @@ struct GameOptionsWindow : Window { case GOW_RESOLUTION_DROPDOWN: SetDParam(0, GetCurRes() == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + GetCurRes()); break; case GOW_SCREENSHOT_DROPDOWN: SetDParam(0, SPECSTR_SCREENSHOT_START + _cur_screenshot_format); break; case GOW_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name); break; - case GOW_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumMissing()); break; + case GOW_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumInvalid()); break; case GOW_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name); break; } } @@ -238,10 +238,10 @@ struct GameOptionsWindow : Window { case GOW_BASE_GRF_STATUS: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseGraphics::GetNumSets(); i++) { - uint missing_files = BaseGraphics::GetSet(i)->GetNumMissing(); - if (missing_files == 0) continue; + uint invalid_files = BaseGraphics::GetSet(i)->GetNumInvalid(); + if (invalid_files == 0) continue; - SetDParam(0, missing_files); + SetDParam(0, invalid_files); *size = maxdim(*size, GetStringBoundingBox(STR_GAME_OPTIONS_BASE_GRF_STATUS)); } break; diff --git a/src/sound.cpp b/src/sound.cpp index 1308411549..7449225b82 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -281,10 +281,14 @@ template { if (BaseMedia::used_set != NULL) return true; - const Tbase_set *best = BaseMedia::available_sets; + const Tbase_set *best = NULL; for (const Tbase_set *c = BaseMedia::available_sets; c != NULL; c = c->next) { - if (best->found_files < c->found_files || - (best->found_files == c->found_files && + /* Skip unuseable sets */ + if (c->GetNumMissing() != 0) continue; + + if (best == NULL || + best->valid_files < c->valid_files || + (best->valid_files == c->valid_files && (best->shortname == c->shortname && best->version < c->version))) { best = c; }