41 #include "misc/autoptr.hpp" |
41 #include "misc/autoptr.hpp" |
42 #include "road.h" |
42 #include "road.h" |
43 #include "cargotype.h" |
43 #include "cargotype.h" |
44 #include "strings.h" |
44 #include "strings.h" |
45 |
45 |
|
46 DEFINE_OLD_POOL_GENERIC(Station, Station) |
|
47 DEFINE_OLD_POOL_GENERIC(RoadStop, RoadStop) |
|
48 |
|
49 |
46 /** |
50 /** |
47 * Called if a new block is added to the station-pool |
51 * Check whether the given tile is a hangar. |
|
52 * @param t the tile to of whether it is a hangar. |
|
53 * @pre IsTileType(t, MP_STATION) |
|
54 * @return true if and only if the tile is a hangar. |
48 */ |
55 */ |
49 static void StationPoolNewBlock(uint start_item) |
56 bool IsHangar(TileIndex t) |
50 { |
57 { |
51 /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. |
58 assert(IsTileType(t, MP_STATION)); |
52 * TODO - This is just a temporary stage, this will be removed. */ |
59 |
53 for (Station *st = GetStation(start_item); st != NULL; st = (st->index + 1U < GetStationPoolSize()) ? GetStation(st->index + 1U) : NULL) st->index = start_item++; |
60 const Station *st = GetStationByTile(t); |
54 } |
61 const AirportFTAClass *apc = st->Airport(); |
55 |
62 |
56 static void StationPoolCleanBlock(uint start_item, uint end_item) |
63 for (uint i = 0; i < apc->nof_depots; i++) { |
57 { |
64 if (st->airport_tile + ToTileIndexDiff(apc->airport_depots[i]) == t) return true; |
58 for (uint i = start_item; i <= end_item; i++) { |
65 } |
59 Station *st = GetStation(i); |
66 |
60 if (st->IsValid()) st->~Station(); |
67 return false; |
61 } |
68 } |
62 } |
|
63 |
|
64 /** |
|
65 * Called if a new block is added to the roadstop-pool |
|
66 */ |
|
67 static void RoadStopPoolNewBlock(uint start_item) |
|
68 { |
|
69 /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. |
|
70 * TODO - This is just a temporary stage, this will be removed. */ |
|
71 for (RoadStop *rs = GetRoadStop(start_item); rs != NULL; rs = (rs->index + 1U < GetRoadStopPoolSize()) ? GetRoadStop(rs->index + 1U) : NULL) { |
|
72 rs->xy = INVALID_TILE; |
|
73 rs->index = start_item++; |
|
74 } |
|
75 } |
|
76 |
|
77 DEFINE_OLD_POOL(Station, Station, StationPoolNewBlock, StationPoolCleanBlock) |
|
78 DEFINE_OLD_POOL(RoadStop, RoadStop, RoadStopPoolNewBlock, NULL) |
|
79 |
|
80 |
69 |
81 RoadStop* GetRoadStopByTile(TileIndex tile, RoadStop::Type type) |
70 RoadStop* GetRoadStopByTile(TileIndex tile, RoadStop::Type type) |
82 { |
71 { |
83 const Station* st = GetStationByTile(tile); |
72 const Station* st = GetStationByTile(tile); |
84 |
73 |
135 } |
124 } |
136 END_TILE_LOOP(tile_cur, w + 2, h + 2, tile - TileDiffXY(1, 1)) |
125 END_TILE_LOOP(tile_cur, w + 2, h + 2, tile - TileDiffXY(1, 1)) |
137 return (closest_station == INVALID_STATION) ? NULL : GetStation(closest_station); |
126 return (closest_station == INVALID_STATION) ? NULL : GetStation(closest_station); |
138 } |
127 } |
139 |
128 |
|
129 /** |
|
130 * Function to check whether the given tile matches some criterion. |
|
131 * @param tile the tile to check |
|
132 * @return true if it matches, false otherwise |
|
133 */ |
|
134 typedef bool (*CMSAMatcher)(TileIndex tile); |
140 |
135 |
141 /** |
136 /** |
142 * Counts the numbers of tiles matching a specific type in the area around |
137 * Counts the numbers of tiles matching a specific type in the area around |
143 * @param tile the center tile of the 'count area' |
138 * @param tile the center tile of the 'count area' |
144 * @param type the type of tile searched for |
139 * @param type the type of tile searched for |
145 * @param industry when type == MP_INDUSTRY, the type of the industry, |
140 * @param industry when type == MP_INDUSTRY, the type of the industry, |
146 * in all other cases this parameter is ignored |
141 * in all other cases this parameter is ignored |
147 * @return the result the noumber of matching tiles around |
142 * @return the result the noumber of matching tiles around |
148 */ |
143 */ |
149 static int CountMapSquareAround(TileIndex tile, TileType type, IndustryType industry) |
144 static int CountMapSquareAround(TileIndex tile, CMSAMatcher cmp) |
150 { |
145 { |
151 int num = 0; |
146 int num = 0; |
152 |
147 |
153 for (int dx = -3; dx <= 3; dx++) { |
148 for (int dx = -3; dx <= 3; dx++) { |
154 for (int dy = -3; dy <= 3; dy++) { |
149 for (int dy = -3; dy <= 3; dy++) { |
155 TileIndex cur_tile = TILE_MASK(tile + TileDiffXY(dx, dy)); |
150 if (cmp(TILE_MASK(tile + TileDiffXY(dx, dy)))) num++; |
156 |
|
157 if (IsTileType(cur_tile, type)) { |
|
158 switch (type) { |
|
159 case MP_INDUSTRY: |
|
160 if (GetIndustryType(cur_tile) == industry) |
|
161 num++; |
|
162 break; |
|
163 |
|
164 case MP_WATER: |
|
165 if (!IsWater(cur_tile)) |
|
166 break; |
|
167 /* FALL THROUGH WHEN WATER TILE */ |
|
168 case MP_TREES: |
|
169 num++; |
|
170 break; |
|
171 |
|
172 default: |
|
173 break; |
|
174 } |
|
175 } |
|
176 } |
151 } |
177 } |
152 } |
178 |
153 |
179 return num; |
154 return num; |
|
155 } |
|
156 |
|
157 /** |
|
158 * Check whether the tile is a mine. |
|
159 * @param tile the tile to investigate. |
|
160 * @return true if and only if the tile is a mine |
|
161 */ |
|
162 static bool CMSAMine(TileIndex tile) |
|
163 { |
|
164 /* No industry */ |
|
165 if (!IsTileType(tile, MP_INDUSTRY)) return false; |
|
166 |
|
167 const IndustrySpec *indsp = GetIndustrySpec(GetIndustryByTile(tile)->type); |
|
168 |
|
169 /* No extractive industry */ |
|
170 if ((indsp->life_type & INDUSTRYLIFE_EXTRACTIVE) == 0) return false; |
|
171 |
|
172 for (uint i = 0; i < lengthof(indsp->produced_cargo); i++) { |
|
173 /* The industry extracts something non-liquid, i.e. no oil or plastic, so it is a mine */ |
|
174 if (indsp->produced_cargo[i] != CT_INVALID && (GetCargo(indsp->produced_cargo[i])->classes & CC_LIQUID) == 0) return true; |
|
175 } |
|
176 |
|
177 return false; |
|
178 } |
|
179 |
|
180 /** |
|
181 * Check whether the tile is water. |
|
182 * @param tile the tile to investigate. |
|
183 * @return true if and only if the tile is a mine |
|
184 */ |
|
185 static bool CMSAWater(TileIndex tile) |
|
186 { |
|
187 return IsTileType(tile, MP_WATER) && IsWater(tile); |
|
188 } |
|
189 |
|
190 /** |
|
191 * Check whether the tile is a tree. |
|
192 * @param tile the tile to investigate. |
|
193 * @return true if and only if the tile is a mine |
|
194 */ |
|
195 static bool CMSATree(TileIndex tile) |
|
196 { |
|
197 return IsTileType(tile, MP_TREES); |
|
198 } |
|
199 |
|
200 /** |
|
201 * Check whether the tile is a forest. |
|
202 * @param tile the tile to investigate. |
|
203 * @return true if and only if the tile is a mine |
|
204 */ |
|
205 static bool CMSAForest(TileIndex tile) |
|
206 { |
|
207 /* No industry */ |
|
208 if (!IsTileType(tile, MP_INDUSTRY)) return false; |
|
209 |
|
210 const IndustrySpec *indsp = GetIndustrySpec(GetIndustryByTile(tile)->type); |
|
211 |
|
212 /* No extractive industry */ |
|
213 if ((indsp->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false; |
|
214 |
|
215 for (uint i = 0; i < lengthof(indsp->produced_cargo); i++) { |
|
216 /* The industry produces wood. */ |
|
217 if (indsp->produced_cargo[i] != CT_INVALID && GetCargo(indsp->produced_cargo[i])->label == 'WOOD') return true; |
|
218 } |
|
219 |
|
220 return false; |
180 } |
221 } |
181 |
222 |
182 #define M(x) ((x) - STR_SV_STNAME) |
223 #define M(x) ((x) - STR_SV_STNAME) |
183 |
224 |
184 static bool GenerateStationName(Station *st, TileIndex tile, int flag) |
225 static bool GenerateStationName(Station *st, TileIndex tile, int flag) |
241 } |
278 } |
242 |
279 |
243 /* Check lakeside */ |
280 /* Check lakeside */ |
244 if (HASBIT(free_names, M(STR_SV_STNAME_LAKESIDE)) && |
281 if (HASBIT(free_names, M(STR_SV_STNAME_LAKESIDE)) && |
245 DistanceFromEdge(tile) < 20 && |
282 DistanceFromEdge(tile) < 20 && |
246 CountMapSquareAround(tile, MP_WATER, 0) >= 5) { |
283 CountMapSquareAround(tile, CMSAWater) >= 5) { |
247 found = M(STR_SV_STNAME_LAKESIDE); |
284 found = M(STR_SV_STNAME_LAKESIDE); |
248 goto done; |
285 goto done; |
249 } |
286 } |
250 |
287 |
251 /* Check woods */ |
288 /* Check woods */ |
252 if (HASBIT(free_names, M(STR_SV_STNAME_WOODS)) && ( |
289 if (HASBIT(free_names, M(STR_SV_STNAME_WOODS)) && ( |
253 CountMapSquareAround(tile, MP_TREES, 0) >= 8 || |
290 CountMapSquareAround(tile, CMSATree) >= 8 || |
254 CountMapSquareAround(tile, MP_INDUSTRY, IT_FOREST) >= 2) |
291 CountMapSquareAround(tile, CMSAForest) >= 2) |
255 ) { |
292 ) { |
256 found = _opt.landscape == LT_TROPIC ? |
293 found = _opt.landscape == LT_TROPIC ? |
257 M(STR_SV_STNAME_FOREST) : M(STR_SV_STNAME_WOODS); |
294 M(STR_SV_STNAME_FOREST) : M(STR_SV_STNAME_WOODS); |
258 goto done; |
295 goto done; |
259 } |
296 } |
888 //XXX can't we pack this in the "else" part of the if above? |
925 //XXX can't we pack this in the "else" part of the if above? |
889 if (!st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TEST)) return CMD_ERROR; |
926 if (!st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TEST)) return CMD_ERROR; |
890 } else { |
927 } else { |
891 /* allocate and initialize new station */ |
928 /* allocate and initialize new station */ |
892 st = new Station(tile_org); |
929 st = new Station(tile_org); |
893 if (st == NULL) return CMD_ERROR; |
930 if (st == NULL) return_cmd_error(STR_3008_TOO_MANY_STATIONS_LOADING); |
894 |
931 |
895 /* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */ |
932 /* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */ |
896 st_auto_delete = st; |
933 st_auto_delete = st; |
897 |
934 |
898 st->town = ClosestTownFromTile(tile_org, (uint)-1); |
935 st->town = ClosestTownFromTile(tile_org, (uint)-1); |
1242 */ |
1279 */ |
1243 CommandCost CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1280 CommandCost CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1244 { |
1281 { |
1245 bool type = HASBIT(p2, 0); |
1282 bool type = HASBIT(p2, 0); |
1246 bool is_drive_through = HASBIT(p2, 1); |
1283 bool is_drive_through = HASBIT(p2, 1); |
1247 bool build_over_road = is_drive_through && IsTileType(tile, MP_STREET) && GetRoadTileType(tile) == ROAD_TILE_NORMAL; |
1284 bool build_over_road = is_drive_through && IsTileType(tile, MP_ROAD) && GetRoadTileType(tile) == ROAD_TILE_NORMAL; |
1248 bool town_owned_road = build_over_road && IsTileOwner(tile, OWNER_TOWN); |
1285 bool town_owned_road = build_over_road && IsTileOwner(tile, OWNER_TOWN); |
1249 RoadTypes rts = (RoadTypes)GB(p2, 2, 3); |
1286 RoadTypes rts = (RoadTypes)GB(p2, 2, 3); |
1250 |
1287 |
1251 if (rts == ROADTYPES_NONE || HASBIT(rts, ROADTYPE_HWAY)) return CMD_ERROR; |
1288 if (rts == ROADTYPES_NONE || HASBIT(rts, ROADTYPE_HWAY)) return CMD_ERROR; |
1252 |
1289 |
1359 UpdateStationVirtCoordDirty(st); |
1396 UpdateStationVirtCoordDirty(st); |
1360 UpdateStationAcceptance(st, false); |
1397 UpdateStationAcceptance(st, false); |
1361 RebuildStationLists(); |
1398 RebuildStationLists(); |
1362 InvalidateWindow(WC_STATION_LIST, st->owner); |
1399 InvalidateWindow(WC_STATION_LIST, st->owner); |
1363 /* success, so don't delete the new station and the new road stop */ |
1400 /* success, so don't delete the new station and the new road stop */ |
1364 st_auto_delete.Release(); |
1401 st_auto_delete.Detach(); |
1365 rs_auto_delete.Release(); |
1402 rs_auto_delete.Detach(); |
1366 } |
1403 } |
1367 return cost; |
1404 return cost; |
1368 } |
1405 } |
1369 |
1406 |
1370 // Remove a bus station |
1407 // Remove a bus station |
1735 if (!IsClearWaterTile(tile) || tile == 0) return_cmd_error(STR_304B_SITE_UNSUITABLE); |
1772 if (!IsClearWaterTile(tile) || tile == 0) return_cmd_error(STR_304B_SITE_UNSUITABLE); |
1736 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST); |
1773 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST); |
1737 |
1774 |
1738 /* allocate and initialize new station */ |
1775 /* allocate and initialize new station */ |
1739 Station *st = new Station(tile); |
1776 Station *st = new Station(tile); |
1740 if (st == NULL) return CMD_ERROR; |
1777 if (st == NULL) return_cmd_error(STR_3008_TOO_MANY_STATIONS_LOADING); |
1741 |
1778 |
1742 /* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */ |
1779 /* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */ |
1743 AutoPtrT<Station> st_auto_delete(st); |
1780 AutoPtrT<Station> st_auto_delete(st); |
1744 |
1781 |
1745 st->town = ClosestTownFromTile(tile, (uint)-1); |
1782 st->town = ClosestTownFromTile(tile, (uint)-1); |
1929 UpdateStationVirtCoordDirty(st); |
1966 UpdateStationVirtCoordDirty(st); |
1930 UpdateStationAcceptance(st, false); |
1967 UpdateStationAcceptance(st, false); |
1931 RebuildStationLists(); |
1968 RebuildStationLists(); |
1932 InvalidateWindow(WC_STATION_LIST, st->owner); |
1969 InvalidateWindow(WC_STATION_LIST, st->owner); |
1933 /* success, so don't delete the new station */ |
1970 /* success, so don't delete the new station */ |
1934 st_auto_delete.Release(); |
1971 st_auto_delete.Detach(); |
1935 } |
1972 } |
1936 return CommandCost(_price.build_dock); |
1973 return CommandCost(_price.build_dock); |
1937 } |
1974 } |
1938 |
1975 |
1939 static CommandCost RemoveDock(Station *st, uint32 flags) |
1976 static CommandCost RemoveDock(Station *st, uint32 flags) |
2061 } else { |
2098 } else { |
2062 image += relocation; |
2099 image += relocation; |
2063 } |
2100 } |
2064 |
2101 |
2065 SpriteID pal; |
2102 SpriteID pal; |
2066 if (HASBIT(_transparent_opt, TO_BUILDINGS)) { |
2103 if (!HASBIT(_transparent_opt, TO_BUILDINGS) && HASBIT(image, PALETTE_MODIFIER_COLOR)) { |
2067 SETBIT(image, PALETTE_MODIFIER_TRANSPARENT); |
|
2068 pal = PALETTE_TO_TRANSPARENT; |
|
2069 } else if (HASBIT(image, PALETTE_MODIFIER_COLOR)) { |
|
2070 pal = palette; |
2104 pal = palette; |
2071 } else { |
2105 } else { |
2072 pal = dtss->pal; |
2106 pal = dtss->pal; |
2073 } |
2107 } |
2074 |
2108 |
2075 if ((byte)dtss->delta_z != 0x80) { |
2109 if ((byte)dtss->delta_z != 0x80) { |
2076 AddSortableSpriteToDraw( |
2110 AddSortableSpriteToDraw( |
2077 image, pal, |
2111 image, pal, |
2078 ti->x + dtss->delta_x, ti->y + dtss->delta_y, |
2112 ti->x + dtss->delta_x, ti->y + dtss->delta_y, |
2079 dtss->size_x, dtss->size_y, |
2113 dtss->size_x, dtss->size_y, |
2080 dtss->size_z, ti->z + dtss->delta_z |
2114 dtss->size_z, ti->z + dtss->delta_z, |
|
2115 HASBIT(_transparent_opt, TO_BUILDINGS) |
2081 ); |
2116 ); |
2082 } else { |
2117 } else { |
2083 AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y); |
2118 AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y); |
2084 } |
2119 } |
2085 } |
2120 } |
2853 AnimateTile_Station, /* animate_tile_proc */ |
2888 AnimateTile_Station, /* animate_tile_proc */ |
2854 TileLoop_Station, /* tile_loop_clear */ |
2889 TileLoop_Station, /* tile_loop_clear */ |
2855 ChangeTileOwner_Station, /* change_tile_owner_clear */ |
2890 ChangeTileOwner_Station, /* change_tile_owner_clear */ |
2856 NULL, /* get_produced_cargo_proc */ |
2891 NULL, /* get_produced_cargo_proc */ |
2857 VehicleEnter_Station, /* vehicle_enter_tile_proc */ |
2892 VehicleEnter_Station, /* vehicle_enter_tile_proc */ |
2858 GetSlopeTileh_Station, /* get_slope_tileh_proc */ |
2893 GetFoundation_Station, /* get_foundation_proc */ |
2859 }; |
2894 }; |
2860 |
2895 |
2861 static const SaveLoad _roadstop_desc[] = { |
2896 static const SaveLoad _roadstop_desc[] = { |
2862 SLE_VAR(RoadStop,xy, SLE_UINT32), |
2897 SLE_VAR(RoadStop,xy, SLE_UINT32), |
2863 SLE_CONDNULL(1, 0, 44), |
2898 SLE_CONDNULL(1, 0, 44), |