|
1 /* $Id$ */ |
|
2 |
|
3 #include "stdafx.h" |
|
4 #include "openttd.h" |
|
5 #include "debug.h" |
|
6 #include "functions.h" |
|
7 #include "gfx.h" |
|
8 #include "gfxinit.h" |
|
9 #include "spritecache.h" |
|
10 #include "table/sprites.h" |
|
11 #include "fileio.h" |
|
12 #include "string.h" |
|
13 #include "newgrf.h" |
|
14 #include "md5.h" |
|
15 #include "variables.h" |
|
16 #include "fontcache.h" |
|
17 #include <string.h> |
|
18 |
|
19 typedef struct MD5File { |
|
20 const char * const filename; // filename |
|
21 const md5_byte_t hash[16]; // md5 sum of the file |
|
22 } MD5File; |
|
23 |
|
24 typedef struct FileList { |
|
25 const MD5File basic[4]; // grf files that always have to be loaded |
|
26 const MD5File landscape[3]; // landscape specific grf files |
|
27 } FileList; |
|
28 |
|
29 enum { |
|
30 SKIP = 0xFFFE, |
|
31 END = 0xFFFF |
|
32 }; |
|
33 |
|
34 #include "table/files.h" |
|
35 #include "table/landscape_sprite.h" |
|
36 |
|
37 static const SpriteID * const _landscape_spriteindexes[] = { |
|
38 _landscape_spriteindexes_1, |
|
39 _landscape_spriteindexes_2, |
|
40 _landscape_spriteindexes_3, |
|
41 }; |
|
42 |
|
43 static const SpriteID * const _slopes_spriteindexes[] = { |
|
44 _slopes_spriteindexes_0, |
|
45 _slopes_spriteindexes_1, |
|
46 _slopes_spriteindexes_2, |
|
47 _slopes_spriteindexes_3, |
|
48 }; |
|
49 |
|
50 |
|
51 static uint LoadGrfFile(const char* filename, uint load_index, int file_index) |
|
52 { |
|
53 uint load_index_org = load_index; |
|
54 |
|
55 FioOpenFile(file_index, filename); |
|
56 |
|
57 DEBUG(sprite, 2, "Reading grf-file '%s'", filename); |
|
58 |
|
59 while (LoadNextSprite(load_index, file_index)) { |
|
60 load_index++; |
|
61 if (load_index >= MAX_SPRITES) { |
|
62 error("Too many sprites. Recompile with higher MAX_SPRITES value or remove some custom GRF files."); |
|
63 } |
|
64 } |
|
65 DEBUG(sprite, 2, "Currently %i sprites are loaded", load_index); |
|
66 |
|
67 return load_index - load_index_org; |
|
68 } |
|
69 |
|
70 |
|
71 static void LoadGrfIndexed(const char* filename, const SpriteID* index_tbl, int file_index) |
|
72 { |
|
73 uint start; |
|
74 |
|
75 FioOpenFile(file_index, filename); |
|
76 |
|
77 DEBUG(sprite, 2, "Reading indexed grf-file '%s'", filename); |
|
78 |
|
79 while ((start = *index_tbl++) != END) { |
|
80 uint end = *index_tbl++; |
|
81 |
|
82 if (start == SKIP) { // skip sprites (amount in second var) |
|
83 SkipSprites(end); |
|
84 } else { // load sprites and use indexes from start to end |
|
85 do { |
|
86 #ifdef NDEBUG |
|
87 LoadNextSprite(start, file_index); |
|
88 #else |
|
89 bool b = LoadNextSprite(start, file_index); |
|
90 assert(b); |
|
91 #endif |
|
92 } while (++start <= end); |
|
93 } |
|
94 } |
|
95 } |
|
96 |
|
97 |
|
98 /* Check that the supplied MD5 hash matches that stored for the supplied filename */ |
|
99 static bool CheckMD5Digest(const MD5File file, md5_byte_t *digest, bool warn) |
|
100 { |
|
101 if (memcmp(file.hash, digest, sizeof(file.hash)) == 0) return true; |
|
102 if (warn) fprintf(stderr, "MD5 of %s is ****INCORRECT**** - File Corrupt.\n", file.filename); |
|
103 return false; |
|
104 } |
|
105 |
|
106 /* Calculate and check the MD5 hash of the supplied filename. |
|
107 * returns true if the checksum is correct */ |
|
108 static bool FileMD5(const MD5File file, bool warn) |
|
109 { |
|
110 FILE *f; |
|
111 char buf[MAX_PATH]; |
|
112 |
|
113 // open file |
|
114 snprintf(buf, lengthof(buf), "%s%s", _paths.data_dir, file.filename); |
|
115 f = fopen(buf, "rb"); |
|
116 |
|
117 #if !defined(WIN32) |
|
118 if (f == NULL) { |
|
119 strtolower(buf + strlen(_paths.data_dir) - 1); |
|
120 f = fopen(buf, "rb"); |
|
121 } |
|
122 #endif |
|
123 |
|
124 #if defined SECOND_DATA_DIR |
|
125 /* If we failed to find the file in the first data directory, we will try the other one */ |
|
126 |
|
127 if (f == NULL) { |
|
128 snprintf(buf, lengthof(buf), "%s%s", _paths.second_data_dir, file.filename); |
|
129 f = fopen(buf, "rb"); |
|
130 |
|
131 if (f == NULL) { |
|
132 strtolower(buf + strlen(_paths.second_data_dir) - 1); |
|
133 f = fopen(buf, "rb"); |
|
134 } |
|
135 } |
|
136 #endif |
|
137 |
|
138 if (f != NULL) { |
|
139 md5_state_t filemd5state; |
|
140 md5_byte_t buffer[1024]; |
|
141 md5_byte_t digest[16]; |
|
142 size_t len; |
|
143 |
|
144 md5_init(&filemd5state); |
|
145 while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0) |
|
146 md5_append(&filemd5state, buffer, len); |
|
147 |
|
148 if (ferror(f) && warn) fprintf(stderr, "Error Reading from %s \n", buf); |
|
149 fclose(f); |
|
150 |
|
151 md5_finish(&filemd5state, digest); |
|
152 return CheckMD5Digest(file, digest, warn); |
|
153 } else { // file not found |
|
154 return false; |
|
155 } |
|
156 } |
|
157 |
|
158 /* Checks, if either the Windows files exist (TRG1R.GRF) or the DOS files (TRG1.GRF) |
|
159 * by comparing the MD5 checksums of the files. _use_dos_palette is set accordingly. |
|
160 * If neither are found, Windows palette is assumed. |
|
161 * |
|
162 * (Note: Also checks sample.cat for corruption) */ |
|
163 void CheckExternalFiles(void) |
|
164 { |
|
165 uint i; |
|
166 // count of files from this version |
|
167 uint dos = 0; |
|
168 uint win = 0; |
|
169 |
|
170 for (i = 0; i < 2; i++) if (FileMD5(files_dos.basic[i], true)) dos++; |
|
171 for (i = 0; i < 3; i++) if (FileMD5(files_dos.landscape[i], true)) dos++; |
|
172 |
|
173 for (i = 0; i < 2; i++) if (FileMD5(files_win.basic[i], true)) win++; |
|
174 for (i = 0; i < 3; i++) if (FileMD5(files_win.landscape[i], true)) win++; |
|
175 |
|
176 if (!FileMD5(sample_cat_win, false) && !FileMD5(sample_cat_dos, false)) |
|
177 ShowInfo("Your 'sample.cat' file is corrupted or missing!"); |
|
178 |
|
179 for (i = 0; i < lengthof(files_openttd); i++) { |
|
180 if (!FileMD5(files_openttd[i], false)) { |
|
181 ShowInfoF("Your '%s' file is corrupted or missing!", files_openttd[i].filename); |
|
182 } |
|
183 } |
|
184 |
|
185 /* |
|
186 * forced DOS palette via command line -> leave it that way |
|
187 * all Windows files present -> Windows palette |
|
188 * all DOS files present -> DOS palette |
|
189 * no Windows files present and any DOS file present -> DOS palette |
|
190 * otherwise -> Windows palette |
|
191 */ |
|
192 if (_use_dos_palette) { |
|
193 return; |
|
194 } else if (win == 5) { |
|
195 _use_dos_palette = false; |
|
196 } else if (dos == 5 || (win == 0 && dos > 0)) { |
|
197 _use_dos_palette = true; |
|
198 } else { |
|
199 _use_dos_palette = false; |
|
200 } |
|
201 } |
|
202 |
|
203 |
|
204 static const SpriteID trg1idx[] = { |
|
205 0, 1, // Mouse cursor, ZZZ |
|
206 /* Medium font */ |
|
207 2, 92, // ' ' till 'z' |
|
208 SKIP, 36, |
|
209 160, 160, // Move ¾ to the correct position |
|
210 98, 98, // Up arrow |
|
211 131, 133, |
|
212 SKIP, 1, // skip currency sign |
|
213 135, 135, |
|
214 SKIP, 1, |
|
215 137, 137, |
|
216 SKIP, 1, |
|
217 139, 139, |
|
218 140, 140, // TODO Down arrow |
|
219 141, 141, |
|
220 142, 142, // TODO Check mark |
|
221 143, 143, // TODO Cross |
|
222 144, 144, |
|
223 145, 145, // TODO Right arrow |
|
224 146, 149, |
|
225 118, 122, // Transport markers |
|
226 SKIP, 2, |
|
227 157, 157, |
|
228 114, 115, // Small up/down arrows |
|
229 SKIP, 1, |
|
230 161, 225, |
|
231 /* Small font */ |
|
232 226, 316, // ' ' till 'z' |
|
233 SKIP, 36, |
|
234 384, 384, // Move ¾ to the correct position |
|
235 322, 322, // Up arrow |
|
236 355, 357, |
|
237 SKIP, 1, // skip currency sign |
|
238 359, 359, |
|
239 SKIP, 1, |
|
240 361, 361, |
|
241 SKIP, 1, |
|
242 363, 363, |
|
243 364, 364, // TODO Down arrow |
|
244 365, 366, |
|
245 SKIP, 1, |
|
246 368, 368, |
|
247 369, 369, // TODO Right arrow |
|
248 370, 373, |
|
249 SKIP, 7, |
|
250 381, 381, |
|
251 SKIP, 3, |
|
252 385, 449, |
|
253 /* Big font */ |
|
254 450, 540, // ' ' till 'z' |
|
255 SKIP, 36, |
|
256 608, 608, // Move ¾ to the correct position |
|
257 SKIP, 1, |
|
258 579, 581, |
|
259 SKIP, 1, |
|
260 583, 583, |
|
261 SKIP, 5, |
|
262 589, 589, |
|
263 SKIP, 15, |
|
264 605, 605, |
|
265 SKIP, 3, |
|
266 609, 625, |
|
267 SKIP, 1, |
|
268 627, 632, |
|
269 SKIP, 1, |
|
270 634, 639, |
|
271 SKIP, 1, |
|
272 641, 657, |
|
273 SKIP, 1, |
|
274 659, 664, |
|
275 SKIP, 2, |
|
276 667, 671, |
|
277 SKIP, 1, |
|
278 673, 673, |
|
279 /* Graphics */ |
|
280 674, 4792, |
|
281 END |
|
282 }; |
|
283 |
|
284 /* NOTE: When adding a normal sprite, increase OPENTTD_SPRITES_COUNT with the |
|
285 * amount of sprites and add them to the end of the list, with the index of |
|
286 * the old sprite-count offset from SPR_OPENTTD_BASE. With this there is no |
|
287 * correspondence of any kind with the ID's in the grf file, but results in |
|
288 * a maximum use of sprite slots. */ |
|
289 static const SpriteID _openttd_grf_indexes[] = { |
|
290 SPR_IMG_AUTORAIL, SPR_CURSOR_WAYPOINT, // icons etc |
|
291 134, 134, // euro symbol medium size |
|
292 582, 582, // euro symbol large size |
|
293 358, 358, // euro symbol tiny |
|
294 SPR_CURSOR_CANAL, SPR_IMG_FASTFORWARD, // more icons |
|
295 648, 648, // nordic char: æ |
|
296 616, 616, // nordic char: Æ |
|
297 666, 666, // nordic char: ø |
|
298 634, 634, // nordic char: Ø |
|
299 SPR_PIN_UP, SPR_CURSOR_CLONE_TRAIN, // more icons |
|
300 382, 383, // ¼ ½ tiny |
|
301 158, 159, // ¼ ½ medium |
|
302 606, 607, // ¼ ½ large |
|
303 360, 360, // ¦ tiny |
|
304 362, 362, // ¨ tiny |
|
305 136, 136, // ¦ medium |
|
306 138, 138, // ¨ medium |
|
307 584, 584, // ¦ large |
|
308 586, 586, // ¨ large |
|
309 626, 626, // Ð large |
|
310 658, 658, // ð large |
|
311 374, 374, // ´ tiny |
|
312 378, 378, // ¸ tiny |
|
313 150, 150, // ´ medium |
|
314 154, 154, // ¸ medium |
|
315 598, 598, // ´ large |
|
316 602, 602, // ¸ large |
|
317 640, 640, // Þ large |
|
318 672, 672, // þ large |
|
319 380, 380, // º tiny |
|
320 156, 156, // º medium |
|
321 604, 604, // º large |
|
322 317, 320, // { | } ~ tiny |
|
323 93, 96, // { | } ~ medium |
|
324 541, 544, // { | } ~ large |
|
325 SPR_HOUSE_ICON, SPR_HOUSE_ICON, |
|
326 585, 585, // § large |
|
327 587, 587, // © large |
|
328 592, 592, // ® large |
|
329 594, 597, // ° ± ² ³ large |
|
330 633, 633, // × large |
|
331 665, 665, // ÷ large |
|
332 SPR_SELL_TRAIN, SPR_SHARED_ORDERS_ICON, |
|
333 377, 377, // · small |
|
334 153, 153, // · medium |
|
335 601, 601, // · large |
|
336 END |
|
337 }; |
|
338 |
|
339 |
|
340 static void LoadSpriteTables(void) |
|
341 { |
|
342 const FileList* files = _use_dos_palette ? &files_dos : &files_win; |
|
343 uint load_index; |
|
344 uint i; |
|
345 |
|
346 LoadGrfIndexed(files->basic[0].filename, trg1idx, 0); |
|
347 DupSprite( 2, 130); // non-breaking space medium |
|
348 DupSprite(226, 354); // non-breaking space tiny |
|
349 DupSprite(450, 578); // non-breaking space large |
|
350 load_index = 4793; |
|
351 |
|
352 for (i = 1; files->basic[i].filename != NULL; i++) { |
|
353 load_index += LoadGrfFile(files->basic[i].filename, load_index, i); |
|
354 } |
|
355 |
|
356 /* Load additional sprites for climates other than temperate */ |
|
357 if (_opt.landscape != LT_NORMAL) { |
|
358 LoadGrfIndexed( |
|
359 files->landscape[_opt.landscape - 1].filename, |
|
360 _landscape_spriteindexes[_opt.landscape - 1], |
|
361 i++ |
|
362 ); |
|
363 } |
|
364 |
|
365 assert(load_index == SPR_SIGNALS_BASE); |
|
366 load_index += LoadGrfFile("nsignalsw.grf", load_index, i++); |
|
367 |
|
368 assert(load_index == SPR_CANALS_BASE); |
|
369 load_index += LoadGrfFile("canalsw.grf", load_index, i++); |
|
370 |
|
371 assert(load_index == SPR_SLOPES_BASE); |
|
372 LoadGrfIndexed("trkfoundw.grf", _slopes_spriteindexes[_opt.landscape], i++); |
|
373 |
|
374 load_index = SPR_AUTORAIL_BASE; |
|
375 load_index += LoadGrfFile("autorail.grf", load_index, i++); |
|
376 |
|
377 assert(load_index == SPR_ELRAIL_BASE); |
|
378 load_index += LoadGrfFile("elrailsw.grf", load_index, i++); |
|
379 |
|
380 assert(load_index == SPR_2CCMAP_BASE); |
|
381 load_index += LoadGrfFile("2ccmap.grf", load_index, i++); |
|
382 |
|
383 assert(load_index == SPR_OPENTTD_BASE); |
|
384 LoadGrfIndexed("openttd.grf", _openttd_grf_indexes, i++); |
|
385 load_index = SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT; |
|
386 |
|
387 assert(load_index == SPR_AIRPORTX_BASE); |
|
388 load_index += LoadGrfFile("airports.grf", load_index, i++); |
|
389 |
|
390 /* Initialize the unicode to sprite mapping table */ |
|
391 InitializeUnicodeGlyphMap(); |
|
392 |
|
393 LoadNewGRF(load_index, i); |
|
394 } |
|
395 |
|
396 |
|
397 void GfxLoadSprites(void) |
|
398 { |
|
399 DEBUG(sprite, 2, "Loading sprite set %d", _opt.landscape); |
|
400 |
|
401 GfxInitSpriteMem(); |
|
402 LoadSpriteTables(); |
|
403 GfxInitPalettes(); |
|
404 } |