changeset 12034:aa140a9c419c draft

(svn r16441) -Codechange: new class SpecializedVehicle used as superclass for all vehicle types
author smatz <smatz@openttd.org>
date Tue, 26 May 2009 22:10:13 +0000
parents 3a06a1a551f5
children dcc31c1d758a
files src/ai/api/ai_vehicle.cpp src/aircraft.h src/aircraft_cmd.cpp src/effectvehicle_base.h src/elrail.cpp src/roadveh.h src/roadveh_cmd.cpp src/saveload/afterload.cpp src/saveload/vehicle_sl.cpp src/settings.cpp src/ship.h src/station.cpp src/train.h src/train_cmd.cpp src/vehicle_base.h
diffstat 15 files changed, 153 insertions(+), 138 deletions(-) [+]
line wrap: on
line diff
--- a/src/ai/api/ai_vehicle.cpp
+++ b/src/ai/api/ai_vehicle.cpp
@@ -28,8 +28,9 @@
 	if (!IsValidVehicle(vehicle_id)) return -1;
 
 	int num = 1;
-	if (::Vehicle::Get(vehicle_id)->type == VEH_TRAIN) {
-		const Train *v = (Train *)::Vehicle::Get(vehicle_id);
+
+	const Train *v = ::Train::GetIfValid(vehicle_id);
+	if (v != NULL) {
 		while ((v = GetNextUnit(v)) != NULL) num++;
 	}
 
--- a/src/aircraft.h
+++ b/src/aircraft.h
@@ -96,7 +96,7 @@
  *
  * As side-effect the vehicle type is set correctly.
  */
-struct Aircraft : public Vehicle {
+struct Aircraft : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
 	AircraftCache acache; ///< Cache of often used calculated values
 
 	uint16 crashed_counter;
@@ -125,10 +125,10 @@
 	void OnNewDay();
 	TileIndex GetOrderStationLocation(StationID station);
 	bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
-	Aircraft *Next() { return (Aircraft *)this->Vehicle::Next(); }
-	const Aircraft *Next() const { return (const Aircraft *)this->Vehicle::Next(); }
 };
 
+#define FOR_ALL_AIRCRAFT(var) FOR_ALL_VEHICLES_OF_TYPE(Aircraft, var)
+
 SpriteID GetRotorImage(const Aircraft *v);
 
 Station *GetTargetAirportIfValid(const Aircraft *v);
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -2073,10 +2073,9 @@
 	/* only 1 station is updated per function call, so it is enough to get entry_point once */
 	const AirportFTAClass *ap = st->Airport();
 
-	Vehicle *u;
-	FOR_ALL_VEHICLES(u) {
-		if (u->type == VEH_AIRCRAFT && IsNormalAircraft(u)) {
-			Aircraft *v = (Aircraft *)u;
+	Aircraft *v;
+	FOR_ALL_AIRCRAFT(v) {
+		if (IsNormalAircraft(v)) {
 			if (v->targetairport == st->index) { // if heading to this airport
 				/* update position of airplane. If plane is not flying, landing, or taking off
 				 * you cannot delete airport, so it doesn't matter */
--- a/src/effectvehicle_base.h
+++ b/src/effectvehicle_base.h
@@ -22,7 +22,7 @@
  *  - bulldozer (road works)
  *  - bubbles (industry)
  */
-struct EffectVehicle : public Vehicle {
+struct EffectVehicle : public SpecializedVehicle<EffectVehicle, VEH_EFFECT> {
 	uint16 animation_state;
 	byte animation_substate;
 
--- a/src/elrail.cpp
+++ b/src/elrail.cpp
@@ -532,8 +532,8 @@
 
 bool SettingsDisableElrail(int32 p1)
 {
-	Vehicle *v;
 	Company *c;
+	Train *t;
 	bool disable = (p1 != 0);
 
 	/* we will now walk through all electric train engines and change their railtypes if it is the wrong one*/
@@ -554,10 +554,7 @@
 	/* when disabling elrails, make sure that all existing trains can run on
 	 *  normal rail too */
 	if (disable) {
-		FOR_ALL_VEHICLES(v) {
-			if (v->type != VEH_TRAIN) continue;
-
-			Train *t = (Train *)v;
+		FOR_ALL_TRAINS(t) {
 			if (t->railtype == RAILTYPE_ELECTRIC) {
 				/* this railroad vehicle is now compatible only with elrail,
 				 *  so add there also normal rail compatibility */
@@ -569,10 +566,9 @@
 	}
 
 	/* Fix the total power and acceleration for trains */
-	FOR_ALL_VEHICLES(v) {
+	FOR_ALL_TRAINS(t) {
 		/* power and acceleration is cached only for front engines */
-		if (v->type == VEH_TRAIN && IsFrontEngine(v)) {
-			Train *t = (Train *)v;
+		if (IsFrontEngine(t)) {
 			TrainPowerChanged(t);
 			UpdateTrainAcceleration(t);
 		}
--- a/src/roadveh.h
+++ b/src/roadveh.h
@@ -123,7 +123,7 @@
  *
  * As side-effect the vehicle type is set correctly.
  */
-struct RoadVehicle : public Vehicle {
+struct RoadVehicle : public SpecializedVehicle<RoadVehicle, VEH_ROAD> {
 	RoadVehicleCache rcache; ///< Cache of often used calculated values
 	byte state;             ///< @see RoadVehicleStates
 	byte frame;
@@ -160,9 +160,8 @@
 	Trackdir GetVehicleTrackdir() const;
 	TileIndex GetOrderStationLocation(StationID station);
 	bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
-	RoadVehicle *First() { return (RoadVehicle *)this->Vehicle::First(); }
-	RoadVehicle *Next() { return (RoadVehicle *)this->Vehicle::Next(); }
-	const RoadVehicle *Next() const { return (const RoadVehicle *)this->Vehicle::Next(); }
 };
 
+#define FOR_ALL_ROADVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(RoadVehicle, var)
+
 #endif /* ROADVEH_H */
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -432,10 +432,8 @@
  */
 CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	Vehicle *u = Vehicle::GetIfValid(p1);
-	if (u == NULL || u->type != VEH_ROAD || !CheckOwnership(u->owner)) return CMD_ERROR;
-
-	RoadVehicle *v = (RoadVehicle *)u;
+	RoadVehicle *v = RoadVehicle::GetIfValid(p1);
+	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 
 	if (v->vehstatus & VS_STOPPED ||
 			v->vehstatus & VS_CRASHED ||
@@ -2065,7 +2063,7 @@
 		}
 	}
 
-	if (flags & DC_EXEC) RoadVehUpdateCache((RoadVehicle *)Vehicle::Get(p1)->First());
+	if (flags & DC_EXEC) RoadVehUpdateCache(RoadVehicle::Get(p1)->First());
 
 	_returned_refit_capacity = total_capacity;
 
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -921,16 +921,14 @@
 
 	/* Elrails got added in rev 24 */
 	if (CheckSavegameVersion(24)) {
-		Vehicle *v;
 		RailType min_rail = RAILTYPE_ELECTRIC;
 
-		FOR_ALL_VEHICLES(v) {
-			if (v->type == VEH_TRAIN) {
-				RailType rt = RailVehInfo(v->engine_type)->railtype;
+		Train *v;
+		FOR_ALL_TRAINS(v) {
+			RailType rt = RailVehInfo(v->engine_type)->railtype;
 
-				((Train *)v)->railtype = rt;
-				if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL;
-			}
+			v->railtype = rt;
+			if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL;
 		}
 
 		/* .. so we convert the entire map from normal to elrail (so maintain "fairness") */
@@ -963,8 +961,8 @@
 			}
 		}
 
-		FOR_ALL_VEHICLES(v) {
-			if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged((Train *)v, true);
+		FOR_ALL_TRAINS(v) {
+			if (IsFrontEngine(v) || IsFreeWagon(v)) TrainConsistChanged(v, true);
 		}
 
 	}
@@ -1046,20 +1044,15 @@
 	}
 
 	if (CheckSavegameVersion(25)) {
-		Vehicle *v;
-		FOR_ALL_VEHICLES(v) {
-			if (v->type == VEH_ROAD) {
-				RoadVehicle *rv = (RoadVehicle *)v;
-				rv->vehstatus &= ~0x40;
-				rv->slot = NULL;
-				rv->slot_age = 0;
-			}
+		RoadVehicle *rv;
+		FOR_ALL_ROADVEHICLES(rv) {
+			rv->vehstatus &= ~0x40;
+			rv->slot = NULL;
+			rv->slot_age = 0;
 		}
 	} else {
-		Vehicle *v;
-		FOR_ALL_VEHICLES(v) {
-			if (v->type != VEH_ROAD) continue;
-			RoadVehicle *rv = (RoadVehicle *)v;
+		RoadVehicle *rv;
+		FOR_ALL_ROADVEHICLES(rv) {
 			if (rv->slot != NULL) rv->slot->num_vehicles++;
 		}
 	}
@@ -1382,10 +1375,8 @@
 
 	if (CheckSavegameVersion(69)) {
 		/* In some old savegames a bit was cleared when it should not be cleared */
-		Vehicle *v;
-		FOR_ALL_VEHICLES(v) {
-			if (v->type != VEH_ROAD) continue;
-			RoadVehicle *rv = (RoadVehicle *)v;
+		RoadVehicle *rv;
+		FOR_ALL_ROADVEHICLES(rv) {
 			if (rv->state == 250 || rv->state == 251) {
 				SetBit(rv->state, RVS_IS_STOPPING);
 			}
@@ -1708,15 +1699,12 @@
 
 	/* Reserve all tracks trains are currently on. */
 	if (CheckSavegameVersion(101)) {
-		Vehicle *u;
-		FOR_ALL_VEHICLES(u) {
-			if (u->type == VEH_TRAIN) {
-				Train *v = (Train *)u;
-				if ((v->track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
-					TryReserveRailTrack(v->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(v->tile)));
-				} else if ((v->track & TRACK_BIT_MASK) != TRACK_BIT_NONE) {
-					TryReserveRailTrack(v->tile, TrackBitsToTrack(v->track));
-				}
+		Train *t;
+		FOR_ALL_TRAINS(t) {
+			if ((t->track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
+				TryReserveRailTrack(t->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(t->tile)));
+			} else if ((t->track & TRACK_BIT_MASK) != TRACK_BIT_NONE) {
+				TryReserveRailTrack(t->tile, TrackBitsToTrack(t->track));
 			}
 		}
 	}
--- a/src/saveload/vehicle_sl.cpp
+++ b/src/saveload/vehicle_sl.cpp
@@ -20,16 +20,14 @@
  */
 void ConnectMultiheadedTrains()
 {
-	Vehicle *v;
+	Train *v;
 
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_TRAIN) {
-			((Train *)v)->other_multiheaded_part = NULL;
-		}
+	FOR_ALL_TRAINS(v) {
+		v->other_multiheaded_part = NULL;
 	}
 
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
+	FOR_ALL_TRAINS(v) {
+		if (IsFrontEngine(v) || IsFreeWagon(v)) {
 			/* Two ways to associate multiheaded parts to each other:
 			 * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>..
 			 * bracket-matching:    Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>..
@@ -45,7 +43,7 @@
 
 			bool sequential_matching = IsFrontEngine(v);
 
-			for (Train *u = (Train *)v; u != NULL; u = (Train *)GetNextVehicle(u)) {
+			for (Train *u = v; u != NULL; u = GetNextVehicle(u)) {
 				if (u->other_multiheaded_part != NULL) continue; // we already linked this one
 
 				if (IsMultiheaded(u)) {
@@ -167,13 +165,11 @@
 		st->airport_flags = 0; // reset airport
 	}
 
-	Vehicle *v;
-	FOR_ALL_VEHICLES(v) {
+	Aircraft *a;
+	FOR_ALL_AIRCRAFT(a) {
 		/* airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor)
 		 * skip those */
-		if (v->type == VEH_AIRCRAFT && IsNormalAircraft(v)) {
-			Aircraft *v_oldstyle = (Aircraft *)v;
-			Aircraft *a = (Aircraft *)v_oldstyle;
+		if (IsNormalAircraft(a)) {
 			/* airplane in terminal stopped doesn't hurt anyone, so goto next */
 			if (a->vehstatus & VS_STOPPED && a->state == 0) {
 				a->state = HANGAR;
@@ -182,7 +178,7 @@
 
 			AircraftLeaveHangar(a); // make airplane visible if it was in a depot for example
 			a->vehstatus &= ~VS_STOPPED; // make airplane moving
-			a->cur_speed = v_oldstyle->max_speed; // so aircraft don't have zero speed while in air
+			a->cur_speed = a->max_speed; // so aircraft don't have zero speed while in air
 			if (!a->current_order.IsType(OT_GOTO_STATION) && !a->current_order.IsType(OT_GOTO_DEPOT)) {
 				/* reset current order so aircraft doesn't have invalid "station-only" order */
 				a->current_order.MakeDummy();
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -695,10 +695,10 @@
 
 static bool UpdateConsists(int32 p1)
 {
-	Vehicle *v;
-	FOR_ALL_VEHICLES(v) {
+	Train *t;
+	FOR_ALL_TRAINS(t) {
 		/* Update the consist of all trains so the maximum speed is set correctly. */
-		if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged((Train *)v, true);
+		if (IsFrontEngine(t) || IsFreeWagon(t)) TrainConsistChanged(t, true);
 	}
 	return true;
 }
@@ -732,10 +732,9 @@
 
 static bool TrainAccelerationModelChanged(int32 p1)
 {
-	Vehicle *v;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_TRAIN && IsFrontEngine(v)) UpdateTrainAcceleration((Train *)v);
+	Train *t;
+	FOR_ALL_TRAINS(t) {
+		if (IsFrontEngine(t)) UpdateTrainAcceleration(t);
 	}
 
 	return true;
--- a/src/ship.h
+++ b/src/ship.h
@@ -22,7 +22,7 @@
  *
  * As side-effect the vehicle type is set correctly.
  */
-struct Ship: public Vehicle {
+struct Ship: public SpecializedVehicle<Ship, VEH_SHIP> {
 	TrackBitsByte state;
 
 	/** Initializes the Vehicle to a ship */
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -69,11 +69,9 @@
 		loading_vehicles.front()->LeaveStation();
 	}
 
-	Vehicle *v;
-	FOR_ALL_VEHICLES(v) {
-		if (v->type != VEH_AIRCRAFT || !IsNormalAircraft(v)) continue;
-
-		Aircraft *a = (Aircraft *)v;
+	Aircraft *a;
+	FOR_ALL_AIRCRAFT(a) {
+		if (!IsNormalAircraft(a)) continue;
 		if (a->targetairport == this->index) a->targetairport = INVALID_STATION;
 	}
 
@@ -463,12 +461,8 @@
 
 	/* Clear the slot assignment of all vehicles heading for this road stop */
 	if (num_vehicles != 0) {
-		Vehicle *v;
-
-		FOR_ALL_VEHICLES(v) {
-			if (v->type != VEH_ROAD) continue;
-			RoadVehicle *rv = (RoadVehicle *)v;
-
+		RoadVehicle *rv;
+		FOR_ALL_ROADVEHICLES(rv) {
 			if (rv->slot == this) ClearSlot(rv);
 		}
 	}
--- a/src/train.h
+++ b/src/train.h
@@ -301,7 +301,7 @@
  *
  * As side-effect the vehicle type is set correctly.
  */
-struct Train : public Vehicle {
+struct Train : public SpecializedVehicle<Train, VEH_TRAIN> {
 	TrainCache tcache;
 
 	/* Link between the two ends of a multiheaded engine */
@@ -338,14 +338,10 @@
 	Trackdir GetVehicleTrackdir() const;
 	TileIndex GetOrderStationLocation(StationID station);
 	bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
-	Train *First() { return (Train *)this->Vehicle::First(); }
-	Train *First() const { return (Train *)this->Vehicle::First(); }
-	Train *Next() { return (Train *)this->Vehicle::Next(); }
-	Train *Next() const { return (Train *)this->Vehicle::Next(); }
-	Train *Previous() { return (Train *)this->Vehicle::Previous(); }
-	Train *Previous() const { return (Train *)this->Vehicle::Previous(); }
 };
 
+#define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)
+
 /**
  * Get the next part of a multi-part engine.
  * Will only work on a multi-part engine (EngineHasArticPart(v) == true),
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -973,18 +973,17 @@
 
 static Train *FindGoodVehiclePos(const Train *src)
 {
-	Vehicle *dst;
 	EngineID eng = src->engine_type;
 	TileIndex tile = src->tile;
 
-	FOR_ALL_VEHICLES(dst) {
-		if (dst->type == VEH_TRAIN && IsFreeWagon(dst) && dst->tile == tile && !HASBITS(dst->vehstatus, VS_CRASHED)) {
+	Train *dst;
+	FOR_ALL_TRAINS(dst) {
+		if (IsFreeWagon(dst) && dst->tile == tile && !HASBITS(dst->vehstatus, VS_CRASHED)) {
 			/* check so all vehicles in the line have the same engine. */
-			Vehicle *v = dst;
-
-			while (v->engine_type == eng) {
-				v = v->Next();
-				if (v == NULL) return (Train *)dst;
+			Train *t = dst;
+			while (t->engine_type == eng) {
+				t = t->Next();
+				if (t == NULL) return dst;
 			}
 		}
 	}
@@ -1045,25 +1044,22 @@
 	VehicleID s = GB(p1, 0, 16);
 	VehicleID d = GB(p1, 16, 16);
 
-	Vehicle *src_v = Vehicle::GetIfValid(s);
-	if (src_v == NULL || src_v->type != VEH_TRAIN || !CheckOwnership(src_v->owner)) return CMD_ERROR;
+	Train *src = Train::GetIfValid(s);
+	if (src == NULL || !CheckOwnership(src->owner)) return CMD_ERROR;
 
 	/* Do not allow moving crashed vehicles inside the depot, it is likely to cause asserts later */
-	if (HASBITS(src_v->vehstatus, VS_CRASHED)) return CMD_ERROR;
-
-	Train *src = (Train *)src_v;
+	if (HASBITS(src->vehstatus, VS_CRASHED)) return CMD_ERROR;
 
 	/* if nothing is selected as destination, try and find a matching vehicle to drag to. */
 	Train *dst;
 	if (d == INVALID_VEHICLE) {
 		dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src);
 	} else {
-		Vehicle *dst_v = Vehicle::GetIfValid(d);
-		if (dst_v == NULL || dst_v->type != VEH_TRAIN || !CheckOwnership(dst_v->owner)) return CMD_ERROR;
+		dst = Train::GetIfValid(d);
+		if (dst == NULL || !CheckOwnership(dst->owner)) return CMD_ERROR;
 
 		/* Do not allow appending to crashed vehicles, too */
-		if (HASBITS(dst_v->vehstatus, VS_CRASHED)) return CMD_ERROR;
-		dst = (Train *)dst_v;
+		if (HASBITS(dst->vehstatus, VS_CRASHED)) return CMD_ERROR;
 	}
 
 	/* if an articulated part is being handled, deal with its parent vehicle */
@@ -1399,13 +1395,12 @@
 	/* Check if we deleted a vehicle window */
 	Window *w = NULL;
 
-	Vehicle *vt = Vehicle::GetIfValid(p1);
-	if (vt == NULL || vt->type != VEH_TRAIN || !CheckOwnership(vt->owner)) return CMD_ERROR;
+	Train *v = Train::GetIfValid(p1);
+	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 	if (p2 > 1) return CMD_ERROR;
 
-	if (HASBITS(vt->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE);
-
-	Train *v = (Train *)vt;
+	if (HASBITS(v->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE);
+
 	while (IsArticulatedPart(v)) v = v->Previous();
 	Train *first = v->First();
 
@@ -1955,10 +1950,8 @@
  */
 CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	Vehicle *vt = Vehicle::GetIfValid(p1);
-	if (vt == NULL || vt->type != VEH_TRAIN || !CheckOwnership(vt->owner)) return CMD_ERROR;
-
-	Train *v = (Train *)vt;
+	Train *v = Train::GetIfValid(p1);
+	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 
 	if (p2 != 0) {
 		/* turn a single unit around */
@@ -2015,10 +2008,10 @@
  */
 CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	Vehicle *v = Vehicle::GetIfValid(p1);
-	if (v == NULL || v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
-
-	if (flags & DC_EXEC) ((Train *)v)->force_proceed = 0x50;
+	Train *t = Train::GetIfValid(p1);
+	if (t == NULL || !CheckOwnership(t->owner)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) t->force_proceed = 0x50;
 
 	return CommandCost();
 }
@@ -2039,10 +2032,9 @@
 	byte new_subtype = GB(p2, 8, 8);
 	bool only_this = HasBit(p2, 16);
 
-	Vehicle *vt = Vehicle::GetIfValid(p1);
-	if (vt == NULL || vt->type != VEH_TRAIN || !CheckOwnership(vt->owner)) return CMD_ERROR;
-
-	Train *v = (Train *)vt;
+	Train *v = Train::GetIfValid(p1);
+	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
+
 	if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED);
 	if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_CAN_T_REFIT_DESTROYED_VEHICLE);
 
@@ -2116,7 +2108,7 @@
 	_returned_refit_capacity = num;
 
 	/* Update the train's cached variables */
-	if (flags & DC_EXEC) TrainConsistChanged((Train *)Vehicle::Get(p1)->First(), false);
+	if (flags & DC_EXEC) TrainConsistChanged(Train::Get(p1)->First(), false);
 
 	return cost;
 }
--- a/src/vehicle_base.h
+++ b/src/vehicle_base.h
@@ -492,6 +492,64 @@
 };
 
 /**
+ * Class defining several overloaded accessors so we don't
+ * have to cast vehicle types that often
+ */
+template <class T, VehicleType Type>
+struct SpecializedVehicle : public Vehicle {
+	static const VehicleType EXPECTED_TYPE = Type; ///< Specialized type
+
+	/**
+	 * Get the first vehicle in the chain
+	 * @return first vehicle in the chain
+	 */
+	FORCEINLINE T *First() const { return (T *)this->Vehicle::First(); }
+
+	/**
+	 * Get next vehicle in the chain
+	 * @return next vehicle in the chain
+	 */
+	FORCEINLINE T *Next() const { return (T *)this->Vehicle::Next(); }
+
+	/**
+	 * Get previous vehicle in the chain
+	 * @return previous vehicle in the chain
+	 */
+	FORCEINLINE T *Previous() const { return (T *)this->Vehicle::Previous(); }
+
+
+	/**
+	 * Tests whether given index is a valid index for vehicle of this type
+	 * @param index tested index
+	 * @return is this index valid index of T?
+	 */
+	static FORCEINLINE bool IsValidID(size_t index)
+	{
+		return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
+	}
+
+	/**
+	 * Gets vehicle with given index
+	 * @return pointer to vehicle with given index casted to T *
+	 */
+	static FORCEINLINE T *Get(size_t index)
+	{
+		return (T *)Vehicle::Get(index);
+	}
+
+	/**
+	 * Returns vehicle if the index is a valid index for this vehicle type
+	 * @return pointer to vehicle with given index if it's a vehicle of this type
+	 */
+	static FORCEINLINE T *GetIfValid(size_t index)
+	{
+		return IsValidID(index) ? Get(index) : NULL ;
+	}
+};
+
+#define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
+
+/**
  * This class 'wraps' Vehicle; you do not actually instantiate this class.
  * You create a Vehicle using AllocateVehicle, so it is added to the pool
  * and you reinitialize that to a Train using:
@@ -499,7 +557,7 @@
  *
  * As side-effect the vehicle type is set correctly.
  */
-struct DisasterVehicle : public Vehicle {
+struct DisasterVehicle : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
 	uint16 image_override;
 	VehicleID big_ufo_destroyer_target;
 
@@ -512,7 +570,6 @@
 	const char *GetTypeString() const { return "disaster vehicle"; }
 	void UpdateDeltaXY(Direction direction);
 	bool Tick();
-	DisasterVehicle *Next() { return (DisasterVehicle*)this->Vehicle::Next(); }
 };
 
 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)