OpenTTD
town_sl.cpp
Go to the documentation of this file.
1 /* $Id: town_sl.cpp 27756 2017-02-26 19:40:53Z frosch $ */
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 #include "../strings_func.h"
18 
19 #include "saveload.h"
20 #include "newgrf_sl.h"
21 
22 #include "../safeguards.h"
23 
28 {
29  Town *town;
30  InitializeBuildingCounts();
31 
32  /* Reset town population and num_houses */
33  FOR_ALL_TOWNS(town) {
34  town->cache.population = 0;
35  town->cache.num_houses = 0;
36  }
37 
38  for (TileIndex t = 0; t < MapSize(); t++) {
39  if (!IsTileType(t, MP_HOUSE)) continue;
40 
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;
45 
46  /* Increase the number of houses for every house, but only once. */
47  if (GetHouseNorthPart(house_id) == 0) town->cache.num_houses++;
48  }
49 
50  /* Update the population and num_house dependent values */
51  FOR_ALL_TOWNS(town) {
52  UpdateTownRadius(town);
53  UpdateTownCargoes(town);
54  }
56 }
57 
67 {
68  for (TileIndex t = 0; t < MapSize(); t++) {
69  if (!IsTileType(t, MP_HOUSE)) continue;
70 
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);
77  }
78  }
79 
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;
83 
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;
102  }
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. */
110  DoClearSquare(t);
111  }
112  }
113 
115 }
116 
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),
121 
122  SLE_CONDNULL(2, 0, 2),
123  SLE_CONDNULL(4, 3, 84),
124  SLE_CONDNULL(2, 0, 91),
125 
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),
130 
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),
134 
135  SLE_CONDNULL(1, 0, 1),
136 
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),
144 
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),
153 
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),
162 
163  SLE_CONDNULL(2, 0, 163),
164 
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),
169 
170  SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TE, 165, SL_MAX_VERSION),
171 
173 
174  SLE_CONDVAR(Town, time_until_rebuild, SLE_FILE_U8 | SLE_VAR_U16, 0, 53),
175  SLE_CONDVAR(Town, grow_counter, SLE_FILE_U8 | SLE_VAR_U16, 0, 53),
176  SLE_CONDVAR(Town, growth_rate, SLE_FILE_U8 | SLE_VAR_I16, 0, 53),
177 
178  SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT16, 54, SL_MAX_VERSION),
179  SLE_CONDVAR(Town, grow_counter, SLE_UINT16, 54, SL_MAX_VERSION),
180 
181  SLE_CONDVAR(Town, growth_rate, SLE_FILE_I16 | SLE_VAR_U16, 54, 164),
182  SLE_CONDVAR(Town, growth_rate, SLE_UINT16, 165, SL_MAX_VERSION),
183 
184  SLE_VAR(Town, fund_buildings_months, SLE_UINT8),
185  SLE_VAR(Town, road_build_months, SLE_UINT8),
186 
187  SLE_CONDVAR(Town, exclusivity, SLE_UINT8, 2, SL_MAX_VERSION),
188  SLE_CONDVAR(Town, exclusive_counter, SLE_UINT8, 2, SL_MAX_VERSION),
189 
190  SLE_CONDVAR(Town, larger_town, SLE_BOOL, 56, SL_MAX_VERSION),
191  SLE_CONDVAR(Town, layout, SLE_UINT8, 113, SL_MAX_VERSION),
192 
193  SLE_CONDLST(Town, psa_list, REF_STORAGE, 161, SL_MAX_VERSION),
194 
195  SLE_CONDVAR(Town, cargo_produced, SLE_UINT32, 166, SL_MAX_VERSION),
196 
197  /* reserve extra space in savegame here. (currently 30 bytes) */
199 
200  SLE_END()
201 };
202 
203 static const SaveLoad _town_supplied_desc[] = {
204  SLE_CONDVAR(TransportedCargoStat<uint32>, old_max, SLE_UINT32, 165, SL_MAX_VERSION),
205  SLE_CONDVAR(TransportedCargoStat<uint32>, new_max, SLE_UINT32, 165, SL_MAX_VERSION),
206  SLE_CONDVAR(TransportedCargoStat<uint32>, old_act, SLE_UINT32, 165, SL_MAX_VERSION),
207  SLE_CONDVAR(TransportedCargoStat<uint32>, new_act, SLE_UINT32, 165, SL_MAX_VERSION),
208 
209  SLE_END()
210 };
211 
212 static const SaveLoad _town_received_desc[] = {
213  SLE_CONDVAR(TransportedCargoStat<uint16>, old_max, SLE_UINT16, 165, SL_MAX_VERSION),
214  SLE_CONDVAR(TransportedCargoStat<uint16>, new_max, SLE_UINT16, 165, SL_MAX_VERSION),
215  SLE_CONDVAR(TransportedCargoStat<uint16>, old_act, SLE_UINT16, 165, SL_MAX_VERSION),
216  SLE_CONDVAR(TransportedCargoStat<uint16>, new_act, SLE_UINT16, 165, SL_MAX_VERSION),
217 
218  SLE_END()
219 };
220 
221 static void Save_HIDS()
222 {
223  Save_NewGRFMapping(_house_mngr);
224 }
225 
226 static void Load_HIDS()
227 {
228  Load_NewGRFMapping(_house_mngr);
229 }
230 
231 const SaveLoad *GetTileMatrixDesc()
232 {
233  /* Here due to private member vars. */
234  static const SaveLoad _tilematrix_desc[] = {
235  SLE_VAR(AcceptanceMatrix, area.tile, SLE_UINT32),
236  SLE_VAR(AcceptanceMatrix, area.w, SLE_UINT16),
237  SLE_VAR(AcceptanceMatrix, area.h, SLE_UINT16),
238  SLE_END()
239  };
240 
241  return _tilematrix_desc;
242 }
243 
244 static void RealSave_Town(Town *t)
245 {
246  SlObject(t, _town_desc);
247 
248  for (CargoID i = 0; i < NUM_CARGO; i++) {
249  SlObject(&t->supplied[i], _town_supplied_desc);
250  }
251  for (int i = TE_BEGIN; i < NUM_TE; i++) {
252  SlObject(&t->received[i], _town_received_desc);
253  }
254 
255  if (IsSavegameVersionBefore(166)) return;
256 
257  SlObject(&t->cargo_accepted, GetTileMatrixDesc());
258  if (t->cargo_accepted.area.w != 0) {
259  uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID;
260  SlArray(t->cargo_accepted.data, arr_len, SLE_UINT32);
261  }
262 }
263 
264 static void Save_TOWN()
265 {
266  Town *t;
267 
268  FOR_ALL_TOWNS(t) {
269  SlSetArrayIndex(t->index);
270  SlAutolength((AutolengthProc*)RealSave_Town, t);
271  }
272 }
273 
274 static void Load_TOWN()
275 {
276  int index;
277 
278  while ((index = SlIterateArray()) != -1) {
279  Town *t = new (index) Town();
280  SlObject(t, _town_desc);
281 
282  for (CargoID i = 0; i < NUM_CARGO; i++) {
283  SlObject(&t->supplied[i], _town_supplied_desc);
284  }
285  for (int i = TE_BEGIN; i < TE_END; i++) {
286  SlObject(&t->received[i], _town_received_desc);
287  }
288 
289  if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1) && GetStringTab(t->townnametype) != TEXT_TAB_OLD_CUSTOM) {
290  SlErrorCorrupt("Invalid town name generator");
291  }
292 
293  if (IsSavegameVersionBefore(166)) continue;
294 
295  SlObject(&t->cargo_accepted, GetTileMatrixDesc());
296  if (t->cargo_accepted.area.w != 0) {
297  uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID;
298  t->cargo_accepted.data = MallocT<uint32>(arr_len);
299  SlArray(t->cargo_accepted.data, arr_len, SLE_UINT32);
300 
301  /* Rebuild total cargo acceptance. */
303  }
304  }
305 }
306 
308 static void Ptrs_TOWN()
309 {
310  /* Don't run when savegame version lower than 161. */
311  if (IsSavegameVersionBefore(161)) return;
312 
313  Town *t;
314  FOR_ALL_TOWNS(t) {
315  SlObject(t, _town_desc);
316  }
317 }
318 
320 extern const ChunkHandler _town_chunk_handlers[] = {
321  { 'HIDS', Save_HIDS, Load_HIDS, NULL, NULL, CH_ARRAY },
322  { 'CITY', Save_TOWN, Load_TOWN, Ptrs_TOWN, NULL, CH_ARRAY | CH_LAST},
323 };