00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "station_map.h"
00008 #include "town.h"
00009 #include "industry.h"
00010 #include "station.h"
00011 #include "player_func.h"
00012 #include "player_base.h"
00013 #include "engine.h"
00014 #include "aircraft.h"
00015 #include "roadveh.h"
00016 #include "ship.h"
00017 #include "train.h"
00018 #include "signs.h"
00019 #include "debug.h"
00020 #include "depot.h"
00021 #include "newgrf_config.h"
00022 #include "ai/ai.h"
00023 #include "ai/default/default.h"
00024 #include "zoom_func.h"
00025 #include "functions.h"
00026 #include "date_func.h"
00027 #include "vehicle_func.h"
00028 #include "variables.h"
00029
00030 #include "table/strings.h"
00031
00032 enum {
00033 HEADER_SIZE = 49,
00034 BUFFER_SIZE = 4096,
00035
00036 OLD_MAP_SIZE = 256 * 256
00037 };
00038
00039 struct LoadgameState {
00040 FILE *file;
00041
00042 uint chunk_size;
00043
00044 bool decoding;
00045 byte decode_char;
00046
00047 uint buffer_count;
00048 uint buffer_cur;
00049 byte buffer[BUFFER_SIZE];
00050
00051 uint total_read;
00052 bool failed;
00053 };
00054
00055
00056 enum OldChunkType {
00057 OC_SIMPLE = 0,
00058 OC_NULL = 1,
00059 OC_CHUNK = 2,
00060 OC_ASSERT = 3,
00061
00062
00063 OC_VAR_I8 = 1 << 8,
00064 OC_VAR_U8 = 2 << 8,
00065 OC_VAR_I16 = 3 << 8,
00066 OC_VAR_U16 = 4 << 8,
00067 OC_VAR_I32 = 5 << 8,
00068 OC_VAR_U32 = 6 << 8,
00069 OC_VAR_I64 = 7 << 8,
00070
00071
00072 OC_FILE_I8 = 1 << 16,
00073 OC_FILE_U8 = 2 << 16,
00074 OC_FILE_I16 = 3 << 16,
00075 OC_FILE_U16 = 4 << 16,
00076 OC_FILE_I32 = 5 << 16,
00077 OC_FILE_U32 = 6 << 16,
00078
00079
00080 OC_INT8 = OC_VAR_I8 | OC_FILE_I8,
00081 OC_UINT8 = OC_VAR_U8 | OC_FILE_U8,
00082 OC_INT16 = OC_VAR_I16 | OC_FILE_I16,
00083 OC_UINT16 = OC_VAR_U16 | OC_FILE_U16,
00084 OC_INT32 = OC_VAR_I32 | OC_FILE_I32,
00085 OC_UINT32 = OC_VAR_U32 | OC_FILE_U32,
00086
00087 OC_TILE = OC_VAR_U32 | OC_FILE_U16,
00088
00089 OC_END = 0
00090 };
00091
00092 DECLARE_ENUM_AS_BIT_SET(OldChunkType);
00093
00094 typedef bool OldChunkProc(LoadgameState *ls, int num);
00095
00096 struct OldChunks {
00097 OldChunkType type;
00098 uint32 amount;
00099
00100 void *ptr;
00101 uint offset;
00102 OldChunkProc *proc;
00103 };
00104
00105
00106 assert_compile(sizeof(TileIndex) == 4);
00107
00108 static uint32 _bump_assert_value;
00109 static bool _read_ttdpatch_flags;
00110
00111 static OldChunkType GetOldChunkType(OldChunkType type) {return (OldChunkType)GB(type, 0, 8);}
00112 static OldChunkType GetOldChunkVarType(OldChunkType type) {return (OldChunkType)(GB(type, 8, 8) << 8);}
00113 static OldChunkType GetOldChunkFileType(OldChunkType type) {return (OldChunkType)(GB(type, 16, 8) << 16);}
00114
00115 static inline byte CalcOldVarLen(OldChunkType type)
00116 {
00117 static const byte type_mem_size[] = {0, 1, 1, 2, 2, 4, 4, 8};
00118 byte length = GB(type, 8, 8);
00119 assert(length != 0 && length < lengthof(type_mem_size));
00120 return type_mem_size[length];
00121 }
00122
00128 static byte ReadByteFromFile(LoadgameState *ls)
00129 {
00130
00131
00132 if (ls->buffer_cur >= ls->buffer_count) {
00133
00134 int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file);
00135
00136
00137 if (count == 0) {
00138 DEBUG(oldloader, 0, "Read past end of file, loading failed");
00139 ls->failed = true;
00140 }
00141
00142 ls->buffer_count = count;
00143 ls->buffer_cur = 0;
00144 }
00145
00146 return ls->buffer[ls->buffer_cur++];
00147 }
00148
00154 static byte ReadByte(LoadgameState *ls)
00155 {
00156
00157
00158
00159
00160
00161
00162 if (ls->chunk_size == 0) {
00163
00164 int8 new_byte = ReadByteFromFile(ls);
00165
00166 if (new_byte < 0) {
00167
00168 ls->decoding = true;
00169 ls->decode_char = ReadByteFromFile(ls);
00170 ls->chunk_size = -new_byte + 1;
00171 } else {
00172 ls->decoding = false;
00173 ls->chunk_size = new_byte + 1;
00174 }
00175 }
00176
00177 ls->total_read++;
00178 ls->chunk_size--;
00179
00180 return ls->decoding ? ls->decode_char : ReadByteFromFile(ls);
00181 }
00182
00183 static inline uint16 ReadUint16(LoadgameState *ls)
00184 {
00185 byte x = ReadByte(ls);
00186 return x | ReadByte(ls) << 8;
00187 }
00188
00189 static inline uint32 ReadUint32(LoadgameState *ls)
00190 {
00191 uint16 x = ReadUint16(ls);
00192 return x | ReadUint16(ls) << 16;
00193 }
00194
00200 static bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks)
00201 {
00202 const OldChunks *chunk = chunks;
00203 byte *base_ptr = (byte*)base;
00204
00205 while (chunk->type != OC_END) {
00206 byte* ptr = (byte*)chunk->ptr;
00207 uint i;
00208
00209 for (i = 0; i < chunk->amount; i++) {
00210 if (ls->failed) return false;
00211
00212
00213 if (GetOldChunkType(chunk->type) != 0) {
00214 switch (GetOldChunkType(chunk->type)) {
00215
00216 case OC_NULL: ReadByte(ls); break;
00217
00218 case OC_CHUNK:
00219
00220
00221 if (!chunk->proc(ls, i)) return false;
00222 break;
00223
00224 case OC_ASSERT:
00225 DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value);
00226 if (ls->total_read != chunk->offset + _bump_assert_value) ls->failed = true;
00227 default: break;
00228 }
00229 } else {
00230 uint64 res = 0;
00231
00232
00233 switch (GetOldChunkFileType(chunk->type)) {
00234 case OC_FILE_I8: res = (int8)ReadByte(ls); break;
00235 case OC_FILE_U8: res = ReadByte(ls); break;
00236 case OC_FILE_I16: res = (int16)ReadUint16(ls); break;
00237 case OC_FILE_U16: res = ReadUint16(ls); break;
00238 case OC_FILE_I32: res = (int32)ReadUint32(ls); break;
00239 case OC_FILE_U32: res = ReadUint32(ls); break;
00240 default: NOT_REACHED();
00241 }
00242
00243
00244 assert(base_ptr != NULL || chunk->ptr != NULL);
00245
00246
00247 if (chunk->ptr == NULL) ptr = base_ptr + chunk->offset;
00248
00249
00250 switch (GetOldChunkVarType(chunk->type)) {
00251 case OC_VAR_I8: *(int8 *)ptr = GB(res, 0, 8); break;
00252 case OC_VAR_U8: *(uint8 *)ptr = GB(res, 0, 8); break;
00253 case OC_VAR_I16:*(int16 *)ptr = GB(res, 0, 16); break;
00254 case OC_VAR_U16:*(uint16*)ptr = GB(res, 0, 16); break;
00255 case OC_VAR_I32:*(int32 *)ptr = res; break;
00256 case OC_VAR_U32:*(uint32*)ptr = res; break;
00257 case OC_VAR_I64:*(int64 *)ptr = res; break;
00258 default: NOT_REACHED();
00259 }
00260
00261
00262 if (chunk->amount > 1 && chunk->ptr != NULL) ptr += CalcOldVarLen(chunk->type);
00263 }
00264 }
00265
00266 chunk++;
00267 }
00268
00269 return true;
00270 }
00271
00277 static void InitLoading(LoadgameState *ls)
00278 {
00279 ls->chunk_size = 0;
00280 ls->total_read = 0;
00281 ls->failed = false;
00282
00283 ls->decoding = false;
00284 ls->decode_char = 0;
00285
00286 ls->buffer_cur = 0;
00287 ls->buffer_count = 0;
00288 memset(ls->buffer, 0, BUFFER_SIZE);
00289
00290 _bump_assert_value = 0;
00291
00292 _read_ttdpatch_flags = false;
00293 }
00294
00295
00296
00297
00298
00299
00300 extern uint32 GetOldTownName(uint32 townnameparts, byte old_town_name_type);
00301
00302 static void FixOldTowns()
00303 {
00304 Town *town;
00305
00306
00307 FOR_ALL_TOWNS(town) {
00308 if (IsInsideMM(town->townnametype, 0x20C1, 0x20C3)) {
00309 town->townnametype = SPECSTR_TOWNNAME_ENGLISH + _opt.town_name;
00310 town->townnameparts = GetOldTownName(town->townnameparts, _opt.town_name);
00311 }
00312 }
00313 }
00314
00315 static void FixOldStations()
00316 {
00317 Station *st;
00318
00319 FOR_ALL_STATIONS(st) {
00320
00321 if (st->train_tile != 0 && GetRailStationAxis(st->train_tile) != AXIS_X) {
00322 Swap(st->trainst_w, st->trainst_h);
00323 }
00324 }
00325 }
00326
00327 static StringID *_old_vehicle_names = NULL;
00328
00329 static void FixOldVehicles()
00330 {
00331
00332 Vehicle* v;
00333
00334 FOR_ALL_VEHICLES(v) {
00335 Vehicle *u;
00336
00337 v->name = CopyFromOldName(_old_vehicle_names[v->index]);
00338
00339
00340 if (v->type == VEH_ROAD &&
00341 v->u.road.state != RVSB_IN_DEPOT &&
00342 v->u.road.state != RVSB_WORMHOLE) {
00343 ClrBit(v->u.road.state, RVS_IS_STOPPING);
00344 }
00345
00346
00347 if (v->type == VEH_ROAD) v->subtype = 0;
00348
00349
00350
00351
00352
00353 if (!IsPlayerBuildableVehicleType(v) ||
00354 (v->IsPrimaryVehicle() && v->current_order.type == OT_NOTHING)) {
00355 v->current_order.type = OT_DUMMY;
00356 }
00357
00358 FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
00359
00360
00361 if (v->orders == u->orders) {
00362 v->next_shared = u;
00363 u->prev_shared = v;
00364 break;
00365 }
00366 }
00367 }
00368 }
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 #define OCL_SVAR(type, base, offset) { type, 1, NULL, (uint)cpp_offsetof(base, offset), NULL }
00385 #define OCL_VAR(type, amount, pointer) { type, amount, pointer, 0, NULL }
00386 #define OCL_END() { OC_END, 0, NULL, 0, NULL }
00387 #define OCL_NULL(amount) { OC_NULL, amount, NULL, 0, NULL }
00388 #define OCL_CHUNK(amount, proc) { OC_CHUNK, amount, NULL, 0, proc }
00389 #define OCL_ASSERT(size) { OC_ASSERT, 1, NULL, size, NULL }
00390
00391
00392
00393
00394
00395 #define REMAP_TOWN_IDX(x) ((x) - (0x0459154 - 0x0458EF0)) / 94
00396 #define REMAP_ORDER_IDX(x) ((x) - (0x045AB08 - 0x0458EF0)) / 2
00397
00398 extern TileIndex *_animated_tile_list;
00399 extern uint _animated_tile_count;
00400 extern char _name_array[512][32];
00401
00402 static byte _old_vehicle_multiplier;
00403 static uint8 _old_map3[OLD_MAP_SIZE * 2];
00404 static bool _new_ttdpatch_format;
00405 static uint32 _old_town_index;
00406 static uint16 _old_string_id;
00407 static uint16 _old_string_id_2;
00408 static uint16 _old_extra_chunk_nums;
00409
00410 static void ReadTTDPatchFlags()
00411 {
00412 int i;
00413
00414 if (_read_ttdpatch_flags) return;
00415
00416 _read_ttdpatch_flags = true;
00417
00418
00419 _old_vehicle_multiplier = _old_map3[0];
00420
00421
00422 if (_old_vehicle_multiplier < 2) _old_vehicle_multiplier++;
00423
00424 _old_vehicle_names = MallocT<StringID>(_old_vehicle_multiplier * 850);
00425
00426
00427
00428
00429
00430
00431 _bump_assert_value = (_old_vehicle_multiplier - 1) * 850 * 128;
00432
00433
00434 _new_ttdpatch_format = (memcmp(&_old_map3[0x1FFFA], "TTDp", 4) == 0);
00435
00436 _old_extra_chunk_nums = _old_map3[_new_ttdpatch_format ? 0x1FFFE : 0x2];
00437
00438
00439 for (i = 0; i < 17; i++) _old_map3[i] = 0;
00440 for (i = 0x1FE00; i < 0x20000; i++) _old_map3[i] = 0;
00441
00442 if (_new_ttdpatch_format) DEBUG(oldloader, 2, "Found TTDPatch game");
00443
00444 DEBUG(oldloader, 3, "Vehicle-multiplier is set to %d (%d vehicles)", _old_vehicle_multiplier, _old_vehicle_multiplier * 850);
00445 }
00446
00447 static const OldChunks town_chunk[] = {
00448 OCL_SVAR( OC_TILE, Town, xy ),
00449 OCL_NULL( 2 ),
00450 OCL_SVAR( OC_UINT16, Town, townnametype ),
00451 OCL_SVAR( OC_UINT32, Town, townnameparts ),
00452 OCL_SVAR( OC_UINT8, Town, grow_counter ),
00453 OCL_NULL( 1 ),
00454 OCL_NULL( 4 ),
00455 OCL_NULL( 2 ),
00456 OCL_SVAR( OC_UINT16, Town, flags12 ),
00457 OCL_NULL( 10 ),
00458
00459 OCL_SVAR( OC_UINT16, Town, ratings[0] ),
00460 OCL_SVAR( OC_UINT16, Town, ratings[1] ),
00461 OCL_SVAR( OC_UINT16, Town, ratings[2] ),
00462 OCL_SVAR( OC_UINT16, Town, ratings[3] ),
00463 OCL_SVAR( OC_UINT16, Town, ratings[4] ),
00464 OCL_SVAR( OC_UINT16, Town, ratings[5] ),
00465 OCL_SVAR( OC_UINT16, Town, ratings[6] ),
00466 OCL_SVAR( OC_UINT16, Town, ratings[7] ),
00467
00468
00469
00470 OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, have_ratings ),
00471 OCL_SVAR( OC_FILE_U32 | OC_VAR_U8, Town, statues ),
00472 OCL_NULL( 2 ),
00473 OCL_SVAR( OC_UINT8, Town, time_until_rebuild ),
00474 OCL_SVAR( OC_UINT8, Town, growth_rate ),
00475
00476 OCL_SVAR( OC_UINT16, Town, new_max_pass ),
00477 OCL_SVAR( OC_UINT16, Town, new_max_mail ),
00478 OCL_SVAR( OC_UINT16, Town, new_act_pass ),
00479 OCL_SVAR( OC_UINT16, Town, new_act_mail ),
00480 OCL_SVAR( OC_UINT16, Town, max_pass ),
00481 OCL_SVAR( OC_UINT16, Town, max_mail ),
00482 OCL_SVAR( OC_UINT16, Town, act_pass ),
00483 OCL_SVAR( OC_UINT16, Town, act_mail ),
00484
00485 OCL_SVAR( OC_UINT8, Town, pct_pass_transported ),
00486 OCL_SVAR( OC_UINT8, Town, pct_mail_transported ),
00487
00488 OCL_SVAR( OC_UINT16, Town, new_act_food ),
00489 OCL_SVAR( OC_UINT16, Town, new_act_water ),
00490 OCL_SVAR( OC_UINT16, Town, act_food ),
00491 OCL_SVAR( OC_UINT16, Town, act_water ),
00492
00493 OCL_SVAR( OC_UINT8, Town, road_build_months ),
00494 OCL_SVAR( OC_UINT8, Town, fund_buildings_months ),
00495
00496 OCL_NULL( 8 ),
00497
00498 OCL_END()
00499 };
00500 static bool LoadOldTown(LoadgameState *ls, int num)
00501 {
00502 return LoadChunk(ls, new (num) Town(), town_chunk);
00503 }
00504
00505 static uint16 _old_order;
00506 static const OldChunks order_chunk[] = {
00507 OCL_VAR ( OC_UINT16, 1, &_old_order ),
00508 OCL_END()
00509 };
00510
00511 static bool LoadOldOrder(LoadgameState *ls, int num)
00512 {
00513 if (!LoadChunk(ls, NULL, order_chunk)) return false;
00514
00515 AssignOrder(new (num) Order(), UnpackOldOrder(_old_order));
00516
00517
00518
00519
00520 if (num > 0 && GetOrder(num)->IsValid())
00521 GetOrder(num - 1)->next = GetOrder(num);
00522
00523 return true;
00524 }
00525
00526 static bool LoadOldAnimTileList(LoadgameState *ls, int num)
00527 {
00528
00529
00530
00531
00532
00533
00534 const OldChunks anim_chunk[] = {
00535 OCL_VAR ( OC_TILE, 256, _animated_tile_list ),
00536 OCL_END ()
00537 };
00538
00539 if (!LoadChunk(ls, NULL, anim_chunk)) return false;
00540
00541
00542 for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) {
00543 if (_animated_tile_list[_animated_tile_count] == 0) break;
00544 }
00545
00546 return true;
00547 }
00548
00549 static const OldChunks depot_chunk[] = {
00550 OCL_SVAR( OC_TILE, Depot, xy ),
00551 OCL_VAR ( OC_UINT32, 1, &_old_town_index ),
00552 OCL_END()
00553 };
00554
00555 static bool LoadOldDepot(LoadgameState *ls, int num)
00556 {
00557 if (!LoadChunk(ls, new (num) Depot(), depot_chunk)) return false;
00558
00559 if (IsValidDepotID(num)) {
00560 GetDepot(num)->town_index = REMAP_TOWN_IDX(_old_town_index);
00561 }
00562
00563 return true;
00564 }
00565
00566 static int32 _old_price;
00567 static uint16 _old_price_frac;
00568 static const OldChunks price_chunk[] = {
00569 OCL_VAR ( OC_INT32, 1, &_old_price ),
00570 OCL_VAR ( OC_UINT16, 1, &_old_price_frac ),
00571 OCL_END()
00572 };
00573
00574 static bool LoadOldPrice(LoadgameState *ls, int num)
00575 {
00576 if (!LoadChunk(ls, NULL, price_chunk)) return false;
00577
00578
00579
00580 ((Money*)&_price)[num] = _old_price;
00581 _price_frac[num] = _old_price_frac;
00582
00583 return true;
00584 }
00585
00586 static const OldChunks cargo_payment_rate_chunk[] = {
00587 OCL_VAR ( OC_INT32, 1, &_old_price ),
00588 OCL_VAR ( OC_UINT16, 1, &_old_price_frac ),
00589
00590 OCL_NULL( 2 ),
00591 OCL_END()
00592 };
00593
00594 static bool LoadOldCargoPaymentRate(LoadgameState *ls, int num)
00595 {
00596 if (!LoadChunk(ls, NULL, cargo_payment_rate_chunk)) return false;
00597
00598 _cargo_payment_rates[num] = -_old_price;
00599 _cargo_payment_rates_frac[num] = _old_price_frac;
00600
00601 return true;
00602 }
00603
00604 static uint8 _old_platforms;
00605 static uint _current_station_id;
00606 static uint16 _waiting_acceptance;
00607 static uint8 _cargo_source;
00608 static uint8 _cargo_days;
00609
00610 static const OldChunks goods_chunk[] = {
00611 OCL_VAR ( OC_UINT16, 1, &_waiting_acceptance ),
00612 OCL_SVAR( OC_UINT8, GoodsEntry, days_since_pickup ),
00613 OCL_SVAR( OC_UINT8, GoodsEntry, rating ),
00614 OCL_VAR ( OC_UINT8, 1, &_cargo_source ),
00615 OCL_VAR ( OC_UINT8, 1, &_cargo_days ),
00616 OCL_SVAR( OC_UINT8, GoodsEntry, last_speed ),
00617 OCL_SVAR( OC_UINT8, GoodsEntry, last_age ),
00618
00619 OCL_END()
00620 };
00621
00622 static bool LoadOldGood(LoadgameState *ls, int num)
00623 {
00624 Station *st = GetStation(_current_station_id);
00625 GoodsEntry *ge = &st->goods[num];
00626 bool ret = LoadChunk(ls, ge, goods_chunk);
00627 if (!ret) return false;
00628
00629 SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
00630 SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, _cargo_source != 0xFF);
00631 if (GB(_waiting_acceptance, 0, 12) != 0) {
00632 CargoPacket *cp = new CargoPacket();
00633 cp->source = (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
00634 cp->count = GB(_waiting_acceptance, 0, 12);
00635 cp->days_in_transit = _cargo_days;
00636 ge->cargo.Append(cp);
00637 }
00638 return ret;
00639 }
00640
00641 static const OldChunks station_chunk[] = {
00642 OCL_SVAR( OC_TILE, Station, xy ),
00643 OCL_VAR ( OC_UINT32, 1, &_old_town_index ),
00644
00645 OCL_NULL( 4 ),
00646 OCL_SVAR( OC_TILE, Station, train_tile ),
00647 OCL_SVAR( OC_TILE, Station, airport_tile ),
00648 OCL_SVAR( OC_TILE, Station, dock_tile ),
00649
00650 OCL_VAR ( OC_UINT8, 1, &_old_platforms ),
00651
00652 OCL_NULL( 1 ),
00653 OCL_NULL( 2 ),
00654
00655 OCL_VAR ( OC_UINT16, 1, &_old_string_id ),
00656
00657 OCL_NULL( 4 ),
00658
00659 OCL_SVAR( OC_UINT16, Station, had_vehicle_of_type ),
00660
00661 OCL_CHUNK( 12, LoadOldGood ),
00662
00663 OCL_SVAR( OC_UINT8, Station, time_since_load ),
00664 OCL_SVAR( OC_UINT8, Station, time_since_unload ),
00665 OCL_SVAR( OC_UINT8, Station, delete_ctr ),
00666 OCL_SVAR( OC_UINT8, Station, owner ),
00667 OCL_SVAR( OC_UINT8, Station, facilities ),
00668 OCL_SVAR( OC_UINT8, Station, airport_type ),
00669
00670
00671
00672
00673 OCL_NULL( 4 ),
00674 OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Station, airport_flags ),
00675 OCL_NULL( 2 ),
00676
00677 OCL_NULL( 4 ),
00678
00679 OCL_END()
00680 };
00681 static bool LoadOldStation(LoadgameState *ls, int num)
00682 {
00683 Station *st = new (num) Station();
00684 _current_station_id = num;
00685
00686 if (!LoadChunk(ls, st, station_chunk))
00687 return false;
00688
00689 if (st->IsValid()) {
00690 if (st->train_tile) {
00691
00692 uint w = GB(_old_platforms, 3, 3);
00693 uint h = GB(_old_platforms, 0, 3);
00694 st->trainst_w = w;
00695 st->trainst_h = h;
00696 }
00697
00698 st->town = GetTown(REMAP_TOWN_IDX(_old_town_index));
00699 st->string_id = RemapOldStringID(_old_string_id);
00700 }
00701
00702 return true;
00703 }
00704
00705 static const OldChunks industry_chunk[] = {
00706 OCL_SVAR( OC_TILE, Industry, xy ),
00707 OCL_VAR ( OC_UINT32, 1, &_old_town_index ),
00708 OCL_SVAR( OC_UINT8, Industry, width ),
00709 OCL_SVAR( OC_UINT8, Industry, height ),
00710 OCL_NULL( 2 ),
00711
00712 OCL_SVAR( OC_UINT16, Industry, produced_cargo_waiting[0] ),
00713 OCL_SVAR( OC_UINT16, Industry, produced_cargo_waiting[1] ),
00714
00715 OCL_SVAR( OC_UINT8, Industry, production_rate[0] ),
00716 OCL_SVAR( OC_UINT8, Industry, production_rate[1] ),
00717
00718 OCL_NULL( 3 ),
00719
00720 OCL_SVAR( OC_UINT8, Industry, prod_level ),
00721
00722 OCL_SVAR( OC_UINT16, Industry, this_month_production[0] ),
00723 OCL_SVAR( OC_UINT16, Industry, this_month_production[1] ),
00724 OCL_SVAR( OC_UINT16, Industry, this_month_transported[0] ),
00725 OCL_SVAR( OC_UINT16, Industry, this_month_transported[1] ),
00726
00727 OCL_SVAR( OC_UINT8, Industry, last_month_pct_transported[0] ),
00728 OCL_SVAR( OC_UINT8, Industry, last_month_pct_transported[1] ),
00729
00730 OCL_SVAR( OC_UINT16, Industry, last_month_production[0] ),
00731 OCL_SVAR( OC_UINT16, Industry, last_month_production[1] ),
00732 OCL_SVAR( OC_UINT16, Industry, last_month_transported[0] ),
00733 OCL_SVAR( OC_UINT16, Industry, last_month_transported[1] ),
00734
00735 OCL_SVAR( OC_UINT8, Industry, type ),
00736 OCL_SVAR( OC_UINT8, Industry, owner ),
00737 OCL_SVAR( OC_UINT8, Industry, random_color ),
00738 OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Industry, last_prod_year ),
00739 OCL_SVAR( OC_UINT16, Industry, counter ),
00740 OCL_SVAR( OC_UINT8, Industry, was_cargo_delivered ),
00741
00742 OCL_NULL( 9 ),
00743
00744 OCL_END()
00745 };
00746
00747 static bool LoadOldIndustry(LoadgameState *ls, int num)
00748 {
00749 Industry *i = new (num) Industry();
00750 if (!LoadChunk(ls, i, industry_chunk)) return false;
00751
00752 if (i->IsValid()) {
00753 i->town = GetTown(REMAP_TOWN_IDX(_old_town_index));
00754 IncIndustryTypeCount(i->type);
00755 }
00756
00757 return true;
00758 }
00759
00760 static PlayerID _current_player_id;
00761 static int32 _old_yearly;
00762
00763 static const OldChunks player_yearly_chunk[] = {
00764 OCL_VAR( OC_INT32, 1, &_old_yearly ),
00765 OCL_END()
00766 };
00767
00768 static bool OldPlayerYearly(LoadgameState *ls, int num)
00769 {
00770 int i;
00771 Player *p = GetPlayer(_current_player_id);
00772
00773 for (i = 0; i < 13; i++) {
00774 if (!LoadChunk(ls, NULL, player_yearly_chunk)) return false;
00775
00776 p->yearly_expenses[num][i] = _old_yearly;
00777 }
00778
00779 return true;
00780 }
00781
00782 static const OldChunks player_economy_chunk[] = {
00783 OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, PlayerEconomyEntry, income ),
00784 OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, PlayerEconomyEntry, expenses ),
00785 OCL_SVAR( OC_INT32, PlayerEconomyEntry, delivered_cargo ),
00786 OCL_SVAR( OC_INT32, PlayerEconomyEntry, performance_history ),
00787 OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, PlayerEconomyEntry, company_value ),
00788
00789 OCL_END()
00790 };
00791
00792 static bool OldPlayerEconomy(LoadgameState *ls, int num)
00793 {
00794 int i;
00795 Player *p = GetPlayer(_current_player_id);
00796
00797 if (!LoadChunk(ls, &p->cur_economy, player_economy_chunk)) return false;
00798
00799
00800 p->cur_economy.income = -p->cur_economy.income;
00801 p->cur_economy.expenses = -p->cur_economy.expenses;
00802
00803 for (i = 0; i < 24; i++) {
00804 if (!LoadChunk(ls, &p->old_economy[i], player_economy_chunk)) return false;
00805
00806 p->old_economy[i].income = -p->old_economy[i].income;
00807 p->old_economy[i].expenses = -p->old_economy[i].expenses;
00808 }
00809
00810 return true;
00811 }
00812
00813 static const OldChunks player_ai_build_rec_chunk[] = {
00814 OCL_SVAR( OC_TILE, AiBuildRec, spec_tile ),
00815 OCL_SVAR( OC_TILE, AiBuildRec, use_tile ),
00816 OCL_SVAR( OC_UINT8, AiBuildRec, rand_rng ),
00817 OCL_SVAR( OC_UINT8, AiBuildRec, cur_building_rule ),
00818 OCL_SVAR( OC_UINT8, AiBuildRec, unk6 ),
00819 OCL_SVAR( OC_UINT8, AiBuildRec, unk7 ),
00820 OCL_SVAR( OC_UINT8, AiBuildRec, buildcmd_a ),
00821 OCL_SVAR( OC_UINT8, AiBuildRec, buildcmd_b ),
00822 OCL_SVAR( OC_UINT8, AiBuildRec, direction ),
00823 OCL_SVAR( OC_UINT8, AiBuildRec, cargo ),
00824
00825 OCL_NULL( 8 ),
00826
00827 OCL_END()
00828 };
00829
00830 static bool OldLoadAIBuildRec(LoadgameState *ls, int num)
00831 {
00832 Player *p = GetPlayer(_current_player_id);
00833
00834 switch (num) {
00835 case 0: return LoadChunk(ls, &_players_ai[p->index].src, player_ai_build_rec_chunk);
00836 case 1: return LoadChunk(ls, &_players_ai[p->index].dst, player_ai_build_rec_chunk);
00837 case 2: return LoadChunk(ls, &_players_ai[p->index].mid1, player_ai_build_rec_chunk);
00838 case 3: return LoadChunk(ls, &_players_ai[p->index].mid2, player_ai_build_rec_chunk);
00839 }
00840
00841 return false;
00842 }
00843 static const OldChunks player_ai_chunk[] = {
00844 OCL_SVAR( OC_UINT8, PlayerAI, state ),
00845 OCL_NULL( 1 ),
00846 OCL_SVAR( OC_UINT8, PlayerAI, state_mode ),
00847 OCL_SVAR( OC_UINT16, PlayerAI, state_counter ),
00848 OCL_SVAR( OC_UINT16, PlayerAI, timeout_counter ),
00849
00850 OCL_CHUNK( 4, OldLoadAIBuildRec ),
00851
00852 OCL_NULL( 20 ),
00853
00854 OCL_SVAR( OC_UINT8, PlayerAI, cargo_type ),
00855 OCL_SVAR( OC_UINT8, PlayerAI, num_wagons ),
00856 OCL_SVAR( OC_UINT8, PlayerAI, build_kind ),
00857 OCL_SVAR( OC_UINT8, PlayerAI, num_build_rec ),
00858 OCL_SVAR( OC_UINT8, PlayerAI, num_loco_to_build ),
00859 OCL_SVAR( OC_UINT8, PlayerAI, num_want_fullload ),
00860
00861 OCL_NULL( 14 ),
00862
00863 OCL_NULL( 2 ),
00864
00865 OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[0] ),
00866 OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[1] ),
00867 OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[2] ),
00868 OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[3] ),
00869 OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[4] ),
00870 OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[5] ),
00871 OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[6] ),
00872 OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[7] ),
00873 OCL_SVAR( OC_UINT16, PlayerAI, wagon_list[8] ),
00874 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[0] ),
00875 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[1] ),
00876 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[2] ),
00877 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[3] ),
00878 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[4] ),
00879 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[5] ),
00880 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[6] ),
00881 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[7] ),
00882 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[8] ),
00883 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[9] ),
00884 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[10] ),
00885 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[11] ),
00886 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[12] ),
00887 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[13] ),
00888 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[14] ),
00889 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[15] ),
00890 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[16] ),
00891 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[17] ),
00892 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[18] ),
00893 OCL_SVAR( OC_UINT8, PlayerAI, order_list_blocks[19] ),
00894
00895 OCL_SVAR( OC_UINT16, PlayerAI, start_tile_a ),
00896 OCL_SVAR( OC_UINT16, PlayerAI, start_tile_b ),
00897 OCL_SVAR( OC_UINT16, PlayerAI, cur_tile_a ),
00898 OCL_SVAR( OC_UINT16, PlayerAI, cur_tile_b ),
00899
00900 OCL_SVAR( OC_UINT8, PlayerAI, start_dir_a ),
00901 OCL_SVAR( OC_UINT8, PlayerAI, start_dir_b ),
00902 OCL_SVAR( OC_UINT8, PlayerAI, cur_dir_a ),
00903 OCL_SVAR( OC_UINT8, PlayerAI, cur_dir_b ),
00904
00905 OCL_SVAR( OC_UINT8, PlayerAI, banned_tile_count ),
00906
00907 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[0] ),
00908 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[0] ),
00909 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[1] ),
00910 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[1] ),
00911 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[2] ),
00912 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[2] ),
00913 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[3] ),
00914 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[3] ),
00915 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[4] ),
00916 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[4] ),
00917 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[5] ),
00918 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[5] ),
00919 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[6] ),
00920 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[6] ),
00921 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[7] ),
00922 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[7] ),
00923 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[8] ),
00924 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[8] ),
00925 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[9] ),
00926 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[9] ),
00927 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[10] ),
00928 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[10] ),
00929 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[11] ),
00930 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[11] ),
00931 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[12] ),
00932 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[12] ),
00933 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[13] ),
00934 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[13] ),
00935 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[14] ),
00936 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[14] ),
00937 OCL_SVAR( OC_TILE, PlayerAI, banned_tiles[15] ),
00938 OCL_SVAR( OC_UINT8, PlayerAI, banned_val[15] ),
00939
00940 OCL_SVAR( OC_UINT8, PlayerAI, railtype_to_use ),
00941 OCL_SVAR( OC_UINT8, PlayerAI, route_type_mask ),
00942
00943 OCL_END()
00944 };
00945
00946 static bool OldPlayerAI(LoadgameState *ls, int num)
00947 {
00948 return LoadChunk(ls, &_players_ai[_current_player_id], player_ai_chunk);
00949 }
00950
00951 uint8 ai_tick;
00952 static const OldChunks player_chunk[] = {
00953 OCL_VAR ( OC_UINT16, 1, &_old_string_id ),
00954 OCL_SVAR( OC_UINT32, Player, name_2 ),
00955 OCL_SVAR( OC_UINT32, Player, face ),
00956 OCL_VAR ( OC_UINT16, 1, &_old_string_id_2 ),
00957 OCL_SVAR( OC_UINT32, Player, president_name_2 ),
00958
00959 OCL_SVAR( OC_INT32, Player, player_money ),
00960 OCL_SVAR( OC_INT32, Player, current_loan ),
00961
00962 OCL_SVAR( OC_UINT8, Player, player_color ),
00963 OCL_SVAR( OC_UINT8, Player, player_money_fraction ),
00964 OCL_SVAR( OC_UINT8, Player, quarters_of_bankrupcy ),
00965 OCL_SVAR( OC_UINT8, Player, bankrupt_asked ),
00966 OCL_SVAR( OC_FILE_U32 | OC_VAR_I64, Player, bankrupt_value ),
00967 OCL_SVAR( OC_UINT16, Player, bankrupt_timeout ),
00968
00969 OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Player, cargo_types ),
00970
00971 OCL_CHUNK( 3, OldPlayerYearly ),
00972 OCL_CHUNK( 1, OldPlayerEconomy ),
00973
00974 OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Player, inaugurated_year),
00975 OCL_SVAR( OC_TILE, Player, last_build_coordinate ),
00976 OCL_SVAR( OC_UINT8, Player, num_valid_stat_ent ),
00977
00978 OCL_CHUNK( 1, OldPlayerAI ),
00979
00980 OCL_SVAR( OC_UINT8, Player, block_preview ),
00981 OCL_VAR( OC_UINT8, 1, &ai_tick ),
00982 OCL_SVAR( OC_UINT8, Player, avail_railtypes ),
00983 OCL_SVAR( OC_TILE, Player, location_of_house ),
00984 OCL_SVAR( OC_UINT8, Player, share_owners[0] ),
00985 OCL_SVAR( OC_UINT8, Player, share_owners[1] ),
00986 OCL_SVAR( OC_UINT8, Player, share_owners[2] ),
00987 OCL_SVAR( OC_UINT8, Player, share_owners[3] ),
00988
00989 OCL_NULL( 8 ),
00990
00991 OCL_END()
00992 };
00993
00994 static bool LoadOldPlayer(LoadgameState *ls, int num)
00995 {
00996 Player *p = GetPlayer((PlayerID)num);
00997
00998 _current_player_id = (PlayerID)num;
00999
01000 if (!LoadChunk(ls, p, player_chunk)) return false;
01001
01002 if (_old_string_id == 0) {
01003 p->is_active = false;
01004 return true;
01005 }
01006
01007 p->name_1 = RemapOldStringID(_old_string_id);
01008 p->president_name_1 = RemapOldStringID(_old_string_id_2);
01009 _players_ai[_current_player_id].tick = ai_tick;
01010
01011 if (num == 0) {
01012
01013 if (p->name_1 == 0)
01014 p->name_1 = STR_SV_UNNAMED;
01015 } else {
01016
01017
01018 p->is_ai = true;
01019 }
01020
01021
01022
01023
01024
01025
01026 if (p->player_money == 893288)
01027 p->player_money = p->current_loan = 100000;
01028
01029 _player_colors[num] = p->player_color;
01030 p->inaugurated_year -= ORIGINAL_BASE_YEAR;
01031 if (p->location_of_house == 0xFFFF)
01032 p->location_of_house = 0;
01033
01034
01035
01036
01037
01038 if (!IsHumanPlayer((PlayerID)num) && _players_ai[p->index].state == 20) _players_ai[p->index].state = 1;
01039
01040 if (p->is_ai && (!_networking || _network_server) && _ai.enabled)
01041 AI_StartNewAI(p->index);
01042
01043 return true;
01044 }
01045
01046 static uint32 _old_order_ptr;
01047 static uint16 _old_next_ptr;
01048 static uint32 _current_vehicle_id;
01049
01050 static const OldChunks vehicle_train_chunk[] = {
01051 OCL_SVAR( OC_UINT8, VehicleRail, track ),
01052 OCL_SVAR( OC_UINT8, VehicleRail, force_proceed ),
01053 OCL_SVAR( OC_UINT16, VehicleRail, crash_anim_pos ),
01054 OCL_SVAR( OC_UINT8, VehicleRail, railtype ),
01055
01056 OCL_NULL( 5 ),
01057
01058 OCL_END()
01059 };
01060
01061 static const OldChunks vehicle_road_chunk[] = {
01062 OCL_SVAR( OC_UINT8, VehicleRoad, state ),
01063 OCL_SVAR( OC_UINT8, VehicleRoad, frame ),
01064 OCL_SVAR( OC_UINT16, VehicleRoad, blocked_ctr ),
01065 OCL_SVAR( OC_UINT8, VehicleRoad, overtaking ),
01066 OCL_SVAR( OC_UINT8, VehicleRoad, overtaking_ctr ),
01067 OCL_SVAR( OC_UINT16, VehicleRoad, crashed_ctr ),
01068 OCL_SVAR( OC_UINT8, VehicleRoad, reverse_ctr ),
01069
01070 OCL_NULL( 1 ),
01071
01072 OCL_END()
01073 };
01074
01075 static const OldChunks vehicle_ship_chunk[] = {
01076 OCL_SVAR( OC_UINT8, VehicleShip, state ),
01077
01078 OCL_NULL( 9 ),
01079
01080 OCL_END()
01081 };
01082
01083 static const OldChunks vehicle_air_chunk[] = {
01084 OCL_SVAR( OC_UINT8, VehicleAir, pos ),
01085 OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, VehicleAir, targetairport ),
01086 OCL_SVAR( OC_UINT16, VehicleAir, crashed_counter ),
01087 OCL_SVAR( OC_UINT8, VehicleAir, state ),
01088
01089 OCL_NULL( 5 ),
01090
01091 OCL_END()
01092 };
01093
01094 static const OldChunks vehicle_special_chunk[] = {
01095 OCL_SVAR( OC_UINT16, VehicleSpecial, animation_state ),
01096 OCL_SVAR( OC_UINT8, VehicleSpecial, animation_substate ),
01097
01098 OCL_NULL( 7 ),
01099
01100 OCL_END()
01101 };
01102
01103 static const OldChunks vehicle_disaster_chunk[] = {
01104 OCL_SVAR( OC_UINT16, VehicleDisaster, image_override ),
01105 OCL_SVAR( OC_UINT16, VehicleDisaster, big_ufo_destroyer_target ),
01106
01107 OCL_NULL( 6 ),
01108
01109 OCL_END()
01110 };
01111
01112 static const OldChunks vehicle_empty_chunk[] = {
01113 OCL_NULL( 10 ),
01114
01115 OCL_END()
01116 };
01117
01118 static bool LoadOldVehicleUnion(LoadgameState *ls, int num)
01119 {
01120 Vehicle *v = GetVehicle(_current_vehicle_id);
01121 uint temp = ls->total_read;
01122 bool res;
01123
01124 switch (v->type) {
01125 default: NOT_REACHED();
01126 case VEH_INVALID : res = LoadChunk(ls, NULL, vehicle_empty_chunk); break;
01127 case VEH_TRAIN : res = LoadChunk(ls, &v->u.rail, vehicle_train_chunk); break;
01128 case VEH_ROAD : res = LoadChunk(ls, &v->u.road, vehicle_road_chunk); break;
01129 case VEH_SHIP : res = LoadChunk(ls, &v->u.ship, vehicle_ship_chunk); break;
01130 case VEH_AIRCRAFT: res = LoadChunk(ls, &v->u.air, vehicle_air_chunk); break;
01131 case VEH_SPECIAL : res = LoadChunk(ls, &v->u.special, vehicle_special_chunk); break;
01132 case VEH_DISASTER: res = LoadChunk(ls, &v->u.disaster, vehicle_disaster_chunk); break;
01133 }
01134
01135
01136 if (ls->total_read - temp != 10) {
01137 DEBUG(oldloader, 0, "Assert failed in VehicleUnion: invalid chunk size");
01138 return false;
01139 }
01140
01141 return res;
01142 }
01143
01144 static uint16 _cargo_count;
01145
01146 static const OldChunks vehicle_chunk[] = {
01147 OCL_SVAR( OC_UINT8, Vehicle, subtype ),
01148
01149 OCL_NULL( 2 ),
01150 OCL_NULL( 2 ),
01151
01152 OCL_VAR ( OC_UINT32, 1, &_old_order_ptr ),
01153 OCL_VAR ( OC_UINT16, 1, &_old_order ),
01154
01155 OCL_SVAR( OC_UINT8, Vehicle, num_orders ),
01156 OCL_SVAR( OC_UINT8, Vehicle, cur_order_index ),
01157 OCL_SVAR( OC_TILE, Vehicle, dest_tile ),
01158 OCL_SVAR( OC_UINT16, Vehicle, load_unload_time_rem ),
01159 OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, date_of_last_service ),
01160 OCL_SVAR( OC_UINT16, Vehicle, service_interval ),
01161 OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, last_station_visited ),
01162 OCL_SVAR( OC_UINT8, Vehicle, tick_counter ),
01163 OCL_SVAR( OC_UINT16, Vehicle, max_speed ),
01164
01165 OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, x_pos ),
01166 OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, y_pos ),
01167 OCL_SVAR( OC_UINT8, Vehicle, z_pos ),
01168 OCL_SVAR( OC_UINT8, Vehicle, direction ),
01169 OCL_NULL( 2 ),
01170 OCL_NULL( 2 ),
01171 OCL_NULL( 1 ),
01172
01173 OCL_SVAR( OC_UINT8, Vehicle, owner ),
01174 OCL_SVAR( OC_TILE, Vehicle, tile ),
01175 OCL_SVAR( OC_UINT16, Vehicle, cur_image ),
01176
01177 OCL_NULL( 8 ),
01178
01179 OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, Vehicle, vehstatus ),
01180 OCL_SVAR( OC_UINT16, Vehicle, cur_speed ),
01181 OCL_SVAR( OC_UINT8, Vehicle, subspeed ),
01182 OCL_SVAR( OC_UINT8, Vehicle, acceleration ),
01183 OCL_SVAR( OC_UINT8, Vehicle, progress ),
01184
01185 OCL_SVAR( OC_UINT8, Vehicle, cargo_type ),
01186 OCL_SVAR( OC_UINT16, Vehicle, cargo_cap ),
01187 OCL_VAR ( OC_UINT16, 1, &_cargo_count ),
01188 OCL_VAR ( OC_UINT8, 1, &_cargo_source ),
01189 OCL_VAR ( OC_UINT8, 1, &_cargo_days ),
01190
01191 OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, age ),
01192 OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, max_age ),
01193 OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Vehicle, build_year ),
01194 OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, unitnumber ),
01195
01196 OCL_SVAR( OC_UINT16, Vehicle, engine_type ),
01197
01198 OCL_SVAR( OC_UINT8, Vehicle, spritenum ),
01199 OCL_SVAR( OC_UINT8, Vehicle, day_counter ),
01200
01201 OCL_SVAR( OC_UINT8, Vehicle, breakdowns_since_last_service ),
01202 OCL_SVAR( OC_UINT8, Vehicle, breakdown_ctr ),
01203 OCL_SVAR( OC_UINT8, Vehicle, breakdown_delay ),
01204 OCL_SVAR( OC_UINT8, Vehicle, breakdown_chance ),
01205
01206 OCL_SVAR( OC_UINT16, Vehicle, reliability ),
01207 OCL_SVAR( OC_UINT16, Vehicle, reliability_spd_dec ),
01208
01209 OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, Vehicle, profit_this_year ),
01210 OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, Vehicle, profit_last_year ),
01211
01212 OCL_VAR ( OC_UINT16, 1, &_old_next_ptr ),
01213
01214 OCL_SVAR( OC_UINT32, Vehicle, value ),
01215
01216 OCL_VAR ( OC_UINT16, 1, &_old_string_id ),
01217
01218 OCL_CHUNK( 1, LoadOldVehicleUnion ),
01219
01220 OCL_NULL( 20 ),
01221
01222 OCL_END()
01223 };
01224
01225 bool LoadOldVehicle(LoadgameState *ls, int num)
01226 {
01227 uint i;
01228
01229
01230 ReadTTDPatchFlags();
01231
01232 for (i = 0; i < _old_vehicle_multiplier; i++) {
01233 _current_vehicle_id = num * _old_vehicle_multiplier + i;
01234
01235
01236 Vehicle *v;
01237 switch (ReadByte(ls)) {
01238 default: NOT_REACHED();
01239 case 0x00 : v = new (_current_vehicle_id) InvalidVehicle(); break;
01240 case 0x10 : v = new (_current_vehicle_id) Train(); break;
01241 case 0x11 : v = new (_current_vehicle_id) RoadVehicle(); break;
01242 case 0x12 : v = new (_current_vehicle_id) Ship(); break;
01243 case 0x13 : v = new (_current_vehicle_id) Aircraft(); break;
01244 case 0x14 : v = new (_current_vehicle_id) SpecialVehicle(); break;
01245 case 0x15 : v = new (_current_vehicle_id) DisasterVehicle(); break;
01246 }
01247 if (!LoadChunk(ls, v, vehicle_chunk)) return false;
01248
01249
01250 if (v->index != _current_vehicle_id) {
01251 DEBUG(oldloader, 0, "Loading failed - vehicle-array is invalid");
01252 return false;
01253 }
01254
01255 if (_old_order_ptr != 0 && _old_order_ptr != 0xFFFFFFFF) {
01256 uint old_id = REMAP_ORDER_IDX(_old_order_ptr);
01257
01258
01259
01260
01261 if (old_id < 5000) v->orders = GetOrder(old_id);
01262 }
01263 AssignOrder(&v->current_order, UnpackOldOrder(_old_order));
01264
01265
01266 switch (v->spritenum) {
01267 case 0xfd: break;
01268 case 0xff: v->spritenum = 0xfe; break;
01269 default: v->spritenum >>= 1; break;
01270 }
01271
01272 if (_old_next_ptr != 0xFFFF) v->next = GetVehiclePoolSize() <= _old_next_ptr ? new (_old_next_ptr) InvalidVehicle() : GetVehicle(_old_next_ptr);
01273
01274 _old_vehicle_names[_current_vehicle_id] = RemapOldStringID(_old_string_id);
01275 v->name = NULL;
01276
01277
01278 if (v->type == VEH_SPECIAL) v->subtype = v->subtype >> 1;
01279
01280 if (_cargo_count != 0) {
01281 CargoPacket *cp = new CargoPacket((_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, _cargo_count);
01282 cp->days_in_transit = _cargo_days;
01283 v->cargo.Append(cp);
01284 }
01285 }
01286
01287 return true;
01288 }
01289
01290 static const OldChunks sign_chunk[] = {
01291 OCL_VAR ( OC_UINT16, 1, &_old_string_id ),
01292 OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, x ),
01293 OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, y ),
01294 OCL_SVAR( OC_FILE_U16 | OC_VAR_I8, Sign, z ),
01295
01296 OCL_NULL( 6 ),
01297
01298 OCL_END()
01299 };
01300
01301 static bool LoadOldSign(LoadgameState *ls, int num)
01302 {
01303 Sign *si = new (num) Sign();
01304 if (!LoadChunk(ls, si, sign_chunk)) return false;
01305
01306 _old_string_id = RemapOldStringID(_old_string_id);
01307 si->name = CopyFromOldName(_old_string_id);
01308
01309 return true;
01310 }
01311
01312 static const OldChunks engine_chunk[] = {
01313 OCL_SVAR( OC_UINT16, Engine, player_avail ),
01314 OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, intro_date ),
01315 OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, age ),
01316 OCL_SVAR( OC_UINT16, Engine, reliability ),
01317 OCL_SVAR( OC_UINT16, Engine, reliability_spd_dec ),
01318 OCL_SVAR( OC_UINT16, Engine, reliability_start ),
01319 OCL_SVAR( OC_UINT16, Engine, reliability_max ),
01320 OCL_SVAR( OC_UINT16, Engine, reliability_final ),
01321 OCL_SVAR( OC_UINT16, Engine, duration_phase_1 ),
01322 OCL_SVAR( OC_UINT16, Engine, duration_phase_2 ),
01323 OCL_SVAR( OC_UINT16, Engine, duration_phase_3 ),
01324
01325 OCL_SVAR( OC_UINT8, Engine, lifelength ),
01326 OCL_SVAR( OC_UINT8, Engine, flags ),
01327 OCL_SVAR( OC_UINT8, Engine, preview_player_rank ),
01328 OCL_SVAR( OC_UINT8, Engine, preview_wait ),
01329
01330 OCL_NULL( 2 ),
01331
01332 OCL_END()
01333 };
01334
01335 static bool LoadOldEngine(LoadgameState *ls, int num)
01336 {
01337 if (!LoadChunk(ls, GetEngine(num), engine_chunk)) return false;
01338
01339
01340 if ((num >= 27 && num < 54) || (num >= 57 && num < 84) || (num >= 89 && num < 116))
01341 GetEngine(num)->age = 0xFFFF;
01342
01343 return true;
01344 }
01345
01346 static bool LoadOldEngineName(LoadgameState *ls, int num)
01347 {
01348 Engine *e = GetEngine(num);
01349 e->name = CopyFromOldName(RemapOldStringID(ReadUint16(ls)));
01350 return true;
01351 }
01352
01353 static const OldChunks subsidy_chunk[] = {
01354 OCL_SVAR( OC_UINT8, Subsidy, cargo_type ),
01355 OCL_SVAR( OC_UINT8, Subsidy, age ),
01356 OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Subsidy, from ),
01357 OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Subsidy, to ),
01358
01359 OCL_END()
01360 };
01361
01362 static inline bool LoadOldSubsidy(LoadgameState *ls, int num)
01363 {
01364 return LoadChunk(ls, &_subsidies[num], subsidy_chunk);
01365 }
01366
01367 static const OldChunks game_difficulty_chunk[] = {
01368 OCL_SVAR( OC_UINT16, GameDifficulty, max_no_competitors ),
01369 OCL_SVAR( OC_UINT16, GameDifficulty, competitor_start_time ),
01370 OCL_SVAR( OC_UINT16, GameDifficulty, number_towns ),
01371 OCL_SVAR( OC_UINT16, GameDifficulty, number_industries ),
01372 OCL_SVAR( OC_UINT16, GameDifficulty, max_loan ),
01373 OCL_SVAR( OC_UINT16, GameDifficulty, initial_interest ),
01374 OCL_SVAR( OC_UINT16, GameDifficulty, vehicle_costs ),
01375 OCL_SVAR( OC_UINT16, GameDifficulty, competitor_speed ),
01376 OCL_SVAR( OC_UINT16, GameDifficulty, competitor_intelligence ),
01377 OCL_SVAR( OC_UINT16, GameDifficulty, vehicle_breakdowns ),
01378 OCL_SVAR( OC_UINT16, GameDifficulty, subsidy_multiplier ),
01379 OCL_SVAR( OC_UINT16, GameDifficulty, construction_cost ),
01380 OCL_SVAR( OC_UINT16, GameDifficulty, terrain_type ),
01381 OCL_SVAR( OC_UINT16, GameDifficulty, quantity_sea_lakes ),
01382 OCL_SVAR( OC_UINT16, GameDifficulty, economy ),
01383 OCL_SVAR( OC_UINT16, GameDifficulty, line_reverse_mode ),
01384 OCL_SVAR( OC_UINT16, GameDifficulty, disasters ),
01385 OCL_END()
01386 };
01387
01388 static inline bool LoadOldGameDifficulty(LoadgameState *ls, int num)
01389 {
01390 return LoadChunk(ls, &_opt.diff, game_difficulty_chunk);
01391 }
01392
01393
01394 static bool LoadOldMapPart1(LoadgameState *ls, int num)
01395 {
01396 uint i;
01397
01398 for (i = 0; i < OLD_MAP_SIZE; i++) {
01399 _m[i].m1 = ReadByte(ls);
01400 }
01401 for (i = 0; i < OLD_MAP_SIZE; i++) {
01402 _m[i].m2 = ReadByte(ls);
01403 }
01404 for (i = 0; i < OLD_MAP_SIZE; i++) {
01405 _old_map3[i * 2] = ReadByte(ls);
01406 _old_map3[i * 2 + 1] = ReadByte(ls);
01407 }
01408 for (i = 0; i < OLD_MAP_SIZE / 4; i++) {
01409 byte b = ReadByte(ls);
01410 _m[i * 4 + 0].m6 = GB(b, 0, 2);
01411 _m[i * 4 + 1].m6 = GB(b, 2, 2);
01412 _m[i * 4 + 2].m6 = GB(b, 4, 2);
01413 _m[i * 4 + 3].m6 = GB(b, 6, 2);
01414 }
01415
01416 return !ls->failed;
01417 }
01418
01419 static bool LoadOldMapPart2(LoadgameState *ls, int num)
01420 {
01421 uint i;
01422
01423 for (i = 0; i < OLD_MAP_SIZE; i++) {
01424 _m[i].type_height = ReadByte(ls);
01425 }
01426 for (i = 0; i < OLD_MAP_SIZE; i++) {
01427 _m[i].m5 = ReadByte(ls);
01428 }
01429
01430 return !ls->failed;
01431 }
01432
01433 static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int num)
01434 {
01435 ReadTTDPatchFlags();
01436
01437 DEBUG(oldloader, 2, "Found %d extra chunk(s)", _old_extra_chunk_nums);
01438
01439 for (int i = 0; i != _old_extra_chunk_nums; i++) {
01440 uint16 id = ReadUint16(ls);
01441 uint32 len = ReadUint32(ls);
01442
01443 switch (id) {
01444
01445
01446 case 0x2:
01447 case 0x8004: {
01448
01449 ReadUint32(ls); ReadByte(ls); len -= 5;
01450
01451 ClearGRFConfigList(&_grfconfig);
01452 while (len != 0) {
01453 uint32 grfid = ReadUint32(ls);
01454
01455 if (ReadByte(ls) == 1) {
01456 GRFConfig *c = CallocT<GRFConfig>(1);
01457 c->grfid = grfid;
01458 c->filename = strdup("TTDP game, no information");
01459
01460 AppendToGRFConfigList(&_grfconfig, c);
01461 DEBUG(oldloader, 3, "TTDPatch game using GRF file with GRFID %0X", BSWAP32(c->grfid));
01462 }
01463 len -= 5;
01464 };
01465
01466
01467 AppendStaticGRFConfigs(&_grfconfig);
01468 } break;
01469
01470
01471 case 0x3: {
01472 uint32 ttdpv = ReadUint32(ls);
01473 DEBUG(oldloader, 3, "Game saved with TTDPatch version %d.%d.%d r%d", GB(ttdpv, 24, 8), GB(ttdpv, 20, 4), GB(ttdpv, 16, 4), GB(ttdpv, 0, 16));
01474 len -= 4;
01475 while (len-- != 0) ReadByte(ls);
01476 } break;
01477
01478 default:
01479 DEBUG(oldloader, 4, "Skipping unknown extra chunk %X", id);
01480 while (len-- != 0) ReadByte(ls);
01481 break;
01482 }
01483 }
01484
01485 return !ls->failed;
01486 }
01487
01488 static uint32 _old_cur_town_ctr;
01489 static const OldChunks main_chunk[] = {
01490 OCL_ASSERT( 0 ),
01491 OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_date ),
01492 OCL_VAR ( OC_UINT16, 1, &_date_fract ),
01493 OCL_NULL( 600 ),
01494 OCL_VAR ( OC_UINT32, 2, &_random.state ),
01495
01496 OCL_ASSERT( 0x264 ),
01497 OCL_CHUNK( 70, LoadOldTown ),
01498 OCL_ASSERT( 0x1C18 ),
01499 OCL_CHUNK(5000, LoadOldOrder ),
01500 OCL_ASSERT( 0x4328 ),
01501
01502 OCL_CHUNK( 1, LoadOldAnimTileList ),
01503 OCL_NULL( 4 ),
01504
01505 OCL_CHUNK( 255, LoadOldDepot ),
01506 OCL_ASSERT( 0x4B26 ),
01507
01508 OCL_VAR ( OC_UINT32, 1, &_old_cur_town_ctr ),
01509 OCL_NULL( 2 ),
01510 OCL_NULL( 2 ),
01511
01512 OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_age_cargo_skip_counter ),
01513 OCL_VAR ( OC_UINT16, 1, &_tick_counter ),
01514 OCL_VAR ( OC_TILE, 1, &_cur_tileloop_tile ),
01515
01516 OCL_CHUNK( 49, LoadOldPrice ),
01517 OCL_CHUNK( 12, LoadOldCargoPaymentRate ),
01518
01519 OCL_ASSERT( 0x4CBA ),
01520
01521 OCL_CHUNK( 1, LoadOldMapPart1 ),
01522
01523 OCL_ASSERT( 0x48CBA ),
01524
01525 OCL_CHUNK(250, LoadOldStation ),
01526 OCL_CHUNK( 90, LoadOldIndustry ),
01527 OCL_CHUNK( 8, LoadOldPlayer ),
01528
01529 OCL_ASSERT( 0x547F2 ),
01530
01531 OCL_CHUNK( 850, LoadOldVehicle ),
01532
01533 OCL_ASSERT( 0x6F0F2 ),
01534
01535 OCL_VAR ( OC_UINT8, 32 * 500, &_name_array[0] ),
01536
01537 OCL_NULL( 0x2000 ),
01538
01539 OCL_CHUNK( 40, LoadOldSign ),
01540 OCL_CHUNK(256, LoadOldEngine ),
01541
01542 OCL_VAR ( OC_UINT16, 1, &_vehicle_id_ctr_day ),
01543
01544 OCL_CHUNK( 8, LoadOldSubsidy ),
01545
01546 OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_next_competitor_start ),
01547 OCL_VAR ( OC_FILE_I16 | OC_VAR_I32, 1, &_saved_scrollpos_x ),
01548 OCL_VAR ( OC_FILE_I16 | OC_VAR_I32, 1, &_saved_scrollpos_y ),
01549 OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_saved_scrollpos_zoom ),
01550
01551 OCL_VAR ( OC_FILE_U32 | OC_VAR_I64, 1, &_economy.max_loan ),
01552 OCL_VAR ( OC_FILE_U32 | OC_VAR_I64, 1, &_economy.max_loan_unround ),
01553 OCL_VAR ( OC_INT16, 1, &_economy.fluct ),
01554
01555 OCL_VAR ( OC_UINT16, 1, &_disaster_delay ),
01556
01557 OCL_NULL( 144 ),
01558
01559 OCL_CHUNK(256, LoadOldEngineName ),
01560
01561 OCL_NULL( 144 ),
01562 OCL_NULL( 2 ),
01563
01564 OCL_VAR ( OC_FILE_U8 | OC_VAR_U16, 1, &_station_tick_ctr ),
01565
01566 OCL_VAR ( OC_UINT8, 1, &_opt.currency ),
01567 OCL_VAR ( OC_UINT8, 1, &_opt.units ),
01568 OCL_VAR ( OC_FILE_U8 | OC_VAR_U32, 1, &_cur_player_tick_index ),
01569
01570 OCL_NULL( 2 ),
01571 OCL_NULL( 8 ),
01572
01573 OCL_VAR ( OC_UINT8, 1, &_economy.infl_amount ),
01574 OCL_VAR ( OC_UINT8, 1, &_economy.infl_amount_pr ),
01575 OCL_VAR ( OC_UINT8, 1, &_economy.interest_rate ),
01576 OCL_NULL( 1 ),
01577 OCL_VAR ( OC_UINT8, 1, &_opt.road_side ),
01578 OCL_VAR ( OC_UINT8, 1, &_opt.town_name ),
01579
01580 OCL_CHUNK( 1, LoadOldGameDifficulty ),
01581
01582 OCL_ASSERT( 0x77130 ),
01583
01584 OCL_VAR ( OC_UINT8, 1, &_opt.diff_level ),
01585 OCL_VAR ( OC_UINT8, 1, &_opt.landscape ),
01586 OCL_VAR ( OC_UINT8, 1, &_trees_tick_ctr ),
01587
01588 OCL_NULL( 1 ),
01589 OCL_VAR ( OC_UINT8, 1, &_opt.snow_line ),
01590
01591 OCL_NULL( 32 ),
01592 OCL_NULL( 36 ),
01593
01594 OCL_ASSERT( 0x77179 ),
01595
01596 OCL_CHUNK( 1, LoadOldMapPart2 ),
01597
01598 OCL_ASSERT( 0x97179 ),
01599
01600
01601 OCL_CHUNK(1, LoadTTDPatchExtraChunks),
01602
01603 OCL_END()
01604 };
01605
01606 static bool LoadOldMain(LoadgameState *ls)
01607 {
01608 int i;
01609
01610
01611 fseek(ls->file, HEADER_SIZE, SEEK_SET);
01612
01613 DEBUG(oldloader, 3, "Reading main chunk...");
01614
01615 _old_vehicle_names = NULL;
01616 if (!LoadChunk(ls, NULL, main_chunk)) {
01617 DEBUG(oldloader, 0, "Loading failed");
01618 free(_old_vehicle_names);
01619 return false;
01620 }
01621 DEBUG(oldloader, 3, "Done, converting game data...");
01622
01623
01624 _opt.landscape = _opt.landscape & 0xF;
01625
01626
01627 _cur_town_ctr = REMAP_TOWN_IDX(_old_cur_town_ctr);
01628
01629
01630 for (i = 0; i < OLD_MAP_SIZE; i++) {
01631 _m[i].m3 = _old_map3[i * 2];
01632 _m[i].m4 = _old_map3[i * 2 + 1];
01633 }
01634
01635 for (i = 0; i < OLD_MAP_SIZE; i ++) {
01636 switch (GetTileType(i)) {
01637 case MP_STATION:
01638 _m[i].m4 = 0;
01639 switch (_m[i].m5) {
01640
01641 case 0x53: case 0x54: _m[i].m5 += 170 - 0x53; break;
01642 case 0x57: case 0x58: _m[i].m5 += 168 - 0x57; break;
01643 case 0x55: case 0x56: _m[i].m5 += 170 - 0x55; break;
01644 case 0x59: case 0x5A: _m[i].m5 += 168 - 0x59; break;
01645 default: break;
01646 }
01647 break;
01648
01649 case MP_RAILWAY:
01650
01651 if (GetRailTileType(i) == RAIL_TILE_SIGNALS) {
01652
01653 if (_m[i].m4)
01654 _m[i].m4 = (_m[i].m4 >> 1) & 7;
01655 }
01656
01657
01658 _m[i].m4 &= 0xF;
01659 break;
01660
01661 case MP_WATER:
01662 if (GetWaterClass(i) == 3) MakeRiver(i, Random());
01663 break;
01664
01665 default:
01666 break;
01667 }
01668 }
01669
01670
01671
01672 Engine *e;
01673 FOR_ALL_ENGINES(e) {
01674 if (_date >= (e->intro_date + 365)) {
01675 e->flags = (e->flags & ~ENGINE_EXCLUSIVE_PREVIEW) | ENGINE_AVAILABLE;
01676 e->player_avail = (byte)-1;
01677 }
01678 }
01679
01680
01681 FixOldTowns();
01682 FixOldStations();
01683 FixOldVehicles();
01684
01685
01686 _opt.diff.town_council_tolerance = Clamp(_opt.diff_level, 0, 2);
01687
01688 DEBUG(oldloader, 3, "Finished converting game data");
01689 DEBUG(oldloader, 1, "TTD(Patch) savegame successfully converted");
01690
01691 free(_old_vehicle_names);
01692
01693 return true;
01694 }
01695
01696 bool LoadOldSaveGame(const char *file)
01697 {
01698 LoadgameState ls;
01699
01700 DEBUG(oldloader, 3, "Trying to load a TTD(Patch) savegame");
01701
01702 InitLoading(&ls);
01703
01704
01705 ls.file = fopen(file, "rb");
01706
01707 if (ls.file == NULL) {
01708 DEBUG(oldloader, 0, "Cannot open file '%s'", file);
01709 return false;
01710 }
01711
01712
01713 if (!LoadOldMain(&ls)) return false;
01714
01715 fclose(ls.file);
01716
01717
01718
01719
01720
01721 MakeWater(0);
01722
01723 _pause_game = 2;
01724
01725 return true;
01726 }
01727
01728 void GetOldSaveGameName(char *title, const char *path, const char *file)
01729 {
01730 char filename[MAX_PATH];
01731 FILE *f;
01732
01733 snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, file);
01734 f = fopen(filename, "rb");
01735 title[0] = '\0';
01736 title[48] = '\0';
01737
01738 if (f == NULL) return;
01739
01740 if (fread(title, 1, 48, f) != 48) snprintf(title, 48, "Corrupt file");
01741
01742 fclose(f);
01743 }