diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -734,7 +734,8 @@ static int UpdateAircraftSpeed(Aircraft /* Adjust distance moved by plane speed setting */ if (_settings_game.vehicle.plane_speed > 1) spd /= _settings_game.vehicle.plane_speed; - if (!(v->direction & 1)) spd = spd * 3 / 4; + /* Convert direction-indepenent speed into direction-dependent speed. (old movement method) */ + spd = v->GetOldAdvanceSpeed(spd); spd += v->progress; v->progress = (byte)spd; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -756,6 +756,13 @@ static void RoadVehArrivesAt(const RoadV } } +/** + * This function looks at the vehicle and updates its speed (cur_speed + * and subspeed) variables. Furthermore, it returns the distance that + * the vehicle can drive this tick. #Vehicle::GetAdvanceDistance() determines + * the distance to drive before moving a step on the map. + * @return distance to drive. + */ static int RoadVehAccelerate(RoadVehicle *v) { uint oldspeed = v->cur_speed; @@ -786,8 +793,7 @@ static int RoadVehAccelerate(RoadVehicle } } - /* Speed is scaled in the same manner as for trains. @see train_cmd.cpp */ - int scaled_spd = spd * 3 >> 2; + int scaled_spd = v->GetAdvanceSpeed(spd); scaled_spd += v->progress; v->progress = 0; @@ -1595,7 +1601,7 @@ static bool RoadVehController(RoadVehicl /* Check how far the vehicle needs to proceed */ int j = RoadVehAccelerate(v); - int adv_spd = (v->direction & 1) ? 192 : 256; + int adv_spd = v->GetAdvanceDistance(); bool blocked = false; while (j >= adv_spd) { j -= adv_spd; @@ -1609,8 +1615,8 @@ static bool RoadVehController(RoadVehicl } if (blocked) break; - /* 192 spd used for going straight, 256 for going diagonally. */ - adv_spd = (v->direction & 1) ? 192 : 256; + /* Determine distance to next map position */ + adv_spd = v->GetAdvanceDistance(); /* Test for a collision, but only if another movement will occur. */ if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break; diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -346,8 +346,8 @@ static bool ShipAccelerate(Vehicle *v) SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); } - /* Decrease somewhat when turning */ - if (!(v->direction & 1)) spd = spd * 3 / 4; + /* Convert direction-indepenent speed into direction-dependent speed. (old movement method) */ + spd = v->GetOldAdvanceSpeed(spd); if (spd == 0) return false; if ((byte)++spd == 0) return true; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2839,10 +2839,8 @@ void Train::MarkDirty() /** * This function looks at the vehicle and updates its speed (cur_speed * and subspeed) variables. Furthermore, it returns the distance that - * the train can drive this tick. This distance is expressed as 256 * n, - * where n is the number of straight (long) tracks the train can - * traverse. This means that moving along a straight track costs 256 - * "speed" and a diagonal track costs 192 "speed". + * the train can drive this tick. #Vehicle::GetAdvanceDistance() determines + * the distance to drive before moving a step on the map. * @return distance to drive. */ int Train::UpdateSpeed() @@ -2869,18 +2867,7 @@ int Train::UpdateSpeed() this->cur_speed = spd = Clamp(this->cur_speed + ((int)spd >> 8), 0, tempmax); } - /* Scale speed by 3/4. Previously this was only done when the train was - * facing diagonally and would apply to however many moves the train made - * regardless the of direction actually moved in. Now it is always scaled, - * 256 spd is used to go straight and 192 is used to go diagonally - * (3/4 of 256). This results in the same effect, but without the error the - * previous method caused. - * - * The scaling is done in this direction and not by multiplying the amount - * to be subtracted by 4/3 so that the leftover speed can be saved in a - * byte in this->progress. - */ - int scaled_spd = spd * 3 >> 2; + int scaled_spd = this->GetAdvanceSpeed(spd); scaled_spd += this->progress; this->progress = 0; // set later in TrainLocoHandler or TrainController @@ -3885,7 +3872,7 @@ static bool TrainLocoHandler(Train *v, b SetWindowDirty(WC_VEHICLE_VIEW, v->index); } - int adv_spd = (v->direction & 1) ? 192 : 256; + int adv_spd = v->GetAdvanceDistance(); if (j < adv_spd) { /* if the vehicle has speed 0, update the last_speed field. */ if (v->cur_speed == 0) SetLastSpeed(v, v->cur_speed); @@ -3897,8 +3884,8 @@ static bool TrainLocoHandler(Train *v, b TrainController(v, NULL); /* Don't continue to move if the train crashed. */ if (CheckTrainCollision(v)) break; - /* 192 spd used for going straight, 256 for going diagonally. */ - adv_spd = (v->direction & 1) ? 192 : 256; + /* Determine distance to next map position */ + adv_spd = v->GetAdvanceDistance(); /* No more moving this tick */ if (j < adv_spd || v->cur_speed == 0) break; diff --git a/src/vehicle_base.h b/src/vehicle_base.h --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -227,6 +227,53 @@ public: virtual void UpdateDeltaXY(Direction direction) {} /** + * Determines the effective direction-specific vehicle movement speed. + * + * This method belongs to the old vehicle movement method: + * A vehicle moves a step every 256 progress units. + * The vehicle speed is scaled by 3/4 when moving in X or Y direction due to the longer distance. + * + * However, this method is slightly wrong in corners, as the leftover progress is not scaled correctly + * when changing movement direction. #GetAdvanceSpeed() and #GetAdvanceDistance() are better wrt. this. + * + * @param speed Direction-independent unscaled speed. + * @return speed scaled by movement direction. 256 units are required for each movement step. + */ + FORCEINLINE uint GetOldAdvanceSpeed(uint speed) + { + return (this->direction & 1) ? speed : speed * 3 / 4; + } + + /** + * Determines the effective vehicle movement speed. + * + * Together with #GetAdvanceDistance() this function is a replacement for #GetOldAdvanceSpeed(). + * + * A vehicle progresses independent of it's movement direction. + * However different amounts of "progress" are needed for moving a step in a specific direction. + * That way the leftover progress does not need any adaption when changing movement direction. + * + * @param speed Direction-independent unscaled speed. + * @return speed, scaled to match #GetAdvanceDistance(). + */ + static FORCEINLINE uint GetAdvanceSpeed(uint speed) + { + return speed * 3 / 4; + } + + /** + * Determines the vehicle "progress" needed for moving a step. + * + * Together with #GetAdvanceSpeed() this function is a replacement for #GetOldAdvanceSpeed(). + * + * @return distance to drive for a movement step on the map. + */ + FORCEINLINE uint GetAdvanceDistance() + { + return (this->direction & 1) ? 192 : 256; + } + + /** * Sets the expense type associated to this vehicle type * @param income whether this is income or (running) expenses of the vehicle */