@@ -1014,9 +1014,7 @@ static bool RoadVehLeaveDepot(RoadVehicle *v, bool first)
v->state = tdir;
v->frame = RVC_DEPOT_START_FRAME;

v->x_pos = x;
v->y_pos = y;
v->UpdatePosition();
v->Travel(x, y);
v->UpdateInclination(true, true);

InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
@@ -1143,16 +1141,12 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)

if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
/* Vehicle has just entered a bridge or tunnel */
v->x_pos = gp.x;
v->y_pos = gp.y;
v->UpdatePosition();
v->Travel(gp.x, gp.y);
v->UpdateInclination(true, true);
return true;
}

v->x_pos = gp.x;
v->y_pos = gp.y;
v->UpdatePosition();
v->Travel(gp.x, gp.y);
if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
return true;
}
@@ -1300,9 +1294,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
v->direction = new_dir;
if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
}
v->x_pos = x;
v->y_pos = y;
v->UpdatePosition();
v->Travel(x, y);
RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
return true;
}
@@ -1366,9 +1358,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
}

v->x_pos = x;
v->y_pos = y;
v->UpdatePosition();
v->Travel(x, y);
RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
return true;
}
@@ -1454,9 +1444,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
/* Check if next inline bay is free and has compatible road. */
if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && (GetRoadTypes(next_tile) & v->compatible_roadtypes) != 0) {
v->frame++;
v->x_pos = x;
v->y_pos = y;
v->UpdatePosition();
v->Travel(x, y);
RoadZPosAffectSpeed(v, v->UpdateInclination(true, false));
return true;
}
@@ -1503,9 +1491,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
/* Move to next frame unless vehicle arrived at a stop position
* in a depot or entered a tunnel/bridge */
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++;
v->x_pos = x;
v->y_pos = y;
v->UpdatePosition();
v->Travel(x, y);
RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
return true;
}
@@ -2952,6 +2952,14 @@ bool AfterLoadGame()
}
}

/* Update performance rating calculation
*/
if (IsSavegameVersionBefore(199)) {
_settings_game.economy.scoring_use_efficiency = 0;
_settings_game.economy.idle_loading_ct_penalty = 2;
}
PerformanceRatingCalculationChanged(0);

/*
* Only keep order-backups for network clients (and when replaying).
* If we are a network server or not networking, then we just loaded a previously
@@ -69,6 +69,7 @@ static const SaveLoad _cargopayment_desc[] = {
SLE_VAR(CargoPayment, route_profit, SLE_INT64),
SLE_VAR(CargoPayment, visual_profit, SLE_INT64),
SLE_CONDVAR(CargoPayment, visual_transfer, SLE_INT64, 181, SL_MAX_VERSION),
SLE_CONDVAR(CargoPayment, cargo_distance, SLE_INT32, 199, SL_MAX_VERSION),
SLE_END()
};

@@ -266,8 +266,9 @@
* 196 27778 1.7.x
* 197 27978 1.8.x
* 198
* 199
*/
extern const uint16 SAVEGAME_VERSION = 198; ///< Current savegame version of OpenTTD.
extern const uint16 SAVEGAME_VERSION = 199; ///< Current savegame version of OpenTTD.

SavegameType _savegame_type; ///< type of savegame we are loading
FileToSaveLoad _file_to_saveload; ///< File to save or load in the openttd loop.
@@ -703,6 +703,12 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
SLE_CONDVAR(Vehicle, current_order_time, SLE_UINT32, 67, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, 67, SL_MAX_VERSION),

SLE_CONDVAR(Vehicle, delivered_cargotiles_this_year, SLE_INT32, 199, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, delivered_cargotiles_last_year, SLE_INT32, 199, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, potential_cargotiles_this_year, SLE_INT32, 199, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, potential_cargotiles_last_year, SLE_INT32, 199, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, cd_distance, SLE_UINT8, 199, SL_MAX_VERSION),

SLE_CONDNULL(10, 2, 143), // old reserved space

SLE_END()
@@ -1604,6 +1604,8 @@ static SettingsContainer &GetSettingsTree()
accounting->Add(new SettingEntry("economy.infrastructure_maintenance"));
accounting->Add(new SettingEntry("difficulty.vehicle_costs"));
accounting->Add(new SettingEntry("difficulty.construction_cost"));
accounting->Add(new SettingEntry("economy.scoring_use_efficiency"));
accounting->Add(new SettingEntry("economy.idle_loading_ct_penalty"));
}

