Fix ICU iterators on leading/trailing whitespace
[openttd/fttd.git] / src / misctile_cmd.cpp
blob4710a05e493e3f19ecb6409181b5e3cbf7712225
1 /* $Id$ */
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 */
10 /** @file misctile_cmd.cpp Handling of misc tiles. */
12 #include "stdafx.h"
13 #include "map/zoneheight.h"
14 #include "map/road.h"
15 #include "tile_cmd.h"
16 #include "bridge.h"
17 #include "signal_func.h"
18 #include "command_func.h"
19 #include "company_func.h"
20 #include "vehicle_func.h"
21 #include "pbs.h"
22 #include "train.h"
23 #include "roadveh.h"
24 #include "depot_base.h"
25 #include "viewport_func.h"
26 #include "newgrf_railtype.h"
27 #include "elrail_func.h"
28 #include "depot_func.h"
29 #include "autoslope.h"
30 #include "road_cmd.h"
31 #include "town.h"
32 #include "tunnelbridge.h"
33 #include "ship.h"
34 #include "company_base.h"
35 #include "strings_func.h"
36 #include "company_gui.h"
37 #include "cheat_type.h"
38 #include "sound_func.h"
39 #include "newgrf_sound.h"
41 #include "pathfinder/yapf/yapf.h"
43 #include "table/strings.h"
44 #include "table/track_land.h"
45 #include "table/road_land.h"
48 /**
49 * Draws a tunnel tile.
50 * @param ti TileInfo of the structure to draw
51 * Please note that in this code, "roads" are treated as railtype 1, whilst the real railtypes are 0, 2 and 3
53 static void DrawTunnel(TileInfo *ti)
55 TransportType transport_type = GetTunnelTransportType(ti->tile);
56 DiagDirection tunnelbridge_direction = GetTunnelBridgeDirection(ti->tile);
58 /* Front view of tunnel bounding boxes:
60 * 122223 <- BB_Z_SEPARATOR
61 * 1 3
62 * 1 3 1,3 = empty helper BB
63 * 1 3 2 = SpriteCombine of tunnel-roof and catenary (tram & elrail)
67 static const int _tunnel_BB[4][12] = {
68 /* tunnnel-roof | Z-separator | tram-catenary
69 * w h bb_x bb_y| x y w h |bb_x bb_y w h */
70 { 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 }, // NE
71 { 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 }, // SE
72 { 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 }, // SW
73 { 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 }, // NW
75 const int *BB_data = _tunnel_BB[tunnelbridge_direction];
77 bool catenary = false;
79 SpriteID image;
80 SpriteID railtype_overlay = 0;
81 if (transport_type == TRANSPORT_RAIL) {
82 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
83 image = rti->base_sprites.tunnel;
84 if (rti->UsesOverlay()) {
85 /* Check if the railtype has custom tunnel portals. */
86 railtype_overlay = GetCustomRailSprite(rti, ti->tile, RTSG_TUNNEL_PORTAL);
87 if (railtype_overlay != 0) image = SPR_RAILTYPE_TUNNEL_BASE; // Draw blank grass tunnel base.
89 } else {
90 image = SPR_TUNNEL_ENTRY_REAR_ROAD;
93 if (IsOnSnow(ti->tile)) image += railtype_overlay != 0 ? 8 : 32;
95 image += tunnelbridge_direction * 2;
96 DrawGroundSprite(image, PAL_NONE);
98 /* PBS debugging, draw reserved tracks darker */
99 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && (transport_type == TRANSPORT_RAIL && HasTunnelHeadReservation(ti->tile))) {
100 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
101 DrawGroundSprite(DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH);
104 if (transport_type == TRANSPORT_ROAD) {
105 RoadTypes rts = GetRoadTypes(ti->tile);
107 if (HasBit(rts, ROADTYPE_TRAM)) {
108 static const SpriteID tunnel_sprites[2][4] = { { 28, 78, 79, 27 }, { 5, 76, 77, 4 } };
110 DrawGroundSprite(SPR_TRAMWAY_BASE + tunnel_sprites[rts - ROADTYPES_TRAM][tunnelbridge_direction], PAL_NONE);
112 /* Do not draw wires if they are invisible */
113 if (!IsInvisibilitySet(TO_CATENARY)) {
114 catenary = true;
115 StartSpriteCombine();
116 AddSortableSpriteToDraw(SPR_TRAMWAY_TUNNEL_WIRES + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR);
119 } else {
120 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
121 if (rti->UsesOverlay()) {
122 SpriteID surface = GetCustomRailSprite(rti, ti->tile, RTSG_TUNNEL);
123 if (surface != 0) DrawGroundSprite(surface + tunnelbridge_direction, PAL_NONE);
126 if (HasCatenaryDrawn(GetRailType(ti->tile))) {
127 /* Maybe draw pylons on the entry side */
128 DrawCatenary(ti);
130 catenary = true;
131 StartSpriteCombine();
132 /* Draw wire above the ramp */
133 DrawCatenaryOnTunnel(ti);
136 if (maptile_has_tunnel_signals(ti->tile)) {
137 static const struct {
138 Point pos[2][2]; // signal position (outwards, inwards), (left side, right side)
139 uint image; // offset from base signal sprite
140 } SignalData[DIAGDIR_END] = {
141 { { { { 0, 3}, { 0, 13} }, { {15, 3}, {15, 13} } }, 0 }, // DIAGDIR_NE
142 { { { { 3, 15}, {13, 15} }, { { 3, 0}, {13, 0} } }, 2 }, // DIAGDIR_SE
143 { { { {15, 13}, {15, 3} }, { { 0, 13}, { 0, 3} } }, 1 }, // DIAGDIR_SW
144 { { { {13, 0}, { 3, 0} }, { {13, 15}, { 3, 15} } }, 3 }, // DIAGDIR_NW
147 assert(maptile_has_tunnel_signal(ti->tile, true) != maptile_has_tunnel_signal(ti->tile, false));
149 DiagDirection dd = tunnelbridge_direction;
150 bool inwards = maptile_has_tunnel_signal(ti->tile, true);
151 if (!inwards) dd = ReverseDiagDir(dd);
153 SignalType type = maptile_get_tunnel_signal_type(ti->tile);
154 SignalVariant variant = maptile_get_tunnel_signal_variant(ti->tile);
155 SignalState condition = maptile_get_tunnel_signal_state(ti->tile, inwards);
157 assert(type == SIGTYPE_NORMAL || (!inwards && type == SIGTYPE_PBS_ONEWAY));
159 SpriteID sprite = GetCustomSignalSprite(GetRailTypeInfo(GetRailType(ti->tile)), ti->tile, type, variant, condition);
160 uint image = SignalData[dd].image;
161 if (sprite != 0) {
162 sprite += image;
163 } else {
164 /* Normal electric signals are stored in a different sprite block than all other signals. */
165 sprite = (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) ? SPR_ORIGINAL_SIGNALS_BASE : SPR_SIGNALS_BASE - 16;
166 sprite += (type == SIGTYPE_NORMAL ? SIGTYPE_NORMAL * 16 : SIGTYPE_PBS_ONEWAY * 16 + 64) + variant * 64 + image * 2 + condition;
169 bool side;
170 switch (_settings_game.construction.train_signal_side) {
171 case 0: side = false; break; // left
172 case 2: side = true; break; // right
173 default: side = _settings_game.vehicle.road_side != 0; break; // driving side
175 uint x = TileX(ti->tile) * TILE_SIZE + SignalData[dd].pos[inwards][side].x;
176 uint y = TileY(ti->tile) * TILE_SIZE + SignalData[dd].pos[inwards][side].y;
178 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, ti->z);
182 if (railtype_overlay != 0 && !catenary) StartSpriteCombine();
184 AddSortableSpriteToDraw(image + 1, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR);
185 /* Draw railtype tunnel portal overlay if defined. */
186 if (railtype_overlay != 0) AddSortableSpriteToDraw(railtype_overlay + tunnelbridge_direction, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR);
188 if (catenary || railtype_overlay != 0) EndSpriteCombine();
190 /* Add helper BB for sprite sorting that separates the tunnel from things beside of it. */
191 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x, ti->y, BB_data[6], BB_data[7], TILE_HEIGHT, ti->z);
192 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x + BB_data[4], ti->y + BB_data[5], BB_data[6], BB_data[7], TILE_HEIGHT, ti->z);
194 DrawBridgeMiddle(ti);
197 static void DrawTrainDepot(TileInfo *ti)
199 assert(IsRailDepotTile(ti->tile));
201 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
203 uint32 palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
205 /* draw depot */
206 const DrawTileSprites *dts;
207 PaletteID pal = PAL_NONE;
208 SpriteID relocation;
210 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
212 if (IsInvisibilitySet(TO_BUILDINGS)) {
213 /* Draw rail instead of depot */
214 dts = &_depot_invisible_gfx_table[GetGroundDepotDirection(ti->tile)];
215 } else {
216 dts = &_depot_gfx_table[GetGroundDepotDirection(ti->tile)];
219 SpriteID image;
220 if (rti->UsesOverlay()) {
221 image = SPR_FLAT_GRASS_TILE;
222 } else {
223 image = dts->ground.sprite;
224 if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
227 /* adjust ground tile for desert
228 * don't adjust for snow, because snow in depots looks weird */
229 if (IsOnSnow(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
230 if (image != SPR_FLAT_GRASS_TILE) {
231 image += rti->snow_offset; // tile with tracks
232 } else {
233 image = SPR_FLAT_SNOW_DESERT_TILE; // flat ground
237 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
239 if (rti->UsesOverlay()) {
240 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
242 switch (GetGroundDepotDirection(ti->tile)) {
243 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
244 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
245 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
246 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
247 default: break;
250 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
251 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
253 switch (GetGroundDepotDirection(ti->tile)) {
254 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
255 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
256 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
257 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
258 default: break;
261 } else {
262 /* PBS debugging, draw reserved tracks darker */
263 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
264 switch (GetGroundDepotDirection(ti->tile)) {
265 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
266 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
267 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
268 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
269 default: break;
274 int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
275 relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
277 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
279 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, palette);
282 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
284 const DrawTileSprites *dts = &_depot_gfx_table[dir];
285 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
286 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
287 uint32 offset = rti->GetRailtypeSpriteOffset();
289 x += 33;
290 y += 17;
292 if (image != SPR_FLAT_GRASS_TILE) image += offset;
293 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
295 DrawSprite(image, PAL_NONE, x, y);
297 if (rti->UsesOverlay()) {
298 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
300 switch (dir) {
301 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
302 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
303 default: break;
307 int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
308 if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
310 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
313 static void DrawRoadDepot(TileInfo *ti)
315 assert(IsRoadDepotTile(ti->tile));
317 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
319 PaletteID palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
321 const DrawTileSprites *dts;
322 if (HasTileRoadType(ti->tile, ROADTYPE_TRAM)) {
323 dts = &_tram_depot[GetGroundDepotDirection(ti->tile)];
324 } else {
325 dts = &_road_depot[GetGroundDepotDirection(ti->tile)];
328 DrawGroundSprite(dts->ground.sprite, PAL_NONE);
329 DrawOrigTileSeq(ti, dts, TO_BUILDINGS, palette);
333 * Draw the road depot sprite.
334 * @param x The x offset to draw at.
335 * @param y The y offset to draw at.
336 * @param dir The direction the depot must be facing.
337 * @param rt The road type of the depot to draw.
339 void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt)
341 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
342 const DrawTileSprites *dts = (rt == ROADTYPE_TRAM) ? &_tram_depot[dir] : &_road_depot[dir];
344 x += 33;
345 y += 17;
347 DrawSprite(dts->ground.sprite, PAL_NONE, x, y);
348 DrawOrigTileSeqInGUI(x, y, dts, palette);
351 static void DrawTile_Misc(TileInfo *ti)
353 switch (GetTileSubtype(ti->tile)) {
354 default: NOT_REACHED();
356 case TT_MISC_CROSSING:
357 DrawLevelCrossing(ti);
358 break;
360 case TT_MISC_AQUEDUCT:
361 DrawAqueductRamp(ti);
362 DrawBridgeMiddle(ti);
363 break;
365 case TT_MISC_TUNNEL:
366 DrawTunnel(ti);
367 break;
369 case TT_MISC_DEPOT:
370 if (IsRailDepot(ti->tile)) {
371 DrawTrainDepot(ti);
372 } else {
373 DrawRoadDepot(ti);
375 break;
379 static int GetSlopePixelZ_Misc(TileIndex tile, uint x, uint y)
381 switch (GetTileSubtype(tile)) {
382 case TT_MISC_AQUEDUCT: {
383 int z;
384 Slope tileh = GetTilePixelSlope(tile, &z);
386 x &= 0xF;
387 y &= 0xF;
389 DiagDirection dir = GetTunnelBridgeDirection(tile);
391 z += ApplyPixelFoundationToSlope(GetBridgeFoundation(tileh, DiagDirToAxis(dir)), &tileh);
393 /* On the bridge ramp? */
394 uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
395 if (5 <= pos && pos <= 10) {
396 return z + ((tileh == SLOPE_FLAT) ? GetBridgePartialPixelZ(dir, x, y) : TILE_HEIGHT);
399 return z + GetPartialPixelZ(x, y, tileh);
402 case TT_MISC_TUNNEL: {
403 int z;
404 Slope tileh = GetTilePixelSlope(tile, &z);
406 x &= 0xF;
407 y &= 0xF;
409 /* In the tunnel entrance? */
410 uint pos = (DiagDirToAxis(GetTunnelBridgeDirection(tile)) == AXIS_X ? y : x);
411 if (5 <= pos && pos <= 10) return z;
413 return z + GetPartialPixelZ(x, y, tileh);
416 default: // TT_MISC_CROSSING, TT_MISC_DEPOT
417 return GetTileMaxPixelZ(tile);
423 * Remove a tunnel from the game.
424 * @param tile Tile containing one of the endpoints.
425 * @param flags Command flags.
426 * @return Succeeded or failed command.
428 static CommandCost RemoveTunnel(TileIndex tile, DoCommandFlag flags)
430 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST);
432 if (_current_company != OWNER_WATER && _game_mode != GM_EDITOR) {
433 if (GetTunnelTransportType(tile) == TRANSPORT_RAIL) {
434 CommandCost ret = CheckOwnership(GetTileOwner(tile));
435 if (ret.Failed()) return ret;
436 } else {
437 RoadTypes rts = GetRoadTypes(tile);
438 Owner road_owner = _current_company;
439 Owner tram_owner = _current_company;
441 if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
442 if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
444 /* We can remove unowned road and if the town allows it */
445 if (road_owner == OWNER_TOWN && !(_settings_game.construction.extra_dynamite || _cheats.magic_bulldozer.value)) {
446 CommandCost ret = CheckTileOwnership(tile);
447 if (ret.Failed()) return ret;
448 } else {
449 if (road_owner == OWNER_NONE || road_owner == OWNER_TOWN) road_owner = _current_company;
450 if (tram_owner == OWNER_NONE) tram_owner = _current_company;
452 CommandCost ret = CheckOwnership(road_owner, tile);
453 if (ret.Failed()) return ret;
454 ret = CheckOwnership(tram_owner, tile);
455 if (ret.Failed()) return ret;
460 TileIndex endtile = GetOtherTunnelEnd(tile);
462 CommandCost ret = TunnelBridgeIsFree(tile, endtile);
463 if (ret.Failed()) return ret;
465 _build_tunnel_endtile = endtile;
467 Town *t = NULL;
468 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
469 t = ClosestTownFromTile(tile); // town penalty rating
471 /* Check if you are allowed to remove the tunnel owned by a town
472 * Removal depends on difficulty settings */
473 CommandCost ret = CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE);
474 if (ret.Failed()) return ret;
477 /* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
478 * you have a "Poor" (0) town rating */
479 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
480 ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags);
483 uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
484 uint nsignals = GetTunnelTransportType(tile) != TRANSPORT_RAIL ? 0 :
485 (maptile_has_tunnel_signals(tile) ? 1 : 0) + (maptile_has_tunnel_signals(endtile) ? 1 : 0);
487 if (flags & DC_EXEC) {
488 if (GetTunnelTransportType(tile) == TRANSPORT_RAIL) {
489 /* We first need to request values before calling DoClearSquare */
490 DiagDirection dir = GetTunnelBridgeDirection(tile);
491 Track track = DiagDirToDiagTrack(dir);
492 Owner owner = GetTileOwner(tile);
494 Train *v1 = NULL;
495 Train *v2 = NULL;
497 if (HasTunnelHeadReservation(tile)) {
498 v1 = GetTrainForReservation(tile, track);
499 if (v1 != NULL) FreeTrainTrackReservation(v1);
502 if (HasTunnelHeadReservation(endtile)) {
503 v2 = GetTrainForReservation(endtile, track);
504 if (v2 != NULL) FreeTrainTrackReservation(v2);
507 if (Company::IsValidID(owner)) {
508 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
509 DirtyCompanyInfrastructureWindows(owner);
512 DoClearSquare(tile);
513 DoClearSquare(endtile);
515 /* cannot use INVALID_DIAGDIR for signal update because the tunnel doesn't exist anymore */
516 AddSideToSignalBuffer(tile, ReverseDiagDir(dir), owner);
517 AddSideToSignalBuffer(endtile, dir, owner);
519 YapfNotifyTrackLayoutChange(tile, track);
520 YapfNotifyTrackLayoutChange(endtile, track);
522 if (v1 != NULL) TryPathReserve(v1);
523 if (v2 != NULL) TryPathReserve(v2);
524 } else {
525 RoadType rt;
526 FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) {
527 /* A full diagonal road tile has two road bits. */
528 Company *c = Company::GetIfValid(GetRoadOwner(tile, rt));
529 if (c != NULL) {
530 c->infrastructure.road[rt] -= len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
531 DirtyCompanyInfrastructureWindows(c->index);
535 DoClearSquare(tile);
536 DoClearSquare(endtile);
540 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_TUNNEL] * len + _price[PR_CLEAR_SIGNALS] * nsignals);
543 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
545 if (_current_company != OWNER_WATER) {
546 CommandCost ret = CheckTileOwnership(tile);
547 if (ret.Failed()) return ret;
550 CommandCost ret = EnsureNoVehicleOnGround(tile);
551 if (ret.Failed()) return ret;
553 if (flags & DC_EXEC) {
554 /* read variables before the depot is removed */
555 DiagDirection dir = GetGroundDepotDirection(tile);
556 Owner owner = GetTileOwner(tile);
557 Train *v = NULL;
559 if (HasDepotReservation(tile)) {
560 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
561 if (v != NULL) FreeTrainTrackReservation(v);
564 Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
565 DirtyCompanyInfrastructureWindows(owner);
567 delete Depot::GetByTile(tile);
568 DoClearSquare(tile);
569 AddSideToSignalBuffer(tile, dir, owner);
570 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
571 if (v != NULL) TryPathReserve(v, true);
574 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
577 static CommandCost RemoveRoadDepot(TileIndex tile, DoCommandFlag flags)
579 if (_current_company != OWNER_WATER) {
580 CommandCost ret = CheckTileOwnership(tile);
581 if (ret.Failed()) return ret;
584 CommandCost ret = EnsureNoVehicleOnGround(tile);
585 if (ret.Failed()) return ret;
587 if (flags & DC_EXEC) {
588 Company *c = Company::GetIfValid(GetTileOwner(tile));
589 if (c != NULL) {
590 /* A road depot has two road bits. */
591 c->infrastructure.road[FIND_FIRST_BIT(GetRoadTypes(tile))] -= 2;
592 DirtyCompanyInfrastructureWindows(c->index);
595 delete Depot::GetByTile(tile);
596 DoClearSquare(tile);
599 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_ROAD]);
602 extern CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits pieces, RoadType rt, bool crossing_check, bool town_check = true);
604 static CommandCost ClearTile_Misc(TileIndex tile, DoCommandFlag flags)
606 switch (GetTileSubtype(tile)) {
607 default: NOT_REACHED();
609 case TT_MISC_CROSSING: {
610 RoadTypes rts = GetRoadTypes(tile);
611 CommandCost ret(EXPENSES_CONSTRUCTION);
613 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_MUST_REMOVE_ROAD_FIRST);
615 /* Must iterate over the roadtypes in a reverse manner because
616 * tram tracks must be removed before the road bits. */
617 RoadType rt = ROADTYPE_TRAM;
618 do {
619 if (HasBit(rts, rt)) {
620 CommandCost tmp_ret = RemoveRoad(tile, flags, GetCrossingRoadBits(tile), rt, false);
621 if (tmp_ret.Failed()) return tmp_ret;
622 ret.AddCost(tmp_ret);
624 } while (rt-- != ROADTYPE_ROAD);
626 if (flags & DC_EXEC) {
627 DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
629 return ret;
632 case TT_MISC_AQUEDUCT: {
633 if (flags & DC_AUTO) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
635 if (_current_company != OWNER_WATER && _game_mode != GM_EDITOR) {
636 Owner owner = GetTileOwner(tile);
637 if (owner != OWNER_NONE) {
638 CommandCost ret = CheckOwnership(owner);
639 if (ret.Failed()) return ret;
643 TileIndex endtile = GetOtherBridgeEnd(tile);
645 CommandCost ret = TunnelBridgeIsFree(tile, endtile);
646 if (ret.Failed()) return ret;
648 uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
650 if (flags & DC_EXEC) {
651 /* Update company infrastructure counts. */
652 Owner owner = GetTileOwner(tile);
653 if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
654 DirtyCompanyInfrastructureWindows(owner);
656 RemoveBridgeMiddleTiles(tile, endtile);
657 DoClearSquare(tile);
658 DoClearSquare(endtile);
661 return CommandCost(EXPENSES_CONSTRUCTION, len * _price[PR_CLEAR_AQUEDUCT]);
664 case TT_MISC_TUNNEL:
665 return RemoveTunnel(tile, flags);
667 case TT_MISC_DEPOT:
668 if (flags & DC_AUTO) {
669 if (!IsTileOwner(tile, _current_company)) {
670 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
672 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
674 return IsRailDepot(tile) ? RemoveTrainDepot(tile, flags) : RemoveRoadDepot(tile, flags);
679 static void GetTileDesc_Misc(TileIndex tile, TileDesc *td)
681 switch (GetTileSubtype(tile)) {
682 default: NOT_REACHED();
684 case TT_MISC_CROSSING: {
685 td->str = STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING;
687 RoadTypes rts = GetRoadTypes(tile);
688 Owner road_owner = HasBit(rts, ROADTYPE_ROAD) ? GetRoadOwner(tile, ROADTYPE_ROAD) : INVALID_OWNER;
689 Owner tram_owner = HasBit(rts, ROADTYPE_TRAM) ? GetRoadOwner(tile, ROADTYPE_TRAM) : INVALID_OWNER;
690 Owner rail_owner = GetTileOwner(tile);
692 td->rail_speed = GetRailTypeInfo(GetRailType(tile))->max_speed;
694 Owner first_owner = (road_owner == INVALID_OWNER ? tram_owner : road_owner);
695 bool mixed_owners = (tram_owner != INVALID_OWNER && tram_owner != first_owner) || (rail_owner != INVALID_OWNER && rail_owner != first_owner);
697 if (mixed_owners) {
698 /* Multiple owners */
699 td->owner_type[0] = (rail_owner == INVALID_OWNER ? STR_NULL : STR_LAND_AREA_INFORMATION_RAIL_OWNER);
700 td->owner[0] = rail_owner;
701 td->owner_type[1] = (road_owner == INVALID_OWNER ? STR_NULL : STR_LAND_AREA_INFORMATION_ROAD_OWNER);
702 td->owner[1] = road_owner;
703 td->owner_type[2] = (tram_owner == INVALID_OWNER ? STR_NULL : STR_LAND_AREA_INFORMATION_TRAM_OWNER);
704 td->owner[2] = tram_owner;
705 } else {
706 /* One to rule them all */
707 td->owner[0] = first_owner;
710 break;
713 case TT_MISC_AQUEDUCT:
714 td->str = STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT;
715 td->owner[0] = GetTileOwner(tile);
716 break;
718 case TT_MISC_TUNNEL:
719 td->owner[0] = GetTileOwner(tile);
721 if (GetTunnelTransportType(tile) == TRANSPORT_RAIL) {
722 td->str = STR_LAI_TUNNEL_DESCRIPTION_RAILROAD;
723 td->rail_speed = GetRailTypeInfo(GetRailType(tile))->max_speed;
724 } else {
725 td->str = STR_LAI_TUNNEL_DESCRIPTION_ROAD;
727 Owner road_owner = INVALID_OWNER;
728 Owner tram_owner = INVALID_OWNER;
729 RoadTypes rts = GetRoadTypes(tile);
730 if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
731 if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
733 /* Is there a mix of owners? */
734 if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) ||
735 (road_owner != INVALID_OWNER && road_owner != td->owner[0])) {
736 uint i = 1;
737 if (road_owner != INVALID_OWNER) {
738 td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER;
739 td->owner[i] = road_owner;
740 i++;
742 if (tram_owner != INVALID_OWNER) {
743 td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER;
744 td->owner[i] = tram_owner;
749 break;
751 case TT_MISC_DEPOT:
752 td->owner[0] = GetTileOwner(tile);
753 td->build_date = Depot::GetByTile(tile)->build_date;
755 if (IsRailDepot(tile)) {
756 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
758 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
759 SetDParamX(td->dparam, 0, rti->strings.name);
760 td->rail_speed = rti->max_speed;
762 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
763 if (td->rail_speed > 0) {
764 td->rail_speed = min(td->rail_speed, 61);
765 } else {
766 td->rail_speed = 61;
769 } else {
770 td->str = STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT;
773 break;
778 static TrackStatus GetTileRailwayStatus_Misc(TileIndex tile, DiagDirection side)
780 switch (GetTileSubtype(tile)) {
781 default: NOT_REACHED();
783 case TT_MISC_CROSSING:
784 return CombineTrackStatus(TrackBitsToTrackdirBits(GetCrossingRailBits(tile)), TRACKDIR_BIT_NONE);
786 case TT_MISC_AQUEDUCT:
787 return 0;
789 case TT_MISC_TUNNEL: {
790 if (GetTunnelTransportType(tile) != TRANSPORT_RAIL) return 0;
792 DiagDirection dir = GetTunnelBridgeDirection(tile);
793 if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
795 TrackdirBits trackdirs = TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir));
796 TrackdirBits red_signals;
797 switch (maptile_get_tunnel_present_signals(tile)) {
798 default: NOT_REACHED();
800 case 0: red_signals = TRACKDIR_BIT_NONE; break;
802 case 1:
803 red_signals = maptile_get_tunnel_signal_state(tile, false) == SIGNAL_STATE_RED ? trackdirs :
804 TrackdirToTrackdirBits(DiagDirToDiagTrackdir(dir));
805 break;
807 case 2:
808 red_signals = maptile_get_tunnel_signal_state(tile, true) == SIGNAL_STATE_RED ? trackdirs :
809 TrackdirToTrackdirBits(DiagDirToDiagTrackdir(ReverseDiagDir(dir)));
810 break;
813 return CombineTrackStatus(trackdirs, red_signals);
816 case TT_MISC_DEPOT: {
817 if (!IsRailDepot(tile)) return 0;
819 DiagDirection dir = GetGroundDepotDirection(tile);
820 if (side != INVALID_DIAGDIR && side != dir) return 0;
821 return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
826 static TrackStatus GetTileRoadStatus_Misc(TileIndex tile, uint sub_mode, DiagDirection side)
828 switch (GetTileSubtype(tile)) {
829 default: NOT_REACHED();
831 case TT_MISC_CROSSING: {
832 if ((GetRoadTypes(tile) & sub_mode) == 0) return 0;
834 Axis axis = GetCrossingRoadAxis(tile);
835 if (side != INVALID_DIAGDIR && axis != DiagDirToAxis(side)) return 0;
837 TrackdirBits trackdirbits = TrackBitsToTrackdirBits(AxisToTrackBits(axis));
838 return CombineTrackStatus(trackdirbits, IsCrossingBarred(tile) ? trackdirbits : TRACKDIR_BIT_NONE);
841 case TT_MISC_AQUEDUCT:
842 return 0;
844 case TT_MISC_TUNNEL: {
845 TransportType transport_type = GetTunnelTransportType(tile);
846 if (transport_type != TRANSPORT_ROAD || (GetRoadTypes(tile) & sub_mode) == 0) return 0;
848 DiagDirection dir = GetTunnelBridgeDirection(tile);
849 if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
850 return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
853 case TT_MISC_DEPOT: {
854 if (!IsRoadDepot(tile) || (GetRoadTypes(tile) & sub_mode) == 0) {
855 return 0;
858 DiagDirection dir = GetGroundDepotDirection(tile);
859 if (side != INVALID_DIAGDIR && side != dir) return 0;
860 return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
865 static TrackdirBits GetTileWaterwayStatus_Misc(TileIndex tile, DiagDirection side)
867 if (!IsTileSubtype(tile, TT_MISC_AQUEDUCT)) return TRACKDIR_BIT_NONE;
869 DiagDirection dir = GetTunnelBridgeDirection(tile);
870 if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return TRACKDIR_BIT_NONE;
871 return TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir));
875 static bool ClickTile_Misc(TileIndex tile)
877 if (!IsGroundDepotTile(tile)) return false;
879 ShowDepotWindow(tile, IsRailDepot(tile) ? VEH_TRAIN : VEH_ROAD);
880 return true;
884 static void TileLoop_Misc(TileIndex tile)
886 switch (_settings_game.game_creation.landscape) {
887 case LT_ARCTIC: {
888 int z = IsTileSubtype(tile, TT_MISC_AQUEDUCT) ? GetTileMaxZ(tile) : GetTileZ(tile);
889 if (IsOnSnow(tile) != (z > GetSnowLine())) {
890 ToggleSnow(tile);
891 MarkTileDirtyByTile(tile);
893 break;
896 case LT_TROPIC:
897 if (GetTropicZone(tile) == TROPICZONE_DESERT && !IsOnDesert(tile)) {
898 SetDesert(tile, true);
899 MarkTileDirtyByTile(tile);
901 break;
904 if (IsTileSubtype(tile, TT_MISC_CROSSING)) {
905 const Town *t = ClosestTownFromTile(tile);
906 UpdateRoadSide(tile, t != NULL ? GetTownRadiusGroup(t, tile) : HZB_TOWN_EDGE);
911 static void ChangeTileOwner_Misc(TileIndex tile, Owner old_owner, Owner new_owner)
913 switch (GetTileSubtype(tile)) {
914 default: NOT_REACHED();
916 case TT_MISC_CROSSING:
917 for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
918 /* Update all roadtypes, no matter if they are present */
919 if (GetRoadOwner(tile, rt) == old_owner) {
920 if (HasTileRoadType(tile, rt)) {
921 /* A level crossing has two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */
922 Company::Get(old_owner)->infrastructure.road[rt] -= 2;
923 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += 2;
926 SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
930 if (GetTileOwner(tile) == old_owner) {
931 if (new_owner == INVALID_OWNER) {
932 DoCommand(tile, 0, GetCrossingRailTrack(tile), DC_EXEC | DC_BANKRUPT, CMD_REMOVE_SINGLE_RAIL);
933 } else {
934 /* Update infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */
935 RailType rt = GetRailType(tile);
936 Company::Get(old_owner)->infrastructure.rail[rt] -= LEVELCROSSING_TRACKBIT_FACTOR;
937 Company::Get(new_owner)->infrastructure.rail[rt] += LEVELCROSSING_TRACKBIT_FACTOR;
939 SetTileOwner(tile, new_owner);
943 break;
945 case TT_MISC_AQUEDUCT: {
946 if (!IsTileOwner(tile, old_owner)) return;
948 TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
949 /* Set number of pieces to zero if it's the southern tile as we
950 * don't want to update the infrastructure counts twice. */
951 uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
953 /* Update company infrastructure counts.
954 * No need to dirty windows here, we'll redraw the whole screen anyway. */
955 Company::Get(old_owner)->infrastructure.water -= num_pieces;
956 if (new_owner != INVALID_OWNER) {
957 Company::Get(new_owner)->infrastructure.water += num_pieces;
958 SetTileOwner(tile, new_owner);
959 } else {
960 SetTileOwner(tile, OWNER_NONE);
962 break;
965 case TT_MISC_TUNNEL: {
966 TileIndex other_end = GetOtherTunnelEnd(tile);
967 /* Set number of pieces to zero if it's the southern tile as we
968 * don't want to update the infrastructure counts twice. */
969 uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
971 for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
972 /* Update all roadtypes, no matter if they are present */
973 if (GetRoadOwner(tile, rt) == old_owner) {
974 if (HasBit(GetRoadTypes(tile), rt)) {
975 /* Update company infrastructure counts. A full diagonal road tile has two road bits.
976 * No need to dirty windows here, we'll redraw the whole screen anyway. */
977 Company::Get(old_owner)->infrastructure.road[rt] -= num_pieces * 2;
978 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_pieces * 2;
981 SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
985 if (!IsTileOwner(tile, old_owner)) return;
987 /* Update company infrastructure counts for rail and water as well.
988 * No need to dirty windows here, we'll redraw the whole screen anyway. */
989 TransportType tt = GetTunnelTransportType(tile);
990 Company *old = Company::Get(old_owner);
991 if (tt == TRANSPORT_RAIL) {
992 old->infrastructure.rail[GetRailType(tile)] -= num_pieces;
993 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += num_pieces;
996 if (new_owner != INVALID_OWNER) {
997 SetTileOwner(tile, new_owner);
998 } else if (tt == TRANSPORT_RAIL) {
999 /* Since all of our vehicles have been removed, it is safe to remove the rail
1000 * tunnel. */
1001 CommandCost ret = DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
1002 assert(ret.Succeeded());
1003 } else {
1004 /* In any other case, we can safely reassign the ownership to OWNER_NONE. */
1005 SetTileOwner(tile, OWNER_NONE);
1008 break;
1011 case TT_MISC_DEPOT:
1012 if (!IsTileOwner(tile, old_owner)) return;
1014 if (new_owner != INVALID_OWNER) {
1015 /* Update company infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */
1016 if (IsRailDepot(tile)) {
1017 RailType rt = GetRailType(tile);
1018 Company::Get(old_owner)->infrastructure.rail[rt]--;
1019 Company::Get(new_owner)->infrastructure.rail[rt]++;
1020 } else {
1021 /* A road depot has two road bits. */
1022 RoadType rt = (RoadType)FIND_FIRST_BIT(GetRoadTypes(tile));
1023 Company::Get(old_owner)->infrastructure.road[rt] -= 2;
1024 Company::Get(new_owner)->infrastructure.road[rt] += 2;
1027 SetTileOwner(tile, new_owner);
1028 } else {
1029 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
1031 break;
1037 * Frame when a vehicle should be hidden in a tunnel with a certain direction.
1038 * This differs per direction, because of visibility / bounding box issues.
1039 * Note that direction, in this case, is the direction leading into the tunnel.
1040 * When entering a tunnel, hide the vehicle when it reaches the given frame.
1041 * When leaving a tunnel, show the vehicle when it is one frame further
1042 * to the 'outside', i.e. at (TILE_SIZE-1) - (frame) + 1
1044 extern const byte _tunnel_visibility_frame[DIAGDIR_END] = {12, 8, 8, 12};
1047 static Foundation GetFoundation_Misc(TileIndex tile, Slope tileh)
1049 switch (GetTileSubtype(tile)) {
1050 case TT_MISC_AQUEDUCT: return GetBridgeFoundation(tileh, DiagDirToAxis(GetTunnelBridgeDirection(tile)));
1051 case TT_MISC_TUNNEL: return FOUNDATION_NONE;
1052 default: return FlatteningFoundation(tileh);
1057 static CommandCost TerraformTile_Misc(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
1059 if (_settings_game.construction.build_on_slopes && AutoslopeEnabled()) {
1060 switch (GetTileSubtype(tile)) {
1061 default: break;
1063 case TT_MISC_CROSSING:
1064 if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) && HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
1065 break;
1067 case TT_MISC_DEPOT:
1068 if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetGroundDepotDirection(tile))) {
1069 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
1071 break;
1075 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
1079 extern const TileTypeProcs _tile_type_misc_procs = {
1080 DrawTile_Misc, // draw_tile_proc
1081 GetSlopePixelZ_Misc, // get_slope_z_proc
1082 ClearTile_Misc, // clear_tile_proc
1083 NULL, // add_accepted_cargo_proc
1084 GetTileDesc_Misc, // get_tile_desc_proc
1085 GetTileRailwayStatus_Misc, // get_tile_railway_status_proc
1086 GetTileRoadStatus_Misc, // get_tile_road_status_proc
1087 GetTileWaterwayStatus_Misc, // get_tile_waterway_status_proc
1088 ClickTile_Misc, // click_tile_proc
1089 NULL, // animate_tile_proc
1090 TileLoop_Misc, // tile_loop_proc
1091 ChangeTileOwner_Misc, // change_tile_owner_proc
1092 NULL, // add_produced_cargo_proc
1093 GetFoundation_Misc, // get_foundation_proc
1094 TerraformTile_Misc, // terraform_tile_proc