Improved breakdowns: Various changes and fixes.

* Revert breakdown_chance to (mostly) its original behaviour.
* Create a new breakdown_chance_factor to hold breakdown_chance
  from improved breakdowns logic.
* Revert airport crash probabilities back to original behaviour, with
  modified behaviour only during emergency landings.
* Low power breakdowns now only reduce the power of the engine which
  has broken down.
* Low power breakdowns no longer reduce speed directly.
* Add callback function to run whenever improved breakdowns setting
  is changed. Reset breakdown_chance_factor where required.
* More whitespace/formatting...
This commit is contained in:
Jonathan G Rennison
2016-01-31 22:55:25 +00:00
parent 9742300a1e
commit 5eed9865d6
14 changed files with 89 additions and 43 deletions

View File

@@ -308,7 +308,7 @@ CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine *
v->reliability_spd_dec = e->reliability_spd_dec; v->reliability_spd_dec = e->reliability_spd_dec;
/* higher speed means higher breakdown chance */ /* higher speed means higher breakdown chance */
/* to somewhat compensate for the fact that fast aircraft spend less time in the air */ /* to somewhat compensate for the fact that fast aircraft spend less time in the air */
v->breakdown_chance = Clamp(64 + (AircraftVehInfo(v->engine_type)->max_speed >> 3), 0, 255); v->breakdown_chance_factor = Clamp(64 + (AircraftVehInfo(v->engine_type)->max_speed >> 3), 0, 255);
v->max_age = e->GetLifeLengthInDays(); v->max_age = e->GetLifeLengthInDays();
_new_vehicle_id = v->index; _new_vehicle_id = v->index;
@@ -1333,18 +1333,18 @@ static void MaybeCrashAirplane(Aircraft *v)
Station *st = Station::Get(v->targetairport); Station *st = Station::Get(v->targetairport);
/* FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports */ /* FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports */
uint32 prob = (_settings_game.vehicle.improved_breakdowns && _settings_game.difficulty.vehicle_breakdowns) ? uint32 prob = (0x4000 << _settings_game.vehicle.plane_crashes);
0x10000 / 10000 : 0x4000 << _settings_game.vehicle.plane_crashes;
if ((st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) && if ((st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) &&
(AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) && (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
!_cheats.no_jetcrash.value) { !_cheats.no_jetcrash.value) {
prob /= 20; prob /= 20;
} else if (!_settings_game.vehicle.improved_breakdowns) { } else {
prob /= 1500; prob /= 1500;
} else if (v->breakdown_ctr == 1 && v->breakdown_type == BREAKDOWN_AIRCRAFT_EM_LANDING) { }
/* Airplanes that are attempting an emergency landing have a 2% chance to crash */ if (_settings_game.vehicle.improved_breakdowns && v->breakdown_ctr == 1 && v->breakdown_type == BREAKDOWN_AIRCRAFT_EM_LANDING) {
prob = 0x10000 / 50; /* Airplanes that are attempting an emergency landing have a 2% chance to crash */
prob = max<uint32>(prob, 0x10000 / 50);
} }
if (GB(Random(), 0, 22) > prob) return; if (GB(Random(), 0, 22) > prob) return;

View File

@@ -78,14 +78,15 @@ void GroundVehicle<T, Type>::CalculatePower(uint32& total_power, uint32& max_te,
for (const T *u = v; u != NULL; u = u->Next()) { for (const T *u = v; u != NULL; u = u->Next()) {
uint32 current_power = u->GetPower() + u->GetPoweredPartPower(u); uint32 current_power = u->GetPower() + u->GetPoweredPartPower(u);
if (breakdowns && u->breakdown_ctr == 1 && u->breakdown_type == BREAKDOWN_LOW_POWER) {
current_power = current_power * u->breakdown_severity / 256;
}
total_power += current_power; total_power += current_power;
/* Only powered parts add tractive effort. */ /* Only powered parts add tractive effort. */
if (current_power > 0) max_te += u->GetWeight() * u->GetTractiveEffort(); if (current_power > 0) max_te += u->GetWeight() * u->GetTractiveEffort();
if (breakdowns && u->breakdown_ctr == 1 && u->breakdown_type == BREAKDOWN_LOW_POWER) {
total_power = total_power * u->breakdown_severity / 256;
}
} }
max_te *= 10000; // Tractive effort in (tonnes * 1000 * 10 =) N. max_te *= 10000; // Tractive effort in (tonnes * 1000 * 10 =) N.
@@ -138,7 +139,6 @@ int GroundVehicle<T, Type>::GetAcceleration()
* and km/h to m/s conversion below result in a maxium of * and km/h to m/s conversion below result in a maxium of
* about 1.1E11, way more than 4.3E9 of int32. */ * about 1.1E11, way more than 4.3E9 of int32. */
int64 power = this->gcache.cached_power * 746ll; int64 power = this->gcache.cached_power * 746ll;
uint32 max_te = this->gcache.cached_max_te; // [N]
/* This is constructed from: /* This is constructed from:
* - axle resistance: U16 power * 10 for 128 vehicles. * - axle resistance: U16 power * 10 for 128 vehicles.
@@ -171,6 +171,7 @@ int GroundVehicle<T, Type>::GetAcceleration()
AccelStatus mode = v->GetAccelerationStatus(); AccelStatus mode = v->GetAccelerationStatus();
/* handle breakdown power reduction */ /* handle breakdown power reduction */
uint32 max_te = this->gcache.cached_max_te; // [N]
if (Type == VEH_TRAIN && mode == AS_ACCEL && HasBit(Train::From(this)->flags, VRF_BREAKDOWN_POWER)) { if (Type == VEH_TRAIN && mode == AS_ACCEL && HasBit(Train::From(this)->flags, VRF_BREAKDOWN_POWER)) {
/* We'd like to cache this, but changing cached_power has too many unwanted side-effects */ /* We'd like to cache this, but changing cached_power has too many unwanted side-effects */
uint32 power_temp; uint32 power_temp;
@@ -219,9 +220,7 @@ int GroundVehicle<T, Type>::GetAcceleration()
breakdown_factor /= (Train::From(this)->tcache.cached_num_engines + 2); breakdown_factor /= (Train::From(this)->tcache.cached_num_engines + 2);
} }
/* breakdown_chance is at least 5 (5 / 128 = ~4% of the normal chance) */ /* breakdown_chance is at least 5 (5 / 128 = ~4% of the normal chance) */
this->breakdown_chance = max(breakdown_factor >> 16, (uint64)5); this->breakdown_chance_factor = max(breakdown_factor >> 16, (uint64)5);
} else {
this->breakdown_chance = 128;
} }
if (mode == AS_ACCEL) { if (mode == AS_ACCEL) {
@@ -235,7 +234,7 @@ int GroundVehicle<T, Type>::GetAcceleration()
* same (maximum) speed. */ * same (maximum) speed. */
int accel = ClampToI32((force - resistance) / (mass * 4)); int accel = ClampToI32((force - resistance) / (mass * 4));
accel = force < resistance ? min(-1, accel) : max(1, accel); accel = force < resistance ? min(-1, accel) : max(1, accel);
if (this->type == VEH_TRAIN ) { if (this->type == VEH_TRAIN) {
if(_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL && if(_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL &&
HasBit(Train::From(this)->flags, VRF_BREAKDOWN_POWER)) { HasBit(Train::From(this)->flags, VRF_BREAKDOWN_POWER)) {
/* We need to apply the power reducation for non-realistic acceleration here */ /* We need to apply the power reducation for non-realistic acceleration here */

View File

@@ -370,22 +370,23 @@ protected:
uint spd = this->subspeed + accel; uint spd = this->subspeed + accel;
this->subspeed = (byte)spd; this->subspeed = (byte)spd;
int tempmax = max_speed;
/* When we are going faster than the maximum speed, reduce the speed /* When we are going faster than the maximum speed, reduce the speed
* somewhat gradually. But never lower than the maximum speed. */ * somewhat gradually. But never lower than the maximum speed. */
int tempmax = ((this->breakdown_ctr == 1) ? this->cur_speed : max_speed);
if (this->breakdown_ctr == 1) { if (this->breakdown_ctr == 1) {
if (this->breakdown_type == BREAKDOWN_LOW_POWER) { if (this->breakdown_type == BREAKDOWN_LOW_POWER) {
if ((this->tick_counter & 0x7) == 0) { if ((this->tick_counter & 0x7) == 0 && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
if (this->cur_speed > (this->breakdown_severity * max_speed) >> 8) { if (this->cur_speed > (this->breakdown_severity * max_speed) >> 8) {
tempmax = this->cur_speed - (this->cur_speed / 10) - 1; tempmax = this->cur_speed - (this->cur_speed / 10) - 1;
} else { } else {
tempmax = (this->breakdown_severity * max_speed) >> 8; tempmax = (this->breakdown_severity * max_speed) >> 8;
} }
} }
} } else if (this->breakdown_type == BREAKDOWN_LOW_SPEED) {
if (this->breakdown_type == BREAKDOWN_LOW_SPEED) {
tempmax = min(max_speed, this->breakdown_severity); tempmax = min(max_speed, this->breakdown_severity);
} else {
tempmax = this->cur_speed;
} }
} }

View File

@@ -298,7 +298,7 @@ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engin
v->reliability = e->reliability; v->reliability = e->reliability;
v->reliability_spd_dec = e->reliability_spd_dec; v->reliability_spd_dec = e->reliability_spd_dec;
v->breakdown_chance = 128; v->breakdown_chance_factor = 128;
v->max_age = e->GetLifeLengthInDays(); v->max_age = e->GetLifeLengthInDays();
_new_vehicle_id = v->index; _new_vehicle_id = v->index;

View File

@@ -2835,14 +2835,15 @@ bool AfterLoadGame()
v->reliability = min(v->First()->reliability, e->reliability); v->reliability = min(v->First()->reliability, e->reliability);
} }
} }
/* FALL THROUGH */
case VEH_ROAD: case VEH_ROAD:
v->breakdown_chance = 128; v->breakdown_chance_factor = 128;
break; break;
case VEH_SHIP: case VEH_SHIP:
v->breakdown_chance = 64; v->breakdown_chance_factor = 64;
break; break;
case VEH_AIRCRAFT: case VEH_AIRCRAFT:
v->breakdown_chance = Clamp(64 + (AircraftVehInfo(v->engine_type)->max_speed >> 3), 0, 255); v->breakdown_chance_factor = Clamp(64 + (AircraftVehInfo(v->engine_type)->max_speed >> 3), 0, 255);
v->breakdown_severity = 40; v->breakdown_severity = 40;
break; break;
default: break; default: break;

View File

@@ -671,6 +671,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
SLE_VAR(Vehicle, breakdown_delay, SLE_UINT8), SLE_VAR(Vehicle, breakdown_delay, SLE_UINT8),
SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8), SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8),
SLE_VAR(Vehicle, breakdown_chance, SLE_UINT8), SLE_VAR(Vehicle, breakdown_chance, SLE_UINT8),
SLE_CONDVAR(Vehicle, breakdown_chance_factor, SLE_UINT8, SL_IB, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, breakdown_type, SLE_UINT8, SL_IB, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, breakdown_type, SLE_UINT8, SL_IB, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, breakdown_severity, SLE_UINT8, SL_IB, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, breakdown_severity, SLE_UINT8, SL_IB, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, build_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Vehicle, build_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30),

