diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp index 2682fb04db..7a47e20ba1 100644 --- a/src/ground_vehicle.hpp +++ b/src/ground_vehicle.hpp @@ -13,6 +13,7 @@ #define GROUND_VEHICLE_HPP #include "vehicle_base.h" +#include "landscape.h" /** What is the status of our acceleration? */ enum AccelStatus { @@ -60,6 +61,7 @@ enum GroundVehicleFlags { * virtual int32 GetSlopeSteepness() const = 0; * virtual uint16 GetInitialMaxSpeed() const = 0; * virtual uint16 GetMaxTrackSpeed() const = 0; + * virtual bool TileMayHaveSlopedTrack() const = 0; */ template struct GroundVehicle : public SpecializedVehicle { @@ -93,6 +95,41 @@ struct GroundVehicle : public SpecializedVehicle { return incl; } + + /** + * Checks if the vehicle is in a slope and sets the required flags in that case. + * @param new_tile True if the vehicle reached a new tile. + * @param turned Indicates if the vehicle has turned. + * @return Old height of the vehicle. + */ + FORCEINLINE byte UpdateInclination(bool new_tile, bool turned) + { + byte old_z = this->z_pos; + this->z_pos = GetSlopeZ(this->x_pos, this->y_pos); + + if (new_tile) { + ClrBit(this->gv_flags, GVF_GOINGUP_BIT); + ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT); + + if (T::From(this)->TileMayHaveSlopedTrack()) { + /* To check whether the current tile is sloped, and in which + * direction it is sloped, we get the 'z' at the center of + * the tile (middle_z) and the edge of the tile (old_z), + * which we then can compare. */ + static const int HALF_TILE_SIZE = TILE_SIZE / 2; + static const int INV_TILE_SIZE_MASK = ~(TILE_SIZE - 1); + + byte middle_z = GetSlopeZ((this->x_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE, (this->y_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE); + + if (middle_z != this->z_pos) { + SetBit(this->gv_flags, (middle_z > old_z) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT); + } + } + } + + this->UpdateViewport(true, turned); + return old_z; + } }; #endif /* GROUND_VEHICLE_HPP */ diff --git a/src/train.h b/src/train.h index 71724c2c3d..b21900ece7 100644 --- a/src/train.h +++ b/src/train.h @@ -483,6 +483,16 @@ protected: // These functions should not be called outside acceleration code. { return GetRailTypeInfo(GetRailType(this->tile))->max_speed; } + + /** + * Checks if the vehicle is at a tile that can be sloped. + * @return True if the tile can be sloped. + */ + FORCEINLINE bool TileMayHaveSlopedTrack() const + { + /* Any track that isn't TRACK_BIT_X or TRACK_BIT_Y cannot be sloped. */ + return this->track == TRACK_BIT_X || this->track == TRACK_BIT_Y; + } }; #define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 83fa327b14..050727a3d4 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2869,36 +2869,6 @@ static void TrainEnterStation(Train *v, StationID station) StationAnimationTrigger(st, v->tile, STAT_ANIM_TRAIN_ARRIVES); } -static byte AfterSetTrainPos(Train *v, bool new_tile) -{ - byte old_z = v->z_pos; - v->z_pos = GetSlopeZ(v->x_pos, v->y_pos); - - if (new_tile) { - ClrBit(v->gv_flags, GVF_GOINGUP_BIT); - ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT); - - if (v->track == TRACK_BIT_X || v->track == TRACK_BIT_Y) { - /* Any track that isn't TRACK_BIT_X or TRACK_BIT_Y cannot be sloped. - * To check whether the current tile is sloped, and in which - * direction it is sloped, we get the 'z' at the center of - * the tile (middle_z) and the edge of the tile (old_z), - * which we then can compare. */ - static const int HALF_TILE_SIZE = TILE_SIZE / 2; - static const int INV_TILE_SIZE_MASK = ~(TILE_SIZE - 1); - - byte middle_z = GetSlopeZ((v->x_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE, (v->y_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE); - - if (middle_z != v->z_pos) { - SetBit(v->gv_flags, (middle_z > old_z) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT); - } - } - } - - VehicleMove(v, true); - return old_z; -} - /* Check if the vehicle is compatible with the specified tile */ static inline bool CheckCompatibleRail(const Train *v, TileIndex tile) { @@ -3322,7 +3292,7 @@ static void TrainController(Train *v, Vehicle *nomove) } /* We need to update signal status, but after the vehicle position hash - * has been updated by AfterSetTrainPos() */ + * has been updated by UpdateInclination() */ update_signals_crossing = true; if (chosen_dir != v->direction) { @@ -3381,7 +3351,7 @@ static void TrainController(Train *v, Vehicle *nomove) v->y_pos = gp.y; /* update the Z position of the vehicle */ - byte old_z = AfterSetTrainPos(v, (gp.new_tile != gp.old_tile)); + byte old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false); if (prev == NULL) { /* This is the first vehicle in the train */ @@ -3537,9 +3507,9 @@ static void ChangeTrainDirRandomly(Train *v) v->UpdateDeltaXY(v->direction); v->cur_image = v->GetImage(v->direction); /* Refrain from updating the z position of the vehicle when on - * a bridge, because AfterSetTrainPos will put the vehicle under + * a bridge, because UpdateInclination() will put the vehicle under * the bridge in that case */ - if (v->track != TRACK_BIT_WORMHOLE) AfterSetTrainPos(v, false); + if (v->track != TRACK_BIT_WORMHOLE) v->UpdateInclination(false, false); } } while ((v = v->Next()) != NULL); }