OpenTTD
town_sl.cpp
Go to the documentation of this file.
1 /* $Id: town_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2 
3 /*
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/>.
8  */
9 
12 #include "../stdafx.h"
13 #include "../newgrf_house.h"
14 #include "../town.h"
15 #include "../landscape.h"
16 #include "../subsidy_func.h"
17 
18 #include "saveload.h"
19 #include "newgrf_sl.h"
20 
21 #include "../safeguards.h"
22 
27 {
28  Town *town;
29  InitializeBuildingCounts();
30 
31  /* Reset town population and num_houses */
32  FOR_ALL_TOWNS(town) {
33  town->cache.population = 0;
34  town->cache.num_houses = 0;
35  }
36 
37  for (TileIndex t = 0; t < MapSize(); t++) {
38  if (!IsTileType(t, MP_HOUSE)) continue;
39 
40  HouseID house_id = GetHouseType(t);
41  town = Town::GetByTile(t);
42  IncreaseBuildingCount(town, house_id);
43  if (IsHouseCompleted(t)) town->cache.population += HouseSpec::Get(house_id)->population;
44 
45  /* Increase the number of houses for every house, but only once. */
46  if (GetHouseNorthPart(house_id) == 0) town->cache.num_houses++;
47  }
48 
49  /* Update the population and num_house dependent values */
50  FOR_ALL_TOWNS(town) {
51  UpdateTownRadius(town);
52  UpdateTownCargoes(town);
53  }
55 }
56 
66 {
67  for (TileIndex t = 0; t < MapSize(); t++) {
68  if (!IsTileType(t, MP_HOUSE)) continue;
69 
70  HouseID house_id = GetCleanHouseType(t);
71  if (!HouseSpec::Get(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) {
72  /* The specs for this type of house are not available any more, so
73  * replace it with the substitute original house type. */
74  house_id = _house_mngr.GetSubstituteID(house_id);
75  SetHouseType(t, house_id);
76  }
77  }
78 
79  /* Check for cases when a NewGRF has set a wrong house substitute type. */
80  for (TileIndex t = 0; t < MapSize(); t++) {
81  if (!IsTileType(t, MP_HOUSE)) continue;
82 
83  HouseID house_type = GetCleanHouseType(t);
84  TileIndex north_tile = t + GetHouseNorthPart(house_type); // modifies 'house_type'!
85  if (t == north_tile) {
86  const HouseSpec *hs = HouseSpec::Get(house_type);
87  bool valid_house = true;
88  if (hs->building_flags & TILE_SIZE_2x1) {
89  TileIndex tile = t + TileDiffXY(1, 0);
90  if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false;
91  } else if (hs->building_flags & TILE_SIZE_1x2) {
92  TileIndex tile = t + TileDiffXY(0, 1);
93  if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false;
94  } else if (hs->building_flags & TILE_SIZE_2x2) {
95  TileIndex tile = t + TileDiffXY(0, 1);
96  if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false;
97  tile = t + TileDiffXY(1, 0);
98  if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 2) valid_house = false;
99  tile = t + TileDiffXY(1, 1);
100  if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 3) valid_house = false;
101  }
102  /* If not all tiles of this house are present remove the house.
103  * The other tiles will get removed later in this loop because
104  * their north tile is not the correct type anymore. */
105  if (!valid_house) DoClearSquare(t);
106  } else if (!IsTileType(north_tile, MP_HOUSE) || GetCleanHouseType(north_tile) != house_type) {
107  /* This tile should be part of a multi-tile building but the
108  * north tile of this house isn't on the map. */
109  DoClearSquare(t);
110  }
111  }
112 
114 }
115 
117 static const SaveLoad _town_desc[] = {
118  SLE_CONDVAR(Town, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
119  SLE_CONDVAR(Town, xy, SLE_UINT32, 6, SL_MAX_VERSION),
120 
121  SLE_CONDNULL(2, 0, 2),
122  SLE_CONDNULL(4, 3, 84),
123  SLE_CONDNULL(2, 0, 91),
124 
125  SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, 66, SL_MAX_VERSION),
126  SLE_VAR(Town, townnametype, SLE_UINT16),
127  SLE_VAR(Town, townnameparts, SLE_UINT32),
129 
130  SLE_VAR(Town, flags, SLE_UINT8),
131  SLE_CONDVAR(Town, statues, SLE_FILE_U8 | SLE_VAR_U16, 0, 103),
132  SLE_CONDVAR(Town, statues, SLE_UINT16, 104, SL_MAX_VERSION),
133 
134  SLE_CONDNULL(1, 0, 1),
135 
136  SLE_CONDVAR(Town, have_ratings, SLE_FILE_U8 | SLE_VAR_U16, 0, 103),
137  SLE_CONDVAR(Town, have_ratings, SLE_UINT16, 104, SL_MAX_VERSION),
138  SLE_CONDARR(Town, ratings, SLE_INT16, 8, 0, 103),
139  SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, 104, SL_MAX_VERSION),
140  /* failed bribe attempts are stored since savegame format 4 */
141  SLE_CONDARR(Town, unwanted, SLE_INT8, 8, 4, 103),
142  SLE_CONDARR(Town, unwanted, SLE_INT8, MAX_COMPANIES, 104, SL_MAX_VERSION),
143 
144  SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_max, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
145  SLE_CONDVAR(Town, supplied[CT_MAIL].old_max, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
146  SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_max, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
147  SLE_CONDVAR(Town, supplied[CT_MAIL].new_max, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
148  SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_act, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
149  SLE_CONDVAR(Town, supplied[CT_MAIL].old_act, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
150  SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_act, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
151  SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_FILE_U16 | SLE_VAR_U32, 0, 8),
152 
153  SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_max, SLE_UINT32, 9, 164),
154  SLE_CONDVAR(Town, supplied[CT_MAIL].old_max, SLE_UINT32, 9, 164),
155  SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_max, SLE_UINT32, 9, 164),
156  SLE_CONDVAR(Town, supplied[CT_MAIL].new_max, SLE_UINT32, 9, 164),
157  SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_act, SLE_UINT32, 9, 164),
158  SLE_CONDVAR(Town, supplied[CT_MAIL].old_act, SLE_UINT32, 9, 164),
159  SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_act, SLE_UINT32, 9, 164),
160  SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_UINT32, 9, 164),
161 
162  SLE_CONDNULL(2, 0, 163),
163 
164  SLE_CONDVAR(Town, received[TE_FOOD].old_act, SLE_UINT16, 0, 164),
165  SLE_CONDVAR(Town, received[TE_WATER].old_act, SLE_UINT16, 0, 164),
166  SLE_CONDVAR(Town, received[TE_FOOD].new_act, SLE_UINT16, 0, 164),
167  SLE_CONDVAR(Town, received[TE_WATER].new_act, SLE_UINT16, 0, 164),
168 
169  SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TE, 165, SL_MAX_VERSION),
170 
172 
173  SLE_CONDVAR(Town, time_until_rebuild, SLE_FILE_U8 | SLE_VAR_U16, 0, 53),
174  SLE_CONDVAR(Town, grow_counter, SLE_FILE_U8 | SLE_VAR_U16, 0, 53),
175  SLE_CONDVAR(Town, growth_rate, SLE_FILE_U8 | SLE_VAR_I16, 0, 53),
176 
177  SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT16, 54, SL_MAX_VERSION),
178  SLE_CONDVAR(Town, grow_counter, SLE_UINT16, 54, SL_MAX_VERSION),
179 
180  SLE_CONDVAR(Town, growth_rate, SLE_FILE_I16 | SLE_VAR_U16, 54, 164),
181  SLE_CONDVAR(Town, growth_rate, SLE_UINT16, 165, SL_MAX_VERSION),
182 
183  SLE_VAR(Town, fund_buildings_months, SLE_UINT8),
184  SLE_VAR(Town, road_build_months, SLE_UINT8),
185 
186  SLE_CONDVAR(Town, exclusivity, SLE_UINT8, 2, SL_MAX_VERSION),
187  SLE_CONDVAR(Town, exclusive_counter, SLE_UINT8, 2, SL_MAX_VERSION),
188 
189  SLE_CONDVAR(Town, larger_town, SLE_BOOL, 56, SL_MAX_VERSION),
190  SLE_CONDVAR(Town, layout, SLE_UINT8, 113, SL_MAX_VERSION),
191 
192  SLE_CONDLST(Town, psa_list, REF_STORAGE, 161, SL_MAX_VERSION),
193 
194  SLE_CONDVAR(Town, cargo_produced, SLE_UINT32, 166, SL_MAX_VERSION),
195 
196  /* reserve extra space in savegame here. (currently 30 bytes) */
198 
199  SLE_END()
200 };
201 
202 static const SaveLoad _town_supplied_desc[] = {
203  SLE_CONDVAR(TransportedCargoStat<uint32>, old_max, SLE_UINT32, 165, SL_MAX_VERSION),
204  SLE_CONDVAR(TransportedCargoStat<uint32>, new_max, SLE_UINT32, 165, SL_MAX_VERSION),
205  SLE_CONDVAR(TransportedCargoStat<uint32>, old_act, SLE_UINT32, 165, SL_MAX_VERSION),
206  SLE_CONDVAR(TransportedCargoStat<uint32>, new_act, SLE_UINT32, 165, SL_MAX_VERSION),
207 
208  SLE_END()
209 };
210 
211 static const SaveLoad _town_received_desc[] = {
212  SLE_CONDVAR(TransportedCargoStat<uint16>, old_max, SLE_UINT16, 165, SL_MAX_VERSION),
213  SLE_CONDVAR(TransportedCargoStat<uint16>, new_max, SLE_UINT16, 165, SL_MAX_VERSION),
214  SLE_CONDVAR(TransportedCargoStat<uint16>, old_act, SLE_UINT16, 165, SL_MAX_VERSION),
215  SLE_CONDVAR(TransportedCargoStat<uint16>, new_act, SLE_UINT16, 165, SL_MAX_VERSION),
216 
217  SLE_END()
218 };
219 
220 static void Save_HIDS()
221 {
222  Save_NewGRFMapping(_house_mngr);
223 }
224 
225 static void Load_HIDS()
226 {
227  Load_NewGRFMapping(_house_mngr);
228 }
229 
230 const SaveLoad *GetTileMatrixDesc()
231 {
232  /* Here due to private member vars. */
233  static const SaveLoad _tilematrix_desc[] = {
234  SLE_VAR(AcceptanceMatrix, area.tile, SLE_UINT32),
235  SLE_VAR(AcceptanceMatrix, area.w, SLE_UINT16),
236  SLE_VAR(AcceptanceMatrix, area.h, SLE_UINT16),
237  SLE_END()
238  };
239 
240  return _tilematrix_desc;
241 }
242 
243 static void RealSave_Town(Town *t)
244 {
245  SlObject(t, _town_desc);
246 
247  for (CargoID i = 0; i < NUM_CARGO; i++) {
248  SlObject(&t->supplied[i], _town_supplied_desc);
249  }
250  for (int i = TE_BEGIN; i < NUM_TE; i++) {
251  SlObject(&t->received[i], _town_received_desc);
252  }
253 
254  if (IsSavegameVersionBefore(166)) return;
255 
256  SlObject(&t->cargo_accepted, GetTileMatrixDesc());
257  if (t->cargo_accepted.area.w != 0) {
258  uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID;
259  SlArray(t->cargo_accepted.data, arr_len, SLE_UINT32);
260  }
261 }
262 
263 static void Save_TOWN()
264 {
265  Town *t;
266 
267  FOR_ALL_TOWNS(t) {
268  SlSetArrayIndex(t->index);
269  SlAutolength((AutolengthProc*)RealSave_Town, t);
270  }
271 }
272 
273 static void Load_TOWN()
274 {
275  int index;
276 
277  while ((index = SlIterateArray()) != -1) {
278  Town *t = new (index) Town();
279  SlObject(t, _town_desc);
280 
281  for (CargoID i = 0; i < NUM_CARGO; i++) {
282  SlObject(&t->supplied[i], _town_supplied_desc);
283  }
284  for (int i = TE_BEGIN; i < TE_END; i++) {
285  SlObject(&t->received[i], _town_received_desc);
286  }
287 
288  if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1) && GB(t->townnametype, 11, 5) != 15) {
289  SlErrorCorrupt("Invalid town name generator");
290  }
291 
292  if (IsSavegameVersionBefore(166)) continue;
293 
294  SlObject(&t->cargo_accepted, GetTileMatrixDesc());
295  if (t->cargo_accepted.area.w != 0) {
296  uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID;
297  t->cargo_accepted.data = MallocT<uint32>(arr_len);
298  SlArray(t->cargo_accepted.data, arr_len, SLE_UINT32);
299 
300  /* Rebuild total cargo acceptance. */
302  }
303  }
304 }
305 
307 static void Ptrs_TOWN()
308 {
309  /* Don't run when savegame version lower than 161. */
310  if (IsSavegameVersionBefore(161)) return;
311 
312  Town *t;
313  FOR_ALL_TOWNS(t) {
314  SlObject(t, _town_desc);
315  }
316 }
317 
319 extern const ChunkHandler _town_chunk_handlers[] = {
320  { 'HIDS', Save_HIDS, Load_HIDS, NULL, NULL, CH_ARRAY },
321  { 'CITY', Save_TOWN, Load_TOWN, Ptrs_TOWN, NULL, CH_ARRAY | CH_LAST},
322 };