|
1 /* $Id$ */ |
|
2 |
|
3 /** @file bridge_cmd.c |
|
4 * This file deals with tunnels and bridges (non-gui stuff) |
|
5 * @todo seperate this file into two |
|
6 */ |
|
7 |
|
8 #include "stdafx.h" |
|
9 #include "openttd.h" |
|
10 #include "bridge_map.h" |
|
11 #include "rail_map.h" |
|
12 #include "road_map.h" |
|
13 #include "table/sprites.h" |
|
14 #include "table/strings.h" |
|
15 #include "functions.h" |
|
16 #include "map.h" |
|
17 #include "tile.h" |
|
18 #include "tunnel_map.h" |
|
19 #include "unmovable_map.h" |
|
20 #include "vehicle.h" |
|
21 #include "viewport.h" |
|
22 #include "command.h" |
|
23 #include "player.h" |
|
24 #include "town.h" |
|
25 #include "sound.h" |
|
26 #include "variables.h" |
|
27 #include "bridge.h" |
|
28 #include "train.h" |
|
29 #include "water_map.h" |
|
30 #include "yapf/yapf.h" |
|
31 #include "date.h" |
|
32 #include "newgrf_sound.h" |
|
33 |
|
34 #include "table/bridge_land.h" |
|
35 |
|
36 const Bridge orig_bridge[] = { |
|
37 /* |
|
38 year of availablity |
|
39 | minimum length |
|
40 | | maximum length |
|
41 | | | price |
|
42 | | | | maximum speed |
|
43 | | | | | sprite to use in GUI string with description |
|
44 | | | | | | | */ |
|
45 { 0, 0, 16, 80, 32, 0xA24 , STR_5012_WOODEN , NULL, 0 }, |
|
46 { 0, 0, 2, 112, 48, 0xA26 | PALETTE_TO_STRUCT_RED , STR_5013_CONCRETE , NULL, 0 }, |
|
47 { 1930, 0, 5, 144, 64, 0xA25 , STR_500F_GIRDER_STEEL , NULL, 0 }, |
|
48 { 0, 2, 10, 168, 80, 0xA22 | PALETTE_TO_STRUCT_CONCRETE, STR_5011_SUSPENSION_CONCRETE, NULL, 0 }, |
|
49 { 1930, 3, 16, 185, 96, 0xA22 , STR_500E_SUSPENSION_STEEL , NULL, 0 }, |
|
50 { 1930, 3, 16, 192, 112, 0xA22 | PALETTE_TO_STRUCT_YELLOW , STR_500E_SUSPENSION_STEEL , NULL, 0 }, |
|
51 { 1930, 3, 7, 224, 160, 0xA23 , STR_5010_CANTILEVER_STEEL , NULL, 0 }, |
|
52 { 1930, 3, 8, 232, 208, 0xA23 | PALETTE_TO_STRUCT_BROWN , STR_5010_CANTILEVER_STEEL , NULL, 0 }, |
|
53 { 1930, 3, 9, 248, 240, 0xA23 | PALETTE_TO_STRUCT_RED , STR_5010_CANTILEVER_STEEL , NULL, 0 }, |
|
54 { 1930, 0, 2, 240, 256, 0xA27 , STR_500F_GIRDER_STEEL , NULL, 0 }, |
|
55 { 1995, 2, 16, 255, 320, 0xA28 , STR_5014_TUBULAR_STEEL , NULL, 0 }, |
|
56 { 2005, 2, 32, 380, 512, 0xA28 | PALETTE_TO_STRUCT_YELLOW , STR_5014_TUBULAR_STEEL , NULL, 0 }, |
|
57 { 2010, 2, 32, 510, 608, 0xA28 | PALETTE_TO_STRUCT_GREY , STR_BRIDGE_TUBULAR_SILICON , NULL, 0 } |
|
58 }; |
|
59 |
|
60 Bridge _bridge[MAX_BRIDGES]; |
|
61 |
|
62 |
|
63 // calculate the price factor for building a long bridge. |
|
64 // basically the cost delta is 1,1, 1, 2,2, 3,3,3, 4,4,4,4, 5,5,5,5,5, 6,6,6,6,6,6, 7,7,7,7,7,7,7, 8,8,8,8,8,8,8,8, |
|
65 int CalcBridgeLenCostFactor(int x) |
|
66 { |
|
67 int n; |
|
68 int r; |
|
69 |
|
70 if (x < 2) return x; |
|
71 x -= 2; |
|
72 for (n = 0, r = 2;; n++) { |
|
73 if (x <= n) return r + x * n; |
|
74 r += n * n; |
|
75 x -= n; |
|
76 } |
|
77 } |
|
78 |
|
79 static inline const PalSpriteID *GetBridgeSpriteTable(int index, byte table) |
|
80 { |
|
81 const Bridge *bridge = &_bridge[index]; |
|
82 assert(table < 7); |
|
83 if (bridge->sprite_table == NULL || bridge->sprite_table[table] == NULL) { |
|
84 return _bridge_sprite_table[index][table]; |
|
85 } else { |
|
86 return bridge->sprite_table[table]; |
|
87 } |
|
88 } |
|
89 |
|
90 static inline byte GetBridgeFlags(int index) { return _bridge[index].flags;} |
|
91 |
|
92 |
|
93 /** Check the slope at the bridge ramps in three easy steps: |
|
94 * - valid slopes without foundation |
|
95 * - valid slopes with foundation |
|
96 * - rest is invalid |
|
97 */ |
|
98 #define M(x) (1 << (x)) |
|
99 static int32 CheckBridgeSlopeNorth(Axis axis, Slope tileh) |
|
100 { |
|
101 uint32 valid; |
|
102 |
|
103 valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_NE) : M(SLOPE_NW)); |
|
104 if (HASBIT(valid, tileh)) return 0; |
|
105 |
|
106 valid = |
|
107 BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_N) | M(SLOPE_STEEP_N) | |
|
108 (axis == AXIS_X ? M(SLOPE_E) | M(SLOPE_STEEP_E) : M(SLOPE_W) | M(SLOPE_STEEP_W)); |
|
109 if (HASBIT(valid, tileh)) return _price.terraform; |
|
110 |
|
111 return CMD_ERROR; |
|
112 } |
|
113 |
|
114 static int32 CheckBridgeSlopeSouth(Axis axis, Slope tileh) |
|
115 { |
|
116 uint32 valid; |
|
117 |
|
118 valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_SW) : M(SLOPE_SE)); |
|
119 if (HASBIT(valid, tileh)) return 0; |
|
120 |
|
121 valid = |
|
122 BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_S) | M(SLOPE_STEEP_S) | |
|
123 (axis == AXIS_X ? M(SLOPE_W) | M(SLOPE_STEEP_W) : M(SLOPE_E) | M(SLOPE_STEEP_E)); |
|
124 if (HASBIT(valid, tileh)) return _price.terraform; |
|
125 |
|
126 return CMD_ERROR; |
|
127 } |
|
128 #undef M |
|
129 |
|
130 |
|
131 uint32 GetBridgeLength(TileIndex begin, TileIndex end) |
|
132 { |
|
133 int x1 = TileX(begin); |
|
134 int y1 = TileY(begin); |
|
135 int x2 = TileX(end); |
|
136 int y2 = TileY(end); |
|
137 |
|
138 return abs(x2 + y2 - x1 - y1) - 1; |
|
139 } |
|
140 |
|
141 bool CheckBridge_Stuff(byte bridge_type, uint bridge_len) |
|
142 { |
|
143 const Bridge *b = &_bridge[bridge_type]; |
|
144 uint max; // max possible length of a bridge (with patch 100) |
|
145 |
|
146 if (bridge_type >= MAX_BRIDGES) return false; |
|
147 if (b->avail_year > _cur_year) return false; |
|
148 |
|
149 max = b->max_length; |
|
150 if (max >= 16 && _patches.longbridges) max = 100; |
|
151 |
|
152 return b->min_length <= bridge_len && bridge_len <= max; |
|
153 } |
|
154 |
|
155 /** Build a Bridge |
|
156 * @param end_tile end tile |
|
157 * @param p1 packed start tile coords (~ dx) |
|
158 * @param p2 various bitstuffed elements |
|
159 * - p2 = (bit 0- 7) - bridge type (hi bh) |
|
160 * - p2 = (bit 8-..) - rail type. bit15 ((x>>8)&0x80) means road bridge. |
|
161 */ |
|
162 int32 CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2) |
|
163 { |
|
164 int bridge_type; |
|
165 TransportType transport; |
|
166 RailType railtype; |
|
167 uint x; |
|
168 uint y; |
|
169 uint sx; |
|
170 uint sy; |
|
171 TileIndex tile_start; |
|
172 TileIndex tile_end; |
|
173 Slope tileh_start; |
|
174 Slope tileh_end; |
|
175 uint z_start; |
|
176 uint z_end; |
|
177 TileIndex tile; |
|
178 TileIndexDiff delta; |
|
179 uint bridge_len; |
|
180 Axis direction; |
|
181 int32 cost, terraformcost, ret; |
|
182 bool allow_on_slopes; |
|
183 |
|
184 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
|
185 |
|
186 /* unpack parameters */ |
|
187 bridge_type = GB(p2, 0, 8); |
|
188 |
|
189 if (p1 >= MapSize()) return CMD_ERROR; |
|
190 |
|
191 // type of bridge |
|
192 if (HASBIT(p2, 15)) { |
|
193 railtype = 0; |
|
194 transport = TRANSPORT_ROAD; |
|
195 } else { |
|
196 if (!ValParamRailtype(GB(p2, 8, 8))) return CMD_ERROR; |
|
197 railtype = GB(p2, 8, 8); |
|
198 transport = TRANSPORT_RAIL; |
|
199 } |
|
200 |
|
201 x = TileX(end_tile); |
|
202 y = TileY(end_tile); |
|
203 sx = TileX(p1); |
|
204 sy = TileY(p1); |
|
205 |
|
206 /* check if valid, and make sure that (x,y) are smaller than (sx,sy) */ |
|
207 if (x == sx) { |
|
208 if (y == sy) return_cmd_error(STR_5008_CANNOT_START_AND_END_ON); |
|
209 direction = AXIS_Y; |
|
210 if (y > sy) uintswap(y,sy); |
|
211 } else if (y == sy) { |
|
212 direction = AXIS_X; |
|
213 if (x > sx) uintswap(x,sx); |
|
214 } else { |
|
215 return_cmd_error(STR_500A_START_AND_END_MUST_BE_IN); |
|
216 } |
|
217 |
|
218 /* set and test bridge length, availability */ |
|
219 bridge_len = sx + sy - x - y - 1; |
|
220 if (!CheckBridge_Stuff(bridge_type, bridge_len)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE); |
|
221 |
|
222 /* retrieve landscape height and ensure it's on land */ |
|
223 tile_start = TileXY(x, y); |
|
224 tile_end = TileXY(sx, sy); |
|
225 if (IsClearWaterTile(tile_start) || IsClearWaterTile(tile_end)) { |
|
226 return_cmd_error(STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH); |
|
227 } |
|
228 |
|
229 tileh_start = GetTileSlope(tile_start, &z_start); |
|
230 tileh_end = GetTileSlope(tile_end, &z_end); |
|
231 |
|
232 if (IsSteepSlope(tileh_start)) z_start += TILE_HEIGHT; |
|
233 if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_start)) { |
|
234 z_start += TILE_HEIGHT; |
|
235 tileh_start = SLOPE_FLAT; |
|
236 } |
|
237 |
|
238 if (IsSteepSlope(tileh_end)) z_end += TILE_HEIGHT; |
|
239 if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_end)) { |
|
240 z_end += TILE_HEIGHT; |
|
241 tileh_end = SLOPE_FLAT; |
|
242 } |
|
243 |
|
244 if (z_start != z_end) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED); |
|
245 |
|
246 // Towns are not allowed to use bridges on slopes. |
|
247 allow_on_slopes = (!_is_old_ai_player |
|
248 && _current_player != OWNER_TOWN && _patches.build_on_slopes); |
|
249 |
|
250 /* Try and clear the start landscape */ |
|
251 |
|
252 ret = DoCommand(tile_start, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
|
253 if (CmdFailed(ret)) return ret; |
|
254 cost = ret; |
|
255 |
|
256 terraformcost = CheckBridgeSlopeNorth(direction, tileh_start); |
|
257 if (CmdFailed(terraformcost) || (terraformcost != 0 && !allow_on_slopes)) |
|
258 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
|
259 cost += terraformcost; |
|
260 |
|
261 /* Try and clear the end landscape */ |
|
262 |
|
263 ret = DoCommand(tile_end, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
|
264 if (CmdFailed(ret)) return ret; |
|
265 cost += ret; |
|
266 |
|
267 // false - end tile slope check |
|
268 terraformcost = CheckBridgeSlopeSouth(direction, tileh_end); |
|
269 if (CmdFailed(terraformcost) || (terraformcost != 0 && !allow_on_slopes)) |
|
270 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
|
271 cost += terraformcost; |
|
272 |
|
273 { |
|
274 TileIndex Heads[] = {tile_start, tile_end}; |
|
275 int i; |
|
276 |
|
277 for (i = 0; i < 2; i++) { |
|
278 if (MayHaveBridgeAbove(Heads[i])) { |
|
279 if (IsBridgeAbove(Heads[i])) { |
|
280 TileIndex north_head = GetNorthernBridgeEnd(Heads[i]); |
|
281 |
|
282 if (direction == GetBridgeAxis(Heads[i])) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST); |
|
283 |
|
284 if (z_start + TILE_HEIGHT == GetBridgeHeight(north_head)) { |
|
285 return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST); |
|
286 } |
|
287 } |
|
288 } |
|
289 } |
|
290 } |
|
291 |
|
292 /* do the drill? */ |
|
293 if (flags & DC_EXEC) { |
|
294 DiagDirection dir = AxisToDiagDir(direction); |
|
295 |
|
296 if (transport == TRANSPORT_RAIL) { |
|
297 MakeRailBridgeRamp(tile_start, _current_player, bridge_type, dir, railtype); |
|
298 MakeRailBridgeRamp(tile_end, _current_player, bridge_type, ReverseDiagDir(dir), railtype); |
|
299 } else { |
|
300 MakeRoadBridgeRamp(tile_start, _current_player, bridge_type, dir); |
|
301 MakeRoadBridgeRamp(tile_end, _current_player, bridge_type, ReverseDiagDir(dir)); |
|
302 } |
|
303 MarkTileDirtyByTile(tile_start); |
|
304 MarkTileDirtyByTile(tile_end); |
|
305 } |
|
306 |
|
307 delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); |
|
308 for (tile = tile_start + delta; tile != tile_end; tile += delta) { |
|
309 uint z; |
|
310 |
|
311 if (GetTileSlope(tile, &z) != SLOPE_FLAT && z >= z_start) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED); |
|
312 |
|
313 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) { |
|
314 /* Disallow crossing bridges for the time being */ |
|
315 return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST); |
|
316 } |
|
317 |
|
318 switch (GetTileType(tile)) { |
|
319 case MP_WATER: |
|
320 if (!EnsureNoVehicle(tile)) return_cmd_error(STR_980E_SHIP_IN_THE_WAY); |
|
321 if (!IsWater(tile) && !IsCoast(tile)) goto not_valid_below; |
|
322 break; |
|
323 |
|
324 case MP_RAILWAY: |
|
325 if (!IsPlainRailTile(tile)) goto not_valid_below; |
|
326 break; |
|
327 |
|
328 case MP_STREET: |
|
329 if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) goto not_valid_below; |
|
330 break; |
|
331 |
|
332 case MP_TUNNEL: |
|
333 break; |
|
334 |
|
335 case MP_STREET_BRIDGE: |
|
336 case MP_RAILWAY_BRIDGE: |
|
337 if (direction == DiagDirToAxis(GetBridgeRampDirection(tile))) goto not_valid_below; |
|
338 if (z_start < GetBridgeHeight(tile)) goto not_valid_below; |
|
339 break; |
|
340 |
|
341 case MP_UNMOVABLE: |
|
342 if (!IsOwnedLand(tile)) goto not_valid_below; |
|
343 break; |
|
344 |
|
345 case MP_CLEAR: |
|
346 if (IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST); |
|
347 break; |
|
348 |
|
349 default: |
|
350 not_valid_below:; |
|
351 /* try and clear the middle landscape */ |
|
352 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
|
353 if (CmdFailed(ret)) return ret; |
|
354 cost += ret; |
|
355 break; |
|
356 } |
|
357 |
|
358 if (flags & DC_EXEC) { |
|
359 SetBridgeMiddle(tile, direction); |
|
360 MarkTileDirtyByTile(tile); |
|
361 } |
|
362 } |
|
363 |
|
364 SetSignalsOnBothDir(tile_start, AxisToTrack(direction)); |
|
365 YapfNotifyTrackLayoutChange(tile_start, AxisToTrack(direction)); |
|
366 |
|
367 /* for human player that builds the bridge he gets a selection to choose from bridges (DC_QUERY_COST) |
|
368 * It's unnecessary to execute this command every time for every bridge. So it is done only |
|
369 * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated |
|
370 */ |
|
371 if (!(flags & DC_QUERY_COST)) { |
|
372 const Bridge *b = &_bridge[bridge_type]; |
|
373 |
|
374 bridge_len += 2; // begin and end tiles/ramps |
|
375 |
|
376 if (IsValidPlayer(_current_player) && !_is_old_ai_player) |
|
377 bridge_len = CalcBridgeLenCostFactor(bridge_len); |
|
378 |
|
379 cost += (int64)bridge_len * _price.build_bridge * b->price >> 8; |
|
380 } |
|
381 |
|
382 return cost; |
|
383 } |
|
384 |
|
385 |
|
386 static inline bool CheckAllowRemoveBridge(TileIndex tile) |
|
387 { |
|
388 /* Floods can remove anything as well as the scenario editor */ |
|
389 if (_current_player == OWNER_WATER || _game_mode == GM_EDITOR) return true; |
|
390 /* Obviously if the bridge/tunnel belongs to us, or no-one, we can remove it */ |
|
391 if (CheckTileOwnership(tile) || IsTileOwner(tile, OWNER_NONE)) return true; |
|
392 /* Otherwise we can only remove town-owned stuff with extra patch-settings, or cheat */ |
|
393 if (IsTileOwner(tile, OWNER_TOWN) && (_patches.extra_dynamite || _cheats.magic_bulldozer.value)) return true; |
|
394 return false; |
|
395 } |
|
396 |
|
397 static bool IsVehicleOnBridge(TileIndex starttile, TileIndex endtile, uint z) |
|
398 { |
|
399 const Vehicle *v; |
|
400 FOR_ALL_VEHICLES(v) { |
|
401 if ((v->tile == starttile || v->tile == endtile) && v->z_pos == z) { |
|
402 _error_message = VehicleInTheWayErrMsg(v); |
|
403 return true; |
|
404 } |
|
405 } |
|
406 return false; |
|
407 } |
|
408 |
|
409 static int32 DoClearBridge(TileIndex tile, uint32 flags) |
|
410 { |
|
411 DiagDirection direction; |
|
412 TileIndexDiff delta; |
|
413 TileIndex endtile; |
|
414 Town *t = NULL; |
|
415 |
|
416 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
|
417 |
|
418 if (!CheckAllowRemoveBridge(tile)) return CMD_ERROR; |
|
419 |
|
420 endtile = GetOtherBridgeEnd(tile); |
|
421 |
|
422 if (!EnsureNoVehicle(tile) || |
|
423 !EnsureNoVehicle(endtile) || |
|
424 IsVehicleOnBridge(tile, endtile, GetBridgeHeight(tile))) { |
|
425 return CMD_ERROR; |
|
426 } |
|
427 |
|
428 direction = GetBridgeRampDirection(tile); |
|
429 delta = TileOffsByDiagDir(direction); |
|
430 |
|
431 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) { |
|
432 t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating |
|
433 |
|
434 /* Check if you are allowed to remove the bridge owned by a town |
|
435 * Removal depends on difficulty settings */ |
|
436 if (!CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE)) { |
|
437 SetDParam(0, t->index); |
|
438 return_cmd_error(STR_2009_LOCAL_AUTHORITY_REFUSES); |
|
439 } |
|
440 } |
|
441 |
|
442 if (flags & DC_EXEC) { |
|
443 TileIndex c; |
|
444 Track track; |
|
445 |
|
446 //checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until |
|
447 // you have a "Poor" (0) town rating |
|
448 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) |
|
449 ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM); |
|
450 |
|
451 DoClearSquare(tile); |
|
452 DoClearSquare(endtile); |
|
453 for (c = tile + delta; c != endtile; c += delta) { |
|
454 ClearBridgeMiddle(c); |
|
455 MarkTileDirtyByTile(c); |
|
456 } |
|
457 |
|
458 UpdateSignalsOnSegment(tile, ReverseDiagDir(direction)); |
|
459 UpdateSignalsOnSegment(endtile, direction); |
|
460 track = AxisToTrack(DiagDirToAxis(direction)); |
|
461 YapfNotifyTrackLayoutChange(tile, track); |
|
462 YapfNotifyTrackLayoutChange(endtile, track); |
|
463 } |
|
464 |
|
465 return (DistanceManhattan(tile, endtile) + 1) * _price.clear_bridge; |
|
466 } |
|
467 |
|
468 |
|
469 static int32 ClearTile_Bridge(TileIndex tile, byte flags) |
|
470 { |
|
471 assert(IsBridgeTile(tile)); |
|
472 if (flags & DC_AUTO) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST); |
|
473 return DoClearBridge(tile, flags); |
|
474 } |
|
475 |
|
476 int32 DoConvertBridgeRail(TileIndex tile, RailType totype, bool exec) |
|
477 { |
|
478 TileIndex endtile; |
|
479 |
|
480 if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) { |
|
481 if (!CheckTileOwnership(tile)) return CMD_ERROR; |
|
482 |
|
483 endtile = GetOtherBridgeEnd(tile); |
|
484 |
|
485 if (!EnsureNoVehicle(tile) || |
|
486 !EnsureNoVehicle(endtile) || |
|
487 IsVehicleOnBridge(tile, endtile, GetBridgeHeight(tile))) { |
|
488 return CMD_ERROR; |
|
489 } |
|
490 |
|
491 if (GetRailType(tile) == totype) return CMD_ERROR; |
|
492 |
|
493 if (exec) { |
|
494 TileIndexDiff delta; |
|
495 Track track; |
|
496 |
|
497 SetRailType(tile, totype); |
|
498 SetRailType(endtile, totype); |
|
499 MarkTileDirtyByTile(tile); |
|
500 MarkTileDirtyByTile(endtile); |
|
501 |
|
502 track = AxisToTrack(DiagDirToAxis(GetBridgeRampDirection(tile))); |
|
503 YapfNotifyTrackLayoutChange(tile, track); |
|
504 YapfNotifyTrackLayoutChange(endtile, track); |
|
505 |
|
506 delta = TileOffsByDiagDir(GetBridgeRampDirection(tile)); |
|
507 for (tile += delta; tile != endtile; tile += delta) { |
|
508 MarkTileDirtyByTile(tile); // TODO encapsulate this into a function |
|
509 } |
|
510 } |
|
511 |
|
512 return (DistanceManhattan(tile, endtile) + 1) * (_price.build_rail >> 1); |
|
513 } else { |
|
514 return CMD_ERROR; |
|
515 } |
|
516 } |
|
517 |
|
518 |
|
519 static void DrawBridgePillars(PalSpriteID image, const TileInfo* ti, Axis axis, uint type, int x, int y, int z) |
|
520 { |
|
521 if (image != 0) { |
|
522 bool drawfarpillar = !HASBIT(GetBridgeFlags(type), 0); |
|
523 int back_height, front_height; |
|
524 int i = z; |
|
525 const byte *p; |
|
526 |
|
527 static const byte _tileh_bits[4][8] = { |
|
528 { 2, 1, 8, 4, 16, 2, 0, 9 }, |
|
529 { 1, 8, 4, 2, 2, 16, 9, 0 }, |
|
530 { 4, 8, 1, 2, 16, 2, 0, 9 }, |
|
531 { 2, 4, 8, 1, 2, 16, 9, 0 } |
|
532 }; |
|
533 |
|
534 if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image); |
|
535 |
|
536 p = _tileh_bits[(image & 1) * 2 + (axis == AXIS_X ? 0 : 1)]; |
|
537 front_height = ti->z + (ti->tileh & p[0] ? TILE_HEIGHT : 0); |
|
538 back_height = ti->z + (ti->tileh & p[1] ? TILE_HEIGHT : 0); |
|
539 |
|
540 if (IsSteepSlope(ti->tileh)) { |
|
541 if (!(ti->tileh & p[2])) front_height += TILE_HEIGHT; |
|
542 if (!(ti->tileh & p[3])) back_height += TILE_HEIGHT; |
|
543 } |
|
544 |
|
545 for (; z >= front_height || z >= back_height; z -= TILE_HEIGHT) { |
|
546 /* HACK set height of the BB of pillars to 1, because the origin of the |
|
547 * sprites is at the top |
|
548 */ |
|
549 if (z >= front_height) { // front facing pillar |
|
550 AddSortableSpriteToDraw(image, x, y, p[4], p[5], 1, z); |
|
551 } |
|
552 |
|
553 if (drawfarpillar && z >= back_height && z < i - TILE_HEIGHT) { // back facing pillar |
|
554 AddSortableSpriteToDraw(image, x - p[6], y - p[7], p[4], p[5], 1, z); |
|
555 } |
|
556 } |
|
557 } |
|
558 } |
|
559 |
|
560 uint GetBridgeFoundation(Slope tileh, Axis axis) |
|
561 { |
|
562 uint i; |
|
563 |
|
564 if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) return tileh; |
|
565 |
|
566 // inclined sloped building |
|
567 switch (tileh) { |
|
568 case SLOPE_W: |
|
569 case SLOPE_STEEP_W: i = 0; break; |
|
570 case SLOPE_S: |
|
571 case SLOPE_STEEP_S: i = 2; break; |
|
572 case SLOPE_E: |
|
573 case SLOPE_STEEP_E: i = 4; break; |
|
574 case SLOPE_N: |
|
575 case SLOPE_STEEP_N: i = 6; break; |
|
576 default: return 0; |
|
577 } |
|
578 if (axis != AXIS_X) ++i; |
|
579 return i + 15; |
|
580 } |
|
581 |
|
582 |
|
583 /** |
|
584 * Draws a bridge tile. |
|
585 * base_offset is where the sprite selection comes into play |
|
586 * and it works a bit like a bitmask.<p> For bridge heads: |
|
587 * <ul><li>Bit 0: direction</li> |
|
588 * <li>Bit 1: northern or southern heads</li> |
|
589 * <li>Bit 2: Set if the bridge head is sloped</li> |
|
590 * <li>Bit 3 and more: Railtype Specific subset</li> |
|
591 * </ul> |
|
592 * Please note that in this code, "roads" are treated as railtype 1, whilst the real railtypes are 0, 2 and 3 |
|
593 */ |
|
594 static void DrawTile_Bridge(TileInfo *ti) |
|
595 { |
|
596 uint32 image; |
|
597 |
|
598 int base_offset; |
|
599 bool ice = HasBridgeSnowOrDesert(ti->tile); |
|
600 |
|
601 if (GetBridgeTransportType(ti->tile) == TRANSPORT_RAIL) { |
|
602 if (GetTrackBits(ti->tile) != TRACK_BIT_X && GetTrackBits(ti->tile) != TRACK_BIT_Y) { |
|
603 DrawTile_Track(ti); |
|
604 return; |
|
605 } |
|
606 base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset; |
|
607 assert(base_offset != 8); /* This one is used for roads */ |
|
608 } else { |
|
609 base_offset = 8; |
|
610 } |
|
611 |
|
612 /* as the lower 3 bits are used for other stuff, make sure they are clear */ |
|
613 assert( (base_offset & 0x07) == 0x00); |
|
614 |
|
615 if (!HASBIT(BRIDGE_NO_FOUNDATION, ti->tileh)) { |
|
616 int f = GetBridgeFoundation(ti->tileh, DiagDirToAxis(GetBridgeRampDirection(ti->tile))); |
|
617 if (f != 0) DrawFoundation(ti, f); |
|
618 } |
|
619 |
|
620 // HACK Wizardry to convert the bridge ramp direction into a sprite offset |
|
621 base_offset += (6 - GetBridgeRampDirection(ti->tile)) % 4; |
|
622 |
|
623 if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head |
|
624 |
|
625 /* Table number 6 always refers to the bridge heads for any bridge type */ |
|
626 image = GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset]; |
|
627 |
|
628 if (!ice) { |
|
629 DrawClearLandTile(ti, 3); |
|
630 } else { |
|
631 DrawGroundSprite(SPR_FLAT_SNOWY_TILE + _tileh_to_sprite[ti->tileh]); |
|
632 } |
|
633 |
|
634 if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti); |
|
635 |
|
636 // draw ramp |
|
637 if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image); |
|
638 /* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on |
|
639 * it doesn't disappear behind it |
|
640 */ |
|
641 AddSortableSpriteToDraw( |
|
642 image, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 1 : 8, ti->z |
|
643 ); |
|
644 |
|
645 if (IsTileType(ti->tile, MP_RAILWAY_BRIDGE) && HasSignals(ti->tile)) DrawSignals(ti->tile, GetTrackBits(ti->tile)); |
|
646 |
|
647 DrawBridgeMiddle(ti); |
|
648 } |
|
649 |
|
650 |
|
651 /** Compute bridge piece. Computes the bridge piece to display depending on the position inside the bridge. |
|
652 * bridges pieces sequence (middle parts) |
|
653 * bridge len 1: 0 |
|
654 * bridge len 2: 0 1 |
|
655 * bridge len 3: 0 4 1 |
|
656 * bridge len 4: 0 2 3 1 |
|
657 * bridge len 5: 0 2 5 3 1 |
|
658 * bridge len 6: 0 2 3 2 3 1 |
|
659 * bridge len 7: 0 2 3 4 2 3 1 |
|
660 * #0 - always as first, #1 - always as last (if len>1) |
|
661 * #2,#3 are to pair in order |
|
662 * for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0) |
|
663 * @param north Northernmost tile of bridge |
|
664 * @param south Southernmost tile of bridge |
|
665 * @return Index of bridge piece |
|
666 */ |
|
667 static uint CalcBridgePiece(uint north, uint south) |
|
668 { |
|
669 if (north == 1) { |
|
670 return 0; |
|
671 } else if (south == 1) { |
|
672 return 1; |
|
673 } else if (north < south) { |
|
674 return north & 1 ? 3 : 2; |
|
675 } else if (north > south) { |
|
676 return south & 1 ? 2 : 3; |
|
677 } else { |
|
678 return north & 1 ? 5 : 4; |
|
679 } |
|
680 } |
|
681 |
|
682 |
|
683 void DrawBridgeMiddle(const TileInfo* ti) |
|
684 { |
|
685 const PalSpriteID* b; |
|
686 PalSpriteID image; |
|
687 uint base_offset; |
|
688 TileIndex rampnorth; |
|
689 TileIndex rampsouth; |
|
690 Axis axis; |
|
691 uint piece; |
|
692 uint type; |
|
693 int x; |
|
694 int y; |
|
695 uint z; |
|
696 |
|
697 if (!IsBridgeAbove(ti->tile)) return; |
|
698 |
|
699 rampnorth = GetNorthernBridgeEnd(ti->tile); |
|
700 rampsouth = GetSouthernBridgeEnd(ti->tile); |
|
701 |
|
702 axis = GetBridgeAxis(ti->tile); |
|
703 piece = CalcBridgePiece( |
|
704 DistanceManhattan(ti->tile, rampnorth), |
|
705 DistanceManhattan(ti->tile, rampsouth) |
|
706 ); |
|
707 type = GetBridgeType(rampsouth); |
|
708 |
|
709 if (GetBridgeTransportType(rampsouth) == TRANSPORT_RAIL) { |
|
710 base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset; |
|
711 } else { |
|
712 base_offset = 8; |
|
713 } |
|
714 |
|
715 b = base_offset + GetBridgeSpriteTable(type, piece); |
|
716 if (axis != AXIS_X) b += 4; |
|
717 |
|
718 x = ti->x; |
|
719 y = ti->y; |
|
720 z = GetBridgeHeight(rampsouth) - 3; |
|
721 |
|
722 image = b[0]; |
|
723 if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image); |
|
724 if (axis == AXIS_X) { |
|
725 AddSortableSpriteToDraw(image, x, y, 16, 11, 1, z); |
|
726 } else { |
|
727 AddSortableSpriteToDraw(image, x, y, 11, 16, 1, z); |
|
728 } |
|
729 |
|
730 image = b[1]; |
|
731 if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image); |
|
732 |
|
733 // draw roof, the component of the bridge which is logically between the vehicle and the camera |
|
734 if (axis == AXIS_X) { |
|
735 y += 12; |
|
736 if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 16, 1, 0x28, z); |
|
737 } else { |
|
738 x += 12; |
|
739 if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 1, 16, 0x28, z); |
|
740 } |
|
741 |
|
742 if (GetRailType(rampsouth) == RAILTYPE_ELECTRIC) DrawCatenary(ti); |
|
743 |
|
744 if (ti->z + 5 == z) { |
|
745 // draw poles below for small bridges |
|
746 image = b[2]; |
|
747 if (image != 0) { |
|
748 if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image); |
|
749 DrawGroundSpriteAt(image, x, y, z); |
|
750 } |
|
751 } else if (_patches.bridge_pillars) { |
|
752 // draw pillars below for high bridges |
|
753 DrawBridgePillars(b[2], ti, axis, type, x, y, z); |
|
754 } |
|
755 } |
|
756 |
|
757 |
|
758 uint SetSpeedLimitOnBridge(Vehicle *v) |
|
759 { |
|
760 uint bridge_speed; |
|
761 if (v->vehstatus & VS_HIDDEN) return v->max_speed; /* in tunnel */ |
|
762 |
|
763 bridge_speed = _bridge[GetBridgeType(v->tile)].speed; |
|
764 |
|
765 if (v->type == VEH_Road) bridge_speed *= 2; /* XXX give vehicles proper speeds */ |
|
766 |
|
767 if (v->cur_speed > bridge_speed) v->cur_speed = bridge_speed; |
|
768 return bridge_speed; |
|
769 } |
|
770 |
|
771 static bool IsCustomBridgeHead(TileIndex tile) |
|
772 { |
|
773 assert(IsBridgeTile(tile)); |
|
774 |
|
775 if (IsTileType(tile, MP_RAILWAY_BRIDGE)) { |
|
776 return !(GetTrackBits(tile) == TRACK_BIT_X || GetTrackBits(tile) == TRACK_BIT_Y); |
|
777 } |
|
778 |
|
779 return false; /* TODO - street bridges */ |
|
780 } |
|
781 |
|
782 |
|
783 /** Gets the absolute z coordinate of a point inside a bridge tile |
|
784 * When we're on the track (that means between position 5 and 10) |
|
785 * on the coordinate perpendicular to the track it returns the base |
|
786 * height of the ramp |
|
787 * Outside this range (from 0 to 4 and from 11 to 15) it returns the |
|
788 * "true" Z coordinate of the tile by taking the slope into account |
|
789 * For custom bridge heads the entire bridge head is flat and has the |
|
790 * same z coordinate |
|
791 * @param tile The index of the tile we are talking about |
|
792 * @param x Absolute or relative x coordinate |
|
793 * @param y Absolute or relative y coordinate |
|
794 * @return Absolute z coordinate |
|
795 */ |
|
796 static uint GetSlopeZ_Bridge(TileIndex tile, uint x, uint y) |
|
797 { |
|
798 uint z, pos; |
|
799 Slope tileh = GetTileSlope(tile, &z); |
|
800 DiagDirection dir = GetBridgeRampDirection(tile); |
|
801 |
|
802 x &= 0xF; |
|
803 y &= 0xF; |
|
804 |
|
805 pos = (DiagDirToAxis(dir) == AXIS_X ? y : x); |
|
806 |
|
807 // On the bridge ramp or flat bridge head? |
|
808 if ( (2 <= pos && pos <= 13) || IsCustomBridgeHead(tile)) { |
|
809 uint delta; |
|
810 |
|
811 if (IsSteepSlope(tileh)) return z + TILE_HEIGHT * 2; |
|
812 |
|
813 if (HASBIT(BRIDGE_HORZ_RAMP, tileh)) return z + TILE_HEIGHT; |
|
814 |
|
815 if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) z += TILE_HEIGHT; |
|
816 switch (dir) { |
|
817 default: NOT_REACHED(); |
|
818 case DIAGDIR_NE: delta = (TILE_SIZE - 1 - x) / 2; break; |
|
819 case DIAGDIR_SE: delta = y / 2; break; |
|
820 case DIAGDIR_SW: delta = x / 2; break; |
|
821 case DIAGDIR_NW: delta = (TILE_SIZE - 1 - y) / 2; break; |
|
822 } |
|
823 return z + 1 + delta; |
|
824 } else { |
|
825 uint f = GetBridgeFoundation(tileh, DiagDirToAxis(dir)); |
|
826 |
|
827 if (f != 0) { |
|
828 if (IsSteepSlope(tileh)) { |
|
829 z += TILE_HEIGHT; |
|
830 } else if (f < 15) { |
|
831 return z + TILE_HEIGHT; |
|
832 } |
|
833 tileh = _inclined_tileh[f - 15]; |
|
834 } |
|
835 } |
|
836 return z + GetPartialZ(x, y, tileh); |
|
837 } |
|
838 |
|
839 static Slope GetSlopeTileh_Bridge(TileIndex tile, Slope tileh) |
|
840 { |
|
841 if (HASBIT(BRIDGE_NO_FOUNDATION, tileh)) { |
|
842 return tileh; |
|
843 } else { |
|
844 uint f = GetBridgeFoundation(tileh, DiagDirToAxis(GetBridgeRampDirection(tile))); |
|
845 |
|
846 if (f == 0) return tileh; |
|
847 if (f < 15) return SLOPE_FLAT; |
|
848 return _inclined_tileh[f - 15]; |
|
849 } |
|
850 } |
|
851 |
|
852 static void GetAcceptedCargo_Bridge(TileIndex tile, AcceptedCargo ac) |
|
853 { |
|
854 /* not used */ |
|
855 } |
|
856 |
|
857 static const StringID _bridge_tile_str[(MAX_BRIDGES + 3) + (MAX_BRIDGES + 3)] = { |
|
858 STR_501F_WOODEN_RAIL_BRIDGE, |
|
859 STR_5020_CONCRETE_RAIL_BRIDGE, |
|
860 STR_501C_STEEL_GIRDER_RAIL_BRIDGE, |
|
861 STR_501E_REINFORCED_CONCRETE_SUSPENSION, |
|
862 STR_501B_STEEL_SUSPENSION_RAIL_BRIDGE, |
|
863 STR_501B_STEEL_SUSPENSION_RAIL_BRIDGE, |
|
864 STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE, |
|
865 STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE, |
|
866 STR_501D_STEEL_CANTILEVER_RAIL_BRIDGE, |
|
867 STR_501C_STEEL_GIRDER_RAIL_BRIDGE, |
|
868 STR_5027_TUBULAR_RAIL_BRIDGE, |
|
869 STR_5027_TUBULAR_RAIL_BRIDGE, |
|
870 STR_5027_TUBULAR_RAIL_BRIDGE, |
|
871 0, 0, 0, |
|
872 |
|
873 STR_5025_WOODEN_ROAD_BRIDGE, |
|
874 STR_5026_CONCRETE_ROAD_BRIDGE, |
|
875 STR_5022_STEEL_GIRDER_ROAD_BRIDGE, |
|
876 STR_5024_REINFORCED_CONCRETE_SUSPENSION, |
|
877 STR_5021_STEEL_SUSPENSION_ROAD_BRIDGE, |
|
878 STR_5021_STEEL_SUSPENSION_ROAD_BRIDGE, |
|
879 STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE, |
|
880 STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE, |
|
881 STR_5023_STEEL_CANTILEVER_ROAD_BRIDGE, |
|
882 STR_5022_STEEL_GIRDER_ROAD_BRIDGE, |
|
883 STR_5028_TUBULAR_ROAD_BRIDGE, |
|
884 STR_5028_TUBULAR_ROAD_BRIDGE, |
|
885 STR_5028_TUBULAR_ROAD_BRIDGE, |
|
886 0, 0, 0, |
|
887 }; |
|
888 |
|
889 static void GetTileDesc_Bridge(TileIndex tile, TileDesc *td) |
|
890 { |
|
891 td->str = _bridge_tile_str[GetBridgeTransportType(tile) << 4 | GetBridgeType(tile)]; |
|
892 td->owner = GetTileOwner(tile); |
|
893 } |
|
894 |
|
895 |
|
896 static void AnimateTile_Bridge(TileIndex tile) |
|
897 { |
|
898 /* not used */ |
|
899 } |
|
900 |
|
901 |
|
902 static void TileLoop_Bridge(TileIndex tile) |
|
903 { |
|
904 bool snow_or_desert = HasBridgeSnowOrDesert(tile); |
|
905 switch (_opt.landscape) { |
|
906 case LT_HILLY: |
|
907 if (snow_or_desert != (GetTileZ(tile) > _opt.snow_line)) { |
|
908 SetBridgeSnowOrDesert(tile, !snow_or_desert); |
|
909 MarkTileDirtyByTile(tile); |
|
910 } |
|
911 break; |
|
912 |
|
913 case LT_DESERT: |
|
914 if (GetTropicZone(tile) == TROPICZONE_DESERT && !snow_or_desert) { |
|
915 SetBridgeSnowOrDesert(tile, true); |
|
916 MarkTileDirtyByTile(tile); |
|
917 } |
|
918 break; |
|
919 } |
|
920 } |
|
921 |
|
922 static void ClickTile_Bridge(TileIndex tile) |
|
923 { |
|
924 /* not used */ |
|
925 } |
|
926 |
|
927 |
|
928 static uint32 GetTileTrackStatus_Bridge(TileIndex tile, TransportType mode) |
|
929 { |
|
930 if (GetBridgeTransportType(tile) != mode) return 0; |
|
931 |
|
932 if (IsTileType(tile, MP_RAILWAY_BRIDGE)) return GetTileTrackStatus_Track(tile, mode); |
|
933 return AxisToTrackBits(DiagDirToAxis(GetBridgeRampDirection(tile))) * 0x101; |
|
934 } |
|
935 |
|
936 |
|
937 static void ChangeTileOwner_Bridge(TileIndex tile, PlayerID old_player, PlayerID new_player) |
|
938 { |
|
939 if (!IsTileOwner(tile, old_player)) return; |
|
940 |
|
941 if (new_player != PLAYER_SPECTATOR) { |
|
942 SetTileOwner(tile, new_player); |
|
943 } else { |
|
944 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); |
|
945 } |
|
946 } |
|
947 |
|
948 |
|
949 static uint32 VehicleEnter_Street_Bridge(Vehicle *v, TileIndex tile, int x, int y) |
|
950 { |
|
951 int z = GetSlopeZ(x, y) - v->z_pos; |
|
952 |
|
953 DiagDirection dir; |
|
954 |
|
955 if (myabs(z) > 2) return 8; |
|
956 |
|
957 if (v->type == VEH_Road) { |
|
958 /* modify speed of vehicle */ |
|
959 uint16 spd = _bridge[GetBridgeType(tile)].speed * 2; |
|
960 if (v->cur_speed > spd) v->cur_speed = spd; |
|
961 } |
|
962 |
|
963 dir = GetBridgeRampDirection(tile); |
|
964 if (DirToDiagDir(v->direction) == dir) { |
|
965 switch (dir) { |
|
966 default: NOT_REACHED(); |
|
967 case DIAGDIR_NE: if ((x & 0xF) != 0) return 0; break; |
|
968 case DIAGDIR_SE: if ((y & 0xF) != TILE_SIZE - 1) return 0; break; |
|
969 case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return 0; break; |
|
970 case DIAGDIR_NW: if ((y & 0xF) != 0) return 0; break; |
|
971 } |
|
972 v->u.road.state = 0xFF; |
|
973 return 4; |
|
974 } else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) { |
|
975 v->tile = tile; |
|
976 if (v->u.road.state == 0xFF) { |
|
977 static const byte road_exit_bridge_state[4] = {8, 9, 0, 1}; |
|
978 v->u.road.state = road_exit_bridge_state[dir]; |
|
979 v->u.road.frame = 0; |
|
980 return 4; |
|
981 } |
|
982 return 0; |
|
983 } |
|
984 return 0; |
|
985 } |
|
986 |
|
987 /** |
|
988 * @retval 0 The vehicle can proceed |
|
989 * @retval 4 The vehicle changed onto of off the bridge (depending on the |
|
990 * status before, check with v->u.rail.track == 0x40) |
|
991 * @retval 8 The vehicle cannot enter the tile |
|
992 */ |
|
993 static uint32 VehicleEnter_Railway_Bridge(Vehicle *v, TileIndex tile, int x, int y) |
|
994 { |
|
995 int z = GetSlopeZ(x, y) - v->z_pos; |
|
996 |
|
997 DiagDirection dir; |
|
998 |
|
999 if (IsCustomBridgeHead(tile)) { |
|
1000 uint h; |
|
1001 GetTileSlope(tile, &h); |
|
1002 |
|
1003 z = h + TILE_HEIGHT - v->z_pos; |
|
1004 } |
|
1005 |
|
1006 if (myabs(z) > 2) return 8; |
|
1007 |
|
1008 if (IsFrontEngine(v)) { |
|
1009 /* modify speed of vehicle */ |
|
1010 uint16 spd = _bridge[GetBridgeType(tile)].speed; |
|
1011 if (v->cur_speed > spd) v->cur_speed = spd; |
|
1012 } |
|
1013 |
|
1014 dir = GetBridgeRampDirection(tile); |
|
1015 |
|
1016 if (v->direction == DiagDirToDir(ReverseDiagDir(dir))) { |
|
1017 /* We are entering the bridge head from the bridge itself */ |
|
1018 if (v->u.rail.track == 0x40) { |
|
1019 /* Get the vehicle out of the wormhole, the track will be chosen later |
|
1020 by the pathfinder */ |
|
1021 v->tile = tile; |
|
1022 v->u.rail.track = TrackToTrackBits(TrackdirToTrack(DiagdirToDiagTrackdir(dir))); |
|
1023 return 4; |
|
1024 } |
|
1025 return 0; |
|
1026 |
|
1027 } else { |
|
1028 TileIndex other_bridge_end_tile; |
|
1029 uint32 bridge_length; |
|
1030 /* We are on the bridge head itself, possibly entering the bridge */ |
|
1031 /* Vehicle will enter the bridge wormhole when it reaches the tile edge in the |
|
1032 * direction of the bridge. */ |
|
1033 TileIndexDiffC diff = TileIndexDiffCByDiagDir(dir); |
|
1034 /* If vehicle didn't reach the edge we can return and try it next time */ |
|
1035 if (((diff.x != 0 ? x : y) & 0x0F) != (diff.x + diff.y > 0 ? TILE_SIZE - 1 : 0)) return 0; |
|
1036 /* We will enter the bridge wormhole. */ |
|
1037 |
|
1038 other_bridge_end_tile = GetOtherBridgeEnd(tile); |
|
1039 bridge_length = GetBridgeLength(tile, other_bridge_end_tile); |
|
1040 if (bridge_length > 0) { |
|
1041 /* Non-zero bridge length. Adjust the other coordinate to the middle of tile |
|
1042 * to allow train controller to select proper vehicle image */ |
|
1043 if (diff.x != 0) v->y_pos = y; else v->x_pos = x; |
|
1044 v->direction = DiagDirToDir(dir); |
|
1045 /* We're about to enter the bridge body, clear all up/down flags just in case */ |
|
1046 v->u.rail.track = 0x40; |
|
1047 v->direction = DiagDirToDir(dir); |
|
1048 CLRBIT(v->u.rail.flags, VRF_GOINGUP); |
|
1049 CLRBIT(v->u.rail.flags, VRF_GOINGDOWN); |
|
1050 return 4; |
|
1051 } else { |
|
1052 /* Zero bridge length. Pretend that nothing extra happened. Custom bridge heads should act as normal tracks. */ |
|
1053 ; |
|
1054 } |
|
1055 } |
|
1056 return 0; |
|
1057 } |
|
1058 |
|
1059 static uint32 VehicleEnter_Bridge(Vehicle *v, TileIndex tile, int x, int y) |
|
1060 { |
|
1061 if (v->type == VEH_Train) return VehicleEnter_Railway_Bridge(v, tile, x, y); |
|
1062 |
|
1063 if (v->type == VEH_Road) return VehicleEnter_Street_Bridge(v, tile, x, y); |
|
1064 |
|
1065 NOT_REACHED(); |
|
1066 } |
|
1067 |
|
1068 const TileTypeProcs _tile_type_bridge_procs = { |
|
1069 DrawTile_Bridge, /* draw_tile_proc */ |
|
1070 GetSlopeZ_Bridge, /* get_slope_z_proc */ |
|
1071 ClearTile_Bridge, /* clear_tile_proc */ |
|
1072 GetAcceptedCargo_Bridge, /* get_accepted_cargo_proc */ |
|
1073 GetTileDesc_Bridge, /* get_tile_desc_proc */ |
|
1074 GetTileTrackStatus_Bridge, /* get_tile_track_status_proc */ |
|
1075 ClickTile_Bridge, /* click_tile_proc */ |
|
1076 AnimateTile_Bridge, /* animate_tile_proc */ |
|
1077 TileLoop_Bridge, /* tile_loop_clear */ |
|
1078 ChangeTileOwner_Bridge, /* change_tile_owner_clear */ |
|
1079 NULL, /* get_produced_cargo_proc */ |
|
1080 VehicleEnter_Bridge, /* vehicle_enter_tile_proc */ |
|
1081 GetSlopeTileh_Bridge, /* get_slope_tileh_proc */ |
|
1082 }; |