changeset 13873:85b3d1a4faff draft

(svn r18402) -Codechange: unify/centralise the code for crashing vehicles
author rubidium <rubidium@openttd.org>
date Fri, 04 Dec 2009 20:29:46 +0000
parents 34c1f1b5cada
children 8110208583b6
files src/aircraft.h src/aircraft_cmd.cpp src/disaster_cmd.cpp src/roadveh.h src/roadveh_cmd.cpp src/train.h src/train_cmd.cpp src/vehicle.cpp src/vehicle_base.h src/water_cmd.cpp
diffstat 10 files changed, 77 insertions(+), 116 deletions(-) [+]
line wrap: on
line diff
--- a/src/aircraft.h
+++ b/src/aircraft.h
@@ -102,6 +102,7 @@
 	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);
 
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -1238,19 +1238,21 @@
 	if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this);
 }
 
+
+uint Aircraft::Crash(bool flooded)
+{
+	uint pass = Vehicle::Crash(flooded) + 2; // pilots
+	this->crashed_counter = flooded ? 9000 : 0; // max 10000, disappear pretty fast when flooded
+
+	return pass;
+}
+
 static void CrashAirplane(Aircraft *v)
 {
-	v->vehstatus |= VS_CRASHED;
-	v->crashed_counter = 0;
-
 	CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
 
-	v->MarkDirty();
-	SetWindowDirty(WC_VEHICLE_VIEW, v->index);
-
-	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);
--- a/src/disaster_cmd.cpp
+++ b/src/disaster_cmd.cpp
@@ -340,18 +340,13 @@
 		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);
-				}
 			}
 		}
 
--- a/src/roadveh.h
+++ b/src/roadveh.h
@@ -125,6 +125,7 @@
 	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);
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -537,21 +537,17 @@
 			v : NULL;
 }
 
+uint RoadVehicle::Crash(bool flooded)
+{
+	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;
+}
+
 static void RoadVehCrash(RoadVehicle *v)
 {
-	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);
-	}
-
-	SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
+	uint pass = v->Crash();
 
 	AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
 
--- a/src/train.h
+++ b/src/train.h
@@ -136,6 +136,7 @@
 	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);
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -3188,56 +3188,34 @@
 	}
 }
 
-static void SetVehicleCrashed(Train *v)
+uint Train::Crash(bool flooded)
 {
-	if (v->crash_anim_pos != 0) return;
-
-	if (v->IsFrontEngine()) {
+	uint pass = 0;
+	if (this->IsFrontEngine()) {
+		pass += 4; // driver
+
 		/* 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);
+
+		/* 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);
 	}
 
-	InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
-
-	for (; v != NULL; v = v->Next()) {
-		v->vehstatus |= VS_CRASHED;
-		MarkSingleVehicleDirty(v);
-	}
-
-	/* 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();
-	}
-
-	return num;
+	pass += Vehicle::Crash(flooded);
+
+	this->crash_anim_pos = flooded ? 4000 : 1; // max 4440, disappear pretty fast when flooded
+	return pass;
 }
 
 /**
@@ -3252,10 +3230,7 @@
 
 	/* 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));
 	}
 
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -112,6 +112,29 @@
 	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
--- a/src/vehicle_base.h
+++ b/src/vehicle_base.h
@@ -324,6 +324,13 @@
 	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?
--- a/src/water_cmd.cpp
+++ b/src/water_cmd.cpp
@@ -789,8 +789,8 @@
 
 	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 @@
 		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);