View File

@@ -1020,7 +1020,7 @@ static bool RoadVehAccelerationModelChanged(int32 p1)
RoadVehicle *rv; RoadVehicle *rv;
FOR_ALL_ROADVEHICLES(rv) { FOR_ALL_ROADVEHICLES(rv) {
if (rv->IsFrontEngine()) { if (rv->IsFrontEngine()) {
rv->breakdown_chance = 128; rv->breakdown_chance_factor = 128;
} }
} }
} }
@@ -1319,6 +1319,32 @@ static bool MaxVehiclesChanged(int32 p1)
return true; return true;
} }
static bool ImprovedBreakdownsSettingChanged(int32 p1)
{
if (!_settings_game.vehicle.improved_breakdowns) return true;
Vehicle *v;
FOR_ALL_VEHICLES(v) {
switch(v->type) {
case VEH_TRAIN:
if (v->IsFrontEngine()) {
v->breakdown_chance_factor = 128;
Train::From(v)->UpdateAcceleration();
}
break;
case VEH_ROAD:
if (v->IsFrontEngine()) {
v->breakdown_chance_factor = 128;
}
break;
default:
break;
}
}
return true;
}
#ifdef ENABLE_NETWORK #ifdef ENABLE_NETWORK

View File

@@ -714,7 +714,7 @@ CommandCost CmdBuildShip(TileIndex tile, DoCommandFlag flags, const Engine *e, u
v->reliability = e->reliability; v->reliability = e->reliability;
v->reliability_spd_dec = e->reliability_spd_dec; v->reliability_spd_dec = e->reliability_spd_dec;
v->breakdown_chance = 64; // ships have a 50% lower breakdown chance than normal v->breakdown_chance_factor = 64; // ships have a 50% lower breakdown chance than normal
v->max_age = e->GetLifeLengthInDays(); v->max_age = e->GetLifeLengthInDays();
_new_vehicle_id = v->index; _new_vehicle_id = v->index;

View File

@@ -42,6 +42,7 @@ static bool InvalidateCompanyInfrastructureWindow(int32 p1);
static bool InvalidateCompanyWindow(int32 p1); static bool InvalidateCompanyWindow(int32 p1);
static bool ZoomMinMaxChanged(int32 p1); static bool ZoomMinMaxChanged(int32 p1);
static bool MaxVehiclesChanged(int32 p1); static bool MaxVehiclesChanged(int32 p1);
static bool ImprovedBreakdownsSettingChanged(int32 p1);
#ifdef ENABLE_NETWORK #ifdef ENABLE_NETWORK
static bool UpdateClientName(int32 p1); static bool UpdateClientName(int32 p1);
@@ -1143,7 +1144,7 @@ from = SL_IB
guiflags = SGF_NO_NETWORK guiflags = SGF_NO_NETWORK
def = false def = false
str = STR_CONFIG_SETTING_IMPROVED_BREAKDOWNS str = STR_CONFIG_SETTING_IMPROVED_BREAKDOWNS
proc = ImprovedBreakdownsSettingChanged
; station.join_stations ; station.join_stations
[SDT_NULL] [SDT_NULL]

View File

@@ -292,7 +292,7 @@ protected: // These functions should not be called outside acceleration code.
*/ */
inline AccelStatus GetAccelerationStatus() const inline AccelStatus GetAccelerationStatus() const
{ {
return (this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK ) || HasBit(this->flags, VRF_BREAKDOWN_BRAKING) ? AS_BRAKE : AS_ACCEL; return ((this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK) || HasBit(this->flags, VRF_BREAKDOWN_BRAKING)) ? AS_BRAKE : AS_ACCEL;
} }
/** /**

View File

@@ -129,7 +129,7 @@ void CheckTrainsLengths()
void CheckBreakdownFlags(Train *v) void CheckBreakdownFlags(Train *v)
{ {
assert(v->IsFrontEngine()); assert(v->IsFrontEngine());
/* clear the flags we're gonna check first, we'll set them again later (if applicable ) */ /* clear the flags we're gonna check first, we'll set them again later (if applicable) */
CLRBITS(v->flags, (1 << VRF_BREAKDOWN_BRAKING) | VRF_IS_BROKEN); CLRBITS(v->flags, (1 << VRF_BREAKDOWN_BRAKING) | VRF_IS_BROKEN);
for (const Train *w = v; w != NULL; w = w->Next()) { for (const Train *w = v; w != NULL; w = w->Next()) {
@@ -492,10 +492,8 @@ void Train::UpdateAcceleration()
if (_settings_game.vehicle.improved_breakdowns) { if (_settings_game.vehicle.improved_breakdowns) {
if (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { if (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
this->breakdown_chance = max(128 * 3 / (this->tcache.cached_num_engines + 2), 5); this->breakdown_chance_factor = max(128 * 3 / (this->tcache.cached_num_engines + 2), 5);
} }
} else {
this->breakdown_chance = 128;
} }
} }
@@ -4055,7 +4053,6 @@ void Train::OnNewDay()
if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this); if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
if (this->IsFrontEngine()) { if (this->IsFrontEngine()) {
CheckIfTrainNeedsService(this); CheckIfTrainNeedsService(this);
CheckOrders(this); CheckOrders(this);

View File

@@ -123,6 +123,8 @@ void VehicleServiceInDepot(Vehicle *v)
v->date_of_last_service = _date; v->date_of_last_service = _date;
v->breakdowns_since_last_service = 0; v->breakdowns_since_last_service = 0;
v->reliability = v->GetEngine()->reliability; v->reliability = v->GetEngine()->reliability;
/* Prevent vehicles from breaking down directly after exiting the depot. */
v->breakdown_chance = 0;
v = v->Next(); v = v->Next();
} while (v != NULL && v->HasEngineType()); } while (v != NULL && v->HasEngineType());
} }
@@ -144,7 +146,7 @@ bool Vehicle::NeedsServicing() const
if ((this->ServiceIntervalIsPercent() ? if ((this->ServiceIntervalIsPercent() ?
(this->reliability >= this->GetEngine()->reliability * (100 - this->service_interval) / 100) : (this->reliability >= this->GetEngine()->reliability * (100 - this->service_interval) / 100) :
(this->date_of_last_service + this->service_interval >= _date)) (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))) {
return false; return false;
} }
@@ -1277,15 +1279,21 @@ void CheckVehicleBreakdown(Vehicle *v)
return; return;
} }
uint32 r1 = Random(); uint32 r = Random();
uint32 r2 = Random();
/* increase chance of failure */
int chance = v->breakdown_chance + 1;
if (Chance16I(1, 25, r)) chance += 25;
chance = min(255, chance);
v->breakdown_chance = chance;
byte chance = 128;
if (_settings_game.vehicle.improved_breakdowns) { if (_settings_game.vehicle.improved_breakdowns) {
/* Dual engines have their breakdown chances reduced to 70% of the normal value */ if (v->type == VEH_TRAIN && Train::From(v)->IsMultiheaded()) {
chance = (v->type == VEH_TRAIN && Train::From(v)->IsMultiheaded()) ? v->First()->breakdown_chance * 7 / 10 : v->First()->breakdown_chance; /* Dual engines have their breakdown chances reduced to 70% of the normal value */
} else if(v->type == VEH_SHIP) { chance = chance * 7 / 10;
chance = 64; }
chance *= v->First()->breakdown_chance_factor;
chance >>= 7;
} }
/** /**
* Chance is (1 - reliability) * breakdown_setting * breakdown_chance / 10. * Chance is (1 - reliability) * breakdown_setting * breakdown_chance / 10.
@@ -1295,9 +1303,12 @@ void CheckVehicleBreakdown(Vehicle *v)
* However, because breakdowns are no longer by definition a complete stop, * However, because breakdowns are no longer by definition a complete stop,
* their impact will be significantly less. * their impact will be significantly less.
*/ */
uint32 r1 = Random();
if ((uint32) (0xffff - v->reliability) * _settings_game.difficulty.vehicle_breakdowns * chance > GB(r1, 0, 24) * 10) { if ((uint32) (0xffff - v->reliability) * _settings_game.difficulty.vehicle_breakdowns * chance > GB(r1, 0, 24) * 10) {
uint32 r2 = Random();
v->breakdown_ctr = GB(r1, 24, 6) + 0xF; v->breakdown_ctr = GB(r1, 24, 6) + 0xF;
v->breakdown_delay = GB(r2, 0, 7) + 0x80; v->breakdown_delay = GB(r2, 0, 7) + 0x80;
v->breakdown_chance = 0;
DetermineBreakdownType(v, r2); DetermineBreakdownType(v, r2);
} }
} }

