76 * 01abcdef => rail w/ signals |
76 * 01abcdef => rail w/ signals |
77 * 10uuuuuu => unused |
77 * 10uuuuuu => unused |
78 * 11uuuudd => rail depot |
78 * 11uuuudd => rail depot |
79 */ |
79 */ |
80 |
80 |
|
81 /** Struct used in EnsureNoTrainOnTrack() */ |
|
82 struct TrainOnTrackData { |
|
83 TileIndex tile; ///< tile to check |
|
84 uint z; ///< tile max Z |
|
85 TrackBits rail_bits; ///< trackbits of interest |
|
86 }; |
|
87 |
|
88 static void *EnsureNoTrainOnTrackProc(Vehicle *v, void *data) |
|
89 { |
|
90 const TrainOnTrackData *info = (const TrainOnTrackData *)data; |
|
91 |
|
92 if (v->tile != info->tile || v->type != VEH_TRAIN) return NULL; |
|
93 if (v->z_pos > info->z) return NULL; |
|
94 |
|
95 if ((v->u.rail.track != info->rail_bits) && !TracksOverlap(v->u.rail.track | info->rail_bits)) return NULL; |
|
96 |
|
97 _error_message = VehicleInTheWayErrMsg(v); |
|
98 return v; |
|
99 } |
|
100 |
|
101 /** |
|
102 * Tests if a vehicle interacts with the specified track. |
|
103 * All track bits interact except parallel TRACK_BIT_HORZ or TRACK_BIT_VERT. |
|
104 * |
|
105 * @param tile The tile. |
|
106 * @param track The track. |
|
107 */ |
|
108 static bool EnsureNoTrainOnTrack(TileIndex tile, Track track) |
|
109 { |
|
110 TrainOnTrackData info; |
|
111 |
|
112 info.tile = tile; |
|
113 info.z = GetTileMaxZ(tile); |
|
114 info.rail_bits = TrackToTrackBits(track); |
|
115 |
|
116 return VehicleFromPos(tile, &info, EnsureNoTrainOnTrackProc) == NULL; |
|
117 } |
|
118 |
81 static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags) |
119 static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags) |
82 { |
120 { |
83 TrackBits current; // The current track layout |
121 TrackBits current; // The current track layout |
84 TrackBits future; // The track layout we want to build |
122 TrackBits future; // The track layout we want to build |
85 _error_message = STR_1001_IMPOSSIBLE_TRACK_COMBINATION; |
123 _error_message = STR_1001_IMPOSSIBLE_TRACK_COMBINATION; |
237 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
275 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
238 |
276 |
239 switch (GetTileType(tile)) { |
277 switch (GetTileType(tile)) { |
240 case MP_RAILWAY: |
278 case MP_RAILWAY: |
241 if (!CheckTrackCombination(tile, trackbit, flags) || |
279 if (!CheckTrackCombination(tile, trackbit, flags) || |
242 !EnsureNoVehicleOnGround(tile)) { |
280 !EnsureNoTrainOnTrack(tile, track)) { |
243 return CMD_ERROR; |
281 return CMD_ERROR; |
244 } |
282 } |
245 if (!IsTileOwner(tile, _current_player) || |
283 if (!IsTileOwner(tile, _current_player) || |
246 !IsCompatibleRail(GetRailType(tile), railtype)) { |
284 !IsCompatibleRail(GetRailType(tile), railtype)) { |
247 /* Get detailed error message */ |
285 /* Get detailed error message */ |
645 Track track = (Track)GB(p1, 0, 3); |
683 Track track = (Track)GB(p1, 0, 3); |
646 bool pre_signal = HASBIT(p1, 3); |
684 bool pre_signal = HASBIT(p1, 3); |
647 SignalVariant sigvar = (pre_signal ^ HASBIT(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC; |
685 SignalVariant sigvar = (pre_signal ^ HASBIT(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC; |
648 CommandCost cost; |
686 CommandCost cost; |
649 |
687 |
650 if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoVehicleOnGround(tile)) |
688 if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoTrainOnTrack(tile, track)) |
651 return CMD_ERROR; |
689 return CMD_ERROR; |
652 |
690 |
653 /* Protect against invalid signal copying */ |
691 /* Protect against invalid signal copying */ |
654 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR; |
692 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR; |
655 |
693 |
2116 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) { |
2154 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) { |
2117 /* enter the depot */ |
2155 /* enter the depot */ |
2118 v->u.rail.track = TRACK_BIT_DEPOT, |
2156 v->u.rail.track = TRACK_BIT_DEPOT, |
2119 v->vehstatus |= VS_HIDDEN; /* hide it */ |
2157 v->vehstatus |= VS_HIDDEN; /* hide it */ |
2120 v->direction = ReverseDir(v->direction); |
2158 v->direction = ReverseDir(v->direction); |
2121 if (v->next == NULL) VehicleEnterDepot(v); |
2159 if (v->Next() == NULL) VehicleEnterDepot(v); |
2122 v->tile = tile; |
2160 v->tile = tile; |
2123 |
2161 |
2124 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
2162 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
2125 return VETSB_ENTERED_WORMHOLE; |
2163 return VETSB_ENTERED_WORMHOLE; |
2126 } |
2164 } |
2127 } else if (fract_coord_leave == fract_coord) { |
2165 } else if (fract_coord_leave == fract_coord) { |
2128 if (DiagDirToDir(dir) == v->direction) { |
2166 if (DiagDirToDir(dir) == v->direction) { |
2129 /* leave the depot? */ |
2167 /* leave the depot? */ |
2130 if ((v = v->next) != NULL) { |
2168 if ((v = v->Next()) != NULL) { |
2131 v->vehstatus &= ~VS_HIDDEN; |
2169 v->vehstatus &= ~VS_HIDDEN; |
2132 v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y); |
2170 v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y); |
2133 } |
2171 } |
2134 } |
2172 } |
2135 } |
2173 } |
2136 |
2174 |
2137 return VETSB_CONTINUE; |
2175 return VETSB_CONTINUE; |
|
2176 } |
|
2177 |
|
2178 static CommandCost TerraformTile_Track(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new) |
|
2179 { |
|
2180 if (IsPlainRailTile(tile)) { |
|
2181 uint z_old; |
|
2182 Slope tileh_old = GetTileSlope(tile, &z_old); |
|
2183 TrackBits rail_bits = GetTrackBits(tile); |
|
2184 |
|
2185 _error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK; |
|
2186 |
|
2187 /* When there is only a single horizontal/vertical track, one corner can be terraformed. */ |
|
2188 Slope allowed_corner; |
|
2189 switch (rail_bits) { |
|
2190 case TRACK_BIT_RIGHT: allowed_corner = SLOPE_W; break; |
|
2191 case TRACK_BIT_UPPER: allowed_corner = SLOPE_S; break; |
|
2192 case TRACK_BIT_LEFT: allowed_corner = SLOPE_E; break; |
|
2193 case TRACK_BIT_LOWER: allowed_corner = SLOPE_N; break; |
|
2194 default: return CMD_ERROR; |
|
2195 } |
|
2196 |
|
2197 Slope track_corners = ComplementSlope(allowed_corner); |
|
2198 |
|
2199 Foundation f_old = GetRailFoundation(tileh_old, rail_bits); |
|
2200 switch (f_old) { |
|
2201 case FOUNDATION_NONE: |
|
2202 /* Everything is valid, which only changes allowed_corner */ |
|
2203 |
|
2204 /* Compute height of track */ |
|
2205 if (tileh_old == track_corners) z_old += TILE_HEIGHT; |
|
2206 if (tileh_new == track_corners) { |
|
2207 z_new += TILE_HEIGHT; |
|
2208 } else { |
|
2209 /* do not build a foundation */ |
|
2210 if ((tileh_new != SLOPE_FLAT) && (tileh_new != allowed_corner)) return CMD_ERROR; |
|
2211 } |
|
2212 |
|
2213 /* Track height must remain unchanged */ |
|
2214 if (z_old != z_new) return CMD_ERROR; |
|
2215 break; |
|
2216 |
|
2217 case FOUNDATION_LEVELED: |
|
2218 /* Is allowed_corner covered by the foundation? */ |
|
2219 if ((tileh_old & allowed_corner) == 0) return CMD_ERROR; |
|
2220 |
|
2221 /* allowed_corner may only be raised -> steep slope */ |
|
2222 if ((z_old != z_new) || (tileh_new != (tileh_old | SLOPE_STEEP))) return CMD_ERROR; |
|
2223 break; |
|
2224 |
|
2225 case FOUNDATION_STEEP_LOWER: |
|
2226 /* Only allow to lower highest corner */ |
|
2227 if ((z_old != z_new) || (tileh_new != (tileh_old & ~SLOPE_STEEP))) return CMD_ERROR; |
|
2228 break; |
|
2229 |
|
2230 case FOUNDATION_STEEP_HIGHER: |
|
2231 return CMD_ERROR; |
|
2232 |
|
2233 default: NOT_REACHED(); |
|
2234 } |
|
2235 |
|
2236 /* Make the ground dirty */ |
|
2237 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN); |
|
2238 |
|
2239 /* allow terraforming, no extra costs */ |
|
2240 return CommandCost(); |
|
2241 } |
|
2242 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
2138 } |
2243 } |
2139 |
2244 |
2140 |
2245 |
2141 extern const TileTypeProcs _tile_type_rail_procs = { |
2246 extern const TileTypeProcs _tile_type_rail_procs = { |
2142 DrawTile_Track, /* draw_tile_proc */ |
2247 DrawTile_Track, /* draw_tile_proc */ |