Make trains break down after collision with road vehicle.

pull/19/head
Jonathan G Rennison 7 years ago
parent 44fa555c6d
commit 350c2bb24f

@ -3646,6 +3646,7 @@ STR_BREAKDOWN_TYPE_CRITICAL :Mechanical fail
STR_BREAKDOWN_TYPE_EM_STOP :Emergency stop
STR_BREAKDOWN_TYPE_LOW_SPEED :Limited to {VELOCITY}
STR_BREAKDOWN_TYPE_LOW_POWER :{COMMA}% Power
STR_BREAKDOWN_TYPE_HIT_RV :Collided with road vehicle
STR_BREAKDOWN_TYPE_DEPOT :Heading to {STATION} Hangar for repairs
STR_BREAKDOWN_TYPE_LANDING :Heading to {STATION} for emergency landing
STR_ERROR_TRAIN_TOO_HEAVY :{WHITE}{VEHICLE} is too heavy

@ -511,20 +511,35 @@ static bool RoadVehIsCrashed(RoadVehicle *v)
return true;
}
struct CheckRoadVehCrashTrainInfo {
const Vehicle *u;
bool found = false;
CheckRoadVehCrashTrainInfo(const Vehicle *u_)
: u(u_) { }
};
/**
* Check routine whether a road and a train vehicle have collided.
* @param v %Train vehicle to test.
* @param data Road vehicle to test.
* @param data Info including road vehicle to test.
* @return %Train vehicle if the vehicles collided, else \c NULL.
*/
static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data)
{
const Vehicle *u = (Vehicle*)data;
return (v->type == VEH_TRAIN &&
abs(v->z_pos - u->z_pos) <= 6 &&
abs(v->x_pos - u->x_pos) <= 4 &&
abs(v->y_pos - u->y_pos) <= 4) ? v : NULL;
CheckRoadVehCrashTrainInfo *info = (CheckRoadVehCrashTrainInfo*) data;
if (v->type == VEH_TRAIN &&
abs(v->z_pos - info->u->z_pos) <= 6 &&
abs(v->x_pos - info->u->x_pos) <= 4 &&
abs(v->y_pos - info->u->y_pos) <= 4) {
info->found = true;
extern void TrainRoadVehicleCrashBreakdown(Vehicle *v);
TrainRoadVehicleCrashBreakdown(v);
return v;
} else {
return NULL;
}
}
uint RoadVehicle::Crash(bool flooded)
@ -570,7 +585,9 @@ static bool RoadVehCheckTrainCrash(RoadVehicle *v)
if (!IsLevelCrossingTile(tile)) continue;
if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) {
CheckRoadVehCrashTrainInfo info(u);
FindVehicleOnPosXY(v->x_pos, v->y_pos, &info, EnumCheckRoadVehCrashTrain);
if (info.found) {
RoadVehCrash(v);
return true;
}

@ -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, 4, 4, "improved_breakdowns", NULL, NULL, NULL },
{ XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 5, 5, "improved_breakdowns", NULL, NULL, NULL },
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
};

@ -28,7 +28,7 @@ enum VehicleRailFlags {
VRF_REVERSING = 0,
VRF_POWEREDWAGON = 3, ///< Wagon is powered.
VRF_REVERSE_DIRECTION = 4, ///< Reverse the visible direction of the vehicle.
VRF_HAS_HIT_RV = 5, ///< Train has hit road vehicle
VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL = 6, ///< Electric train engine is allowed to run on normal rail. */
VRF_TOGGLE_REVERSE = 7, ///< Used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle only).
VRF_TRAIN_STUCK = 8, ///< Train can't get a path reservation.

@ -139,6 +139,7 @@ void CheckBreakdownFlags(Train *v)
} else if (w->breakdown_ctr == 1) {
switch (w->breakdown_type) {
case BREAKDOWN_CRITICAL:
case BREAKDOWN_RV_CRASH:
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;
@ -156,6 +157,9 @@ uint16 GetTrainVehicleMaxSpeed(const Train *u, const RailVehicleInfo *rvi_u, con
speed = min(speed - (speed / (front->tcache.cached_num_engines + 2)) + 1, speed);
}
}
if (HasBit(u->flags, VRF_HAS_HIT_RV) && front->IsFrontEngine()) {
speed = min(speed, 30);
}
return speed;
}
@ -4118,3 +4122,13 @@ Trackdir Train::GetVehicleTrackdir() const
return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction);
}
void TrainRoadVehicleCrashBreakdown(Vehicle *v)
{
Train *t = Train::From(v)->First();
t->breakdown_ctr = 2;
t->breakdown_delay = 255;
t->breakdown_type = BREAKDOWN_RV_CRASH;
t->breakdown_severity = 0;
t->reliability = 0;
}

@ -144,7 +144,8 @@ void VehicleServiceInDepot(Vehicle *v)
if (v->type == VEH_TRAIN) {
if (v->Next() != NULL) VehicleServiceInDepot(v->Next());
if (!(Train::From(v)->IsEngine()) && !(Train::From(v)->IsRearDualheaded())) return;
ClrBit(Train::From(v)->flags,VRF_NEED_REPAIR);
ClrBit(Train::From(v)->flags, VRF_NEED_REPAIR);
ClrBit(Train::From(v)->flags, VRF_HAS_HIT_RV);
Train::From(v)->critical_breakdown_count = 0;
const RailVehicleInfo *rvi = &e->u.rail;
v->vcache.cached_max_speed = rvi->max_speed;
@ -1395,6 +1396,9 @@ bool Vehicle::HandleBreakdown()
if (this->breakdown_type == BREAKDOWN_LOW_POWER ||
this->First()->cur_speed <= ((this->breakdown_type == BREAKDOWN_LOW_SPEED) ? this->breakdown_severity : 0)) {
switch (this->breakdown_type) {
case BREAKDOWN_RV_CRASH:
if (_settings_game.vehicle.improved_breakdowns) SetBit(Train::From(this)->flags, VRF_HAS_HIT_RV);
/* FALL THROUGH */
case BREAKDOWN_CRITICAL:
if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP;
@ -1495,7 +1499,7 @@ bool Vehicle::HandleBreakdown()
}
}
}
return (this->breakdown_type == BREAKDOWN_CRITICAL || this->breakdown_type == BREAKDOWN_EM_STOP);
return (this->breakdown_type == BREAKDOWN_CRITICAL || this->breakdown_type == BREAKDOWN_EM_STOP || this->breakdown_type == BREAKDOWN_RV_CRASH);
default:
if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;

@ -87,6 +87,7 @@ enum BreakdownType {
BREAKDOWN_EM_STOP = 1, ///< Emergency stop
BREAKDOWN_LOW_SPEED = 2, ///< Lower max speed
BREAKDOWN_LOW_POWER = 3, ///< Power reduction
BREAKDOWN_RV_CRASH = 4, ///< Train hit road vehicle
BREAKDOWN_AIRCRAFT_SPEED = BREAKDOWN_CRITICAL, ///< Lower speed until the next airport
BREAKDOWN_AIRCRAFT_DEPOT = BREAKDOWN_EM_STOP, ///< We have to visit a depot at the next airport

Loading…
Cancel
Save