View File

@@ -195,6 +195,7 @@ public:
byte breakdown_severity; ///< severity of the breakdown. Note that lower means more severe byte breakdown_severity; ///< severity of the breakdown. Note that lower means more severe
byte breakdown_type; ///< Type of breakdown byte breakdown_type; ///< Type of breakdown
byte breakdown_chance_factor; ///< Improved breakdowns: current multiplier for breakdown_chance * 128, used for head vehicle only
SpriteID colourmap; ///< NOSAVE: cached colour mapping SpriteID colourmap; ///< NOSAVE: cached colour mapping
/* Related to age and service time */ /* Related to age and service time */

View File

@@ -2632,7 +2632,15 @@ public:
if (w->breakdown_type == BREAKDOWN_LOW_SPEED) { if (w->breakdown_type == BREAKDOWN_LOW_SPEED) {
SetDParam(1, min( w->First()->GetDisplayMaxSpeed(), w->breakdown_severity >> ((v->type == VEH_TRAIN) ? 0 : 1))); SetDParam(1, min( w->First()->GetDisplayMaxSpeed(), w->breakdown_severity >> ((v->type == VEH_TRAIN) ? 0 : 1)));
} else if (w->breakdown_type == BREAKDOWN_LOW_POWER) { } else if (w->breakdown_type == BREAKDOWN_LOW_POWER) {
SetDParam(1, w->breakdown_severity * 100 / 256); int percent;
if (v->type == VEH_TRAIN) {
uint32 power, te;
Train::From(v)->CalculatePower(power, te, true);
percent = (100 * power) / Train::From(v)->gcache.cached_power;
} else {
percent = w->breakdown_severity * 100 / 256;
}
SetDParam(1, percent);
} }
} }
} else if (v->vehstatus & VS_STOPPED) { } else if (v->vehstatus & VS_STOPPED) {