51 #include "table/strings.h" |
51 #include "table/strings.h" |
52 #include "table/train_cmd.h" |
52 #include "table/train_cmd.h" |
53 |
53 |
54 static bool TrainCheckIfLineEnds(Vehicle *v); |
54 static bool TrainCheckIfLineEnds(Vehicle *v); |
55 static void TrainController(Vehicle *v, bool update_image); |
55 static void TrainController(Vehicle *v, bool update_image); |
|
56 static TileIndex TrainApproachingCrossingTile(const Vehicle *v); |
56 |
57 |
57 static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8}; |
58 static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8}; |
58 static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10}; |
59 static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10}; |
59 |
60 |
60 |
61 |
1622 |
1623 |
1623 /* Update train's power incase tiles were different rail type */ |
1624 /* Update train's power incase tiles were different rail type */ |
1624 TrainPowerChanged(v); |
1625 TrainPowerChanged(v); |
1625 } |
1626 } |
1626 |
1627 |
1627 /* Check if the vehicle is a train and is on the tile we are testing */ |
1628 |
1628 static void *TestTrainOnCrossing(Vehicle *v, void *data) |
1629 /** |
1629 { |
1630 * Check if the vehicle is a train |
1630 if (v->type != VEH_TRAIN) return NULL; |
1631 * @param v vehicle on tile |
|
1632 * @return v if it is a train, NULL otherwise |
|
1633 */ |
|
1634 static void *TrainOnTileEnum(Vehicle *v, void *) |
|
1635 { |
|
1636 return (v->type == VEH_TRAIN) ? v : NULL; |
|
1637 } |
|
1638 |
|
1639 |
|
1640 /** |
|
1641 * Checks if a train is approaching a rail-road crossing |
|
1642 * @param v vehicle on tile |
|
1643 * @param data tile with crossing we are testing |
|
1644 * @return v if it is approaching a crossing, NULL otherwise |
|
1645 */ |
|
1646 static void *TrainApproachingCrossingEnum(Vehicle *v, void *data) |
|
1647 { |
|
1648 /* not a train || not front engine || crashed */ |
|
1649 if (v->type != VEH_TRAIN || !IsFrontEngine(v) || v->vehstatus & VS_CRASHED) return NULL; |
|
1650 |
|
1651 TileIndex tile = *(TileIndex*)data; |
|
1652 |
|
1653 if (TrainApproachingCrossingTile(v) != tile) return NULL; |
|
1654 |
1631 return v; |
1655 return v; |
1632 } |
1656 } |
1633 |
1657 |
1634 static void DisableTrainCrossing(TileIndex tile) |
1658 |
1635 { |
1659 /** |
1636 if (IsLevelCrossingTile(tile) && |
1660 * Finds a vehicle approaching rail-road crossing |
1637 IsCrossingBarred(tile) && |
1661 * @param tile tile to test |
1638 VehicleFromPos(tile, NULL, &TestTrainOnCrossing) == NULL) { // empty? |
1662 * @return pointer to vehicle approaching the crossing |
1639 UnbarCrossing(tile); |
1663 * @pre tile is a rail-road crossing |
1640 MarkTileDirtyByTile(tile); |
1664 */ |
1641 } |
1665 static Vehicle *TrainApproachingCrossing(TileIndex tile) |
1642 } |
1666 { |
|
1667 assert(IsLevelCrossingTile(tile)); |
|
1668 |
|
1669 DiagDirection dir = AxisToDiagDir(OtherAxis(GetCrossingRoadAxis(tile))); |
|
1670 TileIndex tile_from = tile + TileOffsByDiagDir(dir); |
|
1671 |
|
1672 Vehicle *v = (Vehicle *)VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum); |
|
1673 |
|
1674 if (v != NULL) return v; |
|
1675 |
|
1676 dir = ReverseDiagDir(dir); |
|
1677 tile_from = tile + TileOffsByDiagDir(dir); |
|
1678 |
|
1679 return (Vehicle *)VehicleFromPos(tile_from, &tile, &TrainApproachingCrossingEnum); |
|
1680 } |
|
1681 |
|
1682 |
|
1683 /** |
|
1684 * Sets correct crossing state |
|
1685 * @param tile tile to update |
|
1686 * @pre tile is a rail-road crossing |
|
1687 */ |
|
1688 void UpdateTrainCrossing(TileIndex tile) |
|
1689 { |
|
1690 assert(IsLevelCrossingTile(tile)); |
|
1691 |
|
1692 UnbarCrossing(tile); |
|
1693 |
|
1694 /* train on crossing || train approaching crossing */ |
|
1695 if (VehicleFromPos(tile, NULL, &TrainOnTileEnum) || TrainApproachingCrossing(tile)) { |
|
1696 BarCrossing(tile); |
|
1697 } |
|
1698 |
|
1699 MarkTileDirtyByTile(tile); |
|
1700 } |
|
1701 |
1643 |
1702 |
1644 /** |
1703 /** |
1645 * Advances wagons for train reversing, needed for variable length wagons. |
1704 * Advances wagons for train reversing, needed for variable length wagons. |
1646 * Needs to be called once before the train is reversed, and once after it. |
1705 * Needs to be called once before the train is reversed, and once after it. |
1647 * @param v First vehicle in chain |
1706 * @param v First vehicle in chain |
1686 if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) { |
1745 if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) { |
1687 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
1746 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); |
1688 } |
1747 } |
1689 |
1748 |
1690 /* Check if we were approaching a rail/road-crossing */ |
1749 /* Check if we were approaching a rail/road-crossing */ |
1691 { |
1750 TileIndex crossing = TrainApproachingCrossingTile(v); |
1692 /* Determine the diagonal direction in which we will exit this tile */ |
|
1693 DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); |
|
1694 /* Calculate next tile */ |
|
1695 TileIndex tile = v->tile + TileOffsByDiagDir(dir); |
|
1696 /* Check if the train left a rail/road-crossing */ |
|
1697 DisableTrainCrossing(tile); |
|
1698 } |
|
1699 |
1751 |
1700 /* count number of vehicles */ |
1752 /* count number of vehicles */ |
1701 int r = 0; ///< number of vehicles - 1 |
1753 int r = 0; ///< number of vehicles - 1 |
1702 for (const Vehicle *u = v; (u = u->Next()) != NULL;) { r++; } |
1754 for (const Vehicle *u = v; (u = u->Next()) != NULL;) { r++; } |
1703 |
1755 |
1717 |
1769 |
1718 /* update all images */ |
1770 /* update all images */ |
1719 for (Vehicle *u = v; u != NULL; u = u->Next()) { u->cur_image = u->GetImage(u->direction); } |
1771 for (Vehicle *u = v; u != NULL; u = u->Next()) { u->cur_image = u->GetImage(u->direction); } |
1720 |
1772 |
1721 ClrBit(v->u.rail.flags, VRF_REVERSING); |
1773 ClrBit(v->u.rail.flags, VRF_REVERSING); |
|
1774 |
|
1775 /* update crossing we were approaching */ |
|
1776 if (crossing != INVALID_TILE) UpdateTrainCrossing(crossing); |
|
1777 |
|
1778 /* maybe we are approaching crossing now, after reversal */ |
|
1779 crossing = TrainApproachingCrossingTile(v); |
|
1780 if (crossing != INVALID_TILE) UpdateTrainCrossing(crossing); |
1722 } |
1781 } |
1723 |
1782 |
1724 /** Reverse train. |
1783 /** Reverse train. |
1725 * @param tile unused |
1784 * @param tile unused |
1726 * @param flags type of operation |
1785 * @param flags type of operation |
2775 |
2834 |
2776 static void SetVehicleCrashed(Vehicle *v) |
2835 static void SetVehicleCrashed(Vehicle *v) |
2777 { |
2836 { |
2778 if (v->u.rail.crash_anim_pos != 0) return; |
2837 if (v->u.rail.crash_anim_pos != 0) return; |
2779 |
2838 |
|
2839 /* we may need to update crossing we were approaching */ |
|
2840 TileIndex crossing = TrainApproachingCrossingTile(v); |
|
2841 |
2780 v->u.rail.crash_anim_pos++; |
2842 v->u.rail.crash_anim_pos++; |
2781 |
2843 |
2782 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2844 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
2783 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
2845 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
2784 |
2846 |
2897 Vehicle *prev; |
2962 Vehicle *prev; |
2898 |
2963 |
2899 /* For every vehicle after and including the given vehicle */ |
2964 /* For every vehicle after and including the given vehicle */ |
2900 for (prev = v->Previous(); v != NULL; prev = v, v = v->Next()) { |
2965 for (prev = v->Previous(); v != NULL; prev = v, v = v->Next()) { |
2901 DiagDirection enterdir = DIAGDIR_BEGIN; |
2966 DiagDirection enterdir = DIAGDIR_BEGIN; |
2902 bool update_signals = false; |
2967 bool update_signals_crossing = false; // will we update signals or crossing state? |
2903 BeginVehicleMove(v); |
2968 BeginVehicleMove(v); |
2904 |
2969 |
2905 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
2970 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
2906 if (v->u.rail.track != TRACK_BIT_WORMHOLE) { |
2971 if (v->u.rail.track != TRACK_BIT_WORMHOLE) { |
2907 /* Not inside tunnel */ |
2972 /* Not inside tunnel */ |
3020 uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
3085 uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
3021 if (HasBit(r, VETS_CANNOT_ENTER)) { |
3086 if (HasBit(r, VETS_CANNOT_ENTER)) { |
3022 goto invalid_rail; |
3087 goto invalid_rail; |
3023 } |
3088 } |
3024 |
3089 |
3025 if (IsLevelCrossingTile(v->tile) && v->Next() == NULL) { |
|
3026 UnbarCrossing(v->tile); |
|
3027 MarkTileDirtyByTile(v->tile); |
|
3028 } |
|
3029 |
|
3030 if (IsFrontEngine(v)) v->load_unload_time_rem = 0; |
3090 if (IsFrontEngine(v)) v->load_unload_time_rem = 0; |
3031 |
3091 |
3032 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { |
3092 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { |
3033 v->tile = gp.new_tile; |
3093 v->tile = gp.new_tile; |
3034 |
3094 |
3040 assert(v->u.rail.track); |
3100 assert(v->u.rail.track); |
3041 } |
3101 } |
3042 |
3102 |
3043 /* We need to update signal status, but after the vehicle position hash |
3103 /* We need to update signal status, but after the vehicle position hash |
3044 * has been updated by AfterSetTrainPos() */ |
3104 * has been updated by AfterSetTrainPos() */ |
3045 update_signals = true; |
3105 update_signals_crossing = true; |
3046 |
3106 |
3047 if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir); |
3107 if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir); |
3048 |
3108 |
3049 v->direction = chosen_dir; |
3109 v->direction = chosen_dir; |
3050 } |
3110 } |
3079 if (prev == NULL) { |
3139 if (prev == NULL) { |
3080 /* This is the first vehicle in the train */ |
3140 /* This is the first vehicle in the train */ |
3081 AffectSpeedByZChange(v, old_z); |
3141 AffectSpeedByZChange(v, old_z); |
3082 } |
3142 } |
3083 |
3143 |
3084 if (update_signals) { |
3144 if (update_signals_crossing) { |
3085 if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir); |
3145 if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir); |
3086 |
3146 |
3087 /* Signals can only change when the first |
3147 /* Signals can only change when the first |
3088 * (above) or the last vehicle moves. */ |
3148 * (above) or the last vehicle moves. */ |
3089 if (v->Next() == NULL) TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); |
3149 if (v->Next() == NULL) { |
|
3150 TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); |
|
3151 if (IsLevelCrossingTile(gp.old_tile)) UpdateTrainCrossing(gp.old_tile); |
|
3152 } |
3090 } |
3153 } |
3091 } |
3154 } |
3092 return; |
3155 return; |
3093 |
3156 |
3094 invalid_rail: |
3157 invalid_rail: |
3145 Owner owner = v->owner; |
3208 Owner owner = v->owner; |
3146 |
3209 |
3147 delete v; |
3210 delete v; |
3148 v = NULL; // make sure nobody will won't try to read 'v' anymore |
3211 v = NULL; // make sure nobody will won't try to read 'v' anymore |
3149 |
3212 |
3150 /* Check if the wagon was on a road/rail-crossing and disable it if no |
3213 /* check if the wagon was on a road/rail-crossing */ |
3151 * others are on it */ |
3214 if (IsLevelCrossingTile(tile)) UpdateTrainCrossing(tile); |
3152 DisableTrainCrossing(tile); |
|
3153 |
3215 |
3154 /* Update signals */ |
3216 /* Update signals */ |
3155 if (IsTileType(tile, MP_TUNNELBRIDGE) || IsTileDepotType(tile, TRANSPORT_RAIL)) { |
3217 if (IsTileType(tile, MP_TUNNELBRIDGE) || IsTileDepotType(tile, TRANSPORT_RAIL)) { |
3156 UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner); |
3218 UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner); |
3157 } else { |
3219 } else { |
3294 return true; |
3356 return true; |
3295 } |
3357 } |
3296 |
3358 |
3297 |
3359 |
3298 /** |
3360 /** |
|
3361 * Determines whether train would like to leave the tile |
|
3362 * @param v train to test |
|
3363 * @return true iff vehicle is NOT entering or inside a depot or tunnel/bridge |
|
3364 */ |
|
3365 static bool TrainCanLeaveTile(const Vehicle *v) |
|
3366 { |
|
3367 /* Exit if inside a tunnel/bridge or a depot */ |
|
3368 if (v->u.rail.track == TRACK_BIT_WORMHOLE || v->u.rail.track == TRACK_BIT_DEPOT) return false; |
|
3369 |
|
3370 TileIndex tile = v->tile; |
|
3371 |
|
3372 /* entering a tunnel/bridge? */ |
|
3373 if (IsTileType(tile, MP_TUNNELBRIDGE)) { |
|
3374 DiagDirection dir = GetTunnelBridgeDirection(tile); |
|
3375 if (DiagDirToDir(dir) == v->direction) return false; |
|
3376 } |
|
3377 |
|
3378 /* entering a depot? */ |
|
3379 if (IsTileDepotType(tile, TRANSPORT_RAIL)) { |
|
3380 DiagDirection dir = ReverseDiagDir(GetRailDepotDirection(tile)); |
|
3381 if (DiagDirToDir(dir) == v->direction) return false; |
|
3382 } |
|
3383 |
|
3384 return true; |
|
3385 } |
|
3386 |
|
3387 |
|
3388 /** |
|
3389 * Determines whether train is approaching a rail-road crossing |
|
3390 * (thus making it barred) |
|
3391 * @param v front engine of train |
|
3392 * @return TileIndex of crossing the train is approaching, else INVALID_TILE |
|
3393 * @pre v in non-crashed front engine |
|
3394 */ |
|
3395 static TileIndex TrainApproachingCrossingTile(const Vehicle *v) |
|
3396 { |
|
3397 assert(IsFrontEngine(v)); |
|
3398 assert(!(v->vehstatus & VS_CRASHED)); |
|
3399 |
|
3400 if (!TrainCanLeaveTile(v)) return INVALID_TILE; |
|
3401 |
|
3402 DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); |
|
3403 TileIndex tile = v->tile + TileOffsByDiagDir(dir); |
|
3404 |
|
3405 /* not a crossing || wrong axis || wrong railtype || wrong owner */ |
|
3406 if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) || |
|
3407 !CheckCompatibleRail(v, tile) || GetTileOwner(tile) != v->owner) { |
|
3408 return INVALID_TILE; |
|
3409 } |
|
3410 |
|
3411 return tile; |
|
3412 } |
|
3413 |
|
3414 |
|
3415 /** |
3299 * Checks for line end. Also, bars crossing at next tile if needed |
3416 * Checks for line end. Also, bars crossing at next tile if needed |
3300 * |
3417 * |
3301 * @param v vehicle we are checking |
3418 * @param v vehicle we are checking |
3302 * @return true iff we did NOT have to reverse |
3419 * @return true iff we did NOT have to reverse |
3303 */ |
3420 */ |
3313 if (break_speed < v->cur_speed) v->cur_speed = break_speed; |
3430 if (break_speed < v->cur_speed) v->cur_speed = break_speed; |
3314 } else { |
3431 } else { |
3315 v->vehstatus &= ~VS_TRAIN_SLOWING; |
3432 v->vehstatus &= ~VS_TRAIN_SLOWING; |
3316 } |
3433 } |
3317 |
3434 |
3318 /* Exit if inside a tunnel/bridge or a depot */ |
3435 if (!TrainCanLeaveTile(v)) return true; |
3319 if (v->u.rail.track == TRACK_BIT_WORMHOLE || v->u.rail.track == TRACK_BIT_DEPOT) return true; |
|
3320 |
|
3321 TileIndex tile = v->tile; |
|
3322 |
|
3323 /* entering a tunnel/bridge? */ |
|
3324 if (IsTileType(tile, MP_TUNNELBRIDGE)) { |
|
3325 DiagDirection dir = GetTunnelBridgeDirection(tile); |
|
3326 if (DiagDirToDir(dir) == v->direction) return true; |
|
3327 } |
|
3328 |
|
3329 /* entering a depot? */ |
|
3330 if (IsTileDepotType(tile, TRANSPORT_RAIL)) { |
|
3331 DiagDirection dir = ReverseDiagDir(GetRailDepotDirection(tile)); |
|
3332 if (DiagDirToDir(dir) == v->direction) return true; |
|
3333 } |
|
3334 |
3436 |
3335 /* Determine the non-diagonal direction in which we will exit this tile */ |
3437 /* Determine the non-diagonal direction in which we will exit this tile */ |
3336 DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); |
3438 DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track); |
3337 /* Calculate next tile */ |
3439 /* Calculate next tile */ |
3338 tile += TileOffsByDiagDir(dir); |
3440 TileIndex tile = v->tile + TileOffsByDiagDir(dir); |
3339 |
3441 |
3340 /* Determine the track status on the next tile */ |
3442 /* Determine the track status on the next tile */ |
3341 uint32 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _reachable_tracks[dir]; |
3443 uint32 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _reachable_tracks[dir]; |
3342 |
3444 |
3343 /* We are sure the train is not entering a depot, it is detected above */ |
3445 /* We are sure the train is not entering a depot, it is detected above */ |