SettingsPage *vehicles = main->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES));
@@ -497,6 +497,8 @@ struct EconomySettings {
uint16 town_noise_population[3]; ///< population to base decision on noise evaluation (@see town_council_tolerance)
bool allow_town_level_crossings; ///< towns are allowed to build level crossings
bool infrastructure_maintenance; ///< enable monthly maintenance fee for owner infrastructure
uint8 scoring_use_efficiency; ///< use vehicle efficiency rather than profit for performance rating calculation
uint8 idle_loading_ct_penalty; ///< cargotiles penalty factor (in 1/4 steps) for vehicles loading and not receiving goods
};

struct LinkGraphSettings {
@@ -608,27 +608,24 @@ static void ShipController(Ship *v)
} else {
/* On a bridge */
if (!IsTileType(gp.new_tile, MP_TUNNELBRIDGE) || !HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
v->x_pos = gp.x;
v->y_pos = gp.y;
v->UpdatePosition();
v->Travel(gp.x, gp.y);
if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
return;
}
}

/* update image of ship, as well as delta XY */
v->x_pos = gp.x;
v->y_pos = gp.y;
v->z_pos = GetSlopePixelZ(gp.x, gp.y);
v->Travel(gp.x, gp.y);

getout:
v->UpdatePosition();
v->UpdateViewport(true, true);
return;

reverse_direction:
dir = ReverseDir(v->direction);
v->direction = dir;
v->UpdatePosition();
goto getout;
}

@@ -42,6 +42,7 @@ static bool InvalidateCompanyInfrastructureWindow(int32 p1);
static bool InvalidateCompanyWindow(int32 p1);
static bool ZoomMinMaxChanged(int32 p1);
static bool MaxVehiclesChanged(int32 p1);
extern bool PerformanceRatingCalculationChanged(int32 p1);

#ifdef ENABLE_NETWORK
static bool UpdateClientName(int32 p1);
@@ -1614,6 +1615,36 @@ strhelp = STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT
proc = InvalidateCompanyInfrastructureWindow
cat = SC_BASIC
[SDT_VAR]
base = GameSettings
var = economy.scoring_use_efficiency
type = SLE_UINT8
guiflags = SGF_MULTISTRING
from = 502
min = 0
max = 1
def = 0
str = STR_CONFIG_SETTING_VEHICLE_SCORING
strhelp = STR_CONFIG_SETTING_VEHICLE_SCORING_HELPTEXT
strval = STR_VEHICLE_SCORING_PROFIT
proc = PerformanceRatingCalculationChanged
cat = SC_BASIC
[SDT_VAR]
base = GameSettings
var = economy.idle_loading_ct_penalty
type = SLE_UINT8
guiflags = SGF_MULTISTRING
from = 502
def = 2
min = 0
max = 3
interval = 1
str = STR_CONFIG_SETTING_EFFICIENCY_IDLE_PENALTY
strhelp = STR_CONFIG_SETTING_EFFICIENCY_IDLE_PENALTY_HELPTEXT
cat = SC_EXPERT
strval = STR_IDLING_PENALTY_NONE
##
[SDT_VAR]
base = GameSettings
@@ -3352,9 +3352,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
gp.old_tile = GetOtherTunnelBridgeEnd(gp.old_tile);
}
} else {
v->x_pos = gp.x;
v->y_pos = gp.y;
v->UpdatePosition();
v->Travel(gp.x, gp.y);
if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
continue;
}
@@ -3363,9 +3361,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
/* update image of train, as well as delta XY */
v->UpdateDeltaXY();

v->x_pos = gp.x;
v->y_pos = gp.y;
v->UpdatePosition();
v->Travel(gp.x, gp.y);

/* update the Z position of the vehicle */
int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false);
@@ -1002,6 +1002,13 @@ void CallVehicleTicks()
break;
}

/* Add potential transported cargo-distance for whole tiles traveled */
if (v->cd_distance >= 16) {
int tiles = v->cd_distance / 16;
v->cd_distance -= tiles * 16;
v->potential_cargotiles_this_year += tiles * v->GetConsistTotalCapacity();
}

