1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
7
8 /** @file script_tunnel.cpp Implementation of ScriptTunnel. */
9
10 #include "../../stdafx.h"
11 #include "script_tunnel.hpp"
12 #include "script_rail.hpp"
13 #include "../script_instance.hpp"
14 #include "../../tunnel_map.h"
15
16 #include "../../safeguards.h"
17
IsTunnelTile(TileIndex tile)18 /* static */ bool ScriptTunnel::IsTunnelTile(TileIndex tile)
19 {
20 if (!::IsValidTile(tile)) return false;
21 return ::IsTunnelTile(tile);
22 }
23
GetOtherTunnelEnd(TileIndex tile)24 /* static */ TileIndex ScriptTunnel::GetOtherTunnelEnd(TileIndex tile)
25 {
26 if (!::IsValidTile(tile)) return INVALID_TILE;
27
28 /* If it's a tunnel already, take the easy way out! */
29 if (IsTunnelTile(tile)) return ::GetOtherTunnelEnd(tile);
30
31 int start_z;
32 Slope start_tileh = ::GetTileSlope(tile, &start_z);
33 DiagDirection direction = ::GetInclinedSlopeDirection(start_tileh);
34 if (direction == INVALID_DIAGDIR) return INVALID_TILE;
35
36 TileIndexDiff delta = ::TileOffsByDiagDir(direction);
37 int end_z;
38 do {
39 tile += delta;
40 if (!::IsValidTile(tile)) return INVALID_TILE;
41
42 ::GetTileSlope(tile, &end_z);
43 } while (start_z != end_z);
44
45 return tile;
46 }
47
48 /**
49 * Helper function to connect a just built tunnel to nearby roads.
50 * @param instance The script instance we have to built the road for.
51 */
_DoCommandReturnBuildTunnel2(class ScriptInstance * instance)52 static void _DoCommandReturnBuildTunnel2(class ScriptInstance *instance)
53 {
54 if (!ScriptTunnel::_BuildTunnelRoad2()) {
55 ScriptInstance::DoCommandReturn(instance);
56 return;
57 }
58
59 /* This can never happen, as in test-mode this callback is never executed,
60 * and in execute-mode, the other callback is called. */
61 NOT_REACHED();
62 }
63
64 /**
65 * Helper function to connect a just built tunnel to nearby roads.
66 * @param instance The script instance we have to built the road for.
67 */
_DoCommandReturnBuildTunnel1(class ScriptInstance * instance)68 static void _DoCommandReturnBuildTunnel1(class ScriptInstance *instance)
69 {
70 if (!ScriptTunnel::_BuildTunnelRoad1()) {
71 ScriptInstance::DoCommandReturn(instance);
72 return;
73 }
74
75 /* This can never happen, as in test-mode this callback is never executed,
76 * and in execute-mode, the other callback is called. */
77 NOT_REACHED();
78 }
79
BuildTunnel(ScriptVehicle::VehicleType vehicle_type,TileIndex start)80 /* static */ bool ScriptTunnel::BuildTunnel(ScriptVehicle::VehicleType vehicle_type, TileIndex start)
81 {
82 EnforcePrecondition(false, ::IsValidTile(start));
83 EnforcePrecondition(false, vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_ROAD);
84 EnforcePrecondition(false, vehicle_type != ScriptVehicle::VT_RAIL || ScriptRail::IsRailTypeAvailable(ScriptRail::GetCurrentRailType()));
85 EnforcePrecondition(false, vehicle_type != ScriptVehicle::VT_ROAD || ScriptRoad::IsRoadTypeAvailable(ScriptRoad::GetCurrentRoadType()));
86 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY || vehicle_type == ScriptVehicle::VT_ROAD);
87
88 uint type = 0;
89 if (vehicle_type == ScriptVehicle::VT_ROAD) {
90 type |= (TRANSPORT_ROAD << 8);
91 type |= ScriptRoad::GetCurrentRoadType();
92 } else {
93 type |= (TRANSPORT_RAIL << 8);
94 type |= ScriptRail::GetCurrentRailType();
95 }
96
97 /* For rail we do nothing special */
98 if (vehicle_type == ScriptVehicle::VT_RAIL) {
99 return ScriptObject::DoCommand(start, type, 0, CMD_BUILD_TUNNEL);
100 }
101
102 ScriptObject::SetCallbackVariable(0, start);
103 return ScriptObject::DoCommand(start, type, 0, CMD_BUILD_TUNNEL, nullptr, &::_DoCommandReturnBuildTunnel1);
104 }
105
_BuildTunnelRoad1()106 /* static */ bool ScriptTunnel::_BuildTunnelRoad1()
107 {
108 /* Build the piece of road on the 'start' side of the tunnel */
109 TileIndex end = ScriptObject::GetCallbackVariable(0);
110 TileIndex start = ScriptTunnel::GetOtherTunnelEnd(end);
111
112 DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start);
113 DiagDirection dir_2 = ::ReverseDiagDir(dir_1);
114
115 return ScriptObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (ScriptObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, nullptr, &::_DoCommandReturnBuildTunnel2);
116 }
117
_BuildTunnelRoad2()118 /* static */ bool ScriptTunnel::_BuildTunnelRoad2()
119 {
120 /* Build the piece of road on the 'end' side of the tunnel */
121 TileIndex end = ScriptObject::GetCallbackVariable(0);
122 TileIndex start = ScriptTunnel::GetOtherTunnelEnd(end);
123
124 DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start);
125 DiagDirection dir_2 = ::ReverseDiagDir(dir_1);
126
127 return ScriptObject::DoCommand(end + ::TileOffsByDiagDir(dir_2), ::DiagDirToRoadBits(dir_1) | (ScriptObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD);
128 }
129
RemoveTunnel(TileIndex tile)130 /* static */ bool ScriptTunnel::RemoveTunnel(TileIndex tile)
131 {
132 EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
133 EnforcePrecondition(false, IsTunnelTile(tile));
134
135 return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR);
136 }
137