4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file town_sl.cpp Code handling saving and loading of towns and houses */
12 #include "../stdafx.h"
13 #include "../newgrf_house.h"
15 #include "../landscape.h"
16 #include "../subsidy_func.h"
17 #include "../strings_func.h"
20 #include "newgrf_sl.h"
22 #include "../safeguards.h"
25 * Rebuild all the cached variables of towns.
27 void RebuildTownCaches()
30 InitializeBuildingCounts();
32 /* Reset town population and num_houses */
34 town
->cache
.population
= 0;
35 town
->cache
.num_houses
= 0;
38 for (TileIndex t
= 0; t
< MapSize(); t
++) {
39 if (!IsTileType(t
, MP_HOUSE
)) continue;
41 HouseID house_id
= GetHouseType(t
);
42 town
= Town::GetByTile(t
);
43 IncreaseBuildingCount(town
, house_id
);
44 if (IsHouseCompleted(t
)) town
->cache
.population
+= HouseSpec::Get(house_id
)->population
;
46 /* Increase the number of houses for every house, but only once. */
47 if (GetHouseNorthPart(house_id
) == 0) town
->cache
.num_houses
++;
50 /* Update the population and num_house dependent values */
52 UpdateTownRadius(town
);
53 UpdateTownCargoes(town
);
55 UpdateTownCargoBitmap();
59 * Check and update town and house values.
61 * Checked are the HouseIDs. Updated are the
62 * town population the number of houses per
63 * town, the town radius and the max passengers
66 void UpdateHousesAndTowns()
68 for (TileIndex t
= 0; t
< MapSize(); t
++) {
69 if (!IsTileType(t
, MP_HOUSE
)) continue;
71 HouseID house_id
= GetCleanHouseType(t
);
72 if (!HouseSpec::Get(house_id
)->enabled
&& house_id
>= NEW_HOUSE_OFFSET
) {
73 /* The specs for this type of house are not available any more, so
74 * replace it with the substitute original house type. */
75 house_id
= _house_mngr
.GetSubstituteID(house_id
);
76 SetHouseType(t
, house_id
);
80 /* Check for cases when a NewGRF has set a wrong house substitute type. */
81 for (TileIndex t
= 0; t
< MapSize(); t
++) {
82 if (!IsTileType(t
, MP_HOUSE
)) continue;
84 HouseID house_type
= GetCleanHouseType(t
);
85 TileIndex north_tile
= t
+ GetHouseNorthPart(house_type
); // modifies 'house_type'!
86 if (t
== north_tile
) {
87 const HouseSpec
*hs
= HouseSpec::Get(house_type
);
88 bool valid_house
= true;
89 if (hs
->building_flags
& TILE_SIZE_2x1
) {
90 TileIndex tile
= t
+ TileDiffXY(1, 0);
91 if (!IsTileType(tile
, MP_HOUSE
) || GetCleanHouseType(tile
) != house_type
+ 1) valid_house
= false;
92 } else if (hs
->building_flags
& TILE_SIZE_1x2
) {
93 TileIndex tile
= t
+ TileDiffXY(0, 1);
94 if (!IsTileType(tile
, MP_HOUSE
) || GetCleanHouseType(tile
) != house_type
+ 1) valid_house
= false;
95 } else if (hs
->building_flags
& TILE_SIZE_2x2
) {
96 TileIndex tile
= t
+ TileDiffXY(0, 1);
97 if (!IsTileType(tile
, MP_HOUSE
) || GetCleanHouseType(tile
) != house_type
+ 1) valid_house
= false;
98 tile
= t
+ TileDiffXY(1, 0);
99 if (!IsTileType(tile
, MP_HOUSE
) || GetCleanHouseType(tile
) != house_type
+ 2) valid_house
= false;
100 tile
= t
+ TileDiffXY(1, 1);
101 if (!IsTileType(tile
, MP_HOUSE
) || GetCleanHouseType(tile
) != house_type
+ 3) valid_house
= false;
103 /* If not all tiles of this house are present remove the house.
104 * The other tiles will get removed later in this loop because
105 * their north tile is not the correct type anymore. */
106 if (!valid_house
) DoClearSquare(t
);
107 } else if (!IsTileType(north_tile
, MP_HOUSE
) || GetCleanHouseType(north_tile
) != house_type
) {
108 /* This tile should be part of a multi-tile building but the
109 * north tile of this house isn't on the map. */
117 /** Save and load of towns. */
118 static const SaveLoad _town_desc
[] = {
119 SLE_CONDVAR(Town
, xy
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
120 SLE_CONDVAR(Town
, xy
, SLE_UINT32
, 6, SL_MAX_VERSION
),
122 SLE_CONDNULL(2, 0, 2), ///< population, no longer in use
123 SLE_CONDNULL(4, 3, 84), ///< population, no longer in use
124 SLE_CONDNULL(2, 0, 91), ///< num_houses, no longer in use
126 SLE_CONDVAR(Town
, townnamegrfid
, SLE_UINT32
, 66, SL_MAX_VERSION
),
127 SLE_VAR(Town
, townnametype
, SLE_UINT16
),
128 SLE_VAR(Town
, townnameparts
, SLE_UINT32
),
129 SLE_CONDSTR(Town
, name
, SLE_STR
| SLF_ALLOW_CONTROL
, 0, 84, SL_MAX_VERSION
),
131 SLE_VAR(Town
, flags
, SLE_UINT8
),
132 SLE_CONDVAR(Town
, statues
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 103),
133 SLE_CONDVAR(Town
, statues
, SLE_UINT16
, 104, SL_MAX_VERSION
),
135 SLE_CONDNULL(1, 0, 1), ///< sort_index, no longer in use
137 SLE_CONDVAR(Town
, have_ratings
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 103),
138 SLE_CONDVAR(Town
, have_ratings
, SLE_UINT16
, 104, SL_MAX_VERSION
),
139 SLE_CONDARR(Town
, ratings
, SLE_INT16
, 8, 0, 103),
140 SLE_CONDARR(Town
, ratings
, SLE_INT16
, MAX_COMPANIES
, 104, SL_MAX_VERSION
),
141 /* failed bribe attempts are stored since savegame format 4 */
142 SLE_CONDARR(Town
, unwanted
, SLE_INT8
, 8, 4, 103),
143 SLE_CONDARR(Town
, unwanted
, SLE_INT8
, MAX_COMPANIES
, 104, SL_MAX_VERSION
),
145 SLE_CONDVAR(Town
, supplied
[CT_PASSENGERS
].old_max
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 8),
146 SLE_CONDVAR(Town
, supplied
[CT_MAIL
].old_max
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 8),
147 SLE_CONDVAR(Town
, supplied
[CT_PASSENGERS
].new_max
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 8),
148 SLE_CONDVAR(Town
, supplied
[CT_MAIL
].new_max
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 8),
149 SLE_CONDVAR(Town
, supplied
[CT_PASSENGERS
].old_act
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 8),
150 SLE_CONDVAR(Town
, supplied
[CT_MAIL
].old_act
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 8),
151 SLE_CONDVAR(Town
, supplied
[CT_PASSENGERS
].new_act
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 8),
152 SLE_CONDVAR(Town
, supplied
[CT_MAIL
].new_act
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 8),
154 SLE_CONDVAR(Town
, supplied
[CT_PASSENGERS
].old_max
, SLE_UINT32
, 9, 164),
155 SLE_CONDVAR(Town
, supplied
[CT_MAIL
].old_max
, SLE_UINT32
, 9, 164),
156 SLE_CONDVAR(Town
, supplied
[CT_PASSENGERS
].new_max
, SLE_UINT32
, 9, 164),
157 SLE_CONDVAR(Town
, supplied
[CT_MAIL
].new_max
, SLE_UINT32
, 9, 164),
158 SLE_CONDVAR(Town
, supplied
[CT_PASSENGERS
].old_act
, SLE_UINT32
, 9, 164),
159 SLE_CONDVAR(Town
, supplied
[CT_MAIL
].old_act
, SLE_UINT32
, 9, 164),
160 SLE_CONDVAR(Town
, supplied
[CT_PASSENGERS
].new_act
, SLE_UINT32
, 9, 164),
161 SLE_CONDVAR(Town
, supplied
[CT_MAIL
].new_act
, SLE_UINT32
, 9, 164),
163 SLE_CONDNULL(2, 0, 163), ///< pct_pass_transported / pct_mail_transported, now computed on the fly
165 SLE_CONDVAR(Town
, received
[TE_FOOD
].old_act
, SLE_UINT16
, 0, 164),
166 SLE_CONDVAR(Town
, received
[TE_WATER
].old_act
, SLE_UINT16
, 0, 164),
167 SLE_CONDVAR(Town
, received
[TE_FOOD
].new_act
, SLE_UINT16
, 0, 164),
168 SLE_CONDVAR(Town
, received
[TE_WATER
].new_act
, SLE_UINT16
, 0, 164),
170 SLE_CONDARR(Town
, goal
, SLE_UINT32
, NUM_TE
, 165, SL_MAX_VERSION
),
172 SLE_CONDSTR(Town
, text
, SLE_STR
| SLF_ALLOW_CONTROL
, 0, 168, SL_MAX_VERSION
),
174 SLE_CONDVAR(Town
, time_until_rebuild
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 53),
175 SLE_CONDVAR(Town
, grow_counter
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 53),
176 SLE_CONDVAR(Town
, growth_rate
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 53),
178 SLE_CONDVAR(Town
, time_until_rebuild
, SLE_FILE_U16
| SLE_VAR_I32
, 54, SL_PATCH_PACK_TOWN_BUILDINGS
-1),
179 SLE_CONDVAR(Town
, time_until_rebuild
, SLE_INT32
, SL_PATCH_PACK_TOWN_BUILDINGS
, SL_MAX_VERSION
),
181 SLE_CONDVAR(Town
, grow_counter
, SLE_FILE_U16
| SLE_VAR_I32
, 54, SL_PATCH_PACK_1_26
-1),
182 SLE_CONDVAR(Town
, grow_counter
, SLE_INT32
, SL_PATCH_PACK_1_26
, SL_MAX_VERSION
),
184 SLE_CONDVAR(Town
, growth_rate
, SLE_FILE_I16
| SLE_VAR_I32
, 54, 164),
185 SLE_CONDVAR(Town
, growth_rate
, SLE_FILE_U16
| SLE_VAR_I32
, 165, SL_PATCH_PACK_1_26
-1),
186 SLE_CONDVAR(Town
, growth_rate
, SLE_INT32
, SL_PATCH_PACK_1_26
, SL_MAX_VERSION
),
188 SLE_VAR(Town
, fund_buildings_months
, SLE_UINT8
),
189 SLE_VAR(Town
, road_build_months
, SLE_UINT8
),
191 SLE_CONDVAR(Town
, exclusivity
, SLE_UINT8
, 2, SL_MAX_VERSION
),
192 SLE_CONDVAR(Town
, exclusive_counter
, SLE_UINT8
, 2, SL_MAX_VERSION
),
194 SLE_CONDVAR(Town
, larger_town
, SLE_BOOL
, 56, SL_MAX_VERSION
),
195 SLE_CONDVAR(Town
, layout
, SLE_UINT8
, 113, SL_MAX_VERSION
),
197 SLE_CONDLST(Town
, psa_list
, REF_STORAGE
, 161, SL_MAX_VERSION
),
199 SLE_CONDVAR(Town
, cargo_produced
, SLE_UINT32
, 166, SL_MAX_VERSION
),
201 /* reserve extra space in savegame here. (currently 30 bytes) */
202 SLE_CONDNULL(30, 2, SL_MAX_VERSION
),
207 static const SaveLoad _town_supplied_desc
[] = {
208 SLE_CONDVAR(TransportedCargoStat
<uint32
>, old_max
, SLE_UINT32
, 165, SL_MAX_VERSION
),
209 SLE_CONDVAR(TransportedCargoStat
<uint32
>, new_max
, SLE_UINT32
, 165, SL_MAX_VERSION
),
210 SLE_CONDVAR(TransportedCargoStat
<uint32
>, old_act
, SLE_UINT32
, 165, SL_MAX_VERSION
),
211 SLE_CONDVAR(TransportedCargoStat
<uint32
>, new_act
, SLE_UINT32
, 165, SL_MAX_VERSION
),
216 static const SaveLoad _town_received_desc
[] = {
217 SLE_CONDVAR(TransportedCargoStat
<uint16
>, old_max
, SLE_UINT16
, 165, SL_MAX_VERSION
),
218 SLE_CONDVAR(TransportedCargoStat
<uint16
>, new_max
, SLE_UINT16
, 165, SL_MAX_VERSION
),
219 SLE_CONDVAR(TransportedCargoStat
<uint16
>, old_act
, SLE_UINT16
, 165, SL_MAX_VERSION
),
220 SLE_CONDVAR(TransportedCargoStat
<uint16
>, new_act
, SLE_UINT16
, 165, SL_MAX_VERSION
),
225 static void Save_HIDS()
227 Save_NewGRFMapping(_house_mngr
);
230 static void Load_HIDS()
232 Load_NewGRFMapping(_house_mngr
);
235 const SaveLoad
*GetTileMatrixDesc()
237 /* Here due to private member vars. */
238 static const SaveLoad _tilematrix_desc
[] = {
239 SLE_VAR(AcceptanceMatrix
, area
.tile
, SLE_UINT32
),
240 SLE_VAR(AcceptanceMatrix
, area
.w
, SLE_UINT16
),
241 SLE_VAR(AcceptanceMatrix
, area
.h
, SLE_UINT16
),
245 return _tilematrix_desc
;
248 static void RealSave_Town(Town
*t
)
250 SlObject(t
, _town_desc
);
252 for (CargoID i
= 0; i
< NUM_CARGO
; i
++) {
253 SlObject(&t
->supplied
[i
], _town_supplied_desc
);
255 for (int i
= TE_BEGIN
; i
< NUM_TE
; i
++) {
256 SlObject(&t
->received
[i
], _town_received_desc
);
259 SlObject(&t
->cargo_accepted
, GetTileMatrixDesc());
260 if (t
->cargo_accepted
.area
.w
!= 0) {
261 uint arr_len
= t
->cargo_accepted
.area
.w
/ AcceptanceMatrix::GRID
* t
->cargo_accepted
.area
.h
/ AcceptanceMatrix::GRID
;
262 SlArray(t
->cargo_accepted
.data
, arr_len
, SLE_UINT32
);
266 static void Save_TOWN()
271 SlSetArrayIndex(t
->index
);
272 SlAutolength((AutolengthProc
*)RealSave_Town
, t
);
276 static void Load_TOWN()
280 while ((index
= SlIterateArray()) != -1) {
281 Town
*t
= new (index
) Town();
282 SlObject(t
, _town_desc
);
284 for (CargoID i
= 0; i
< NUM_CARGO
; i
++) {
285 SlObject(&t
->supplied
[i
], _town_supplied_desc
);
287 for (int i
= TE_BEGIN
; i
< TE_END
; i
++) {
288 SlObject(&t
->received
[i
], _town_received_desc
);
291 if (t
->townnamegrfid
== 0 && !IsInsideMM(t
->townnametype
, SPECSTR_TOWNNAME_START
, SPECSTR_TOWNNAME_LAST
+ 1) && GetStringTab(t
->townnametype
) != TEXT_TAB_OLD_CUSTOM
) {
292 SlErrorCorrupt("Invalid town name generator");
295 if (IsSavegameVersionBefore(166)) continue;
297 SlObject(&t
->cargo_accepted
, GetTileMatrixDesc());
298 if (t
->cargo_accepted
.area
.w
!= 0) {
299 uint arr_len
= t
->cargo_accepted
.area
.w
/ AcceptanceMatrix::GRID
* t
->cargo_accepted
.area
.h
/ AcceptanceMatrix::GRID
;
300 t
->cargo_accepted
.data
= MallocT
<uint32
>(arr_len
);
301 SlArray(t
->cargo_accepted
.data
, arr_len
, SLE_UINT32
);
303 /* Rebuild total cargo acceptance. */
304 UpdateTownCargoTotal(t
);
309 /** Fix pointers when loading town data. */
310 static void Ptrs_TOWN()
312 /* Don't run when savegame version lower than 161. */
313 if (IsSavegameVersionBefore(161)) return;
317 SlObject(t
, _town_desc
);
321 /** Chunk handler for towns. */
322 extern const ChunkHandler _town_chunk_handlers
[] = {
323 { 'HIDS', Save_HIDS
, Load_HIDS
, nullptr, nullptr, CH_ARRAY
},
324 { 'CITY', Save_TOWN
, Load_TOWN
, Ptrs_TOWN
, nullptr, CH_ARRAY
| CH_LAST
},