|
@@ -100,6 +100,34 @@ void CheckTrainsLengths()
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Checks the breakdown flags (VehicleRailFlags 9-12) and sets the correct value in the first vehicle of the consist.
|
|
|
* This function is generally only called to check if a flag may be cleared.
|
|
|
* @param v the front engine
|
|
|
* @param flags bitmask of the flags to check.
|
|
|
*/
|
|
|
void CheckBreakdownFlags(Train *v)
|
|
|
{
|
|
|
assert(v->IsFrontEngine());
|
|
|
/* 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);
|
|
|
|
|
|
for (const Train *w = v; w != NULL; w = w->Next()) {
|
|
|
if (v->IsEngine() || w->IsMultiheaded()) {
|
|
|
if (w->breakdown_ctr == 2) {
|
|
|
SetBit(v->flags, VRF_BREAKDOWN_BRAKING);
|
|
|
} else if (w->breakdown_ctr == 1) {
|
|
|
switch (w->breakdown_type) {
|
|
|
case BREAKDOWN_CRITICAL:
|
|
|
case BREAKDOWN_EM_STOP: SetBit(v->flags, VRF_BREAKDOWN_STOPPED); break;
|
|
|
case BREAKDOWN_LOW_SPEED: SetBit(v->flags, VRF_BREAKDOWN_SPEED); break;
|
|
|
case BREAKDOWN_LOW_POWER: SetBit(v->flags, VRF_BREAKDOWN_POWER); break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Recalculates the cached stuff of a train. Should be called each time a vehicle is added
|
|
|
* to/removed from the chain, and when the game is loaded.
|
|
|
* Note: this needs to be called too for 'wagon chains' (in the depot, without an engine)
|
|
@@ -115,6 +143,7 @@ void Train::ConsistChanged(ConsistChange
|
|
|
EngineID first_engine = this->IsFrontEngine() ? this->engine_type : INVALID_ENGINE;
|
|
|
this->gcache.cached_total_length = 0;
|
|
|
this->compatible_railtypes = RAILTYPES_NONE;
|
|
|
this->tcache.cached_num_engines = 0;
|
|
|
|
|
|
bool train_can_tilt = true;
|
|
|
int min_curve_speed_mod = INT_MAX;
|
|
@@ -185,8 +214,13 @@ void Train::ConsistChanged(ConsistChange
|
|
|
/* max speed is the minimum of the speed limits of all vehicles in the consist */
|
|
|
if ((rvi_u->railveh_type != RAILVEH_WAGON || _settings_game.vehicle.wagon_speed_limits) && !UsesWagonOverride(u)) {
|
|
|
uint16 speed = GetVehicleProperty(u, PROP_TRAIN_SPEED, rvi_u->max_speed);
|
|
|
if (HasBit(u->flags, VRF_NEED_REPAIR)) speed = u->vcache.cached_max_speed;
|
|
|
if (speed != 0) max_speed = std::min(speed, max_speed);
|
|
|
}
|
|
|
|
|
|
if(u->IsEngine() || u-> IsMultiheaded()) {
|
|
|
this->tcache.cached_num_engines++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
uint16 new_cap = e_u->DetermineCapacity(u);
|
|
@@ -420,6 +454,10 @@ int Train::GetCurrentMaxSpeed() const
|
|
|
}
|
|
|
|
|
|
max_speed = std::min<int>(max_speed, this->current_order.GetMaxSpeed());
|
|
|
if ( HasBit(this->flags, VRF_BREAKDOWN_SPEED) ) {
|
|
|
max_speed = std::min<int>(max_speed, this->GetBreakdownSpeed());
|
|
|
}
|
|
|
|
|
|
return std::min<int>(max_speed, this->gcache.cached_max_track_speed);
|
|
|
}
|
|
|
|
|
@@ -432,6 +470,14 @@ void Train::UpdateAcceleration()
|
|
|
uint weight = this->gcache.cached_weight;
|
|
|
assert(weight != 0);
|
|
|
this->acceleration = Clamp(power / weight * 4, 1, 255);
|
|
|
|
|
|
if (_settings_game.vehicle.improved_breakdowns) {
|
|
|
if (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
|
|
|
this->breakdown_chance = std::max(128 * 3 / (this->tcache.cached_num_engines + 2), 5);
|
|
|
}
|
|
|
} else {
|
|
|
this->breakdown_chance = 128;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -697,6 +743,8 @@ static void AddRearEngineToMultiheadedTr
|
|
|
u->refit_cap = v->refit_cap;
|
|
|
u->railtype = v->railtype;
|
|
|
u->engine_type = v->engine_type;
|
|
|
u->reliability = v->reliability;
|
|
|
u->reliability_spd_dec = v->reliability_spd_dec;
|
|
|
u->date_of_last_service = v->date_of_last_service;
|
|
|
u->build_year = v->build_year;
|
|
|
u->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
|
|
@@ -1936,7 +1984,7 @@ CommandCost CmdReverseTrainDirection(DoC
|
|
|
}
|
|
|
} else {
|
|
|
/* turn the whole train around */
|
|
|
if ((v->vehstatus & VS_CRASHED) || v->breakdown_ctr != 0) return CMD_ERROR;
|
|
|
if ((v->vehstatus & VS_CRASHED) || HasBit(v->flags, VRF_BREAKDOWN_STOPPED)) return CMD_ERROR;
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
|
|
/* Properly leave the station if we are loading and won't be loading anymore */
|
|
@@ -2816,6 +2864,25 @@ int Train::UpdateSpeed()
|
|
|
return this->DoUpdateSpeed(this->GetAcceleration(), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 2, this->GetCurrentMaxSpeed());
|
|
|
}
|
|
|
}
|
|
|
/**
|
|
|
* Handle all breakdown related stuff for a train consist.
|
|
|
* @param v The front engine.
|
|
|
*/
|
|
|
static bool HandlePossibleBreakdowns(Train *v)
|
|
|
{
|
|
|
assert(v->IsFrontEngine());
|
|
|
for (Train *u = v; u != NULL; u = u->Next()) {
|
|
|
if (u->breakdown_ctr != 0 && (u->IsEngine() || u->IsMultiheaded())) {
|
|
|
if (u->breakdown_ctr <= 2) {
|
|
|
if ( u->HandleBreakdown() ) return true;
|
|
|
/* We check the order of v (the first vehicle) instead of u here! */
|
|
|
} else if (!v->current_order.IsType(OT_LOADING)) {
|
|
|
u->breakdown_ctr--;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Trains enters a station, send out a news item if it is the first train, and start loading.
|
|
@@ -3691,12 +3758,8 @@ static bool TrainCheckIfLineEnds(Train *
|
|
|
{
|
|
|
/* First, handle broken down train */
|
|
|
|
|
|
int t = v->breakdown_ctr;
|
|
|
if (t > 1) {
|
|
|
if(HasBit(v->flags, VRF_BREAKDOWN_BRAKING)) {
|
|
|
v->vehstatus |= VS_TRAIN_SLOWING;
|
|
|
|
|
|
uint16 break_speed = _breakdown_speeds[GB(~t, 4, 4)];
|
|
|
if (break_speed < v->cur_speed) v->cur_speed = break_speed;
|
|
|
} else {
|
|
|
v->vehstatus &= ~VS_TRAIN_SLOWING;
|
|
|
}
|
|
@@ -3751,7 +3814,7 @@ static bool TrainLocoHandler(Train *v, b
|
|
|
}
|
|
|
|
|
|
/* train is broken down? */
|
|
|
if (v->HandleBreakdown()) return true;
|
|
|
if ( HandlePossibleBreakdowns(v) ) return true;
|
|
|
|
|
|
if (HasBit(v->flags, VRF_REVERSING) && v->cur_speed == 0) {
|
|
|
ReverseTrainDirection(v);
|
|
@@ -3892,6 +3955,7 @@ Money Train::GetRunningCost() const
|
|
|
if (e->u.rail.running_cost_class == INVALID_PRICE) continue;
|
|
|
|
|
|
uint cost_factor = GetVehicleProperty(v, PROP_TRAIN_RUNNING_COST_FACTOR, e->u.rail.running_cost);
|
|
|
cost_factor *= _settings_game.economy.running_cost_multiplier_rail;
|
|
|
if (cost_factor == 0) continue;
|
|
|
|
|
|
/* Halve running cost for multiheaded parts */
|
|
@@ -3986,7 +4050,6 @@ void Train::OnNewDay()
|
|
|
if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
|
|
|
|
|
|
if (this->IsFrontEngine()) {
|
|
|
CheckVehicleBreakdown(this);
|
|
|
|
|
|
CheckIfTrainNeedsService(this);
|
|
|
|
|
@@ -4011,6 +4074,9 @@ void Train::OnNewDay()
|
|
|
SetWindowClassesDirty(WC_TRAINS_LIST);
|
|
|
}
|
|
|
}
|
|
|
if(IsEngine() || IsMultiheaded()) {
|
|
|
CheckVehicleBreakdown(this);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|