summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/aircraft.h1
-rw-r--r--src/aircraft_cmd.cpp20
-rw-r--r--src/disaster_cmd.cpp7
-rw-r--r--src/roadveh.h1
-rw-r--r--src/roadveh_cmd.cpp22
-rw-r--r--src/train.h1
-rw-r--r--src/train_cmd.cpp59
-rw-r--r--src/vehicle.cpp23
-rw-r--r--src/vehicle_base.h7
-rw-r--r--src/water_cmd.cpp46
10 files changed, 74 insertions, 113 deletions
diff --git a/src/aircraft.h b/src/aircraft.h
index d1664886a..983d3e0e9 100644
--- a/src/aircraft.h
+++ b/src/aircraft.h
@@ -102,6 +102,7 @@ struct Aircraft : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
bool IsInDepot() const { return (this->vehstatus & VS_HIDDEN) != 0 && IsHangarTile(this->tile); }
bool Tick();
void OnNewDay();
+ uint Crash(bool flooded = false);
TileIndex GetOrderStationLocation(StationID station);
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp
index d363fd3d4..dd2884a8c 100644
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -1238,19 +1238,21 @@ void Aircraft::MarkDirty()
if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this);
}
-static void CrashAirplane(Aircraft *v)
+
+uint Aircraft::Crash(bool flooded)
{
- v->vehstatus |= VS_CRASHED;
- v->crashed_counter = 0;
+ uint pass = Vehicle::Crash(flooded) + 2; // pilots
+ this->crashed_counter = flooded ? 9000 : 0; // max 10000, disappear pretty fast when flooded
- CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
+ return pass;
+}
- v->MarkDirty();
- SetWindowDirty(WC_VEHICLE_VIEW, v->index);
+static void CrashAirplane(Aircraft *v)
+{
+ CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
- uint amt = 2;
- if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) amt += v->cargo.Count();
- SetDParam(0, amt);
+ uint pass = v->Crash();
+ SetDParam(0, pass);
v->cargo.Truncate(0);
v->Next()->cargo.Truncate(0);
diff --git a/src/disaster_cmd.cpp b/src/disaster_cmd.cpp
index b1fed1ee9..f2b9badec 100644
--- a/src/disaster_cmd.cpp
+++ b/src/disaster_cmd.cpp
@@ -340,18 +340,13 @@ static bool DisasterTick_Ufo(DisasterVehicle *v)
if (z <= u->z_pos && (u->vehstatus & VS_HIDDEN) == 0) {
v->age++;
if (u->crashed_ctr == 0) {
- u->crashed_ctr++;
+ u->Crash();
AddVehicleNewsItem(STR_NEWS_DISASTER_SMALL_UFO,
NS_ACCIDENT,
u->index); // delete the news, when the roadvehicle is gone
AI::NewEvent(u->owner, new AIEventVehicleCrashed(u->index, u->tile, AIEventVehicleCrashed::CRASH_RV_UFO));
-
- for (Vehicle *w = u; w != NULL; w = w->Next()) {
- w->vehstatus |= VS_CRASHED;
- MarkSingleVehicleDirty(w);
- }
}
}
diff --git a/src/roadveh.h b/src/roadveh.h
index 9eb610a70..835ddc0ad 100644
--- a/src/roadveh.h
+++ b/src/roadveh.h
@@ -125,6 +125,7 @@ struct RoadVehicle : public SpecializedVehicle<RoadVehicle, VEH_ROAD> {
bool IsStoppedInDepot() const;
bool Tick();
void OnNewDay();
+ uint Crash(bool flooded = false);
Trackdir GetVehicleTrackdir() const;
TileIndex GetOrderStationLocation(StationID station);
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp
index ab9982b87..d6c44da4a 100644
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -537,21 +537,17 @@ static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data)
v : NULL;
}
-static void RoadVehCrash(RoadVehicle *v)
+uint RoadVehicle::Crash(bool flooded)
{
- uint16 pass = 1;
-
- v->crashed_ctr++;
-
- for (Vehicle *u = v; u != NULL; u = u->Next()) {
- if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count();
-
- u->vehstatus |= VS_CRASHED;
-
- MarkSingleVehicleDirty(u);
- }
+ uint pass = Vehicle::Crash(flooded);
+ if (this->IsRoadVehFront()) pass += 1; // driver
+ this->crashed_ctr = flooded ? 2000 : 1; // max 2220, disappear pretty fast when flooded
+ return pass;
+}
- SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
+static void RoadVehCrash(RoadVehicle *v)
+{
+ uint pass = v->Crash();
AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
diff --git a/src/train.h b/src/train.h
index 9705c3123..f4f8d741b 100644
--- a/src/train.h
+++ b/src/train.h
@@ -136,6 +136,7 @@ struct Train : public SpecializedVehicle<Train, VEH_TRAIN> {
bool IsStoppedInDepot() const { return CheckTrainStoppedInDepot(this) >= 0; }
bool Tick();
void OnNewDay();
+ uint Crash(bool flooded = false);
Trackdir GetVehicleTrackdir() const;
TileIndex GetOrderStationLocation(StationID station);
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index e6d67abd1..27d8f3a01 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -3188,56 +3188,34 @@ void Train::ReserveTrackUnderConsist() const
}
}
-static void SetVehicleCrashed(Train *v)
+uint Train::Crash(bool flooded)
{
- if (v->crash_anim_pos != 0) return;
+ uint pass = 0;
+ if (this->IsFrontEngine()) {
+ pass += 4; // driver
- if (v->IsFrontEngine()) {
/* Remove the reserved path in front of the train if it is not stuck.
* Also clear all reserved tracks the train is currently on. */
- if (!HasBit(v->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
- for (const Train *u = v; u != NULL; u = u->Next()) {
- ClearPathReservation(u, u->tile, u->GetVehicleTrackdir());
- if (IsTileType(u->tile, MP_TUNNELBRIDGE)) {
+ if (!HasBit(this->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(this);
+ for (const Train *v = this; v != NULL; v = v->Next()) {
+ ClearPathReservation(v, v->tile, v->GetVehicleTrackdir());
+ if (IsTileType(v->tile, MP_TUNNELBRIDGE)) {
/* ClearPathReservation will not free the wormhole exit
* if the train has just entered the wormhole. */
- SetTunnelBridgeReservation(GetOtherTunnelBridgeEnd(u->tile), false);
+ SetTunnelBridgeReservation(GetOtherTunnelBridgeEnd(v->tile), false);
}
}
- }
-
- /* we may need to update crossing we were approaching */
- TileIndex crossing = TrainApproachingCrossingTile(v);
-
- v->crash_anim_pos++;
-
- SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
- SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
-
- if (v->track == TRACK_BIT_DEPOT) {
- SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
- }
- InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
-
- for (; v != NULL; v = v->Next()) {
- v->vehstatus |= VS_CRASHED;
- MarkSingleVehicleDirty(v);
+ /* we may need to update crossing we were approaching,
+ * but must be updated after the train has been marked crashed */
+ TileIndex crossing = TrainApproachingCrossingTile(this);
+ if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
}
- /* must be updated after the train has been marked crashed */
- if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
-}
-
-static uint CountPassengersInTrain(const Train *v)
-{
- uint num = 0;
-
- for (; v != NULL; v = v->Next()) {
- if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo.Count();
- }
+ pass += Vehicle::Crash(flooded);
- return num;
+ this->crash_anim_pos = flooded ? 4000 : 1; // max 4440, disappear pretty fast when flooded
+ return pass;
}
/**
@@ -3252,10 +3230,7 @@ static uint TrainCrashed(Train *v)
/* do not crash train twice */
if (!(v->vehstatus & VS_CRASHED)) {
- /* two drivers + passengers */
- num = 2 + CountPassengersInTrain(v);
-
- SetVehicleCrashed(v);
+ num = v->Crash();
AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_TRAIN));
}
diff --git a/src/vehicle.cpp b/src/vehicle.cpp
index ab4af88bb..1a94c9f82 100644
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -112,6 +112,29 @@ bool Vehicle::NeedsAutomaticServicing() const
return NeedsServicing();
}
+uint Vehicle::Crash(bool flooded)
+{
+ assert((this->vehstatus & VS_CRASHED) == 0);
+ assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
+
+ uint pass = 0;
+ /* crash all wagons, and count passengers */
+ for (Vehicle *v = this; v != NULL; v = v->Next()) {
+ if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
+ v->vehstatus |= VS_CRASHED;
+ MarkSingleVehicleDirty(v);
+ }
+
+ /* Dirty some windows */
+ InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
+ SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
+ SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
+ SetWindowDirty(WC_VEHICLE_DEPOT, this->tile);
+
+ return pass;
+}
+
+
/**
* Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
* @param engine The engine that caused the problem
diff --git a/src/vehicle_base.h b/src/vehicle_base.h
index 1e94d9e75..f01a6e935 100644
--- a/src/vehicle_base.h
+++ b/src/vehicle_base.h
@@ -324,6 +324,13 @@ public:
virtual void OnNewDay() {};
/**
+ * Crash the (whole) vehicle chain.
+ * @param flooded whether the cause of the crash is flooding or not.
+ * @return the number of lost souls.
+ */
+ virtual uint Crash(bool flooded = false);
+
+ /**
* Update vehicle sprite- and position caches
* @param moved Was the vehicle moved?
* @param turned Did the vehicle direction change?
diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp
index 6b155e24a..befe7df8a 100644
--- a/src/water_cmd.cpp
+++ b/src/water_cmd.cpp
@@ -789,8 +789,8 @@ static void FloodVehicle(Vehicle *v)
if (v->type == VEH_AIRCRAFT) {
/* Crashing aircraft are always at z_pos == 1, never on z_pos == 0,
- * because that's always the shadow. Except for the heliport, because
- * that station has a big z_offset for the aircraft. */
+ * because that's always the shadow. Except for the heliport, because
+ * that station has a big z_offset for the aircraft. */
if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
const Station *st = Station::GetByTile(v->tile);
const AirportFTAClass *airport = st->Airport();
@@ -800,47 +800,7 @@ static void FloodVehicle(Vehicle *v)
v = v->First();
}
- uint pass = 0;
- /* crash all wagons, and count passengers */
- for (Vehicle *u = v; u != NULL; u = u->Next()) {
- if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count();
- u->vehstatus |= VS_CRASHED;
- MarkSingleVehicleDirty(u);
- }
-
- switch (v->type) {
- default: NOT_REACHED();
- case VEH_TRAIN: {
- Train *t = Train::From(v);
- if (t->IsFrontEngine()) {
- pass += 4; // driver
- /* FreeTrainTrackReservation() calls GetVehicleTrackdir() that doesn't like crashed vehicles.
- * In this case, v->direction matches v->u.rail.track, so we can do this (it wasn't crashed before) */
- t->vehstatus &= ~VS_CRASHED;
- if (!HasBit(t->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(t);
- t->vehstatus |= VS_CRASHED;
- }
- t->crash_anim_pos = 4000; // max 4440, disappear pretty fast
- InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
- break;
- }
-
- case VEH_ROAD: {
- RoadVehicle *rv = RoadVehicle::From(v);
- if (rv->IsRoadVehFront()) pass += 1; // driver
- rv->crashed_ctr = 2000; // max 2220, disappear pretty fast
- InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
- } break;
-
- case VEH_AIRCRAFT:
- pass += 2; // driver
- Aircraft::From(v)->crashed_counter = 9000; // max 10000, disappear pretty fast
- InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
- break;
- }
-
- SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
- SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
+ uint pass = v->Crash(true);
AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
SetDParam(0, pass);