diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -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(max_speed, this->current_order.GetMaxSpeed()); + if ( HasBit(this->flags, VRF_BREAKDOWN_SPEED) ) { + max_speed = std::min(max_speed, this->GetBreakdownSpeed()); + } + return std::min(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); + } } /**