tron@2186: /* $Id$ */ tron@2186: belugas@6201: /** @file misc.cpp */ belugas@6201: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" tron@2308: #include "currency.h" maedhros@6453: #include "landscape.h" rubidium@8763: #include "news_func.h" truelight@0: #include "saveload.h" matthijs@1752: #include "vehicle_gui.h" tron@2159: #include "variables.h" truelight@2706: #include "ai/ai.h" maedhros@6332: #include "newgrf_house.h" peter1138@6091: #include "cargotype.h" rubidium@6643: #include "group.h" rubidium@8224: #include "viewport_func.h" rubidium@8119: #include "economy_func.h" rubidium@8123: #include "zoom_func.h" rubidium@8131: #include "functions.h" rubidium@8139: #include "map_func.h" rubidium@8140: #include "date_func.h" rubidium@8144: #include "vehicle_func.h" rubidium@8144: #include "texteff.hpp" rubidium@8214: #include "string_func.h" rubidium@8224: #include "gfx_func.h" rubidium@8376: #include "core/alloc_func.hpp" rubidium@8224: rubidium@8264: #include "table/strings.h" rubidium@8264: #include "table/sprites.h" truelight@0: tron@1328: char _name_array[512][32]; truelight@0: rubidium@6247: void InitializeVehicles(); rubidium@6247: void InitializeWaypoints(); rubidium@6247: void InitializeDepots(); rubidium@6247: void InitializeEngines(); rubidium@6247: void InitializeOrders(); rubidium@6247: void InitializeClearLand(); rubidium@6247: void InitializeRailGui(); rubidium@6247: void InitializeRoadGui(); rubidium@6247: void InitializeAirportGui(); rubidium@6247: void InitializeDockGui(); rubidium@6247: void InitializeIndustries(); rubidium@6247: void InitializeMainGui(); rubidium@6247: void InitializeTowns(); rubidium@6247: void InitializeTrees(); rubidium@6247: void InitializeSigns(); rubidium@6247: void InitializeStations(); rubidium@7010: void InitializeCargoPackets(); rubidium@6247: static void InitializeNameMgr(); rubidium@6247: void InitializePlayers(); rubidium@6247: static void InitializeCheats(); rubidium@6247: void InitializeNPF(); truelight@0: truelight@2828: void InitializeGame(int mode, uint size_x, uint size_y) truelight@0: { ludde@2051: AllocateMap(size_x, size_y); ludde@2051: rubidium@7889: SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, VHM_NONE, WC_MAIN_WINDOW, 0); truelight@0: truelight@6231: _pause_game = 0; truelight@0: _fast_forward = 0; truelight@0: _tick_counter = 0; truelight@7018: _realtime_tick = 0; truelight@0: _date_fract = 0; truelight@0: _cur_tileloop_tile = 0; truelight@201: truelight@2828: if ((mode & IG_DATE_RESET) == IG_DATE_RESET) { rubidium@4295: SetDate(ConvertYMDToDate(_patches.starting_year, 0, 1)); truelight@0: } truelight@0: peter1138@2848: InitializeEngines(); truelight@0: InitializeVehicles(); truelight@1542: InitializeWaypoints(); truelight@4347: InitializeDepots(); truelight@1024: InitializeOrders(); rubidium@6643: InitializeGroup(); truelight@0: truelight@0: InitNewsItemStructs(); ludde@2051: InitializeLandscape(); truelight@0: InitializeClearLand(); truelight@0: InitializeRailGui(); truelight@0: InitializeRoadGui(); truelight@0: InitializeAirportGui(); truelight@0: InitializeDockGui(); truelight@0: InitializeTowns(); truelight@0: InitializeTrees(); truelight@988: InitializeSigns(); truelight@0: InitializeStations(); rubidium@7010: InitializeCargoPackets(); truelight@0: InitializeIndustries(); maedhros@6332: InitializeBuildingCounts(); celestar@3622: InitializeMainGui(); truelight@201: truelight@0: InitializeNameMgr(); darkvater@164: InitializeVehiclesGuiList(); truelight@0: InitializeTrains(); matthijs@1247: InitializeNPF(); truelight@0: truelight@2706: AI_Initialize(); truelight@0: InitializePlayers(); truelight@0: InitializeCheats(); truelight@0: truelight@0: InitTextEffects(); rubidium@7454: InitChatMessage(); truelight@0: InitializeAnimatedTiles(); truelight@0: truelight@0: InitializeLandscapeVariables(false); truelight@0: truelight@0: ResetObjectToPlace(); truelight@0: } truelight@0: peter1138@4862: bool IsCustomName(StringID id) peter1138@4862: { peter1138@4862: return GB(id, 11, 5) == 15; peter1138@4862: } peter1138@4862: truelight@0: rubidium@6247: static void InitializeCheats() truelight@0: { truelight@201: memset(&_cheats, 0, sizeof(Cheats)); truelight@0: } truelight@0: truelight@0: rubidium@6247: static void InitializeNameMgr() truelight@0: { truelight@0: memset(_name_array, 0, sizeof(_name_array)); truelight@0: } truelight@0: peter1138@8258: /* Copy and convert old custom names to UTF-8 */ peter1138@8258: char *CopyFromOldName(StringID id) truelight@0: { peter1138@8258: if (!IsCustomName(id)) return NULL; truelight@0: peter1138@8258: if (CheckSavegameVersion(37)) { peter1138@8258: /* Old names were 32 characters long, so 128 characters should be peter1138@8258: * plenty to allow for expansion when converted to UTF-8. */ peter1138@8258: char tmp[128]; peter1138@8258: const char *strfrom = _name_array[GB(id, 0, 9)]; peter1138@5108: char *strto = tmp; peter1138@5108: peter1138@5108: for (; *strfrom != '\0'; strfrom++) { peter1138@5108: WChar c = (byte)*strfrom; peter1138@8258: peter1138@8258: /* Map from non-ISO8859-15 characters to UTF-8. */ peter1138@5108: switch (c) { peter1138@5108: case 0xA4: c = 0x20AC; break; // Euro peter1138@5108: case 0xA6: c = 0x0160; break; // S with caron peter1138@5108: case 0xA8: c = 0x0161; break; // s with caron peter1138@5108: case 0xB4: c = 0x017D; break; // Z with caron peter1138@5108: case 0xB8: c = 0x017E; break; // z with caron peter1138@5108: case 0xBC: c = 0x0152; break; // OE ligature peter1138@5108: case 0xBD: c = 0x0153; break; // oe ligature peter1138@5108: case 0xBE: c = 0x0178; break; // Y with diaresis peter1138@5108: default: break; peter1138@5108: } peter1138@8258: peter1138@8258: /* Check character will fit into our buffer. */ peter1138@5108: if (strto + Utf8CharLen(c) > lastof(tmp)) break; peter1138@8258: peter1138@5108: strto += Utf8Encode(strto, c); peter1138@5108: } peter1138@5108: peter1138@5108: /* Terminate the new string and copy it back to the name array */ peter1138@5108: *strto = '\0'; peter1138@8258: peter1138@8258: return strdup(tmp); peter1138@8258: } else { peter1138@8258: /* Name will already be in UTF-8. */ peter1138@8258: return strdup(_name_array[GB(id, 0, 9)]); peter1138@5108: } peter1138@5108: } peter1138@5108: belugas@6201: /* Calculate constants that depend on the landscape type. */ truelight@0: void InitializeLandscapeVariables(bool only_constants) truelight@0: { peter1138@6091: if (only_constants) return; truelight@201: peter1138@6350: for (CargoID i = 0; i < NUM_CARGO; i++) { peter1138@6091: _cargo_payment_rates[i] = GetCargo(i)->initial_payment; peter1138@6091: _cargo_payment_rates_frac[i] = 0; truelight@0: } truelight@0: } truelight@0: rubidium@6247: static void Load_NAME() truelight@0: { truelight@0: int index; truelight@201: truelight@0: while ((index = SlIterateArray()) != -1) { rubidium@6491: SlArray(_name_array[index], SlGetFieldLength(), SLE_UINT8); truelight@0: } truelight@0: } truelight@0: truelight@0: static const SaveLoadGlobVarList _date_desc[] = { truelight@4383: SLEG_CONDVAR(_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), truelight@4383: SLEG_CONDVAR(_date, SLE_INT32, 31, SL_MAX_VERSION), rubidium@4344: SLEG_VAR(_date_fract, SLE_UINT16), rubidium@4344: SLEG_VAR(_tick_counter, SLE_UINT16), rubidium@4344: SLEG_VAR(_vehicle_id_ctr_day, SLE_UINT16), rubidium@4344: SLEG_VAR(_age_cargo_skip_counter, SLE_UINT8), tron@5971: SLE_CONDNULL(1, 0, 45), rubidium@4344: SLEG_CONDVAR(_cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), rubidium@4344: SLEG_CONDVAR(_cur_tileloop_tile, SLE_UINT32, 6, SL_MAX_VERSION), rubidium@4344: SLEG_VAR(_disaster_delay, SLE_UINT16), rubidium@4344: SLEG_VAR(_station_tick_ctr, SLE_UINT16), rubidium@8434: SLEG_VAR(_random.state[0], SLE_UINT32), rubidium@8434: SLEG_VAR(_random.state[1], SLE_UINT32), rubidium@4344: SLEG_CONDVAR(_cur_town_ctr, SLE_FILE_U8 | SLE_VAR_U32, 0, 9), rubidium@4344: SLEG_CONDVAR(_cur_town_ctr, SLE_UINT32, 10, SL_MAX_VERSION), rubidium@4344: SLEG_VAR(_cur_player_tick_index, SLE_FILE_U8 | SLE_VAR_U32), rubidium@4344: SLEG_VAR(_next_competitor_start, SLE_FILE_U16 | SLE_VAR_U32), rubidium@4344: SLEG_VAR(_trees_tick_ctr, SLE_UINT8), truelight@6231: SLEG_CONDVAR(_pause_game, SLE_UINT8, 4, SL_MAX_VERSION), rubidium@4344: SLEG_CONDVAR(_cur_town_iter, SLE_UINT32, 11, SL_MAX_VERSION), Darkvater@3046: SLEG_END() truelight@0: }; truelight@0: belugas@6201: /* Save load date related variables as well as persistent tick counters belugas@6201: * XXX: currently some unrelated stuff is just put here */ rubidium@6247: static void SaveLoad_DATE() truelight@0: { truelight@0: SlGlobList(_date_desc); truelight@0: } truelight@0: truelight@0: truelight@0: static const SaveLoadGlobVarList _view_desc[] = { rubidium@4344: SLEG_CONDVAR(_saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), rubidium@4344: SLEG_CONDVAR(_saved_scrollpos_x, SLE_INT32, 6, SL_MAX_VERSION), rubidium@4344: SLEG_CONDVAR(_saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), rubidium@4344: SLEG_CONDVAR(_saved_scrollpos_y, SLE_INT32, 6, SL_MAX_VERSION), rubidium@4344: SLEG_VAR(_saved_scrollpos_zoom, SLE_UINT8), Darkvater@3046: SLEG_END() truelight@0: }; truelight@0: rubidium@6247: static void SaveLoad_VIEW() truelight@0: { truelight@0: SlGlobList(_view_desc); truelight@0: } truelight@0: tron@1218: static uint32 _map_dim_x; tron@1218: static uint32 _map_dim_y; tron@1218: tron@1218: static const SaveLoadGlobVarList _map_dimensions[] = { Darkvater@3046: SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION), Darkvater@3046: SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION), Darkvater@3046: SLEG_END() tron@1218: }; tron@1218: rubidium@6247: static void Save_MAPS() tron@1218: { tron@1219: _map_dim_x = MapSizeX(); tron@1219: _map_dim_y = MapSizeY(); tron@1218: SlGlobList(_map_dimensions); tron@1218: } tron@1218: rubidium@6247: static void Load_MAPS() tron@1218: { tron@1218: SlGlobList(_map_dimensions); ludde@2051: AllocateMap(_map_dim_x, _map_dim_y); tron@1218: } tron@1218: rubidium@8376: enum { rubidium@8376: MAP_SL_BUF_SIZE = 4096 rubidium@8376: }; rubidium@8376: rubidium@6247: static void Load_MAPT() ludde@2050: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2295: rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type_height = buf[j]; truelight@817: } truelight@0: } truelight@0: rubidium@6247: static void Save_MAPT() tron@1093: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2295: tron@2295: SlSetLength(size); rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].type_height; rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); tron@2295: } truelight@0: } truelight@0: rubidium@6247: static void Load_MAP1() tron@1093: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2295: rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j]; tron@2295: } tron@2295: } tron@2295: rubidium@6247: static void Save_MAP1() tron@2295: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2295: tron@2295: SlSetLength(size); rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m1; rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); tron@2295: } truelight@0: } truelight@0: rubidium@6247: static void Load_MAP2() tron@1093: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2049: rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, tron@2049: /* In those versions the m2 was 8 bits */ truelight@2685: CheckSavegameVersion(5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16 tron@2049: ); rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j]; tron@2049: } tron@2049: } tron@2049: rubidium@6247: static void Save_MAP2() tron@2049: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2049: rubidium@8376: SlSetLength(size * sizeof(uint16)); rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m2; rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT16); tron@2049: } tron@2049: } tron@2049: rubidium@6247: static void Load_MAP3() tron@2049: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2295: rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j]; tron@2295: } tron@2049: } tron@2049: rubidium@6247: static void Save_MAP3() tron@2049: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2295: tron@2295: SlSetLength(size); rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m3; rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); tron@2295: } tron@2049: } tron@2049: rubidium@6247: static void Load_MAP4() tron@2049: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2295: rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j]; tron@2295: } tron@2295: } tron@2295: rubidium@6247: static void Save_MAP4() tron@2295: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2295: tron@2295: SlSetLength(size); rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m4; rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); tron@2295: } tron@2295: } tron@2295: rubidium@6247: static void Load_MAP5() tron@2295: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2295: rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j]; tron@2295: } tron@2295: } tron@2295: rubidium@6247: static void Save_MAP5() tron@2295: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2295: tron@2295: SlSetLength(size); rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m5; rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); tron@2295: } tron@2049: } tron@2049: rubidium@6247: static void Load_MAP6() tron@2049: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2049: celestar@5385: if (CheckSavegameVersion(42)) { rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: /* 1024, otherwise we overflow on 64x64 maps! */ rubidium@8376: SlArray(buf, 1024, SLE_UINT8); rubidium@8376: for (uint j = 0; j != 1024; j++) { belugas@5596: _m[i++].m6 = GB(buf[j], 0, 2); belugas@5596: _m[i++].m6 = GB(buf[j], 2, 2); belugas@5596: _m[i++].m6 = GB(buf[j], 4, 2); belugas@5596: _m[i++].m6 = GB(buf[j], 6, 2); celestar@5385: } celestar@5385: } celestar@5385: } else { rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m6 = buf[j]; tron@2049: } tron@2049: } tron@2049: } tron@2049: rubidium@6247: static void Save_MAP6() tron@2049: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); tron@2049: celestar@5385: SlSetLength(size); rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m6; rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); tron@2049: } truelight@0: } truelight@0: maedhros@6332: static void Load_MAP7() maedhros@6332: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); maedhros@6332: rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j]; maedhros@6332: } maedhros@6332: } maedhros@6332: maedhros@6332: static void Save_MAP7() maedhros@6332: { rubidium@8376: SmallStackSafeStackAlloc buf; rubidium@8376: TileIndex size = MapSize(); maedhros@6332: maedhros@6332: SlSetLength(size); rubidium@8376: for (TileIndex i = 0; i != size;) { rubidium@8376: for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m7; rubidium@8376: SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); maedhros@6332: } maedhros@6332: } truelight@0: rubidium@6247: static void Save_CHTS() truelight@0: { truelight@0: byte count = sizeof(_cheats)/sizeof(Cheat); truelight@0: Cheat* cht = (Cheat*) &_cheats; truelight@0: Cheat* cht_last = &cht[count]; truelight@0: tron@2951: SlSetLength(count * 2); tron@2951: for (; cht != cht_last; cht++) { truelight@0: SlWriteByte(cht->been_used); truelight@0: SlWriteByte(cht->value); truelight@0: } truelight@0: } truelight@0: rubidium@6247: static void Load_CHTS() truelight@0: { tron@2989: Cheat* cht = (Cheat*)&_cheats; tron@2989: uint count = SlGetFieldLength() / 2; truelight@0: smatz@8819: for (uint i = 0; i < count; i++) { rubidium@5587: cht[i].been_used = (SlReadByte() != 0); rubidium@5587: cht[i].value = (SlReadByte() != 0); truelight@0: } truelight@0: } truelight@0: truelight@0: rubidium@5587: extern const ChunkHandler _misc_chunk_handlers[] = { rubidium@4344: { 'MAPS', Save_MAPS, Load_MAPS, CH_RIFF }, rubidium@4344: { 'MAPT', Save_MAPT, Load_MAPT, CH_RIFF }, rubidium@4344: { 'MAPO', Save_MAP1, Load_MAP1, CH_RIFF }, rubidium@4344: { 'MAP2', Save_MAP2, Load_MAP2, CH_RIFF }, rubidium@4344: { 'M3LO', Save_MAP3, Load_MAP3, CH_RIFF }, rubidium@4344: { 'M3HI', Save_MAP4, Load_MAP4, CH_RIFF }, rubidium@4344: { 'MAP5', Save_MAP5, Load_MAP5, CH_RIFF }, belugas@5596: { 'MAPE', Save_MAP6, Load_MAP6, CH_RIFF }, maedhros@6332: { 'MAP7', Save_MAP7, Load_MAP7, CH_RIFF }, truelight@0: peter1138@8258: { 'NAME', NULL, Load_NAME, CH_ARRAY}, truelight@0: { 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF}, truelight@0: { 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF}, rubidium@4344: { 'CHTS', Save_CHTS, Load_CHTS, CH_RIFF | CH_LAST} truelight@0: };