OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

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
26 void RebuildTownCaches()
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 }
54 UpdateTownCargoBitmap();
55 }
56
65 void UpdateHousesAndTowns()
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
113 RebuildTownCaches();
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),
128 SLE_CONDSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, 0, 84, SL_MAX_VERSION),
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
171 SLE_CONDSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, 0, 168, SL_MAX_VERSION),
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) */
197 SLE_CONDNULL(30, 2, SL_MAX_VERSION),
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. */
301 UpdateTownCargoTotal(t);
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 };