v->motion_counter += front->cur_speed;
/* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
@@ -1540,6 +1547,22 @@ void VehicleEnterDepot(Vehicle *v)
}


/**
* Move to the x, y coordinates as part of regular travel.
* @param x new x position
* @param y new y position
*/
void Vehicle::Travel(int x, int y)
{
/* Update cargotiles delta distance */
int delta = abs(this->x_pos - x) + abs(this->y_pos - y);
this->cd_distance += delta;

this->x_pos = x;
this->y_pos = y;
this->UpdatePosition();
}

/**
* Update the position of the vehicle. This will update the hash that tells
* which vehicles are on a tile.
@@ -2729,6 +2752,10 @@ void VehiclesYearlyLoop()

v->profit_last_year = v->profit_this_year;
v->profit_this_year = 0;
v->delivered_cargotiles_last_year = v->delivered_cargotiles_this_year;
v->delivered_cargotiles_this_year = 0;
v->potential_cargotiles_last_year = v->potential_cargotiles_this_year;
v->potential_cargotiles_this_year = 0;
SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
}
}
@@ -240,6 +240,11 @@ struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist
Money profit_last_year; ///< Profit last year << 8, low 8 bits are fract
Money value; ///< Value of the vehicle

OverflowSafeInt32 delivered_cargotiles_this_year; ///< How much cargo units * distance were delivered this year
OverflowSafeInt32 delivered_cargotiles_last_year; ///< How much cargo units * distance were delivered last year
OverflowSafeInt32 potential_cargotiles_this_year; ///< How much cargo units * distance could have been delivered this year
OverflowSafeInt32 potential_cargotiles_last_year; ///< How much cargo units * distance could have been delivered last year

CargoPayment *cargo_payment; ///< The cargo payment we're currently in

Rect coord; ///< NOSAVE: Graphical bounding box of the vehicle, i.e. what to redraw on moves.
@@ -295,6 +300,7 @@ struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist
byte acceleration; ///< used by train & aircraft
uint32 motion_counter; ///< counter to occasionally play a vehicle sound.
byte progress; ///< The percentage (if divided by 256) this vehicle already crossed the tile unit.
byte cd_distance; ///< Distance (in movement steps) traveled for potential cargotiles calculation

byte random_bits; ///< Bits used for determining which randomized variational spritegroups to use when drawing.
byte waiting_triggers; ///< Triggers to be yet matched before rerandomizing the random bits.
@@ -571,6 +577,32 @@ struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist
*/
Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }

/**
* Get transportation efficiency of the vehicle this year.
* The percentage of capacity delivered over capacity potential.
* @return percentage efficiency, 0 if vehicle had no potential
*/
int32 GetEfficiencyThisYear() const
{
if (this->potential_cargotiles_this_year == 0)
return 0;
else
return this->delivered_cargotiles_this_year * 100 / this->potential_cargotiles_this_year;
}

/**
* Get transportation efficiency of the vehicle last year.
* The percentage of capacity delivered over capacity potential.
* @return percentage efficiency, 0 if vehicle had no potential
*/
int32 GetEfficiencyLastYear() const
{
if (this->potential_cargotiles_last_year == 0)
return 0;
else
return this->delivered_cargotiles_last_year * 100 / this->potential_cargotiles_last_year;
}

void SetNext(Vehicle *next);

