75 * 11uuuudd => rail depot |
77 * 11uuuudd => rail depot |
76 */ |
78 */ |
77 |
79 |
78 static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags) |
80 static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags) |
79 { |
81 { |
80 TrackBits current; /* The current track layout */ |
82 TrackBits current; // The current track layout |
81 TrackBits future; /* The track layout we want to build */ |
83 TrackBits future; // The track layout we want to build |
82 _error_message = STR_1001_IMPOSSIBLE_TRACK_COMBINATION; |
84 _error_message = STR_1001_IMPOSSIBLE_TRACK_COMBINATION; |
83 |
85 |
84 if (!IsPlainRailTile(tile)) return false; |
86 if (!IsPlainRailTile(tile)) return false; |
85 |
87 |
86 /* So, we have a tile with tracks on it (and possibly signals). Let's see |
88 /* So, we have a tile with tracks on it (and possibly signals). Let's see |
188 |
190 |
189 |
191 |
190 static uint32 CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile) |
192 static uint32 CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile) |
191 { |
193 { |
192 if (IsSteepSlope(tileh)) { |
194 if (IsSteepSlope(tileh)) { |
193 if (existing == 0) { |
195 if (_patches.build_on_slopes && existing == 0) { |
194 TrackBits valid = TRACK_BIT_CROSS | (HASBIT(1 << SLOPE_STEEP_W | 1 << SLOPE_STEEP_E, tileh) ? TRACK_BIT_VERT : TRACK_BIT_HORZ); |
196 TrackBits valid = TRACK_BIT_CROSS | (HASBIT(1 << SLOPE_STEEP_W | 1 << SLOPE_STEEP_E, tileh) ? TRACK_BIT_VERT : TRACK_BIT_HORZ); |
195 if (valid & rail_bits) return _eco->GetPrice(CEconomy::TERRAFORM); |
197 if (valid & rail_bits) return _eco->GetPrice(CEconomy::TERRAFORM); |
196 } |
198 } |
197 } else { |
199 } else { |
198 rail_bits |= existing; |
200 rail_bits |= existing; |
199 |
201 |
200 // don't allow building on the lower side of a coast |
202 /* don't allow building on the lower side of a coast */ |
201 if (IsTileType(tile, MP_WATER) && |
203 if (IsTileType(tile, MP_WATER) && |
202 ~_valid_tileh_slopes[1][tileh] & rail_bits) { |
204 ~_valid_tileh_slopes[1][tileh] & rail_bits) { |
203 return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER); |
205 return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER); |
204 } |
206 } |
205 |
207 |
206 // no special foundation |
208 /* no special foundation */ |
207 if ((~_valid_tileh_slopes[0][tileh] & rail_bits) == 0) |
209 if ((~_valid_tileh_slopes[0][tileh] & rail_bits) == 0) |
208 return 0; |
210 return 0; |
209 |
211 |
210 if ((~_valid_tileh_slopes[1][tileh] & rail_bits) == 0 || ( // whole tile is leveled up |
212 if ((~_valid_tileh_slopes[1][tileh] & rail_bits) == 0 || ( // whole tile is leveled up |
211 (rail_bits == TRACK_BIT_X || rail_bits == TRACK_BIT_Y) && |
213 (rail_bits == TRACK_BIT_X || rail_bits == TRACK_BIT_Y) && |
250 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
252 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
251 |
253 |
252 switch (GetTileType(tile)) { |
254 switch (GetTileType(tile)) { |
253 case MP_RAILWAY: |
255 case MP_RAILWAY: |
254 if (!CheckTrackCombination(tile, trackbit, flags) || |
256 if (!CheckTrackCombination(tile, trackbit, flags) || |
255 !EnsureNoVehicle(tile)) { |
257 !EnsureNoVehicleOnGround(tile)) { |
256 return CMD_ERROR; |
258 return CMD_ERROR; |
257 } |
259 } |
258 if (!IsTileOwner(tile, _current_player) || |
260 if (!IsTileOwner(tile, _current_player) || |
259 !IsCompatibleRail(GetRailType(tile), railtype)) { |
261 !IsCompatibleRail(GetRailType(tile), railtype)) { |
260 // Get detailed error message |
262 /* Get detailed error message */ |
261 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
263 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
262 } |
264 } |
263 |
265 |
264 ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile); |
266 ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile); |
265 if (CmdFailed(ret)) return ret; |
267 if (CmdFailed(ret)) return ret; |
286 if (!HASBIT(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) { |
288 if (!HASBIT(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) { |
287 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
289 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION); |
288 } |
290 } |
289 #undef M |
291 #undef M |
290 |
292 |
291 if (!EnsureNoVehicle(tile)) return CMD_ERROR; |
293 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR; |
292 |
294 |
293 if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) { |
295 if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) { |
294 if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS); |
296 if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS); |
295 |
297 |
296 if ((track == TRACK_X && GetRoadBits(tile) == ROAD_Y) || |
298 if ((track == TRACK_X && GetRoadBits(tile) == ROAD_Y) || |
350 switch (GetTileType(tile)) { |
352 switch (GetTileType(tile)) { |
351 case MP_STREET: { |
353 case MP_STREET: { |
352 if (!IsLevelCrossing(tile) || |
354 if (!IsLevelCrossing(tile) || |
353 GetCrossingRailBits(tile) != trackbit || |
355 GetCrossingRailBits(tile) != trackbit || |
354 (_current_player != OWNER_WATER && !CheckTileOwnership(tile)) || |
356 (_current_player != OWNER_WATER && !CheckTileOwnership(tile)) || |
355 !EnsureNoVehicle(tile)) { |
357 !EnsureNoVehicleOnGround(tile)) { |
356 return CMD_ERROR; |
358 return CMD_ERROR; |
357 } |
359 } |
358 |
360 |
359 cost += _eco->GetPrice(CEconomy::PRICE_RAIL_REMOVE, tile, true); |
361 cost += _eco->GetPrice(CEconomy::PRICE_RAIL_REMOVE, tile, true); |
360 if (flags & DC_EXEC) { |
362 if (flags & DC_EXEC) { |
434 int ey = TileY(end); |
436 int ey = TileY(end); |
435 int dx, dy, trdx, trdy; |
437 int dx, dy, trdx, trdy; |
436 |
438 |
437 if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR; |
439 if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR; |
438 |
440 |
439 // calculate delta x,y from start to end tile |
441 /* calculate delta x,y from start to end tile */ |
440 dx = ex - x; |
442 dx = ex - x; |
441 dy = ey - y; |
443 dy = ey - y; |
442 |
444 |
443 // calculate delta x,y for the first direction |
445 /* calculate delta x,y for the first direction */ |
444 trdx = _trackdelta[*trackdir].x; |
446 trdx = _trackdelta[*trackdir].x; |
445 trdy = _trackdelta[*trackdir].y; |
447 trdy = _trackdelta[*trackdir].y; |
446 |
448 |
447 if (!IsDiagonalTrackdir(*trackdir)) { |
449 if (!IsDiagonalTrackdir(*trackdir)) { |
448 trdx += _trackdelta[*trackdir ^ 1].x; |
450 trdx += _trackdelta[*trackdir ^ 1].x; |
449 trdy += _trackdelta[*trackdir ^ 1].y; |
451 trdy += _trackdelta[*trackdir ^ 1].y; |
450 } |
452 } |
451 |
453 |
452 // validate the direction |
454 /* validate the direction */ |
453 while ( |
455 while ( |
454 (trdx <= 0 && dx > 0) || |
456 (trdx <= 0 && dx > 0) || |
455 (trdx >= 0 && dx < 0) || |
457 (trdx >= 0 && dx < 0) || |
456 (trdy <= 0 && dy > 0) || |
458 (trdy <= 0 && dy > 0) || |
457 (trdy >= 0 && dy < 0) |
459 (trdy >= 0 && dy < 0) |
463 } else { // other direction is invalid too, invalid drag |
465 } else { // other direction is invalid too, invalid drag |
464 return CMD_ERROR; |
466 return CMD_ERROR; |
465 } |
467 } |
466 } |
468 } |
467 |
469 |
468 // (for diagonal tracks, this is already made sure of by above test), but: |
470 /* (for diagonal tracks, this is already made sure of by above test), but: |
469 // for non-diagonal tracks, check if the start and end tile are on 1 line |
471 * for non-diagonal tracks, check if the start and end tile are on 1 line */ |
470 if (!IsDiagonalTrackdir(*trackdir)) { |
472 if (!IsDiagonalTrackdir(*trackdir)) { |
471 trdx = _trackdelta[*trackdir].x; |
473 trdx = _trackdelta[*trackdir].x; |
472 trdy = _trackdelta[*trackdir].y; |
474 trdy = _trackdelta[*trackdir].y; |
473 if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx)) |
475 if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx)) |
474 return CMD_ERROR; |
476 return CMD_ERROR; |
517 |
519 |
518 if (tile == end_tile) break; |
520 if (tile == end_tile) break; |
519 |
521 |
520 tile += ToTileIndexDiff(_trackdelta[trackdir]); |
522 tile += ToTileIndexDiff(_trackdelta[trackdir]); |
521 |
523 |
522 // toggle railbit for the non-diagonal tracks |
524 /* toggle railbit for the non-diagonal tracks */ |
523 if (!IsDiagonalTrackdir(trackdir)) ToggleBitT(trackdir, 0); |
525 if (!IsDiagonalTrackdir(trackdir)) ToggleBitT(trackdir, 0); |
524 } |
526 } |
525 |
527 |
526 return (total_cost == 0) ? CMD_ERROR : total_cost; |
528 return (total_cost == 0) ? CMD_ERROR : total_cost; |
527 } |
529 } |
625 Track track = (Track)GB(p1, 0, 3); |
627 Track track = (Track)GB(p1, 0, 3); |
626 bool pre_signal = HASBIT(p1, 3); |
628 bool pre_signal = HASBIT(p1, 3); |
627 SignalVariant sigvar = (pre_signal ^ HASBIT(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC; |
629 SignalVariant sigvar = (pre_signal ^ HASBIT(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC; |
628 int32 cost; |
630 int32 cost; |
629 |
631 |
630 if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoVehicle(tile)) |
632 if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoVehicleOnGround(tile)) |
631 return CMD_ERROR; |
633 return CMD_ERROR; |
632 |
634 |
633 /* Protect against invalid signal copying */ |
635 /* Protect against invalid signal copying */ |
634 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR; |
636 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR; |
635 |
637 |
651 } |
653 } |
652 |
654 |
653 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
655 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
654 |
656 |
655 if (!HasSignalOnTrack(tile, track)) { |
657 if (!HasSignalOnTrack(tile, track)) { |
656 // build new signals |
658 /* build new signals */ |
657 cost = _eco->GetPrice(CEconomy::BUILD_SIGNALS); |
659 cost = _eco->GetPrice(CEconomy::BUILD_SIGNALS); |
658 } else { |
660 } else { |
659 if (p2 != 0 && sigvar != GetSignalVariant(tile)) { |
661 if (p2 != 0 && sigvar != GetSignalVariant(tile)) { |
660 // convert signals <-> semaphores |
662 /* convert signals <-> semaphores */ |
661 cost = _eco->GetPrice(CEconomy::BUILD_SIGNALS) + _eco->GetPrice(CEconomy::REMOVE_SIGNALS); |
663 cost = _eco->GetPrice(CEconomy::BUILD_SIGNALS) + _eco->GetPrice(CEconomy::REMOVE_SIGNALS); |
662 } else { |
664 } else { |
663 // it is free to change orientation/pre-exit-combo signals |
665 /* it is free to change orientation/pre-exit-combo signals */ |
664 cost = 0; |
666 cost = 0; |
665 } |
667 } |
666 } |
668 } |
667 |
669 |
668 if (flags & DC_EXEC) { |
670 if (flags & DC_EXEC) { |
669 if (!HasSignals(tile)) { |
671 if (!HasSignals(tile)) { |
670 // there are no signals at all on this tile yet |
672 /* there are no signals at all on this tile yet */ |
671 SetHasSignals(tile, true); |
673 SetHasSignals(tile, true); |
672 _m[tile].m2 |= 0xF0; // all signals are on |
674 _m[tile].m2 |= 0xF0; // all signals are on |
673 _m[tile].m3 &= ~0xF0; // no signals built by default |
675 _m[tile].m3 &= ~0xF0; // no signals built by default |
674 SetSignalType(tile, SIGTYPE_NORMAL); |
676 SetSignalType(tile, SIGTYPE_NORMAL); |
675 SetSignalVariant(tile, sigvar); |
677 SetSignalVariant(tile, sigvar); |
676 } |
678 } |
677 |
679 |
678 if (p2 == 0) { |
680 if (p2 == 0) { |
679 if (!HasSignalOnTrack(tile, track)) { |
681 if (!HasSignalOnTrack(tile, track)) { |
680 // build new signals |
682 /* build new signals */ |
681 _m[tile].m3 |= SignalOnTrack(track); |
683 _m[tile].m3 |= SignalOnTrack(track); |
682 } else { |
684 } else { |
683 if (pre_signal) { |
685 if (pre_signal) { |
684 // cycle between normal -> pre -> exit -> combo -> ... |
686 /* cycle between normal -> pre -> exit -> combo -> ... */ |
685 SignalType type = GetSignalType(tile); |
687 SignalType type = GetSignalType(tile); |
686 |
688 |
687 SetSignalType(tile, type == SIGTYPE_COMBO ? SIGTYPE_NORMAL : (SignalType)(type + 1)); |
689 SetSignalType(tile, type == SIGTYPE_COMBO ? SIGTYPE_NORMAL : (SignalType)(type + 1)); |
688 } else { |
690 } else { |
689 CycleSignalSide(tile, track); |
691 CycleSignalSide(tile, track); |
743 |
745 |
744 if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR; |
746 if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR; |
745 |
747 |
746 track = TrackdirToTrack(trackdir); /* trackdir might have changed, keep track in sync */ |
748 track = TrackdirToTrack(trackdir); /* trackdir might have changed, keep track in sync */ |
747 |
749 |
748 // copy the signal-style of the first rail-piece if existing |
750 /* copy the signal-style of the first rail-piece if existing */ |
749 if (HasSignals(tile)) { |
751 if (HasSignals(tile)) { |
750 signals = _m[tile].m3 & SignalOnTrack(track); |
752 signals = _m[tile].m3 & SignalOnTrack(track); |
751 if (signals == 0) signals = SignalOnTrack(track); /* Can this actually occur? */ |
753 if (signals == 0) signals = SignalOnTrack(track); /* Can this actually occur? */ |
752 |
754 |
753 // copy signal/semaphores style (independent of CTRL) |
755 /* copy signal/semaphores style (independent of CTRL) */ |
754 semaphores = GetSignalVariant(tile) != SIG_ELECTRIC; |
756 semaphores = GetSignalVariant(tile) != SIG_ELECTRIC; |
755 } else { // no signals exist, drag a two-way signal stretch |
757 } else { // no signals exist, drag a two-way signal stretch |
756 signals = SignalOnTrack(track); |
758 signals = SignalOnTrack(track); |
757 } |
759 } |
758 |
760 |
764 * signals - is there a signal/semaphore on the first tile, copy its style (two-way/single-way) |
766 * signals - is there a signal/semaphore on the first tile, copy its style (two-way/single-way) |
765 * and convert all others to semaphore/signal |
767 * and convert all others to semaphore/signal |
766 * remove - 1 remove signals, 0 build signals */ |
768 * remove - 1 remove signals, 0 build signals */ |
767 signal_ctr = total_cost = 0; |
769 signal_ctr = total_cost = 0; |
768 for (;;) { |
770 for (;;) { |
769 // only build/remove signals with the specified density |
771 /* only build/remove signals with the specified density */ |
770 if (signal_ctr % signal_density == 0) { |
772 if (signal_ctr % signal_density == 0) { |
771 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3); |
773 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3); |
772 SB(p1, 3, 1, mode); |
774 SB(p1, 3, 1, mode); |
773 SB(p1, 4, 1, semaphores); |
775 SB(p1, 4, 1, semaphores); |
774 ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS); |
776 ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS); |
783 if (tile == end_tile) break; |
785 if (tile == end_tile) break; |
784 |
786 |
785 tile += ToTileIndexDiff(_trackdelta[trackdir]); |
787 tile += ToTileIndexDiff(_trackdelta[trackdir]); |
786 signal_ctr++; |
788 signal_ctr++; |
787 |
789 |
788 // toggle railbit for the non-diagonal tracks (|, -- tracks) |
790 /* toggle railbit for the non-diagonal tracks (|, -- tracks) */ |
789 if (!IsDiagonalTrackdir(trackdir)) ToggleBitT(trackdir, 0); |
791 if (!IsDiagonalTrackdir(trackdir)) ToggleBitT(trackdir, 0); |
790 } |
792 } |
791 |
793 |
792 return error ? CMD_ERROR : total_cost; |
794 return error ? CMD_ERROR : total_cost; |
793 } |
795 } |
812 { |
814 { |
813 Track track = (Track)GB(p1, 0, 3); |
815 Track track = (Track)GB(p1, 0, 3); |
814 |
816 |
815 if (!ValParamTrackOrientation(track) || |
817 if (!ValParamTrackOrientation(track) || |
816 !IsTileType(tile, MP_RAILWAY) || |
818 !IsTileType(tile, MP_RAILWAY) || |
817 !EnsureNoVehicle(tile) || |
819 !EnsureNoVehicleOnGround(tile) || |
818 !HasSignalOnTrack(tile, track)) { |
820 !HasSignalOnTrack(tile, track)) { |
819 return CMD_ERROR; |
821 return CMD_ERROR; |
820 } |
822 } |
821 |
823 |
822 /* Only water can remove signals from anyone */ |
824 /* Only water can remove signals from anyone */ |
869 { |
871 { |
870 if (!CheckTileOwnership(tile)) return CMD_ERROR; |
872 if (!CheckTileOwnership(tile)) return CMD_ERROR; |
871 |
873 |
872 if (GetRailType(tile) == totype) return CMD_ERROR; |
874 if (GetRailType(tile) == totype) return CMD_ERROR; |
873 |
875 |
874 if (!EnsureNoVehicle(tile) && (!IsCompatibleRail(GetRailType(tile), totype) || IsPlainRailTile(tile))) return CMD_ERROR; |
876 if (!EnsureNoVehicleOnGround(tile) && (!IsCompatibleRail(GetRailType(tile), totype) || IsPlainRailTile(tile))) return CMD_ERROR; |
875 |
877 |
876 // 'hidden' elrails can't be downgraded to normal rail when elrails are disabled |
878 /* 'hidden' elrails can't be downgraded to normal rail when elrails are disabled */ |
877 if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR; |
879 if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR; |
878 |
880 |
879 // change type. |
881 /* change type. */ |
880 if (exec) { |
882 if (exec) { |
881 SetRailType(tile, totype); |
883 SetRailType(tile, totype); |
882 MarkTileDirtyByTile(tile); |
884 MarkTileDirtyByTile(tile); |
883 |
885 |
884 // notify YAPF about the track layout change |
886 /* notify YAPF about the track layout change */ |
885 TrackBits tracks = GetTrackBits(tile); |
887 TrackBits tracks = GetTrackBits(tile); |
886 while (tracks != TRACK_BIT_NONE) { |
888 while (tracks != TRACK_BIT_NONE) { |
887 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks)); |
889 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks)); |
888 } |
890 } |
889 |
891 |
925 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
927 SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); |
926 |
928 |
927 if (!ValParamRailtype(p2)) return CMD_ERROR; |
929 if (!ValParamRailtype(p2)) return CMD_ERROR; |
928 if (p1 >= MapSize()) return CMD_ERROR; |
930 if (p1 >= MapSize()) return CMD_ERROR; |
929 |
931 |
930 // make sure sx,sy are smaller than ex,ey |
932 /* make sure sx,sy are smaller than ex,ey */ |
931 ex = TileX(tile); |
933 ex = TileX(tile); |
932 ey = TileY(tile); |
934 ey = TileY(tile); |
933 sx = TileX(p1); |
935 sx = TileX(p1); |
934 sy = TileY(p1); |
936 sy = TileY(p1); |
935 if (ex < sx) Swap(ex, sx); |
937 if (ex < sx) Swap(ex, sx); |
973 static int32 RemoveTrainDepot(TileIndex tile, uint32 flags) |
975 static int32 RemoveTrainDepot(TileIndex tile, uint32 flags) |
974 { |
976 { |
975 if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) |
977 if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) |
976 return CMD_ERROR; |
978 return CMD_ERROR; |
977 |
979 |
978 if (!EnsureNoVehicle(tile)) |
980 if (!EnsureNoVehicleOnGround(tile)) |
979 return CMD_ERROR; |
981 return CMD_ERROR; |
980 |
982 |
981 if (flags & DC_EXEC) { |
983 if (flags & DC_EXEC) { |
982 DiagDirection dir = GetRailDepotDirection(tile); |
984 DiagDirection dir = GetRailDepotDirection(tile); |
983 |
985 |
1190 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); |
1192 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); |
1191 SpriteID image; |
1193 SpriteID image; |
1192 SpriteID pal = PAL_NONE; |
1194 SpriteID pal = PAL_NONE; |
1193 bool junction = false; |
1195 bool junction = false; |
1194 |
1196 |
1195 // Select the sprite to use. |
1197 /* Select the sprite to use. */ |
1196 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) || |
1198 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) || |
1197 (image++, track == TRACK_BIT_X) || |
1199 (image++, track == TRACK_BIT_X) || |
1198 (image++, track == TRACK_BIT_UPPER) || |
1200 (image++, track == TRACK_BIT_UPPER) || |
1199 (image++, track == TRACK_BIT_LOWER) || |
1201 (image++, track == TRACK_BIT_LOWER) || |
1200 (image++, track == TRACK_BIT_RIGHT) || |
1202 (image++, track == TRACK_BIT_RIGHT) || |
1214 if (ti->tileh != SLOPE_FLAT) { |
1216 if (ti->tileh != SLOPE_FLAT) { |
1215 uint foundation = GetRailFoundation(ti->tileh, track); |
1217 uint foundation = GetRailFoundation(ti->tileh, track); |
1216 |
1218 |
1217 if (foundation != 0) DrawFoundation(ti, foundation); |
1219 if (foundation != 0) DrawFoundation(ti, foundation); |
1218 |
1220 |
1219 // DrawFoundation() modifies ti. |
1221 /* DrawFoundation() modifies it. |
1220 // Default sloped sprites.. |
1222 * Default sloped sprites.. */ |
1221 if (ti->tileh != SLOPE_FLAT) |
1223 if (ti->tileh != SLOPE_FLAT) |
1222 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y; |
1224 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y; |
1223 } |
1225 } |
1224 |
1226 |
1225 switch (GetRailGroundType(ti->tile)) { |
1227 switch (GetRailGroundType(ti->tile)) { |
1228 default: break; |
1230 default: break; |
1229 } |
1231 } |
1230 |
1232 |
1231 DrawGroundSprite(image, pal); |
1233 DrawGroundSprite(image, pal); |
1232 |
1234 |
1233 // Draw track pieces individually for junction tiles |
1235 /* Draw track pieces individually for junction tiles */ |
1234 if (junction) { |
1236 if (junction) { |
1235 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE); |
1237 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE); |
1236 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE); |
1238 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE); |
1237 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE); |
1239 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE); |
1238 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE); |
1240 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE); |
1290 |
1292 |
1291 if (_display_opt & DO_FULL_DETAIL) DrawTrackDetails(ti); |
1293 if (_display_opt & DO_FULL_DETAIL) DrawTrackDetails(ti); |
1292 |
1294 |
1293 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails); |
1295 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails); |
1294 } else { |
1296 } else { |
1295 // draw depot/waypoint |
1297 /* draw depot/waypoint */ |
1296 const DrawTileSprites* dts; |
1298 const DrawTileSprites* dts; |
1297 const DrawTileSeqStruct* dtss; |
1299 const DrawTileSeqStruct* dtss; |
1298 uint32 relocation; |
1300 uint32 relocation; |
1299 |
1301 |
1300 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh); |
1302 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, ti->tileh); |
1305 relocation = rti->total_offset; |
1307 relocation = rti->total_offset; |
1306 |
1308 |
1307 image = dts->ground_sprite; |
1309 image = dts->ground_sprite; |
1308 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset; |
1310 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset; |
1309 |
1311 |
1310 // adjust ground tile for desert |
1312 /* adjust ground tile for desert |
1311 // don't adjust for snow, because snow in depots looks weird |
1313 * don't adjust for snow, because snow in depots looks weird */ |
1312 if (IsSnowRailGround(ti->tile) && _opt.landscape == LT_TROPIC) { |
1314 if (IsSnowRailGround(ti->tile) && _opt.landscape == LT_TROPIC) { |
1313 if (image != SPR_FLAT_GRASS_TILE) { |
1315 if (image != SPR_FLAT_GRASS_TILE) { |
1314 image += rti->snow_offset; // tile with tracks |
1316 image += rti->snow_offset; // tile with tracks |
1315 } else { |
1317 } else { |
1316 image = SPR_FLAT_SNOWY_TILE; // flat ground |
1318 image = SPR_FLAT_SNOWY_TILE; // flat ground |
1317 } |
1319 } |
1318 } |
1320 } |
1319 } else { |
1321 } else { |
1320 // look for customization |
1322 /* look for customization */ |
1321 byte stat_id = GetWaypointByTile(ti->tile)->stat_id; |
1323 byte stat_id = GetWaypointByTile(ti->tile)->stat_id; |
1322 const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, stat_id); |
1324 const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, stat_id); |
1323 |
1325 |
1324 if (statspec != NULL) { |
1326 if (statspec != NULL) { |
1325 // emulate station tile - open with building |
1327 /* emulate station tile - open with building */ |
1326 const Station* st = ComposeWaypointStation(ti->tile); |
1328 const Station* st = ComposeWaypointStation(ti->tile); |
1327 uint gfx = 2; |
1329 uint gfx = 2; |
1328 |
1330 |
1329 if (HASBIT(statspec->callbackmask, CBM_CUSTOM_LAYOUT)) { |
1331 if (HASBIT(statspec->callbackmask, CBM_CUSTOM_LAYOUT)) { |
1330 uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile); |
1332 uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile); |
1350 } else { |
1352 } else { |
1351 goto default_waypoint; |
1353 goto default_waypoint; |
1352 } |
1354 } |
1353 } else { |
1355 } else { |
1354 default_waypoint: |
1356 default_waypoint: |
1355 // There is no custom layout, fall back to the default graphics |
1357 /* There is no custom layout, fall back to the default graphics */ |
1356 dts = &_waypoint_gfx_table[GetWaypointAxis(ti->tile)]; |
1358 dts = &_waypoint_gfx_table[GetWaypointAxis(ti->tile)]; |
1357 relocation = 0; |
1359 relocation = 0; |
1358 image = dts->ground_sprite + rti->total_offset; |
1360 image = dts->ground_sprite + rti->total_offset; |
1359 if (IsSnowRailGround(ti->tile)) image += rti->snow_offset; |
1361 if (IsSnowRailGround(ti->tile)) image += rti->snow_offset; |
1360 } |
1362 } |
1375 image += rti->total_offset; |
1377 image += rti->total_offset; |
1376 } else { |
1378 } else { |
1377 image += relocation; |
1379 image += relocation; |
1378 } |
1380 } |
1379 |
1381 |
1380 if (_display_opt & DO_TRANS_BUILDINGS) { |
1382 if (HASBIT(_transparent_opt, TO_BUILDINGS)) { |
1381 SETBIT(image, PALETTE_MODIFIER_TRANSPARENT); |
1383 SETBIT(image, PALETTE_MODIFIER_TRANSPARENT); |
1382 pal = PALETTE_TO_TRANSPARENT; |
1384 pal = PALETTE_TO_TRANSPARENT; |
1383 } else if (HASBIT(image, PALETTE_MODIFIER_COLOR)) { |
1385 } else if (HASBIT(image, PALETTE_MODIFIER_COLOR)) { |
1384 pal = _drawtile_track_palette; |
1386 pal = _drawtile_track_palette; |
1385 } else { |
1387 } else { |
1437 int cur; |
1439 int cur; |
1438 int cur_stack; |
1440 int cur_stack; |
1439 bool stop; |
1441 bool stop; |
1440 bool has_presignal; |
1442 bool has_presignal; |
1441 |
1443 |
1442 // presignal info |
1444 /* presignal info */ |
1443 int presignal_exits; |
1445 int presignal_exits; |
1444 int presignal_exits_free; |
1446 int presignal_exits_free; |
1445 |
1447 |
1446 // these are used to keep track of the signals that change. |
1448 /* these are used to keep track of the signals that change. */ |
1447 TrackdirByte bit[NUM_SSD_ENTRY]; |
1449 TrackdirByte bit[NUM_SSD_ENTRY]; |
1448 TileIndex tile[NUM_SSD_ENTRY]; |
1450 TileIndex tile[NUM_SSD_ENTRY]; |
1449 |
1451 |
1450 // these are used to keep track of the stack that modifies presignals recursively |
1452 /* these are used to keep track of the stack that modifies presignals recursively */ |
1451 TileIndex next_tile[NUM_SSD_STACK]; |
1453 TileIndex next_tile[NUM_SSD_STACK]; |
1452 DiagDirectionByte next_dir[NUM_SSD_STACK]; |
1454 DiagDirectionByte next_dir[NUM_SSD_STACK]; |
1453 |
1455 |
1454 }; |
1456 }; |
1455 |
1457 |
1457 { |
1459 { |
1458 SetSignalsData* ssd = (SetSignalsData*)data; |
1460 SetSignalsData* ssd = (SetSignalsData*)data; |
1459 |
1461 |
1460 if (!IsTileType(tile, MP_RAILWAY)) return false; |
1462 if (!IsTileType(tile, MP_RAILWAY)) return false; |
1461 |
1463 |
1462 // the tile has signals? |
1464 /* the tile has signals? */ |
1463 if (HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) { |
1465 if (HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) { |
1464 if (HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir))) { |
1466 if (HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir))) { |
1465 // yes, add the signal to the list of signals |
1467 /* yes, add the signal to the list of signals */ |
1466 if (ssd->cur != NUM_SSD_ENTRY) { |
1468 if (ssd->cur != NUM_SSD_ENTRY) { |
1467 ssd->tile[ssd->cur] = tile; // remember the tile index |
1469 ssd->tile[ssd->cur] = tile; // remember the tile index |
1468 ssd->bit[ssd->cur] = trackdir; // and the controlling bit number |
1470 ssd->bit[ssd->cur] = trackdir; // and the controlling bit number |
1469 ssd->cur++; |
1471 ssd->cur++; |
1470 } |
1472 } |
1471 |
1473 |
1472 // remember if this block has a presignal. |
1474 /* remember if this block has a presignal. */ |
1473 ssd->has_presignal |= IsPresignalEntry(tile); |
1475 ssd->has_presignal |= IsPresignalEntry(tile); |
1474 } |
1476 } |
1475 |
1477 |
1476 if (HasSignalOnTrackdir(tile, trackdir) && IsPresignalExit(tile)) { |
1478 if (HasSignalOnTrackdir(tile, trackdir) && IsPresignalExit(tile)) { |
1477 // this is an exit signal that points out from the segment |
1479 /* this is an exit signal that points out from the segment */ |
1478 ssd->presignal_exits++; |
1480 ssd->presignal_exits++; |
1479 if (GetSignalStateByTrackdir(tile, trackdir) != SIGNAL_STATE_RED) |
1481 if (GetSignalStateByTrackdir(tile, trackdir) != SIGNAL_STATE_RED) |
1480 ssd->presignal_exits_free++; |
1482 ssd->presignal_exits_free++; |
1481 } |
1483 } |
1482 |
1484 |
1530 direction = GetBridgeRampDirection(tile); |
1532 direction = GetBridgeRampDirection(tile); |
1531 } |
1533 } |
1532 |
1534 |
1533 dest.track = 1 << (direction & 1); // get the trackbit the vehicle would have if it has not entered the tunnel yet (ie is still visible) |
1535 dest.track = 1 << (direction & 1); // get the trackbit the vehicle would have if it has not entered the tunnel yet (ie is still visible) |
1534 |
1536 |
1535 // check for a vehicle with that trackdir on the start tile of the tunnel |
1537 /* check for a vehicle with that trackdir on the start tile of the tunnel */ |
1536 if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL) return true; |
1538 if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL) return true; |
1537 |
1539 |
1538 // check for a vehicle with that trackdir on the end tile of the tunnel |
1540 /* check for a vehicle with that trackdir on the end tile of the tunnel */ |
1539 if (VehicleFromPos(end, &dest, SignalVehicleCheckProc) != NULL) return true; |
1541 if (VehicleFromPos(end, &dest, SignalVehicleCheckProc) != NULL) return true; |
1540 |
1542 |
1541 // now check all tiles from start to end for a warping vehicle |
1543 /* now check all tiles from start to end for a warping vehicle |
1542 // NOTE: the hashes for tiles may overlap, so this could maybe be optimised a bit by not checking every tile? |
1544 * NOTE: the hashes for tiles may overlap, so this could maybe be optimised a bit by not checking every tile? */ |
1543 dest.track = 0x40; //Vehicle inside a tunnel or on a bridge |
1545 dest.track = 0x40; //Vehicle inside a tunnel or on a bridge |
1544 for (; tile != end; tile += TileOffsByDiagDir(direction)) { |
1546 for (; tile != end; tile += TileOffsByDiagDir(direction)) { |
1545 if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL) |
1547 if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL) |
1546 return true; |
1548 return true; |
1547 } |
1549 } |
1548 |
1550 |
1549 // no vehicle found |
1551 /* no vehicle found */ |
1550 return false; |
1552 return false; |
1551 } |
1553 } |
1552 |
1554 |
1553 return VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL; |
1555 return VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL; |
1554 } |
1556 } |
1599 |
1601 |
1600 static void ChangeSignalStates(SetSignalsData *ssd) |
1602 static void ChangeSignalStates(SetSignalsData *ssd) |
1601 { |
1603 { |
1602 int i; |
1604 int i; |
1603 |
1605 |
1604 // thinking about presignals... |
1606 /* thinking about presignals... |
1605 // the presignal is green if, |
1607 * the presignal is green if, |
1606 // if no train is in the segment AND |
1608 * if no train is in the segment AND |
1607 // there is at least one green exit signal OR |
1609 * there is at least one green exit signal OR |
1608 // there are no exit signals in the segment |
1610 * there are no exit signals in the segment */ |
1609 |
1611 |
1610 // then mark the signals in the segment accordingly |
1612 /* then mark the signals in the segment accordingly */ |
1611 for (i = 0; i != ssd->cur; i++) { |
1613 for (i = 0; i != ssd->cur; i++) { |
1612 TileIndex tile = ssd->tile[i]; |
1614 TileIndex tile = ssd->tile[i]; |
1613 byte bit = SignalAgainstTrackdir(ssd->bit[i]); |
1615 byte bit = SignalAgainstTrackdir(ssd->bit[i]); |
1614 uint16 m2 = _m[tile].m2; |
1616 uint16 m2 = _m[tile].m2; |
1615 |
1617 |
1616 // presignals don't turn green if there is at least one presignal exit and none are free |
1618 /* presignals don't turn green if there is at least one presignal exit and none are free */ |
1617 if (IsPresignalEntry(tile)) { |
1619 if (IsPresignalEntry(tile)) { |
1618 int ex = ssd->presignal_exits, exfree = ssd->presignal_exits_free; |
1620 int ex = ssd->presignal_exits, exfree = ssd->presignal_exits_free; |
1619 |
1621 |
1620 // subtract for dual combo signals so they don't count themselves |
1622 /* subtract for dual combo signals so they don't count themselves */ |
1621 if (IsPresignalExit(tile) && HasSignalOnTrackdir(tile, ssd->bit[i])) { |
1623 if (IsPresignalExit(tile) && HasSignalOnTrackdir(tile, ssd->bit[i])) { |
1622 ex--; |
1624 ex--; |
1623 if (GetSignalStateByTrackdir(tile, ssd->bit[i]) != SIGNAL_STATE_RED) exfree--; |
1625 if (GetSignalStateByTrackdir(tile, ssd->bit[i]) != SIGNAL_STATE_RED) exfree--; |
1624 } |
1626 } |
1625 |
1627 |
1626 // if we have exits and none are free, make red. |
1628 /* if we have exits and none are free, make red. */ |
1627 if (ex && !exfree) goto make_red; |
1629 if (ex && !exfree) goto make_red; |
1628 } |
1630 } |
1629 |
1631 |
1630 // check if the signal is unaffected. |
1632 /* check if the signal is unaffected. */ |
1631 if (ssd->stop) { |
1633 if (ssd->stop) { |
1632 make_red: |
1634 make_red: |
1633 // turn red |
1635 /* turn red */ |
1634 if ((bit & m2) == 0) continue; |
1636 if ((bit & m2) == 0) continue; |
1635 } else { |
1637 } else { |
1636 // turn green |
1638 /* turn green */ |
1637 if ((bit & m2) != 0) continue; |
1639 if ((bit & m2) != 0) continue; |
1638 } |
1640 } |
1639 |
1641 |
1640 /* Update signals on the other side of this exit-combo signal; it changed. */ |
1642 /* Update signals on the other side of this exit-combo signal; it changed. */ |
1641 if (IsPresignalExit(tile)) { |
1643 if (IsPresignalExit(tile)) { |
1661 int result = -1; |
1663 int result = -1; |
1662 |
1664 |
1663 ssd.cur_stack = 0; |
1665 ssd.cur_stack = 0; |
1664 |
1666 |
1665 for (;;) { |
1667 for (;;) { |
1666 // go through one segment and update all signals pointing into that segment. |
1668 /* go through one segment and update all signals pointing into that segment. */ |
1667 ssd.cur = ssd.presignal_exits = ssd.presignal_exits_free = 0; |
1669 ssd.cur = ssd.presignal_exits = ssd.presignal_exits_free = 0; |
1668 ssd.has_presignal = false; |
1670 ssd.has_presignal = false; |
1669 |
1671 |
1670 FollowTrack(tile, 0xC000 | TRANSPORT_RAIL, direction, SetSignalsEnumProc, SetSignalsAfterProc, &ssd); |
1672 FollowTrack(tile, 0xC000 | TRANSPORT_RAIL, direction, SetSignalsEnumProc, SetSignalsAfterProc, &ssd); |
1671 ChangeSignalStates(&ssd); |
1673 ChangeSignalStates(&ssd); |
1672 |
1674 |
1673 // remember the result only for the first iteration. |
1675 /* remember the result only for the first iteration. */ |
1674 if (result < 0) { |
1676 if (result < 0) { |
1675 // stay in depot while segment is occupied or while all presignal exits are blocked |
1677 /* stay in depot while segment is occupied or while all presignal exits are blocked */ |
1676 result = ssd.stop || (ssd.presignal_exits > 0 && ssd.presignal_exits_free == 0); |
1678 result = ssd.stop || (ssd.presignal_exits > 0 && ssd.presignal_exits_free == 0); |
1677 } |
1679 } |
1678 |
1680 |
1679 // if any exit signals were changed, we need to keep going to modify the stuff behind those. |
1681 /* if any exit signals were changed, we need to keep going to modify the stuff behind those. */ |
1680 if (ssd.cur_stack == 0) break; |
1682 if (ssd.cur_stack == 0) break; |
1681 |
1683 |
1682 // one or more exit signals were changed, so we need to update another segment too. |
1684 /* one or more exit signals were changed, so we need to update another segment too. */ |
1683 tile = ssd.next_tile[--ssd.cur_stack]; |
1685 tile = ssd.next_tile[--ssd.cur_stack]; |
1684 direction = ssd.next_dir[ssd.cur_stack]; |
1686 direction = ssd.next_dir[ssd.cur_stack]; |
1685 } |
1687 } |
1686 |
1688 |
1687 return result != 0; |
1689 return result != 0; |
1770 |
1772 |
1771 if (!IsPlainRailTile(tile)) return; |
1773 if (!IsPlainRailTile(tile)) return; |
1772 |
1774 |
1773 new_ground = RAIL_GROUND_GRASS; |
1775 new_ground = RAIL_GROUND_GRASS; |
1774 |
1776 |
1775 if (old_ground != RAIL_GROUND_BARREN) { /* wait until bottom is green */ |
1777 if (old_ground != RAIL_GROUND_BARREN) { // wait until bottom is green |
1776 /* determine direction of fence */ |
1778 /* determine direction of fence */ |
1777 TrackBits rail = GetTrackBits(tile); |
1779 TrackBits rail = GetTrackBits(tile); |
1778 |
1780 |
1779 switch (rail) { |
1781 switch (rail) { |
1780 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break; |
1782 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break; |
1964 byte fract_coord; |
1966 byte fract_coord; |
1965 byte fract_coord_leave; |
1967 byte fract_coord_leave; |
1966 DiagDirection dir; |
1968 DiagDirection dir; |
1967 int length; |
1969 int length; |
1968 |
1970 |
1969 // this routine applies only to trains in depot tiles |
1971 /* this routine applies only to trains in depot tiles */ |
1970 if (v->type != VEH_TRAIN || !IsTileDepotType(tile, TRANSPORT_RAIL)) return VETSB_CONTINUE; |
1972 if (v->type != VEH_TRAIN || !IsTileDepotType(tile, TRANSPORT_RAIL)) return VETSB_CONTINUE; |
1971 |
1973 |
1972 /* depot direction */ |
1974 /* depot direction */ |
1973 dir = GetRailDepotDirection(tile); |
1975 dir = GetRailDepotDirection(tile); |
1974 |
1976 |