|
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 (f != NULL) { |
|
125 md5_state_t filemd5state; |
|
126 md5_byte_t buffer[1024]; |
|
127 md5_byte_t digest[16]; |
|
128 size_t len; |
|
129 |
|
130 md5_init(&filemd5state); |
|
131 while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0) |
|
132 md5_append(&filemd5state, buffer, len); |
|
133 |
|
134 if (ferror(f) && warn) fprintf(stderr, "Error Reading from %s \n", buf); |
|
135 fclose(f); |
|
136 |
|
137 md5_finish(&filemd5state, digest); |
|
138 return CheckMD5Digest(file, digest, warn); |
|
139 } else { // file not found |
|
140 return false; |
|
141 } |
|
142 } |
|
143 |
|
144 /* Checks, if either the Windows files exist (TRG1R.GRF) or the DOS files (TRG1.GRF) |
|
145 * by comparing the MD5 checksums of the files. _use_dos_palette is set accordingly. |
|
146 * If neither are found, Windows palette is assumed. |
|
147 * |
|
148 * (Note: Also checks sample.cat for corruption) */ |
|
149 void CheckExternalFiles(void) |
|
150 { |
|
151 uint i; |
|
152 // count of files from this version |
|
153 uint dos = 0; |
|
154 uint win = 0; |
|
155 |
|
156 for (i = 0; i < 2; i++) if (FileMD5(files_dos.basic[i], true)) dos++; |
|
157 for (i = 0; i < 3; i++) if (FileMD5(files_dos.landscape[i], true)) dos++; |
|
158 |
|
159 for (i = 0; i < 2; i++) if (FileMD5(files_win.basic[i], true)) win++; |
|
160 for (i = 0; i < 3; i++) if (FileMD5(files_win.landscape[i], true)) win++; |
|
161 |
|
162 if (!FileMD5(sample_cat_win, false) && !FileMD5(sample_cat_dos, false)) |
|
163 fprintf(stderr, "Your sample.cat file is corrupted or missing!\n"); |
|
164 |
|
165 for (i = 0; i < lengthof(files_openttd); i++) { |
|
166 if (!FileMD5(files_openttd[i], false)) { |
|
167 fprintf(stderr, "Your %s file is corrupted or missing!\n", files_openttd[i].filename); |
|
168 } |
|
169 } |
|
170 |
|
171 /* |
|
172 * forced DOS palette via command line -> leave it that way |
|
173 * all Windows files present -> Windows palette |
|
174 * all DOS files present -> DOS palette |
|
175 * no Windows files present and any DOS file present -> DOS palette |
|
176 * otherwise -> Windows palette |
|
177 */ |
|
178 if (_use_dos_palette) { |
|
179 return; |
|
180 } else if (win == 5) { |
|
181 _use_dos_palette = false; |
|
182 } else if (dos == 5 || (win == 0 && dos > 0)) { |
|
183 _use_dos_palette = true; |
|
184 } else { |
|
185 _use_dos_palette = false; |
|
186 } |
|
187 } |
|
188 |
|
189 |
|
190 static const SpriteID trg1idx[] = { |
|
191 0, 1, // Mouse cursor, ZZZ |
|
192 /* Medium font */ |
|
193 2, 92, // ' ' till 'z' |
|
194 SKIP, 36, |
|
195 160, 160, // Move ¾ to the correct position |
|
196 98, 98, // Up arrow |
|
197 131, 133, |
|
198 SKIP, 1, // skip currency sign |
|
199 135, 135, |
|
200 SKIP, 1, |
|
201 137, 137, |
|
202 SKIP, 1, |
|
203 139, 139, |
|
204 140, 140, // TODO Down arrow |
|
205 141, 141, |
|
206 142, 142, // TODO Check mark |
|
207 143, 143, // TODO Cross |
|
208 144, 144, |
|
209 145, 145, // TODO Right arrow |
|
210 146, 149, |
|
211 118, 122, // Transport markers |
|
212 SKIP, 2, |
|
213 157, 157, |
|
214 114, 115, // Small up/down arrows |
|
215 SKIP, 1, |
|
216 161, 225, |
|
217 /* Small font */ |
|
218 226, 316, // ' ' till 'z' |
|
219 SKIP, 36, |
|
220 384, 384, // Move ¾ to the correct position |
|
221 322, 322, // Up arrow |
|
222 355, 357, |
|
223 SKIP, 1, // skip currency sign |
|
224 359, 359, |
|
225 SKIP, 1, |
|
226 361, 361, |
|
227 SKIP, 1, |
|
228 363, 363, |
|
229 364, 364, // TODO Down arrow |
|
230 365, 366, |
|
231 SKIP, 1, |
|
232 368, 368, |
|
233 369, 369, // TODO Right arrow |
|
234 370, 373, |
|
235 SKIP, 7, |
|
236 381, 381, |
|
237 SKIP, 3, |
|
238 385, 449, |
|
239 /* Big font */ |
|
240 450, 540, // ' ' till 'z' |
|
241 SKIP, 36, |
|
242 608, 608, // Move ¾ to the correct position |
|
243 SKIP, 1, |
|
244 579, 581, |
|
245 SKIP, 1, |
|
246 583, 583, |
|
247 SKIP, 5, |
|
248 589, 589, |
|
249 SKIP, 15, |
|
250 605, 605, |
|
251 SKIP, 3, |
|
252 609, 625, |
|
253 SKIP, 1, |
|
254 627, 632, |
|
255 SKIP, 1, |
|
256 634, 639, |
|
257 SKIP, 1, |
|
258 641, 657, |
|
259 SKIP, 1, |
|
260 659, 664, |
|
261 SKIP, 2, |
|
262 667, 671, |
|
263 SKIP, 1, |
|
264 673, 673, |
|
265 /* Graphics */ |
|
266 674, 4792, |
|
267 END |
|
268 }; |
|
269 |
|
270 /* NOTE: When adding a normal sprite, increase OPENTTD_SPRITES_COUNT with the |
|
271 * amount of sprites and add them to the end of the list, with the index of |
|
272 * the old sprite-count offset from SPR_OPENTTD_BASE. With this there is no |
|
273 * correspondence of any kind with the ID's in the grf file, but results in |
|
274 * a maximum use of sprite slots. */ |
|
275 static const SpriteID _openttd_grf_indexes[] = { |
|
276 SPR_IMG_AUTORAIL, SPR_CURSOR_WAYPOINT, // icons etc |
|
277 134, 134, // euro symbol medium size |
|
278 582, 582, // euro symbol large size |
|
279 358, 358, // euro symbol tiny |
|
280 SPR_CURSOR_CANAL, SPR_IMG_FASTFORWARD, // more icons |
|
281 648, 648, // nordic char: æ |
|
282 616, 616, // nordic char: Æ |
|
283 666, 666, // nordic char: ø |
|
284 634, 634, // nordic char: Ø |
|
285 SPR_PIN_UP, SPR_CURSOR_CLONE_TRAIN, // more icons |
|
286 382, 383, // ¼ ½ tiny |
|
287 158, 159, // ¼ ½ medium |
|
288 606, 607, // ¼ ½ large |
|
289 360, 360, // ¦ tiny |
|
290 362, 362, // ¨ tiny |
|
291 136, 136, // ¦ medium |
|
292 138, 138, // ¨ medium |
|
293 584, 584, // ¦ large |
|
294 586, 586, // ¨ large |
|
295 626, 626, // Ð large |
|
296 658, 658, // ð large |
|
297 374, 374, // ´ tiny |
|
298 378, 378, // ¸ tiny |
|
299 150, 150, // ´ medium |
|
300 154, 154, // ¸ medium |
|
301 598, 598, // ´ large |
|
302 602, 602, // ¸ large |
|
303 640, 640, // Þ large |
|
304 672, 672, // þ large |
|
305 380, 380, // º tiny |
|
306 156, 156, // º medium |
|
307 604, 604, // º large |
|
308 317, 320, // { | } ~ tiny |
|
309 93, 96, // { | } ~ medium |
|
310 541, 544, // { | } ~ large |
|
311 SPR_HOUSE_ICON, SPR_HOUSE_ICON, |
|
312 585, 585, // § large |
|
313 587, 587, // © large |
|
314 592, 592, // ® large |
|
315 594, 597, // ° ± ² ³ large |
|
316 633, 633, // × large |
|
317 665, 665, // ÷ large |
|
318 SPR_SELL_TRAIN, SPR_SHARED_ORDERS_ICON, |
|
319 377, 377, // · small |
|
320 153, 153, // · medium |
|
321 601, 601, // · large |
|
322 END |
|
323 }; |
|
324 |
|
325 |
|
326 static void LoadSpriteTables(void) |
|
327 { |
|
328 const FileList* files = _use_dos_palette ? &files_dos : &files_win; |
|
329 uint load_index; |
|
330 uint i; |
|
331 |
|
332 LoadGrfIndexed(files->basic[0].filename, trg1idx, 0); |
|
333 DupSprite( 2, 130); // non-breaking space medium |
|
334 DupSprite(226, 354); // non-breaking space tiny |
|
335 DupSprite(450, 578); // non-breaking space large |
|
336 load_index = 4793; |
|
337 |
|
338 for (i = 1; files->basic[i].filename != NULL; i++) { |
|
339 load_index += LoadGrfFile(files->basic[i].filename, load_index, i); |
|
340 } |
|
341 |
|
342 /* Load additional sprites for climates other than temperate */ |
|
343 if (_opt.landscape != LT_NORMAL) { |
|
344 LoadGrfIndexed( |
|
345 files->landscape[_opt.landscape - 1].filename, |
|
346 _landscape_spriteindexes[_opt.landscape - 1], |
|
347 i++ |
|
348 ); |
|
349 } |
|
350 |
|
351 assert(load_index == SPR_SIGNALS_BASE); |
|
352 load_index += LoadGrfFile("nsignalsw.grf", load_index, i++); |
|
353 |
|
354 assert(load_index == SPR_CANALS_BASE); |
|
355 load_index += LoadGrfFile("canalsw.grf", load_index, i++); |
|
356 |
|
357 assert(load_index == SPR_SLOPES_BASE); |
|
358 LoadGrfIndexed("trkfoundw.grf", _slopes_spriteindexes[_opt.landscape], i++); |
|
359 |
|
360 load_index = SPR_AUTORAIL_BASE; |
|
361 load_index += LoadGrfFile("autorail.grf", load_index, i++); |
|
362 |
|
363 assert(load_index == SPR_ELRAIL_BASE); |
|
364 load_index += LoadGrfFile("elrailsw.grf", load_index, i++); |
|
365 |
|
366 assert(load_index == SPR_2CCMAP_BASE); |
|
367 load_index += LoadGrfFile("2ccmap.grf", load_index, i++); |
|
368 |
|
369 assert(load_index == SPR_OPENTTD_BASE); |
|
370 LoadGrfIndexed("openttd.grf", _openttd_grf_indexes, i++); |
|
371 load_index = SPR_OPENTTD_BASE + OPENTTD_SPRITES_COUNT; |
|
372 |
|
373 assert(load_index == SPR_AIRPORTX_BASE); |
|
374 load_index += LoadGrfFile("airports.grf", load_index, i++); |
|
375 |
|
376 /* Initialize the unicode to sprite mapping table */ |
|
377 InitializeUnicodeGlyphMap(); |
|
378 |
|
379 LoadNewGRF(load_index, i); |
|
380 } |
|
381 |
|
382 |
|
383 void GfxLoadSprites(void) |
|
384 { |
|
385 DEBUG(sprite, 2, "Loading sprite set %d", _opt.landscape); |
|
386 |
|
387 GfxInitSpriteMem(); |
|
388 LoadSpriteTables(); |
|
389 GfxInitPalettes(); |
|
390 } |