/**
@@ -720,6 +752,11 @@ struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist

this->profit_this_year = src->profit_this_year;
this->profit_last_year = src->profit_last_year;

this->delivered_cargotiles_last_year = src->delivered_cargotiles_last_year;
this->delivered_cargotiles_this_year = src->delivered_cargotiles_this_year;
this->potential_cargotiles_last_year = src->potential_cargotiles_last_year;
this->potential_cargotiles_this_year = src->potential_cargotiles_this_year;
}


@@ -754,6 +791,7 @@ struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist
void UpdateVisualEffect(bool allow_power_change = true);
void ShowVisualEffect() const;

void Travel(int x, int y);
void UpdatePosition();
void UpdateViewport(bool dirty);
void UpdatePositionAndViewport();
@@ -49,6 +49,8 @@ static GUIVehicleList::SortFunction VehicleNameSorter;
static GUIVehicleList::SortFunction VehicleAgeSorter;
static GUIVehicleList::SortFunction VehicleProfitThisYearSorter;
static GUIVehicleList::SortFunction VehicleProfitLastYearSorter;
static GUIVehicleList::SortFunction VehicleEfficiencyThisYearSorter;
static GUIVehicleList::SortFunction VehicleEfficiencyLastYearSorter;
static GUIVehicleList::SortFunction VehicleCargoSorter;
static GUIVehicleList::SortFunction VehicleReliabilitySorter;
static GUIVehicleList::SortFunction VehicleMaxSpeedSorter;
@@ -64,6 +66,8 @@ GUIVehicleList::SortFunction * const BaseVehicleListWindow::vehicle_sorter_funcs
&VehicleAgeSorter,
&VehicleProfitThisYearSorter,
&VehicleProfitLastYearSorter,
&VehicleEfficiencyThisYearSorter,
&VehicleEfficiencyLastYearSorter,
&VehicleCargoSorter,
&VehicleReliabilitySorter,
&VehicleMaxSpeedSorter,
@@ -80,6 +84,8 @@ const StringID BaseVehicleListWindow::vehicle_sorter_names[] = {
STR_SORT_BY_AGE,
STR_SORT_BY_PROFIT_THIS_YEAR,
STR_SORT_BY_PROFIT_LAST_YEAR,
STR_SORT_BY_EFFICIENCY_THIS_YEAR,
STR_SORT_BY_EFFICIENCY_LAST_YEAR,
STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE,
STR_SORT_BY_RELIABILITY,
STR_SORT_BY_MAX_SPEED,
@@ -1132,6 +1138,20 @@ static int CDECL VehicleProfitLastYearSorter(const Vehicle * const *a, const Veh
return (r != 0) ? r : VehicleNumberSorter(a, b);
}

/** Sort vehicles by this year actual/potential delivered cargotiles */
static int CDECL VehicleEfficiencyThisYearSorter(const Vehicle * const *a, const Vehicle * const *b)
{
int r = ClampToI32((*a)->GetEfficiencyThisYear() - (*b)->GetEfficiencyThisYear());
return (r != 0) ? r : VehicleNumberSorter(a, b);
}

/** Sort vehicles by last year actual/potential delivered cargotiles */
static int CDECL VehicleEfficiencyLastYearSorter(const Vehicle * const *a, const Vehicle * const *b)
{
int r = ClampToI32((*a)->GetEfficiencyLastYear() - (*b)->GetEfficiencyLastYear());
return (r != 0) ? r : VehicleNumberSorter(a, b);
}

/** Sort vehicles by their cargo */
static int CDECL VehicleCargoSorter(const Vehicle * const *a, const Vehicle * const *b)
{
@@ -1393,11 +1413,15 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int
const Vehicle *v = this->vehicles[i];
StringID str;

SetDParam(0, v->GetDisplayProfitThisYear());
SetDParam(1, v->GetDisplayProfitLastYear());
SetDParam(0, STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR);
SetDParam(1, v->GetDisplayProfitThisYear());
SetDParam(2, v->GetDisplayProfitLastYear());
SetDParam(3, STR_VEHICLE_LIST_EFFICIENCY_THIS_YEAR_LAST_YEAR);
SetDParam(4, v->GetEfficiencyThisYear());
SetDParam(5, v->GetEfficiencyLastYear());

DrawVehicleImage(v, image_left, image_right, y + FONT_HEIGHT_SMALL - 1, selected_vehicle, EIT_IN_LIST, 0);
DrawString(text_left, text_right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1, STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR);
DrawString(text_left, text_right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1, STR_VEHICLE_LIST_PROFIT_EFFICIENCY_LINE);

if (v->name != NULL) {
/* The vehicle got a name so we will print it */
@@ -2085,9 +2109,13 @@ struct VehicleDetailsWindow : Window {
y += FONT_HEIGHT_NORMAL;

/* Draw profit */
SetDParam(0, v->GetDisplayProfitThisYear());
SetDParam(1, v->GetDisplayProfitLastYear());
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR);
SetDParam(0, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR);
SetDParam(1, v->GetDisplayProfitThisYear());
SetDParam(2, v->GetDisplayProfitLastYear());
SetDParam(3, STR_VEHICLE_INFO_EFFICIENCY_THIS_YEAR_LAST_YEAR);
SetDParam(4, v->GetEfficiencyThisYear());
SetDParam(5, v->GetEfficiencyLastYear());
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_PROFIT_EFFICIENCY_LINE);
y += FONT_HEIGHT_NORMAL;

/* Draw breakdown & reliability */