Implement critical breakdown speed reduction for road vehicles

This commit is contained in:
Jonathan G Rennison 2018-01-04 19:18:24 +00:00
parent beda7ebb39
commit 0a80aec634
8 changed files with 42 additions and 6 deletions

View File

@ -3675,7 +3675,7 @@ STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Name air
STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Age: {LTBLUE}{STRING2}{BLACK} Running Cost: {LTBLUE}{CURRENCY_LONG}/yr
STR_RUNNING :{LTBLUE}Running
STR_NEED_REPAIR :{ORANGE}Train needs repair - max speed reduced to {VELOCITY}
STR_NEED_REPAIR :{ORANGE}Vehicle needs repair - max speed reduced to {VELOCITY}
STR_CURRENT_STATUS :{BLACK}Current status: {STRING3}
# The next two need to stay in this order

View File

@ -97,6 +97,8 @@ struct RoadVehicle FINAL : public GroundVehicle<RoadVehicle, VEH_ROAD> {
RoadType roadtype;
RoadTypes compatible_roadtypes;
byte critical_breakdown_count; ///< Counter for the number of critical breakdowns since last service
/** We don't want GCC to zero our struct! It already is zeroed and has an index! */
RoadVehicle() : GroundVehicleBase() {}
/** We want to 'destruct' the right class. */
@ -124,6 +126,8 @@ struct RoadVehicle FINAL : public GroundVehicle<RoadVehicle, VEH_ROAD> {
bool IsBus() const;
int GetCurrentMaxSpeed() const;
int GetEffectiveMaxSpeed() const;
int GetDisplayEffectiveMaxSpeed() const { return this->GetEffectiveMaxSpeed() / 2; }
int UpdateSpeed();
protected: // These functions should not be called outside acceleration code.

View File

@ -430,13 +430,29 @@ void RoadVehicle::UpdateDeltaXY(Direction direction)
this->z_extent = 6;
}
/**
* Calculates the maximum speed of the vehicle, taking into account speed reductions following critical breakdowns
* @return Maximum speed of the vehicle.
*/
int RoadVehicle::GetEffectiveMaxSpeed() const
{
int max_speed = this->vcache.cached_max_speed;
for (uint i = 0; i < this->critical_breakdown_count; i++) {
max_speed = min(max_speed - (max_speed / 3) + 1, max_speed);
}
/* clamp speed to be no less than lower of 5mph and 1/8 of base speed */
return max<uint16>(max_speed, min<uint16>(10, (this->vcache.cached_max_speed + 7) >> 3));
}
/**
* Calculates the maximum speed of the vehicle under its current conditions.
* @return Maximum speed of the vehicle.
*/
inline int RoadVehicle::GetCurrentMaxSpeed() const
{
int max_speed = this->vcache.cached_max_speed;
int max_speed = this->GetEffectiveMaxSpeed();
/* Limit speed to 50% while reversing, 75% in curves. */
for (const RoadVehicle *u = this; u != NULL; u = u->Next()) {

View File

@ -117,6 +117,11 @@ void DrawRoadVehDetails(const Vehicle *v, int left, int right, int y)
/* Draw Transfer credits text */
SetDParam(0, feeder_share);
DrawString(left, right, y + 3 * FONT_HEIGHT_NORMAL + 3 + y_offset, STR_VEHICLE_INFO_FEEDER_CARGO_VALUE);
if (RoadVehicle::From(v)->critical_breakdown_count > 0) {
SetDParam(0, RoadVehicle::From(v)->GetDisplayEffectiveMaxSpeed());
DrawString(left, right, y + 4 * FONT_HEIGHT_NORMAL + 4 + y_offset, STR_NEED_REPAIR);
}
}
/**

View File

@ -45,7 +45,7 @@ std::vector<uint32> _sl_xv_discardable_chunk_ids; ///< list of chunks
static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version os SLXI chunk
const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 5, 5, "improved_breakdowns", NULL, NULL, NULL },
{ XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 6, 6, "improved_breakdowns", NULL, NULL, NULL },
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
};

View File

@ -750,6 +750,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
SLE_CONDNULL(4, 69, 130),
SLE_CONDNULL(2, 6, 130),
SLE_CONDNULL(16, 2, 143), // old reserved space
SLE_CONDVAR_X(RoadVehicle, critical_breakdown_count, SLE_UINT8, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_IMPROVED_BREAKDOWNS, 6)),
SLE_END()
};

View File

@ -153,6 +153,8 @@ void VehicleServiceInDepot(Vehicle *v)
Train::From(v)->ConsistChanged(CCF_REFIT);
CLRBITS(Train::From(v)->flags, (1 << VRF_BREAKDOWN_BRAKING) | VRF_IS_BROKEN );
}
} else if (v->type == VEH_ROAD) {
RoadVehicle::From(v)->critical_breakdown_count = 0;
}
v->vehstatus &= ~VS_AIRCRAFT_BROKEN;
SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
@ -185,7 +187,8 @@ bool Vehicle::NeedsServicing() const
if ((this->ServiceIntervalIsPercent() ?
(this->reliability >= this->GetEngine()->reliability * (100 - this->service_interval) / 100) :
(this->date_of_last_service + this->service_interval >= _date))
&& !(this->type == VEH_TRAIN && HasBit(Train::From(this)->flags, VRF_NEED_REPAIR))) {
&& !(this->type == VEH_TRAIN && HasBit(Train::From(this)->flags, VRF_NEED_REPAIR))
&& !(this->type == VEH_ROAD && RoadVehicle::From(this)->critical_breakdown_count > 0)) {
return false;
}
@ -1458,6 +1461,13 @@ bool Vehicle::HandleBreakdown()
EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
if (u != NULL) u->animation_state = this->breakdown_delay * 2;
}
if (_settings_game.vehicle.improved_breakdowns) {
if (this->type == VEH_ROAD) {
if (RoadVehicle::From(this)->critical_breakdown_count != 255) {
RoadVehicle::From(this)->critical_breakdown_count++;
}
}
}
/* FALL THROUGH */
case BREAKDOWN_EM_STOP:
this->cur_speed = 0;

View File

@ -1942,13 +1942,13 @@ struct VehicleDetailsWindow : Window {
uint desired_height;
if (v->HasArticulatedPart()) {
/* An articulated RV has its text drawn under the sprite instead of after it, hence 15 pixels extra. */
desired_height = WD_FRAMERECT_TOP + ScaleGUITrad(15) + 3 * FONT_HEIGHT_NORMAL + 2 + WD_FRAMERECT_BOTTOM;
desired_height = WD_FRAMERECT_TOP + ScaleGUITrad(15) + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM;
/* Add space for the cargo amount for each part. */
for (const Vehicle *u = v; u != NULL; u = u->Next()) {
if (u->cargo_cap != 0) desired_height += FONT_HEIGHT_NORMAL + 1;
}
} else {
desired_height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM;
desired_height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + 4 + WD_FRAMERECT_BOTTOM;
}
return desired_height;
}