00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "fios.h"
00014 #include "newgrf.h"
00015 #include "3rdparty/md5/md5.h"
00016 #include "fontcache.h"
00017 #include "gfx_func.h"
00018 #include "settings_type.h"
00019
00020
00021 #define SET_TYPE "graphics"
00022 #include "base_media_func.h"
00023
00024 #include "table/sprites.h"
00025 #include "table/palette_convert.h"
00026
00028 PaletteType _use_palette = PAL_AUTODETECT;
00030 bool _palette_remap_grf[MAX_FILE_SLOTS];
00032 const byte *_palette_remap = NULL;
00034 const byte *_palette_reverse_remap = NULL;
00035
00036 #include "table/landscape_sprite.h"
00037
00038 static const SpriteID * const _landscape_spriteindexes[] = {
00039 _landscape_spriteindexes_1,
00040 _landscape_spriteindexes_2,
00041 _landscape_spriteindexes_3,
00042 };
00043
00044 static uint LoadGrfFile(const char *filename, uint load_index, int file_index)
00045 {
00046 uint load_index_org = load_index;
00047 uint sprite_id = 0;
00048
00049 FioOpenFile(file_index, filename);
00050
00051 DEBUG(sprite, 2, "Reading grf-file '%s'", filename);
00052
00053 while (LoadNextSprite(load_index, file_index, sprite_id)) {
00054 load_index++;
00055 sprite_id++;
00056 if (load_index >= MAX_SPRITES) {
00057 usererror("Too many sprites. Recompile with higher MAX_SPRITES value or remove some custom GRF files.");
00058 }
00059 }
00060 DEBUG(sprite, 2, "Currently %i sprites are loaded", load_index);
00061
00062 return load_index - load_index_org;
00063 }
00064
00065
00066 static void LoadSpritesIndexed(int file_index, uint *sprite_id, const SpriteID *index_tbl)
00067 {
00068 uint start;
00069 while ((start = *index_tbl++) != END) {
00070 uint end = *index_tbl++;
00071
00072 do {
00073 bool b = LoadNextSprite(start, file_index, *sprite_id);
00074 assert(b);
00075 (*sprite_id)++;
00076 } while (++start <= end);
00077 }
00078 }
00079
00080 static void LoadGrfIndexed(const char *filename, const SpriteID *index_tbl, int file_index)
00081 {
00082 uint sprite_id = 0;
00083
00084 FioOpenFile(file_index, filename);
00085
00086 DEBUG(sprite, 2, "Reading indexed grf-file '%s'", filename);
00087
00088 LoadSpritesIndexed(file_index, &sprite_id, index_tbl);
00089 }
00090
00096 void CheckExternalFiles()
00097 {
00098 if (BaseGraphics::GetUsedSet() == NULL || BaseSounds::GetUsedSet() == NULL) return;
00099
00100 BaseGraphics::DeterminePalette();
00101 const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
00102
00103 DEBUG(grf, 1, "Using the %s base graphics set with the %s palette", used_set->name, _use_palette == PAL_DOS ? "DOS" : "Windows");
00104
00105 static const size_t ERROR_MESSAGE_LENGTH = 256;
00106 static const size_t MISSING_FILE_MESSAGE_LENGTH = 128;
00107
00108
00109
00110
00111 char error_msg[MISSING_FILE_MESSAGE_LENGTH * (GraphicsSet::NUM_FILES + SoundsSet::NUM_FILES) + 2 * ERROR_MESSAGE_LENGTH];
00112 error_msg[0] = '\0';
00113 char *add_pos = error_msg;
00114 const char *last = lastof(error_msg);
00115
00116 if (used_set->GetNumInvalid() != 0) {
00117
00118 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. See section 4.1 of readme.txt.\n\nThe following files are corrupted or missing:\n", used_set->name);
00119 for (uint i = 0; i < GraphicsSet::NUM_FILES; i++) {
00120 MD5File::ChecksumResult res = used_set->files[i].CheckMD5(DATA_DIR);
00121 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);
00122 }
00123 add_pos += seprintf(add_pos, last, "\n");
00124 }
00125
00126 const SoundsSet *sounds_set = BaseSounds::GetUsedSet();
00127 if (sounds_set->GetNumInvalid() != 0) {
00128 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. See section 4.1 of readme.txt.\n\nThe following files are corrupted or missing:\n", sounds_set->name);
00129
00130 assert_compile(SoundsSet::NUM_FILES == 1);
00131
00132
00133 add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", sounds_set->files->filename, sounds_set->files->CheckMD5(DATA_DIR) == MD5File::CR_MISMATCH ? "corrupt" : "missing", sounds_set->files->missing_warning);
00134 }
00135
00136 if (add_pos != error_msg) ShowInfoF("%s", error_msg);
00137 }
00138
00139
00140 static void LoadSpriteTables()
00141 {
00142 memset(_palette_remap_grf, 0, sizeof(_palette_remap_grf));
00143 uint i = FIRST_GRF_SLOT;
00144 const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
00145
00146 _palette_remap_grf[i] = (_use_palette != used_set->palette);
00147 LoadGrfFile(used_set->files[GFT_BASE].filename, 0, i++);
00148
00149
00150
00151
00152
00153
00154
00155 _palette_remap_grf[i] = (_use_palette != used_set->palette);
00156 LoadGrfFile(used_set->files[GFT_LOGOS].filename, 4793, i++);
00157
00158
00159
00160
00161
00162
00163 if (_settings_game.game_creation.landscape != LT_TEMPERATE) {
00164 _palette_remap_grf[i] = (_use_palette != used_set->palette);
00165 LoadGrfIndexed(
00166 used_set->files[GFT_ARCTIC + _settings_game.game_creation.landscape - 1].filename,
00167 _landscape_spriteindexes[_settings_game.game_creation.landscape - 1],
00168 i++
00169 );
00170 }
00171
00172
00173 InitializeUnicodeGlyphMap();
00174
00175
00176
00177
00178
00179
00180 GRFConfig *top = _grfconfig;
00181 GRFConfig *master = CallocT<GRFConfig>(1);
00182 master->filename = strdup(used_set->files[GFT_EXTRA].filename);
00183 FillGRFDetails(master, false);
00184 master->windows_paletted = (used_set->palette == PAL_WINDOWS);
00185 ClrBit(master->flags, GCF_INIT_ONLY);
00186 master->next = top;
00187 _grfconfig = master;
00188
00189 LoadNewGRF(SPR_NEWGRFS_BASE, i);
00190
00191
00192 ClearGRFConfig(&master);
00193 _grfconfig = top;
00194 }
00195
00196
00197 void GfxLoadSprites()
00198 {
00199 DEBUG(sprite, 2, "Loading sprite set %d", _settings_game.game_creation.landscape);
00200
00201 GfxInitSpriteMem();
00202 LoadSpriteTables();
00203 GfxInitPalettes();
00204 }
00205
00206 bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path)
00207 {
00208 bool ret = this->BaseSet<GraphicsSet, MAX_GFT, DATA_DIR>::FillSetDetails(ini, path);
00209 if (ret) {
00210 IniGroup *metadata = ini->GetGroup("metadata");
00211 IniItem *item;
00212
00213 fetch_metadata("palette");
00214 this->palette = (*item->value == 'D' || *item->value == 'd') ? PAL_DOS : PAL_WINDOWS;
00215 }
00216 return true;
00217 }
00218
00219
00228 MD5File::ChecksumResult MD5File::CheckMD5(Subdirectory subdir) const
00229 {
00230 size_t size;
00231 FILE *f = FioFOpenFile(this->filename, "rb", subdir, &size);
00232
00233 if (f == NULL) return CR_NO_FILE;
00234
00235 Md5 checksum;
00236 uint8 buffer[1024];
00237 uint8 digest[16];
00238 size_t len;
00239
00240 while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
00241 size -= len;
00242 checksum.Append(buffer, len);
00243 }
00244
00245 FioFCloseFile(f);
00246
00247 checksum.Finish(digest);
00248 return memcmp(this->hash, digest, sizeof(this->hash)) == 0 ? CR_MATCH : CR_MISMATCH;
00249 }
00250
00252 static const char * const _graphics_file_names[] = { "base", "logos", "arctic", "tropical", "toyland", "extra" };
00253
00255 template <class T, size_t Tnum_files, Subdirectory Tsubdir>
00256 const char * const *BaseSet<T, Tnum_files, Tsubdir>::file_names = _graphics_file_names;
00257
00258 extern void UpdateNewGRFConfigPalette();
00259
00265 void BaseGraphics::DeterminePalette()
00266 {
00267 assert(BaseGraphics::used_set != NULL);
00268 if (_use_palette >= MAX_PAL) _use_palette = BaseGraphics::used_set->palette;
00269
00270 switch (_use_palette) {
00271 case PAL_DOS:
00272 _palette_remap = _palmap_w2d;
00273 _palette_reverse_remap = _palmap_d2w;
00274 break;
00275
00276 case PAL_WINDOWS:
00277 _palette_remap = _palmap_d2w;
00278 _palette_reverse_remap = _palmap_w2d;
00279 break;
00280
00281 default:
00282 NOT_REACHED();
00283 }
00284
00285 UpdateNewGRFConfigPalette();
00286 }
00287
00288 template <class Tbase_set>
00289 bool BaseMedia<Tbase_set>::DetermineBestSet()
00290 {
00291 if (BaseMedia<Tbase_set>::used_set != NULL) return true;
00292
00293 const Tbase_set *best = NULL;
00294 for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
00295
00296 if (c->GetNumMissing() != 0) continue;
00297
00298 if (best == NULL ||
00299 best->valid_files < c->valid_files ||
00300 (best->valid_files == c->valid_files && (
00301 (best->shortname == c->shortname && best->version < c->version) ||
00302 (best->palette != _use_palette && c->palette == _use_palette)))) {
00303 best = c;
00304 }
00305 }
00306
00307 BaseMedia<Tbase_set>::used_set = best;
00308 return BaseMedia<Tbase_set>::used_set != NULL;
00309 }
00310
00311 template <class Tbase_set>
00312 const char *BaseMedia<Tbase_set>::GetExtension()
00313 {
00314 return ".obg";
00315 }
00316
00317 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<GraphicsSet>, GraphicsSet)