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