31 #include "functions.h" |
29 #include "functions.h" |
32 #include "window_func.h" |
30 #include "window_func.h" |
33 #include "vehicle_func.h" |
31 #include "vehicle_func.h" |
34 #include "sound_func.h" |
32 #include "sound_func.h" |
35 #include "variables.h" |
33 #include "variables.h" |
36 |
34 #include "player_func.h" |
37 |
35 #include "settings_type.h" |
38 static Vehicle *FindFloodableVehicleOnTile(TileIndex tile); |
36 #include "clear_map.h" |
39 static void FloodVehicle(Vehicle *v); |
37 #include "tree_map.h" |
|
38 |
|
39 #include "table/sprites.h" |
|
40 #include "table/strings.h" |
|
41 |
|
42 /** |
|
43 * Describes the behaviour of a tile during flooding. |
|
44 */ |
|
45 enum FloodingBehaviour { |
|
46 FLOOD_NONE, ///< The tile does not flood neighboured tiles. |
|
47 FLOOD_ACTIVE, ///< The tile floods neighboured tiles. |
|
48 FLOOD_PASSIVE, ///< The tile does not actively flood neighboured tiles, but it prevents them from drying up. |
|
49 FLOOD_DRYUP, ///< The tile drys up if it is not constantly flooded from neighboured tiles. |
|
50 }; |
|
51 |
|
52 /** |
|
53 * Describes from which directions a specific slope can be flooded (if the tile is floodable at all). |
|
54 */ |
|
55 static const uint8 _flood_from_dirs[] = { |
|
56 (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE), // SLOPE_FLAT |
|
57 (1 << DIR_NE) | (1 << DIR_SE), // SLOPE_W |
|
58 (1 << DIR_NW) | (1 << DIR_NE), // SLOPE_S |
|
59 (1 << DIR_NE), // SLOPE_SW |
|
60 (1 << DIR_NW) | (1 << DIR_SW), // SLOPE_E |
|
61 0, // SLOPE_EW |
|
62 (1 << DIR_NW), // SLOPE_SE |
|
63 (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE), // SLOPE_WSE, SLOPE_STEEP_S |
|
64 (1 << DIR_SW) | (1 << DIR_SE), // SLOPE_N |
|
65 (1 << DIR_SE), // SLOPE_NW |
|
66 0, // SLOPE_NS |
|
67 (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE), // SLOPE_NWS, SLOPE_STEEP_W |
|
68 (1 << DIR_SW), // SLOPE_NE |
|
69 (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE), // SLOPE_ENW, SLOPE_STEEP_N |
|
70 (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW), // SLOPE_SEN, SLOPE_STEEP_E |
|
71 }; |
|
72 |
|
73 /** |
|
74 * Marks tile dirty if it is a canal or river tile. |
|
75 * Called to avoid glitches when flooding tiles next to canal tile. |
|
76 * |
|
77 * @param tile tile to check |
|
78 */ |
|
79 static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile) |
|
80 { |
|
81 if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile); |
|
82 } |
|
83 |
|
84 /** |
|
85 * Marks the tiles around a tile as dirty, if they are canals or rivers. |
|
86 * |
|
87 * @param tile The center of the tile where all other tiles are marked as dirty |
|
88 * @ingroup dirty |
|
89 */ |
|
90 static void MarkCanalsAndRiversAroundDirty(TileIndex tile) |
|
91 { |
|
92 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) { |
|
93 MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir)); |
|
94 } |
|
95 } |
40 |
96 |
41 /** |
97 /** |
42 * Makes a tile canal or water depending on the surroundings. |
98 * Makes a tile canal or water depending on the surroundings. |
43 * This as for example docks and shipdepots do not store |
99 * This as for example docks and shipdepots do not store |
44 * whether the tile used to be canal or 'normal' water. |
100 * whether the tile used to be canal or 'normal' water. |
45 * @param t the tile to change. |
101 * @param t the tile to change. |
46 * @param o the owner of the new tile. |
102 * @param o the owner of the new tile. |
47 */ |
103 */ |
48 void MakeWaterOrCanalDependingOnSurroundings(TileIndex t, Owner o) |
104 void SetWaterClassDependingOnSurroundings(TileIndex t) |
49 { |
105 { |
50 assert(GetTileSlope(t, NULL) == SLOPE_FLAT); |
106 assert(GetTileSlope(t, NULL) == SLOPE_FLAT); |
51 |
107 |
52 /* Mark tile dirty in all cases */ |
108 /* Mark tile dirty in all cases */ |
53 MarkTileDirtyByTile(t); |
109 MarkTileDirtyByTile(t); |
54 |
110 |
55 /* Non-sealevel -> canal */ |
|
56 if (TileHeight(t) != 0) { |
|
57 MakeCanal(t, o); |
|
58 return; |
|
59 } |
|
60 |
|
61 bool has_water = false; |
111 bool has_water = false; |
62 bool has_canal = false; |
112 bool has_canal = false; |
|
113 bool has_river = false; |
63 |
114 |
64 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { |
115 for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { |
65 TileIndex neighbour = TileAddByDiagDir(t, dir); |
116 TileIndex neighbour = TileAddByDiagDir(t, dir); |
66 if (IsTileType(neighbour, MP_WATER)) { |
117 switch (GetTileType(neighbour)) { |
67 has_water |= IsSea(neighbour) || IsCoast(neighbour) || (IsShipDepot(neighbour) && GetShipDepotWaterOwner(neighbour) == OWNER_WATER); |
118 case MP_WATER: |
68 has_canal |= IsCanal(neighbour) || (IsShipDepot(neighbour) && GetShipDepotWaterOwner(neighbour) != OWNER_WATER); |
119 has_water |= IsSea(neighbour) || IsCoast(neighbour) || (IsShipDepot(neighbour) && GetShipDepotWaterOwner(neighbour) == OWNER_WATER); |
|
120 has_canal |= IsCanal(neighbour) || (IsShipDepot(neighbour) && GetShipDepotWaterOwner(neighbour) != OWNER_WATER); |
|
121 has_river |= IsRiver(neighbour); |
|
122 break; |
|
123 |
|
124 case MP_RAILWAY: |
|
125 /* Shore or flooded halftile */ |
|
126 has_water |= (GetRailGroundType(neighbour) == RAIL_GROUND_WATER); |
|
127 break; |
|
128 |
|
129 case MP_TREES: |
|
130 /* trees on shore */ |
|
131 has_water |= (GetTreeGround(neighbour) == TREE_GROUND_SHORE); |
|
132 break; |
|
133 |
|
134 default: break; |
69 } |
135 } |
70 } |
136 } |
71 if (has_canal || !has_water) { |
137 |
72 MakeCanal(t, o); |
138 if (has_river && !has_canal) { |
|
139 SetWaterClass(t, WATER_CLASS_RIVER); |
|
140 } else if (has_canal || !has_water) { |
|
141 SetWaterClass(t, WATER_CLASS_CANAL); |
73 } else { |
142 } else { |
74 MakeWater(t); |
143 SetWaterClass(t, WATER_CLASS_SEA); |
75 } |
144 } |
76 } |
145 } |
77 |
146 |
78 |
147 |
79 /** Build a ship depot. |
148 /** Build a ship depot. |
90 |
159 |
91 Axis axis = Extract<Axis, 0>(p1); |
160 Axis axis = Extract<Axis, 0>(p1); |
92 |
161 |
93 tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); |
162 tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); |
94 |
163 |
95 if (!IsWaterTile(tile) || !IsWaterTile(tile2)) |
164 if (!IsWaterTile(tile) || !IsWaterTile(tile2)) { |
96 return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER); |
165 return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER); |
|
166 } |
97 |
167 |
98 if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST); |
168 if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST); |
99 |
169 |
|
170 if (GetTileSlope(tile, NULL) != SLOPE_FLAT || GetTileSlope(tile2, NULL) != SLOPE_FLAT) { |
|
171 /* Prevent depots on rapids */ |
|
172 return_cmd_error(STR_0239_SITE_UNSUITABLE); |
|
173 } |
|
174 |
|
175 WaterClass wc1 = GetWaterClass(tile); |
|
176 WaterClass wc2 = GetWaterClass(tile2); |
100 Owner o1 = GetTileOwner(tile); |
177 Owner o1 = GetTileOwner(tile); |
101 Owner o2 = GetTileOwner(tile2); |
178 Owner o2 = GetTileOwner(tile2); |
102 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
179 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
103 if (CmdFailed(ret)) return CMD_ERROR; |
180 if (CmdFailed(ret)) return CMD_ERROR; |
104 ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
181 ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
109 AutoPtrT<Depot> d_auto_delete = depot; |
186 AutoPtrT<Depot> d_auto_delete = depot; |
110 |
187 |
111 if (flags & DC_EXEC) { |
188 if (flags & DC_EXEC) { |
112 depot->town_index = ClosestTownFromTile(tile, (uint)-1)->index; |
189 depot->town_index = ClosestTownFromTile(tile, (uint)-1)->index; |
113 |
190 |
114 MakeShipDepot(tile, _current_player, DEPOT_NORTH, axis, o1); |
191 MakeShipDepot(tile, _current_player, DEPOT_NORTH, axis, wc1, o1); |
115 MakeShipDepot(tile2, _current_player, DEPOT_SOUTH, axis, o2); |
192 MakeShipDepot(tile2, _current_player, DEPOT_SOUTH, axis, wc2, o2); |
116 MarkTileDirtyByTile(tile); |
193 MarkTileDirtyByTile(tile); |
117 MarkTileDirtyByTile(tile2); |
194 MarkTileDirtyByTile(tile2); |
118 d_auto_delete.Detach(); |
195 d_auto_delete.Detach(); |
119 } |
196 } |
120 |
197 |
121 return CommandCost(EXPENSES_CONSTRUCTION, _price.build_ship_depot); |
198 return CommandCost(EXPENSES_CONSTRUCTION, _price.build_ship_depot); |
122 } |
199 } |
123 |
200 |
124 void MakeWaterOrCanalDependingOnOwner(TileIndex tile, Owner o) |
201 void MakeWaterKeepingClass(TileIndex tile, Owner o) |
125 { |
202 { |
126 if (o == OWNER_WATER) { |
203 assert(IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_STATION) && (IsBuoy(tile) || IsDock(tile)))); |
127 MakeWater(tile); |
204 |
128 } else { |
205 switch (GetWaterClass(tile)) { |
129 MakeCanal(tile, o); |
206 case WATER_CLASS_SEA: MakeWater(tile); break; |
|
207 case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break; |
|
208 case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break; |
130 } |
209 } |
131 } |
210 } |
132 |
211 |
133 static CommandCost RemoveShipDepot(TileIndex tile, uint32 flags) |
212 static CommandCost RemoveShipDepot(TileIndex tile, uint32 flags) |
134 { |
213 { |
165 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
244 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
166 if (CmdFailed(ret)) return CMD_ERROR; |
245 if (CmdFailed(ret)) return CMD_ERROR; |
167 |
246 |
168 delta = TileOffsByDiagDir(dir); |
247 delta = TileOffsByDiagDir(dir); |
169 /* lower tile */ |
248 /* lower tile */ |
|
249 WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL; |
|
250 |
170 ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
251 ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
171 if (CmdFailed(ret)) return CMD_ERROR; |
252 if (CmdFailed(ret)) return CMD_ERROR; |
172 if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) { |
253 if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) { |
173 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
254 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
174 } |
255 } |
175 |
256 |
176 /* upper tile */ |
257 /* upper tile */ |
|
258 WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL; |
|
259 |
177 ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
260 ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
178 if (CmdFailed(ret)) return CMD_ERROR; |
261 if (CmdFailed(ret)) return CMD_ERROR; |
179 if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) { |
262 if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) { |
180 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
263 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
181 } |
264 } |
206 if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile + delta) || !EnsureNoVehicleOnGround(tile - delta)) |
291 if (!EnsureNoVehicleOnGround(tile) || !EnsureNoVehicleOnGround(tile + delta) || !EnsureNoVehicleOnGround(tile - delta)) |
207 return CMD_ERROR; |
292 return CMD_ERROR; |
208 |
293 |
209 if (flags & DC_EXEC) { |
294 if (flags & DC_EXEC) { |
210 DoClearSquare(tile); |
295 DoClearSquare(tile); |
211 MakeWaterOrCanalDependingOnSurroundings(tile + delta, _current_player); |
296 MakeWaterKeepingClass(tile + delta, GetTileOwner(tile)); |
212 MakeWaterOrCanalDependingOnSurroundings(tile - delta, _current_player); |
297 MakeWaterKeepingClass(tile - delta, GetTileOwner(tile)); |
|
298 MarkTileDirtyByTile(tile - delta); |
|
299 MarkTileDirtyByTile(tile + delta); |
|
300 MarkCanalsAndRiversAroundDirty(tile - delta); |
|
301 MarkCanalsAndRiversAroundDirty(tile + delta); |
213 } |
302 } |
214 |
303 |
215 return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water * 2); |
304 return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water * 2); |
216 } |
|
217 |
|
218 /** |
|
219 * Marks the tiles around a tile as dirty. |
|
220 * |
|
221 * This functions marks the tiles around a given tile as dirty for repaint. |
|
222 * |
|
223 * @param tile The center of the tile where all other tiles are marked as dirty |
|
224 * @ingroup dirty |
|
225 * @see TerraformAddDirtyTileAround |
|
226 */ |
|
227 static void MarkTilesAroundDirty(TileIndex tile) |
|
228 { |
|
229 MarkTileDirtyByTile(TILE_ADDXY(tile, 0, 1)); |
|
230 MarkTileDirtyByTile(TILE_ADDXY(tile, 0, -1)); |
|
231 MarkTileDirtyByTile(TILE_ADDXY(tile, 1, 0)); |
|
232 MarkTileDirtyByTile(TILE_ADDXY(tile, -1, 0)); |
|
233 } |
305 } |
234 |
306 |
235 /** Builds a lock (ship-lift) |
307 /** Builds a lock (ship-lift) |
236 * @param tile tile where to place the lock |
308 * @param tile tile where to place the lock |
237 * @param flags type of operation |
309 * @param flags type of operation |
238 * @param p1 unused |
310 * @param p1 unused |
239 * @param p2 unused |
311 * @param p2 unused |
240 */ |
312 */ |
241 CommandCost CmdBuildLock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
313 CommandCost CmdBuildLock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
242 { |
314 { |
243 DiagDirection dir; |
315 DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile, NULL)); |
244 |
316 if (dir == INVALID_DIAGDIR) return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
245 switch (GetTileSlope(tile, NULL)) { |
317 |
246 case SLOPE_SW: dir = DIAGDIR_SW; break; |
318 /* Disallow building of locks on river rapids */ |
247 case SLOPE_SE: dir = DIAGDIR_SE; break; |
319 if (IsWaterTile(tile)) return_cmd_error(STR_0239_SITE_UNSUITABLE); |
248 case SLOPE_NW: dir = DIAGDIR_NW; break; |
320 |
249 case SLOPE_NE: dir = DIAGDIR_NE; break; |
|
250 default: return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
|
251 } |
|
252 return DoBuildShiplift(tile, dir, flags); |
321 return DoBuildShiplift(tile, dir, flags); |
253 } |
322 } |
254 |
323 |
255 /** Build a piece of canal. |
324 /** Build a piece of canal. |
256 * @param tile end tile of stretch-dragging |
325 * @param tile end tile of stretch-dragging |
257 * @param flags type of operation |
326 * @param flags type of operation |
258 * @param p1 start tile of stretch-dragging |
327 * @param p1 start tile of stretch-dragging |
259 * @param p2 ctrl pressed - toggles ocean / canals at sealevel (ocean only allowed in the scenario editor) |
328 * @param p2 specifies canal (0), water (1) or river (2); last two can only be built in scenario editor |
260 */ |
329 */ |
261 CommandCost CmdBuildCanal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
330 CommandCost CmdBuildCanal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
262 { |
331 { |
263 CommandCost cost(EXPENSES_CONSTRUCTION); |
332 CommandCost cost(EXPENSES_CONSTRUCTION); |
264 int size_x, size_y; |
333 int size_x, size_y; |
265 int x; |
334 int x; |
266 int y; |
335 int y; |
267 int sx, sy; |
336 int sx, sy; |
268 |
337 |
269 if (p1 >= MapSize()) return CMD_ERROR; |
338 if (p1 >= MapSize()) return CMD_ERROR; |
|
339 |
270 /* Outside of the editor you can only build canals, not oceans */ |
340 /* Outside of the editor you can only build canals, not oceans */ |
271 if (HasBit(p2, 0) && _game_mode != GM_EDITOR) return CMD_ERROR; |
341 if (p2 != 0 && _game_mode != GM_EDITOR) return CMD_ERROR; |
272 |
342 |
273 x = TileX(tile); |
343 x = TileX(tile); |
274 y = TileY(tile); |
344 y = TileY(tile); |
275 sx = TileX(p1); |
345 sx = TileX(p1); |
276 sy = TileY(p1); |
346 sy = TileY(p1); |
284 if (_game_mode != GM_EDITOR && (sx != x && sy != y)) return CMD_ERROR; |
354 if (_game_mode != GM_EDITOR && (sx != x && sy != y)) return CMD_ERROR; |
285 |
355 |
286 BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) { |
356 BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) { |
287 CommandCost ret; |
357 CommandCost ret; |
288 |
358 |
289 if (GetTileSlope(tile, NULL) != SLOPE_FLAT) { |
359 Slope slope = GetTileSlope(tile, NULL); |
|
360 if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) { |
290 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED); |
361 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED); |
291 } |
362 } |
292 |
363 |
293 /* can't make water of water! */ |
364 /* can't make water of water! */ |
294 if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || HasBit(p2, 0))) continue; |
365 if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || p2 == 1)) continue; |
295 |
366 |
296 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
367 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
297 if (CmdFailed(ret)) return ret; |
368 if (CmdFailed(ret)) return ret; |
298 cost.AddCost(ret); |
369 cost.AddCost(ret); |
299 |
370 |
300 if (flags & DC_EXEC) { |
371 if (flags & DC_EXEC) { |
301 if (TileHeight(tile) == 0 && HasBit(p2, 0)) { |
372 if (TileHeight(tile) == 0 && p2 == 1) { |
302 MakeWater(tile); |
373 MakeWater(tile); |
|
374 } else if (p2 == 2) { |
|
375 MakeRiver(tile, Random()); |
303 } else { |
376 } else { |
304 MakeCanal(tile, _current_player); |
377 MakeCanal(tile, _current_player, Random()); |
305 } |
378 } |
306 MarkTileDirtyByTile(tile); |
379 MarkTileDirtyByTile(tile); |
307 MarkTilesAroundDirty(tile); |
380 MarkCanalsAndRiversAroundDirty(tile); |
308 } |
381 } |
309 |
382 |
310 cost.AddCost(_price.clear_water); |
383 cost.AddCost(_price.clear_water); |
311 } END_TILE_LOOP(tile, size_x, size_y, 0); |
384 } END_TILE_LOOP(tile, size_x, size_y, 0); |
312 |
385 |
371 default: |
450 default: |
372 NOT_REACHED(); |
451 NOT_REACHED(); |
373 } |
452 } |
374 } |
453 } |
375 |
454 |
376 /** return true if a tile is a water tile. */ |
455 /** |
377 static bool IsWateredTile(TileIndex tile) |
456 * return true if a tile is a water tile wrt. a certain direction. |
|
457 * |
|
458 * @param tile The tile of interest. |
|
459 * @param from The direction of interest. |
|
460 * @return true iff the tile is water in the view of 'from'. |
|
461 * |
|
462 */ |
|
463 static bool IsWateredTile(TileIndex tile, Direction from) |
378 { |
464 { |
379 switch (GetTileType(tile)) { |
465 switch (GetTileType(tile)) { |
380 case MP_WATER: |
466 case MP_WATER: |
381 if (!IsCoast(tile)) return true; |
467 if (!IsCoast(tile)) return true; |
382 |
|
383 switch (GetTileSlope(tile, NULL)) { |
468 switch (GetTileSlope(tile, NULL)) { |
384 case SLOPE_W: |
469 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE); |
385 case SLOPE_S: |
470 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW); |
386 case SLOPE_E: |
471 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW); |
387 case SLOPE_N: |
472 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE); |
388 return true; |
473 default: return false; |
389 |
474 } |
390 default: |
475 |
391 return false; |
476 case MP_RAILWAY: |
392 } |
477 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) { |
393 |
478 assert(IsPlainRailTile(tile)); |
394 case MP_STATION: return IsOilRig(tile) || IsDock(tile) || IsBuoy(tile); |
479 switch (GetTileSlope(tile, NULL)) { |
|
480 case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE); |
|
481 case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW); |
|
482 case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW); |
|
483 case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE); |
|
484 default: return false; |
|
485 } |
|
486 } |
|
487 return false; |
|
488 |
|
489 case MP_STATION: return IsOilRig(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile); |
395 case MP_INDUSTRY: return (GetIndustrySpec(GetIndustryType(tile))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0; |
490 case MP_INDUSTRY: return (GetIndustrySpec(GetIndustryType(tile))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0; |
396 default: return false; |
491 default: return false; |
397 } |
492 } |
398 } |
493 } |
399 |
494 |
|
495 static void DrawWaterEdges(SpriteID base, TileIndex tile) |
|
496 { |
|
497 uint wa; |
|
498 |
|
499 /* determine the edges around with water. */ |
|
500 wa = IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0; |
|
501 wa += IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1; |
|
502 wa += IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2; |
|
503 wa += IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3; |
|
504 |
|
505 if (!(wa & 1)) DrawGroundSprite(base, PAL_NONE); |
|
506 if (!(wa & 2)) DrawGroundSprite(base + 1, PAL_NONE); |
|
507 if (!(wa & 4)) DrawGroundSprite(base + 2, PAL_NONE); |
|
508 if (!(wa & 8)) DrawGroundSprite(base + 3, PAL_NONE); |
|
509 |
|
510 /* right corner */ |
|
511 switch (wa & 0x03) { |
|
512 case 0: DrawGroundSprite(base + 4, PAL_NONE); break; |
|
513 case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawGroundSprite(base + 8, PAL_NONE); break; |
|
514 } |
|
515 |
|
516 /* bottom corner */ |
|
517 switch (wa & 0x06) { |
|
518 case 0: DrawGroundSprite(base + 5, PAL_NONE); break; |
|
519 case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawGroundSprite(base + 9, PAL_NONE); break; |
|
520 } |
|
521 |
|
522 /* left corner */ |
|
523 switch (wa & 0x0C) { |
|
524 case 0: DrawGroundSprite(base + 6, PAL_NONE); break; |
|
525 case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawGroundSprite(base + 10, PAL_NONE); break; |
|
526 } |
|
527 |
|
528 /* upper corner */ |
|
529 switch (wa & 0x09) { |
|
530 case 0: DrawGroundSprite(base + 7, PAL_NONE); break; |
|
531 case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawGroundSprite(base + 11, PAL_NONE); break; |
|
532 } |
|
533 } |
|
534 |
|
535 /** Draw a plain sea water tile with no edges */ |
|
536 void DrawSeaWater(TileIndex tile) |
|
537 { |
|
538 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE); |
|
539 } |
|
540 |
400 /** draw a canal styled water tile with dikes around */ |
541 /** draw a canal styled water tile with dikes around */ |
401 void DrawCanalWater(TileIndex tile) |
542 void DrawCanalWater(TileIndex tile, bool draw_base) |
402 { |
543 { |
403 uint wa; |
544 if (draw_base) DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE); |
404 |
545 |
405 /* Test for custom graphics, else use the default */ |
546 /* Test for custom graphics, else use the default */ |
406 SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile); |
547 SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile); |
407 if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE; |
548 if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE; |
408 |
549 |
409 /* determine the edges around with water. */ |
550 DrawWaterEdges(dikes_base, tile); |
410 wa = IsWateredTile(TILE_ADDXY(tile, -1, 0)) << 0; |
|
411 wa += IsWateredTile(TILE_ADDXY(tile, 0, 1)) << 1; |
|
412 wa += IsWateredTile(TILE_ADDXY(tile, 1, 0)) << 2; |
|
413 wa += IsWateredTile(TILE_ADDXY(tile, 0, -1)) << 3; |
|
414 |
|
415 if (!(wa & 1)) DrawGroundSprite(dikes_base, PAL_NONE); |
|
416 if (!(wa & 2)) DrawGroundSprite(dikes_base + 1, PAL_NONE); |
|
417 if (!(wa & 4)) DrawGroundSprite(dikes_base + 2, PAL_NONE); |
|
418 if (!(wa & 8)) DrawGroundSprite(dikes_base + 3, PAL_NONE); |
|
419 |
|
420 /* right corner */ |
|
421 switch (wa & 0x03) { |
|
422 case 0: DrawGroundSprite(dikes_base + 4, PAL_NONE); break; |
|
423 case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1))) DrawGroundSprite(dikes_base + 8, PAL_NONE); break; |
|
424 } |
|
425 |
|
426 /* bottom corner */ |
|
427 switch (wa & 0x06) { |
|
428 case 0: DrawGroundSprite(dikes_base + 5, PAL_NONE); break; |
|
429 case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1))) DrawGroundSprite(dikes_base + 9, PAL_NONE); break; |
|
430 } |
|
431 |
|
432 /* left corner */ |
|
433 switch (wa & 0x0C) { |
|
434 case 0: DrawGroundSprite(dikes_base + 6, PAL_NONE); break; |
|
435 case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1))) DrawGroundSprite(dikes_base + 10, PAL_NONE); break; |
|
436 } |
|
437 |
|
438 /* upper corner */ |
|
439 switch (wa & 0x09) { |
|
440 case 0: DrawGroundSprite(dikes_base + 7, PAL_NONE); break; |
|
441 case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1))) DrawGroundSprite(dikes_base + 11, PAL_NONE); break; |
|
442 } |
|
443 } |
551 } |
444 |
552 |
445 struct LocksDrawTileStruct { |
553 struct LocksDrawTileStruct { |
446 int8 delta_x, delta_y, delta_z; |
554 int8 delta_x, delta_y, delta_z; |
447 byte width, height, depth; |
555 byte width, height, depth; |
478 wdts->unk, ti->z + wdts->delta_z, |
586 wdts->unk, ti->z + wdts->delta_z, |
479 IsTransparencySet(TO_BUILDINGS)); |
587 IsTransparencySet(TO_BUILDINGS)); |
480 } |
588 } |
481 } |
589 } |
482 |
590 |
|
591 void DrawRiverWater(const TileInfo *ti, bool draw_base) |
|
592 { |
|
593 SpriteID image = SPR_FLAT_WATER_TILE; |
|
594 SpriteID edges_base = GetCanalSprite(CF_RIVER_EDGE, ti->tile); |
|
595 |
|
596 if (ti->tileh != SLOPE_FLAT) { |
|
597 image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile); |
|
598 if (image == 0) { |
|
599 switch (ti->tileh) { |
|
600 case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break; |
|
601 case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP; break; |
|
602 case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP; break; |
|
603 case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break; |
|
604 default: image = SPR_FLAT_WATER_TILE; break; |
|
605 } |
|
606 } else { |
|
607 switch (ti->tileh) { |
|
608 default: NOT_REACHED(); |
|
609 case SLOPE_SE: edges_base += 12; break; |
|
610 case SLOPE_NE: image += 1; edges_base += 24; break; |
|
611 case SLOPE_SW: image += 2; edges_base += 36; break; |
|
612 case SLOPE_NW: image += 3; edges_base += 48; break; |
|
613 } |
|
614 } |
|
615 } |
|
616 |
|
617 if (draw_base) DrawGroundSprite(image, PAL_NONE); |
|
618 |
|
619 /* Draw river edges if available. */ |
|
620 if (edges_base > 48) DrawWaterEdges(edges_base, ti->tile); |
|
621 } |
|
622 |
|
623 void DrawShoreTile(Slope tileh) |
|
624 { |
|
625 /* Converts the enum Slope into an offset based on SPR_SHORE_BASE. |
|
626 * This allows to calculate the proper sprite to display for this Slope */ |
|
627 static const byte tileh_to_shoresprite[32] = { |
|
628 0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0, |
|
629 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0, |
|
630 }; |
|
631 |
|
632 assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier. |
|
633 assert(tileh != SLOPE_FLAT); // Shore is never flat |
|
634 |
|
635 assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour |
|
636 |
|
637 DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE); |
|
638 } |
|
639 |
483 static void DrawTile_Water(TileInfo *ti) |
640 static void DrawTile_Water(TileInfo *ti) |
484 { |
641 { |
485 switch (GetWaterTileType(ti->tile)) { |
642 switch (GetWaterTileType(ti->tile)) { |
486 case WATER_TILE_CLEAR: |
643 case WATER_TILE_CLEAR: |
487 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE); |
644 switch (GetWaterClass(ti->tile)) { |
488 if (IsCanal(ti->tile)) DrawCanalWater(ti->tile); |
645 case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break; |
|
646 case WATER_CLASS_CANAL: DrawCanalWater(ti->tile, true); break; |
|
647 case WATER_CLASS_RIVER: DrawRiverWater(ti, true); break; |
|
648 } |
489 DrawBridgeMiddle(ti); |
649 DrawBridgeMiddle(ti); |
490 break; |
650 break; |
491 |
651 |
492 case WATER_TILE_COAST: { |
652 case WATER_TILE_COAST: { |
493 /* Converts the enum Slope into an offset based on SPR_SHORE_BASE. |
653 DrawShoreTile(ti->tileh); |
494 * This allows to calculate the proper sprite to display for this Slope */ |
|
495 static const byte tileh_to_shoresprite[32] = { |
|
496 0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0, |
|
497 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0, |
|
498 }; |
|
499 |
|
500 assert(!IsSteepSlope(ti->tileh)); |
|
501 DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[ti->tileh], PAL_NONE); |
|
502 DrawBridgeMiddle(ti); |
654 DrawBridgeMiddle(ti); |
503 } break; |
655 } break; |
504 |
656 |
505 case WATER_TILE_LOCK: { |
657 case WATER_TILE_LOCK: { |
506 const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)]; |
658 const WaterDrawTileStruct *t = _shiplift_display_seq[GetSection(ti->tile)]; |
566 static void AnimateTile_Water(TileIndex tile) |
718 static void AnimateTile_Water(TileIndex tile) |
567 { |
719 { |
568 /* not used */ |
720 /* not used */ |
569 } |
721 } |
570 |
722 |
571 /** |
|
572 * Marks tile dirty if it is a canal tile. |
|
573 * Called to avoid glitches when flooding tiles next to canal tile. |
|
574 * |
|
575 * @param tile tile to check |
|
576 */ |
|
577 static inline void MarkTileDirtyIfCanal(TileIndex tile) { |
|
578 if (IsTileType(tile, MP_WATER) && IsCanal(tile)) MarkTileDirtyByTile(tile); |
|
579 } |
|
580 |
|
581 /** |
|
582 * Floods neighboured floodable tiles |
|
583 * |
|
584 * @param tile The water source tile that causes the flooding. |
|
585 * @param offs[0] Destination tile to flood. |
|
586 * @param offs[1] First corner of edge between source and dest tile. |
|
587 * @param offs[2] Second corder of edge between source and dest tile. |
|
588 * @param offs[3] Third corner of dest tile. |
|
589 * @param offs[4] Fourth corner of dest tile. |
|
590 */ |
|
591 static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs) |
|
592 { |
|
593 TileIndex target = TILE_ADD(tile, ToTileIndexDiff(offs[0])); |
|
594 |
|
595 /* type of this tile mustn't be water already. */ |
|
596 if (IsTileType(target, MP_WATER)) return; |
|
597 |
|
598 /* Are both corners of the edge between source and dest on height 0 ? */ |
|
599 if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[1]))) != 0 || |
|
600 TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[2]))) != 0) { |
|
601 return; |
|
602 } |
|
603 |
|
604 /* Is any corner of the dest tile raised? (First two corners already checked above. */ |
|
605 if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[3]))) != 0 || |
|
606 TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[4]))) != 0) { |
|
607 /* make coast.. */ |
|
608 switch (GetTileType(target)) { |
|
609 case MP_RAILWAY: { |
|
610 if (!IsPlainRailTile(target)) break; |
|
611 |
|
612 FloodHalftile(target); |
|
613 |
|
614 Vehicle *v = FindFloodableVehicleOnTile(target); |
|
615 if (v != NULL) FloodVehicle(v); |
|
616 |
|
617 break; |
|
618 } |
|
619 |
|
620 case MP_CLEAR: |
|
621 case MP_TREES: |
|
622 _current_player = OWNER_WATER; |
|
623 if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) { |
|
624 MakeShore(target); |
|
625 MarkTileDirtyByTile(target); |
|
626 } |
|
627 break; |
|
628 |
|
629 default: |
|
630 break; |
|
631 } |
|
632 } else { |
|
633 /* Flood vehicles */ |
|
634 _current_player = OWNER_WATER; |
|
635 |
|
636 Vehicle *v = FindFloodableVehicleOnTile(target); |
|
637 if (v != NULL) FloodVehicle(v); |
|
638 |
|
639 /* flood flat tile */ |
|
640 if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) { |
|
641 MakeWater(target); |
|
642 MarkTileDirtyByTile(target); |
|
643 /* Mark surrounding canal tiles dirty too to avoid glitches */ |
|
644 MarkTileDirtyIfCanal(target + TileDiffXY(0, 1)); |
|
645 MarkTileDirtyIfCanal(target + TileDiffXY(1, 0)); |
|
646 MarkTileDirtyIfCanal(target + TileDiffXY(0, -1)); |
|
647 MarkTileDirtyIfCanal(target + TileDiffXY(-1, 0)); |
|
648 } |
|
649 } |
|
650 } |
|
651 |
723 |
652 /** |
724 /** |
653 * Finds a vehicle to flood. |
725 * Finds a vehicle to flood. |
654 * It does not find vehicles that are already crashed on bridges, i.e. flooded. |
726 * It does not find vehicles that are already crashed on bridges, i.e. flooded. |
655 * @param tile the tile where to find a vehicle to flood |
727 * @param tile the tile where to find a vehicle to flood |
770 SndPlayVehicleFx(SND_12_EXPLOSION, v); |
842 SndPlayVehicleFx(SND_12_EXPLOSION, v); |
771 } |
843 } |
772 } |
844 } |
773 |
845 |
774 /** |
846 /** |
|
847 * Returns the behaviour of a tile during flooding. |
|
848 * |
|
849 * @return Behaviour of the tile |
|
850 */ |
|
851 static FloodingBehaviour GetFloodingBehaviour(TileIndex tile) |
|
852 { |
|
853 /* FLOOD_ACTIVE: 'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, rail with flooded halftile |
|
854 * FLOOD_DRYUP: coast with more than one corner raised, coast with rail-track, coast with trees |
|
855 * FLOOD_PASSIVE: oilrig, dock, water-industries |
|
856 * FLOOD_NONE: canals, rivers, everything else |
|
857 */ |
|
858 switch (GetTileType(tile)) { |
|
859 case MP_WATER: |
|
860 if (IsCoast(tile)) { |
|
861 Slope tileh = GetTileSlope(tile, NULL); |
|
862 return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP); |
|
863 } else { |
|
864 return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE; |
|
865 } |
|
866 |
|
867 case MP_RAILWAY: |
|
868 if (GetRailGroundType(tile) == RAIL_GROUND_WATER) { |
|
869 return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP); |
|
870 } |
|
871 return FLOOD_NONE; |
|
872 |
|
873 case MP_TREES: |
|
874 return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE); |
|
875 |
|
876 case MP_STATION: |
|
877 if (IsBuoy(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) return FLOOD_ACTIVE; |
|
878 if (IsOilRig(tile) || IsDock(tile)) return FLOOD_PASSIVE; |
|
879 return FLOOD_NONE; |
|
880 |
|
881 case MP_INDUSTRY: |
|
882 return ((GetIndustrySpec(GetIndustryType(tile))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0 ? FLOOD_PASSIVE : FLOOD_NONE); |
|
883 |
|
884 default: |
|
885 return FLOOD_NONE; |
|
886 } |
|
887 } |
|
888 |
|
889 /** |
|
890 * Floods a tile. |
|
891 */ |
|
892 static void DoFloodTile(TileIndex target) |
|
893 { |
|
894 if (IsTileType(target, MP_WATER)) return; |
|
895 |
|
896 bool flooded = false; // Will be set to true if something is changed. |
|
897 |
|
898 _current_player = OWNER_WATER; |
|
899 |
|
900 Slope tileh = GetTileSlope(target, NULL); |
|
901 if (tileh != SLOPE_FLAT) { |
|
902 /* make coast.. */ |
|
903 switch (GetTileType(target)) { |
|
904 case MP_RAILWAY: { |
|
905 if (!IsPlainRailTile(target)) break; |
|
906 |
|
907 flooded = FloodHalftile(target); |
|
908 |
|
909 Vehicle *v = FindFloodableVehicleOnTile(target); |
|
910 if (v != NULL) FloodVehicle(v); |
|
911 |
|
912 break; |
|
913 } |
|
914 |
|
915 case MP_TREES: |
|
916 if (!IsSlopeWithOneCornerRaised(tileh)) { |
|
917 SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3); |
|
918 MarkTileDirtyByTile(target); |
|
919 flooded = true; |
|
920 break; |
|
921 } |
|
922 /* FALL THROUGH */ |
|
923 case MP_CLEAR: |
|
924 if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) { |
|
925 MakeShore(target); |
|
926 MarkTileDirtyByTile(target); |
|
927 flooded = true; |
|
928 } |
|
929 break; |
|
930 |
|
931 default: |
|
932 break; |
|
933 } |
|
934 } else { |
|
935 /* Flood vehicles */ |
|
936 Vehicle *v = FindFloodableVehicleOnTile(target); |
|
937 if (v != NULL) FloodVehicle(v); |
|
938 |
|
939 /* flood flat tile */ |
|
940 if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) { |
|
941 MakeWater(target); |
|
942 MarkTileDirtyByTile(target); |
|
943 flooded = true; |
|
944 } |
|
945 } |
|
946 |
|
947 if (flooded) { |
|
948 /* Mark surrounding canal tiles dirty too to avoid glitches */ |
|
949 MarkCanalsAndRiversAroundDirty(target); |
|
950 |
|
951 /* update signals if needed */ |
|
952 UpdateSignalsInBuffer(); |
|
953 } |
|
954 |
|
955 _current_player = OWNER_NONE; |
|
956 } |
|
957 |
|
958 /** |
|
959 * Drys a tile up. |
|
960 */ |
|
961 static void DoDryUp(TileIndex tile) |
|
962 { |
|
963 _current_player = OWNER_WATER; |
|
964 |
|
965 switch (GetTileType(tile)) { |
|
966 case MP_RAILWAY: |
|
967 assert(IsPlainRailTile(tile)); |
|
968 assert(GetRailGroundType(tile) == RAIL_GROUND_WATER); |
|
969 |
|
970 RailGroundType new_ground; |
|
971 switch (GetTrackBits(tile)) { |
|
972 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break; |
|
973 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break; |
|
974 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break; |
|
975 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break; |
|
976 default: NOT_REACHED(); |
|
977 } |
|
978 SetRailGroundType(tile, new_ground); |
|
979 MarkTileDirtyByTile(tile); |
|
980 break; |
|
981 |
|
982 case MP_TREES: |
|
983 SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3); |
|
984 MarkTileDirtyByTile(tile); |
|
985 break; |
|
986 |
|
987 case MP_WATER: |
|
988 assert(IsCoast(tile)); |
|
989 |
|
990 if (CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) { |
|
991 MakeClear(tile, CLEAR_GRASS, 3); |
|
992 MarkTileDirtyByTile(tile); |
|
993 } |
|
994 break; |
|
995 |
|
996 default: NOT_REACHED(); |
|
997 } |
|
998 |
|
999 _current_player = OWNER_NONE; |
|
1000 } |
|
1001 |
|
1002 /** |
775 * Let a water tile floods its diagonal adjoining tiles |
1003 * Let a water tile floods its diagonal adjoining tiles |
776 * called from tunnelbridge_cmd, and by TileLoop_Industry() and TileLoop_Track() |
1004 * called from tunnelbridge_cmd, and by TileLoop_Industry() and TileLoop_Track() |
777 * |
1005 * |
778 * @param tile the water/shore tile that floods |
1006 * @param tile the water/shore tile that floods |
779 */ |
1007 */ |
780 void TileLoop_Water(TileIndex tile) |
1008 void TileLoop_Water(TileIndex tile) |
781 { |
1009 { |
782 static const TileIndexDiffC _tile_loop_offs_array[][5] = { |
1010 switch (GetFloodingBehaviour(tile)) { |
783 // tile to mod shore? shore? |
1011 case FLOOD_ACTIVE: |
784 {{-1, 0}, {0, 0}, {0, 1}, {-1, 0}, {-1, 1}}, |
1012 for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) { |
785 {{ 0, 1}, {0, 1}, {1, 1}, { 0, 2}, { 1, 2}}, |
1013 TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir)); |
786 {{ 1, 0}, {1, 0}, {1, 1}, { 2, 0}, { 2, 1}}, |
1014 if (dest == INVALID_TILE) continue; |
787 {{ 0, -1}, {0, 0}, {1, 0}, { 0, -1}, { 1, -1}} |
1015 |
788 }; |
1016 uint z_dest; |
789 |
1017 Slope slope_dest = (Slope)(GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP); |
790 /* Ensure buoys on canal borders do not flood */ |
1018 if (z_dest > 0) continue; |
791 if (IsCanalBuoyTile(tile)) return; |
1019 |
792 /* Ensure only sea and coast floods, not canals or rivers */ |
1020 if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue; |
793 if (IsTileType(tile, MP_WATER) && !(IsSea(tile) || IsCoast(tile))) return; |
1021 |
794 |
1022 DoFloodTile(dest); |
795 /* floods in all four diagonal directions with the exception of the edges */ |
1023 } |
796 if (IsInsideMM(TileX(tile), 1, MapSizeX() - 3 + 1) && |
1024 break; |
797 IsInsideMM(TileY(tile), 1, MapSizeY() - 3 + 1)) { |
1025 |
798 uint i; |
1026 case FLOOD_DRYUP: { |
799 |
1027 Slope slope_here = (Slope)(GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP); |
800 for (i = 0; i != lengthof(_tile_loop_offs_array); i++) { |
1028 uint check_dirs = _flood_from_dirs[slope_here]; |
801 TileLoopWaterHelper(tile, _tile_loop_offs_array[i]); |
1029 uint dir; |
|
1030 FOR_EACH_SET_BIT(dir, check_dirs) { |
|
1031 TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir)); |
|
1032 if (dest == INVALID_TILE) continue; |
|
1033 |
|
1034 FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest); |
|
1035 if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return; |
|
1036 } |
|
1037 DoDryUp(tile); |
|
1038 break; |
802 } |
1039 } |
803 } |
1040 |
804 |
1041 default: return; |
805 /* _current_player can be changed by TileLoopWaterHelper.. reset it back here */ |
1042 } |
806 _current_player = OWNER_NONE; |
1043 } |
807 |
1044 |
808 /* edges */ |
1045 void ConvertGroundTilesIntoWaterTiles() |
809 if (TileX(tile) == 0 && IsInsideMM(TileY(tile), 1, MapSizeY() - 3 + 1)) { //NE |
1046 { |
810 TileLoopWaterHelper(tile, _tile_loop_offs_array[2]); |
1047 TileIndex tile; |
811 } |
1048 uint z; |
812 |
1049 Slope slope; |
813 if (TileX(tile) == MapSizeX() - 2 && IsInsideMM(TileY(tile), 1, MapSizeY() - 3 + 1)) { //SW |
1050 |
814 TileLoopWaterHelper(tile, _tile_loop_offs_array[0]); |
1051 for (tile = 0; tile < MapSize(); ++tile) { |
815 } |
1052 slope = GetTileSlope(tile, &z); |
816 |
1053 if (IsTileType(tile, MP_CLEAR) && z == 0) { |
817 if (TileY(tile) == 0 && IsInsideMM(TileX(tile), 1, MapSizeX() - 3 + 1)) { //NW |
1054 /* Make both water for tiles at level 0 |
818 TileLoopWaterHelper(tile, _tile_loop_offs_array[1]); |
1055 * and make shore, as that looks much better |
819 } |
1056 * during the generation. */ |
820 |
1057 switch (slope) { |
821 if (TileY(tile) == MapSizeY() - 2 && IsInsideMM(TileX(tile), 1, MapSizeX() - 3 + 1)) { //SE |
1058 case SLOPE_FLAT: |
822 TileLoopWaterHelper(tile, _tile_loop_offs_array[3]); |
1059 MakeWater(tile); |
|
1060 break; |
|
1061 |
|
1062 case SLOPE_N: |
|
1063 case SLOPE_E: |
|
1064 case SLOPE_S: |
|
1065 case SLOPE_W: |
|
1066 MakeShore(tile); |
|
1067 break; |
|
1068 |
|
1069 default: |
|
1070 uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP]; |
|
1071 uint dir; |
|
1072 FOR_EACH_SET_BIT(dir, check_dirs) { |
|
1073 TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir)); |
|
1074 Slope slope_dest = (Slope)(GetTileSlope(dest, NULL) & ~SLOPE_STEEP); |
|
1075 if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) { |
|
1076 MakeShore(tile); |
|
1077 break; |
|
1078 } |
|
1079 } |
|
1080 break; |
|
1081 } |
|
1082 } |
823 } |
1083 } |
824 } |
1084 } |
825 |
1085 |
826 static uint32 GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode) |
1086 static uint32 GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode) |
827 { |
1087 { |