changeset 11984:b6d3e583be86 draft

(svn r16390) -Codechange: move u.road to RoadVehicle.
author rubidium <rubidium@openttd.org>
date Fri, 22 May 2009 20:22:20 +0000
parents 6fae1efe3ae2
children e05790b0a6c6
files src/ai/api/ai_vehicle.cpp src/articulated_vehicles.cpp src/depot_gui.cpp src/disaster_cmd.cpp src/newgrf_engine.cpp src/openttd.cpp src/road_cmd.cpp src/roadveh.h src/roadveh_cmd.cpp src/roadveh_gui.cpp src/saveload/afterload.cpp src/saveload/oldloader_sl.cpp src/saveload/vehicle_sl.cpp src/station.cpp src/station_cmd.cpp src/tunnelbridge_cmd.cpp src/vehicle.cpp src/vehicle_base.h src/vehicle_gui.cpp src/water_cmd.cpp src/yapf/follow_track.hpp src/yapf/yapf_road.cpp
diffstat 22 files changed, 308 insertions(+), 287 deletions(-) [+]
line wrap: on
line diff
--- a/src/ai/api/ai_vehicle.cpp
+++ b/src/ai/api/ai_vehicle.cpp
@@ -45,7 +45,7 @@
 		case VEH_ROAD: {
 			uint total_length = 0;
 			for (const Vehicle *u = v; u != NULL; u = u->Next()) {
-				total_length += u->u.road.cached_veh_length;
+				total_length += ((RoadVehicle*)u)->cached_veh_length;
 			}
 			return total_length;
 		}
@@ -368,7 +368,7 @@
 	if (!IsValidVehicle(vehicle_id)) return AIRoad::ROADTYPE_INVALID;
 	if (GetVehicleType(vehicle_id) != VT_ROAD) return AIRoad::ROADTYPE_INVALID;
 
-	return (AIRoad::RoadType)::Vehicle::Get(vehicle_id)->u.road.roadtype;
+	return (AIRoad::RoadType)((RoadVehicle*)::Vehicle::Get(vehicle_id))->roadtype;
 }
 
 /* static */ int32 AIVehicle::GetCapacity(VehicleID vehicle_id, CargoID cargo)
--- a/src/articulated_vehicles.cpp
+++ b/src/articulated_vehicles.cpp
@@ -327,28 +327,30 @@
 				SetArticulatedPart(u);
 				break;
 
-			case VEH_ROAD:
-				u = new RoadVehicle();
-				u->subtype = 0;
+			case VEH_ROAD: {
+				RoadVehicle *front = (RoadVehicle *)v;
+				RoadVehicle *rv = new RoadVehicle();
+				rv->subtype = 0;
 				previous->SetNext(u);
-				u->u.road.first_engine = v->engine_type;
-				u->u.road.cached_veh_length = 8; // Callback is called when the consist is finished
-				u->u.road.state = RVSB_IN_DEPOT;
+				rv->first_engine = front->engine_type;
+				rv->cached_veh_length = 8; // Callback is called when the consist is finished
+				rv->state = RVSB_IN_DEPOT;
 
-				u->u.road.roadtype = v->u.road.roadtype;
-				u->u.road.compatible_roadtypes = v->u.road.compatible_roadtypes;
+				rv->roadtype = front->roadtype;
+				rv->compatible_roadtypes = front->compatible_roadtypes;
 
-				u->spritenum = e_artic->u.road.image_index;
+				rv->spritenum = e_artic->image_index;
 				if (e_artic->CanCarryCargo()) {
-					u->cargo_type = e_artic->GetDefaultCargoType();
-					u->cargo_cap = e_artic->u.road.capacity;  // Callback 36 is called when the consist is finished
+					rv->cargo_type = e_artic->GetDefaultCargoType();
+					rv->cargo_cap = e_artic->u.road.capacity;  // Callback 36 is called when the consist is finished
 				} else {
-					u->cargo_type = v->cargo_type; // Needed for livery selection
-					u->cargo_cap = 0;
+					rv->cargo_type = front->cargo_type; // Needed for livery selection
+					rv->cargo_cap = 0;
 				}
 
-				SetRoadVehArticPart(u);
-				break;
+				SetRoadVehArticPart(rv);
+				u = rv;
+			} break;
 		}
 
 		/* get common values from first engine */
--- a/src/depot_gui.cpp
+++ b/src/depot_gui.cpp
@@ -5,6 +5,7 @@
 #include "train.h"
 #include "ship.h"
 #include "aircraft.h"
+#include "roadveh.h"
 #include "gui.h"
 #include "textbuf_gui.h"
 #include "viewport_func.h"
@@ -517,7 +518,7 @@
 							break;
 
 						case VEH_ROAD:
-							_cursor.short_vehicle_offset = 16 - v->u.road.cached_veh_length * 2;
+							_cursor.short_vehicle_offset = 16 - ((RoadVehicle *)v)->cached_veh_length * 2;
 							break;
 
 						default:
--- a/src/disaster_cmd.cpp
+++ b/src/disaster_cmd.cpp
@@ -314,11 +314,12 @@
 		return false;
 	} else {
 		/* Target a vehicle */
-		Vehicle *u = Vehicle::Get(v->dest_tile);
-		if (u->type != VEH_ROAD || !IsRoadVehFront(u)) {
+		Vehicle *u_tmp = Vehicle::Get(v->dest_tile);
+		if (u_tmp->type != VEH_ROAD || !IsRoadVehFront(u_tmp)) {
 			delete v;
 			return false;
 		}
+		RoadVehicle *u = (RoadVehicle *)u_tmp;
 
 		uint dist = Delta(v->x_pos, u->x_pos) + Delta(v->y_pos, u->y_pos);
 
@@ -336,8 +337,8 @@
 
 		if (z <= u->z_pos && (u->vehstatus & VS_HIDDEN) == 0) {
 			v->age++;
-			if (u->u.road.crashed_ctr == 0) {
-				u->u.road.crashed_ctr++;
+			if (u->crashed_ctr == 0) {
+				u->crashed_ctr++;
 
 				AddNewsItem(STR_NEWS_DISASTER_SMALL_UFO,
 					NS_ACCIDENT_VEHICLE,
--- a/src/newgrf_engine.cpp
+++ b/src/newgrf_engine.cpp
@@ -5,6 +5,7 @@
 #include "stdafx.h"
 #include "debug.h"
 #include "train.h"
+#include "roadveh.h"
 #include "company_func.h"
 #include "newgrf_engine.h"
 #include "newgrf_spritegroup.h"
@@ -435,7 +436,7 @@
 	} else if (v->type == VEH_TRAIN) {
 		l = GetEngineLivery(v->engine_type, v->owner, v->u.rail.first_engine, v);
 	} else if (v->type == VEH_ROAD) {
-		l = GetEngineLivery(v->engine_type, v->owner, v->u.road.first_engine, v);
+		l = GetEngineLivery(v->engine_type, v->owner, ((RoadVehicle *)v)->first_engine, v);
 	} else {
 		l = GetEngineLivery(v->engine_type, v->owner, INVALID_ENGINE, v);
 	}
@@ -780,17 +781,18 @@
 			}
 			break;
 
-		case VEH_ROAD:
+		case VEH_ROAD: {
+			RoadVehicle *rv = (RoadVehicle *)v;
 			switch (variable - 0x80) {
-				case 0x62: return v->u.road.state;
-				case 0x64: return v->u.road.blocked_ctr;
-				case 0x65: return GB(v->u.road.blocked_ctr, 8, 8);
-				case 0x66: return v->u.road.overtaking;
-				case 0x67: return v->u.road.overtaking_ctr;
-				case 0x68: return v->u.road.crashed_ctr;
-				case 0x69: return GB(v->u.road.crashed_ctr, 8, 8);
+				case 0x62: return rv->state;
+				case 0x64: return rv->blocked_ctr;
+				case 0x65: return GB(rv->blocked_ctr, 8, 8);
+				case 0x66: return rv->overtaking;
+				case 0x67: return rv->overtaking_ctr;
+				case 0x68: return rv->crashed_ctr;
+				case 0x69: return GB(rv->crashed_ctr, 8, 8);
 			}
-			break;
+		} break;
 
 		case VEH_AIRCRAFT: {
 			Aircraft *a = (Aircraft *)v;
@@ -885,7 +887,7 @@
 			group = use_cache ? v->u.rail.cached_override : GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->u.rail.first_engine);
 			if (group != NULL) return group;
 		} else if (v->type == VEH_ROAD) {
-			group = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->u.road.first_engine);
+			group = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, ((RoadVehicle *)v)->first_engine);
 			if (group != NULL) return group;
 		}
 	}
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -1119,7 +1119,7 @@
 				switch (v->type) {
 					case VEH_ROAD: {
 						extern byte GetRoadVehLength(const RoadVehicle *v);
-						if (GetRoadVehLength((RoadVehicle *)v) != v->u.road.cached_veh_length) {
+						if (GetRoadVehLength((RoadVehicle *)v) != ((RoadVehicle *)v)->cached_veh_length) {
 							DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i\n", v->index, (int)v->owner, v->unitnumber);
 						}
 					} break;
--- a/src/road_cmd.cpp
+++ b/src/road_cmd.cpp
@@ -1547,20 +1547,22 @@
 			}
 			break;
 
-		case ROAD_TILE_DEPOT:
-			if (v->type == VEH_ROAD &&
-					v->u.road.frame == RVC_DEPOT_STOP_FRAME &&
-					_roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == v->u.road.state) {
-				v->u.road.state = RVSB_IN_DEPOT;
-				v->vehstatus |= VS_HIDDEN;
-				v->direction = ReverseDir(v->direction);
-				if (v->Next() == NULL) VehicleEnterDepot(v);
-				v->tile = tile;
+		case ROAD_TILE_DEPOT: {
+			if (v->type != VEH_ROAD) break;
 
-				InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
+			RoadVehicle *rv = (RoadVehicle *)v;
+			if (rv->frame == RVC_DEPOT_STOP_FRAME &&
+					_roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == rv->state) {
+				rv->state = RVSB_IN_DEPOT;
+				rv->vehstatus |= VS_HIDDEN;
+				rv->direction = ReverseDir(rv->direction);
+				if (rv->Next() == NULL) VehicleEnterDepot(rv);
+				rv->tile = tile;
+
+				InvalidateWindowData(WC_VEHICLE_DEPOT, rv->tile);
 				return VETSB_ENTERED_WORMHOLE;
 			}
-			break;
+		} break;
 
 		default: break;
 	}
--- a/src/roadveh.h
+++ b/src/roadveh.h
@@ -12,6 +12,41 @@
 
 struct RoadVehicle;
 
+/** Road vehicle states */
+enum RoadVehicleStates {
+	/*
+	 * Lower 4 bits are used for vehicle track direction. (Trackdirs)
+	 * When in a road stop (bit 5 or bit 6 set) these bits give the
+	 * track direction of the entry to the road stop.
+	 * As the entry direction will always be a diagonal
+	 * direction (X_NE, Y_SE, X_SW or Y_NW) only bits 0 and 3
+	 * are needed to hold this direction. Bit 1 is then used to show
+	 * that the vehicle is using the second road stop bay.
+	 * Bit 2 is then used for drive-through stops to show the vehicle
+	 * is stopping at this road stop.
+	 */
+
+	/* Numeric values */
+	RVSB_IN_DEPOT                = 0xFE,                      ///< The vehicle is in a depot
+	RVSB_WORMHOLE                = 0xFF,                      ///< The vehicle is in a tunnel and/or bridge
+
+	/* Bit numbers */
+	RVS_USING_SECOND_BAY         =    1,                      ///< Only used while in a road stop
+	RVS_IS_STOPPING              =    2,                      ///< Only used for drive-through stops. Vehicle will stop here
+	RVS_DRIVE_SIDE               =    4,                      ///< Only used when retrieving move data
+	RVS_IN_ROAD_STOP             =    5,                      ///< The vehicle is in a road stop
+	RVS_IN_DT_ROAD_STOP          =    6,                      ///< The vehicle is in a drive-through road stop
+
+	/* Bit sets of the above specified bits */
+	RVSB_IN_ROAD_STOP            = 1 << RVS_IN_ROAD_STOP,     ///< The vehicle is in a road stop
+	RVSB_IN_ROAD_STOP_END        = RVSB_IN_ROAD_STOP + TRACKDIR_END,
+	RVSB_IN_DT_ROAD_STOP         = 1 << RVS_IN_DT_ROAD_STOP,  ///< The vehicle is in a drive-through road stop
+	RVSB_IN_DT_ROAD_STOP_END     = RVSB_IN_DT_ROAD_STOP + TRACKDIR_END,
+
+	RVSB_TRACKDIR_MASK           = 0x0F,                      ///< The mask used to extract track dirs
+	RVSB_ROAD_STOP_TRACKDIR_MASK = 0x09                       ///< Only bits 0 and 3 are used to encode the trackdir for road stops
+};
+
 /** State information about the Road Vehicle controller */
 enum {
 	RDE_NEXT_TILE = 0x80, ///< We should enter the next tile
@@ -84,6 +119,21 @@
  * As side-effect the vehicle type is set correctly.
  */
 struct RoadVehicle : public Vehicle {
+	byte state;             ///< @see RoadVehicleStates
+	byte frame;
+	uint16 blocked_ctr;
+	byte overtaking;
+	byte overtaking_ctr;
+	uint16 crashed_ctr;
+	byte reverse_ctr;
+	struct RoadStop *slot;
+	byte slot_age;
+	EngineID first_engine;
+	byte cached_veh_length;
+
+	RoadType roadtype;
+	RoadTypes compatible_roadtypes;
+
 	/** Initializes the Vehicle to a road vehicle */
 	RoadVehicle() { this->type = VEH_ROAD; }
 
@@ -99,7 +149,7 @@
 	int GetDisplaySpeed() const { return this->cur_speed / 2; }
 	int GetDisplayMaxSpeed() const { return this->max_speed / 2; }
 	Money GetRunningCost() const { return RoadVehInfo(this->engine_type)->running_cost * GetPriceByIndex(RoadVehInfo(this->engine_type)->running_cost_class); }
-	bool IsInDepot() const { return this->u.road.state == RVSB_IN_DEPOT; }
+	bool IsInDepot() const { return this->state == RVSB_IN_DEPOT; }
 	bool IsStoppedInDepot() const;
 	bool Tick();
 	void OnNewDay();
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -142,10 +142,10 @@
 		assert(u->First() == v);
 
 		/* Update the 'first engine' */
-		u->u.road.first_engine = (v == u) ? INVALID_ENGINE : v->engine_type;
+		u->first_engine = (v == u) ? INVALID_ENGINE : v->engine_type;
 
 		/* Update the length of the vehicle. */
-		u->u.road.cached_veh_length = GetRoadVehLength(u);
+		u->cached_veh_length = GetRoadVehLength(u);
 
 		/* Invalidate the vehicle colour map */
 		u->colourmap = PAL_NONE;
@@ -206,7 +206,7 @@
 
 //		v->running_ticks = 0;
 
-		v->u.road.state = RVSB_IN_DEPOT;
+		v->state = RVSB_IN_DEPOT;
 		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
 
 		v->spritenum = rvi->image_index;
@@ -220,7 +220,7 @@
 //		v->load_unload_time_rem = 0;
 //		v->progress = 0;
 
-//		v->u.road.overtaking = 0;
+//		v->overtaking = 0;
 
 		v->last_station_visited = INVALID_STATION;
 		v->max_speed = rvi->max_speed;
@@ -242,9 +242,9 @@
 		v->random_bits = VehicleRandomBits();
 		SetRoadVehFront(v);
 
-		v->u.road.roadtype = HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
-		v->u.road.compatible_roadtypes = RoadTypeToRoadTypes(v->u.road.roadtype);
-		v->u.road.cached_veh_length = 8;
+		v->roadtype = HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
+		v->compatible_roadtypes = RoadTypeToRoadTypes(v->roadtype);
+		v->cached_veh_length = 8;
 
 		v->vehicle_flags = 0;
 		if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
@@ -255,7 +255,7 @@
 
 		/* Call various callbacks after the whole consist has been constructed */
 		for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
-			u->u.road.cached_veh_length = GetRoadVehLength(u);
+			u->cached_veh_length = GetRoadVehLength(u);
 			/* Cargo capacity is zero if and only if the vehicle cannot carry anything */
 			if (u->cargo_cap != 0) u->cargo_cap = GetVehicleProperty(u, 0x0F, u->cargo_cap);
 		}
@@ -279,11 +279,11 @@
 
 void ClearSlot(RoadVehicle *v)
 {
-	RoadStop *rs = v->u.road.slot;
-	if (v->u.road.slot == NULL) return;
+	RoadStop *rs = v->slot;
+	if (v->slot == NULL) return;
 
-	v->u.road.slot = NULL;
-	v->u.road.slot_age = 0;
+	v->slot = NULL;
+	v->slot_age = 0;
 
 	assert(rs->num_vehicles != 0);
 	rs->num_vehicles--;
@@ -299,7 +299,7 @@
 	if (IsRoadVehFront(this) && !(this->vehstatus & VS_STOPPED)) return false;
 
 	for (const RoadVehicle *v = this; v != NULL; v = v->Next()) {
-		if (v->u.road.state != RVSB_IN_DEPOT || v->tile != tile) return false;
+		if (v->state != RVSB_IN_DEPOT || v->tile != tile) return false;
 	}
 	return true;
 }
@@ -366,7 +366,7 @@
 			/* See where we are now */
 			Trackdir trackdir = v->GetVehicleTrackdir();
 
-			NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, v->tile, ReverseTrackdir(trackdir), false, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES, 0);
+			NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, v->tile, ReverseTrackdir(trackdir), false, TRANSPORT_ROAD, v->compatible_roadtypes, v->owner, INVALID_RAILTYPES, 0);
 
 			if (ftd.best_bird_dist == 0) return GetDepotByTile(ftd.node.tile); // Target found
 		} break;
@@ -380,7 +380,7 @@
 
 			/* search in all directions */
 			for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
-				FollowTrack(v->tile, PATHFIND_FLAGS_NONE, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, d, EnumRoadSignalFindDepot, NULL, &rfdd);
+				FollowTrack(v->tile, PATHFIND_FLAGS_NONE, TRANSPORT_ROAD, v->compatible_roadtypes, d, EnumRoadSignalFindDepot, NULL, &rfdd);
 			}
 
 			if (rfdd.best_length != UINT_MAX) return GetDepotByTile(rfdd.tile);
@@ -432,14 +432,16 @@
  */
 CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 {
-	Vehicle *v = Vehicle::GetIfValid(p1);
-	if (v == NULL || v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR;
+	Vehicle *u = Vehicle::GetIfValid(p1);
+	if (u == NULL || u->type != VEH_ROAD || !CheckOwnership(u->owner)) return CMD_ERROR;
+
+	RoadVehicle *v = (RoadVehicle *)u;
 
 	if (v->vehstatus & VS_STOPPED ||
 			v->vehstatus & VS_CRASHED ||
 			v->breakdown_ctr != 0 ||
-			v->u.road.overtaking != 0 ||
-			v->u.road.state == RVSB_WORMHOLE ||
+			v->overtaking != 0 ||
+			v->state == RVSB_WORMHOLE ||
 			v->IsInDepot() ||
 			v->cur_speed < 5) {
 		return CMD_ERROR;
@@ -449,7 +451,7 @@
 
 	if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
 
-	if (flags & DC_EXEC) v->u.road.reverse_ctr = 180;
+	if (flags & DC_EXEC) v->reverse_ctr = 180;
 
 	return CommandCost();
 }
@@ -494,7 +496,7 @@
 	rs->SetEntranceBusy(false);
 
 	/* Free the parking bay */
-	rs->FreeBay(HasBit(v->u.road.state, RVS_USING_SECOND_BAY));
+	rs->FreeBay(HasBit(v->state, RVS_USING_SECOND_BAY));
 }
 
 static void DeleteLastRoadVeh(RoadVehicle *v)
@@ -542,12 +544,12 @@
 
 static bool RoadVehIsCrashed(RoadVehicle *v)
 {
-	v->u.road.crashed_ctr++;
-	if (v->u.road.crashed_ctr == 2) {
+	v->crashed_ctr++;
+	if (v->crashed_ctr == 2) {
 		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
-	} else if (v->u.road.crashed_ctr <= 45) {
+	} else if (v->crashed_ctr <= 45) {
 		if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
-	} else if (v->u.road.crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) {
+	} else if (v->crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) {
 		bool ret = v->Next() != NULL;
 		DeleteLastRoadVeh(v);
 		return ret;
@@ -572,7 +574,7 @@
 {
 	uint16 pass = 1;
 
-	v->u.road.crashed_ctr++;
+	v->crashed_ctr++;
 
 	for (Vehicle *u = v; u != NULL; u = u->Next()) {
 		if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count();
@@ -604,7 +606,7 @@
 static bool RoadVehCheckTrainCrash(RoadVehicle *v)
 {
 	for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
-		if (u->u.road.state == RVSB_WORMHOLE) continue;
+		if (u->state == RVSB_WORMHOLE) continue;
 
 		TileIndex tile = u->tile;
 
@@ -732,7 +734,7 @@
 	RoadVehFindData rvf;
 	RoadVehicle *front = v->First();
 
-	if (front->u.road.reverse_ctr != 0) return NULL;
+	if (front->reverse_ctr != 0) return NULL;
 
 	rvf.x = x;
 	rvf.y = y;
@@ -740,7 +742,7 @@
 	rvf.veh = v;
 	rvf.best_diff = UINT_MAX;
 
-	if (front->u.road.state == RVSB_WORMHOLE) {
+	if (front->state == RVSB_WORMHOLE) {
 		FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
 		FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
 	} else {
@@ -752,11 +754,11 @@
 	 * drive just through it. The ultimate backup-code of TTD.
 	 * It can be disabled. */
 	if (rvf.best_diff == UINT_MAX) {
-		front->u.road.blocked_ctr = 0;
+		front->blocked_ctr = 0;
 		return NULL;
 	}
 
-	if (++front->u.road.blocked_ctr > 1480) return NULL;
+	if (++front->blocked_ctr > 1480) return NULL;
 
 	return (RoadVehicle *)rvf.best;
 }
@@ -769,7 +771,7 @@
 			st->had_vehicle_of_type |= HVOT_BUS;
 			SetDParam(0, st->index);
 			AddNewsItem(
-				v->u.road.roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_ROAD_BUS_ARRIVAL : STR_NEWS_FIRST_ROAD_PASSENGER_TRAM_ARRIVAL,
+				v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_ROAD_BUS_ARRIVAL : STR_NEWS_FIRST_ROAD_PASSENGER_TRAM_ARRIVAL,
 				(v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
 				v->index,
 				st->index
@@ -782,7 +784,7 @@
 			st->had_vehicle_of_type |= HVOT_TRUCK;
 			SetDParam(0, st->index);
 			AddNewsItem(
-				v->u.road.roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_ROAD_TRUCK_ARRIVAL : STR_NEWS_FIRST_ROAD_CARGO_TRAM_ARRIVAL,
+				v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_ROAD_TRUCK_ARRIVAL : STR_NEWS_FIRST_ROAD_CARGO_TRAM_ARRIVAL,
 				(v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
 				v->index,
 				st->index
@@ -795,7 +797,7 @@
 static int RoadVehAccelerate(RoadVehicle *v)
 {
 	uint oldspeed = v->cur_speed;
-	uint accel = 256 + (v->u.road.overtaking != 0 ? 256 : 0);
+	uint accel = 256 + (v->overtaking != 0 ? 256 : 0);
 	uint spd = v->subspeed + accel;
 
 	v->subspeed = (uint8)spd;
@@ -808,7 +810,7 @@
 	v->cur_speed = spd = Clamp(v->cur_speed + ((int)spd >> 8), 0, tempmax);
 
 	/* Apply bridge speed limit */
-	if (v->u.road.state == RVSB_WORMHOLE && !(v->vehstatus & VS_HIDDEN)) {
+	if (v->state == RVSB_WORMHOLE && !(v->vehstatus & VS_HIDDEN)) {
 		v->cur_speed = min(v->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed * 2);
 	}
 
@@ -877,7 +879,7 @@
  */
 static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
 {
-	TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->u.road.compatible_roadtypes);
+	TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->compatible_roadtypes);
 	TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
 	TrackdirBits red_signals = TrackStatusToRedSignals(ts); // barred level crossing
 	TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
@@ -903,7 +905,7 @@
 	}
 
 	/* Trams can't overtake other trams */
-	if (v->u.road.roadtype == ROADTYPE_TRAM) return;
+	if (v->roadtype == ROADTYPE_TRAM) return;
 
 	/* Don't overtake in stations */
 	if (IsTileType(v->tile, MP_STATION)) return;
@@ -915,7 +917,7 @@
 	if (v->direction != u->direction || !(v->direction & 1)) return;
 
 	/* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
-	if (v->u.road.state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->u.road.state & RVSB_TRACKDIR_MASK))) return;
+	if (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->state & RVSB_TRACKDIR_MASK))) return;
 
 	od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
 
@@ -932,12 +934,12 @@
 	if (CheckRoadBlockedForOvertaking(&od)) return;
 
 	if (od.u->cur_speed == 0 || od.u->vehstatus& VS_STOPPED) {
-		v->u.road.overtaking_ctr = 0x11;
-		v->u.road.overtaking = 0x10;
+		v->overtaking_ctr = 0x11;
+		v->overtaking = 0x10;
 	} else {
 //		if (CheckRoadBlockedForOvertaking(&od)) return;
-		v->u.road.overtaking_ctr = 0;
-		v->u.road.overtaking = 0x10;
+		v->overtaking_ctr = 0;
+		v->overtaking = 0x10;
 	}
 }
 
@@ -1008,12 +1010,12 @@
 	FindRoadToChooseData frd;
 	Trackdir best_track;
 
-	TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes);
+	TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes);
 	TrackdirBits red_signals = TrackStatusToRedSignals(ts); // crossing
 	TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts);
 
 	if (IsTileType(tile, MP_ROAD)) {
-		if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->u.road.compatible_roadtypes) == 0)) {
+		if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) {
 			/* Road depot owned by another company or with the wrong orientation */
 			trackdirs = TRACKDIR_BIT_NONE;
 		}
@@ -1052,9 +1054,9 @@
 		return_track(_road_reverse_table[enterdir]);
 	}
 
-	if (v->u.road.reverse_ctr != 0) {
+	if (v->reverse_ctr != 0) {
 		bool reverse = true;
-		if (v->u.road.roadtype == ROADTYPE_TRAM) {
+		if (v->roadtype == ROADTYPE_TRAM) {
 			/* Trams may only reverse on a tile if it contains at least the straight
 			 * trackbits or when it is a valid turning tile (i.e. one roadbit) */
 			RoadBits rb = GetAnyRoadBits(tile, ROADTYPE_TRAM);
@@ -1063,7 +1065,7 @@
 			          (rb == DiagDirToRoadBits(enterdir));
 		}
 		if (reverse) {
-			v->u.road.reverse_ctr = 0;
+			v->reverse_ctr = 0;
 			if (v->tile != tile) {
 				return_track(_road_reverse_table[enterdir]);
 			}
@@ -1095,7 +1097,7 @@
 			Trackdir trackdir = DiagDirToDiagTrackdir(enterdir);
 			/* debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir); */
 
-			NPFFoundTargetData ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES);
+			NPFFoundTargetData ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_ROAD, v->compatible_roadtypes, v->owner, INVALID_RAILTYPES);
 			if (ftd.best_trackdir == INVALID_TRACKDIR) {
 				/* We are already at our target. Just do something
 				 * @todo: maybe display error?
@@ -1148,7 +1150,7 @@
 				if (best_track == INVALID_TRACKDIR) best_track = (Trackdir)i; // in case we don't find the path, just pick a track
 				frd.maxtracklen = UINT_MAX;
 				frd.mindist = UINT_MAX;
-				FollowTrack(tile, PATHFIND_FLAGS_NONE, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, _road_pf_directions[i], EnumRoadTrackFindDist, NULL, &frd);
+				FollowTrack(tile, PATHFIND_FLAGS_NONE, TRANSPORT_ROAD, v->compatible_roadtypes, _road_pf_directions[i], EnumRoadTrackFindDist, NULL, &frd);
 
 				if (frd.mindist < best_dist || (frd.mindist == best_dist && frd.maxtracklen < best_maxlen)) {
 					best_dist = frd.mindist;
@@ -1181,7 +1183,7 @@
 	fstd.dest_coords = tile;
 	fstd.station_index = INVALID_STATION; // indicates that the destination is a tile, not a station
 
-	uint dist = NPFRouteToStationOrTile(v->tile, trackdir, false, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES).best_path_dist;
+	uint dist = NPFRouteToStationOrTile(v->tile, trackdir, false, &fstd, TRANSPORT_ROAD, v->compatible_roadtypes, v->owner, INVALID_RAILTYPES).best_path_dist;
 	/* change units from NPF_TILE_LENGTH to # of tiles */
 	if (dist != UINT_MAX) dist = (dist + NPF_TILE_LENGTH - 1) / NPF_TILE_LENGTH;
 
@@ -1205,14 +1207,14 @@
 {
 	/* Don't leave if not all the wagons are in the depot. */
 	for (const RoadVehicle *u = v; u != NULL; u = u->Next()) {
-		if (u->u.road.state != RVSB_IN_DEPOT || u->tile != v->tile) return false;
+		if (u->state != RVSB_IN_DEPOT || u->tile != v->tile) return false;
 	}
 
 	DiagDirection dir = GetRoadDepotDirection(v->tile);
 	v->direction = DiagDirToDir(dir);
 
 	Trackdir tdir = _roadveh_depot_exit_trackdir[dir];
-	const RoadDriveEntry *rdp = _road_drive_data[v->u.road.roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir];
+	const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir];
 
 	int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
 	int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
@@ -1229,8 +1231,8 @@
 	}
 
 	v->vehstatus &= ~VS_HIDDEN;
-	v->u.road.state = tdir;
-	v->u.road.frame = RVC_DEPOT_START_FRAME;
+	v->state = tdir;
+	v->frame = RVC_DEPOT_START_FRAME;
 
 	v->UpdateDeltaXY(v->direction);
 	SetRoadVehPosition(v, x, y);
@@ -1248,7 +1250,7 @@
 		return _road_reverse_table[entry_dir];
 	}
 
-	byte prev_state = prev->u.road.state;
+	byte prev_state = prev->state;
 	Trackdir dir;
 
 	if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
@@ -1299,7 +1301,7 @@
 	};
 	RoadBits required = required_roadbits[dir & 0x07];
 
-	if ((required & GetAnyRoadBits(tile, v->u.road.roadtype, true)) == ROAD_NONE) {
+	if ((required & GetAnyRoadBits(tile, v->roadtype, true)) == ROAD_NONE) {
 		dir = INVALID_TRACKDIR;
 	}
 
@@ -1327,16 +1329,16 @@
 
 static bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
 {
-	if (v->u.road.overtaking != 0)  {
+	if (v->overtaking != 0)  {
 		if (IsTileType(v->tile, MP_STATION)) {
 			/* Force us to be not overtaking! */
-			v->u.road.overtaking = 0;
-		} else if (++v->u.road.overtaking_ctr >= 35) {
+			v->overtaking = 0;
+		} else if (++v->overtaking_ctr >= 35) {
 			/* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
 			 *  if the vehicle started a corner. To protect that, only allow an abort of
 			 *  overtake if we are on straight roads */
-			if (v->u.road.state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->u.road.state)) {
-				v->u.road.overtaking = 0;
+			if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
+				v->overtaking = 0;
 			}
 		}
 	}
@@ -1346,7 +1348,7 @@
 	 * by the previous vehicle in the chain when it gets to the right place. */
 	if (v->IsInDepot()) return true;
 
-	if (v->u.road.state == RVSB_WORMHOLE) {
+	if (v->state == RVSB_WORMHOLE) {
 		/* Vehicle is entering a depot or is on a bridge or in a tunnel */
 		GetNewVehiclePosResult gp = GetNewVehiclePos(v);
 
@@ -1373,10 +1375,10 @@
 
 	/* Get move position data for next frame.
 	 * For a drive-through road stop use 'straight road' move data.
-	 * In this case v->u.road.state is masked to give the road stop entry direction. */
-	RoadDriveEntry rd = _road_drive_data[v->u.road.roadtype][(
-		(HasBit(v->u.road.state, RVS_IN_DT_ROAD_STOP) ? v->u.road.state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->u.road.state) +
-		(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking][v->u.road.frame + 1];
+	 * In this case v->state is masked to give the road stop entry direction. */
+	RoadDriveEntry rd = _road_drive_data[v->roadtype][(
+		(HasBit(v->state, RVS_IN_DT_ROAD_STOP) ? v->state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->state) +
+		(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
 
 	if (rd.x & RDE_NEXT_TILE) {
 		TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
@@ -1399,7 +1401,7 @@
 		uint start_frame = RVC_DEFAULT_START_FRAME;
 		if (IsReversingRoadTrackdir(dir)) {
 			/* Turning around */
-			if (v->u.road.roadtype == ROADTYPE_TRAM) {
+			if (v->roadtype == ROADTYPE_TRAM) {
 				/* Determine the road bits the tram needs to be able to turn around
 				 * using the 'big' corner loop. */
 				RoadBits needed;
@@ -1451,7 +1453,7 @@
 		}
 
 		/* Get position data for first frame on the new tile */
-		const RoadDriveEntry *rdp = _road_drive_data[v->u.road.roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking];
+		const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking];
 
 		int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
 		int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
@@ -1476,8 +1478,8 @@
 			goto again;
 		}
 
-		if (IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
-			if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
+		if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
+			if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
 				/* New direction is trying to turn vehicle around.
 				 * We can't turn at the exit of a road stop so wait.*/
 				v->cur_speed = 0;
@@ -1488,9 +1490,9 @@
 
 				/* Vehicle is leaving a road stop tile, mark bay as free
 				 * For drive-through stops, only do it if the vehicle stopped here */
-				if (IsStandardRoadStopTile(v->tile) || HasBit(v->u.road.state, RVS_IS_STOPPING)) {
-					rs->FreeBay(HasBit(v->u.road.state, RVS_USING_SECOND_BAY));
-					ClrBit(v->u.road.state, RVS_IS_STOPPING);
+				if (IsStandardRoadStopTile(v->tile) || HasBit(v->state, RVS_IS_STOPPING)) {
+					rs->FreeBay(HasBit(v->state, RVS_USING_SECOND_BAY));
+					ClrBit(v->state, RVS_IS_STOPPING);
 				}
 				if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(false);
 			}
@@ -1498,8 +1500,8 @@
 
 		if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
 			v->tile = tile;
-			v->u.road.state = (byte)dir;
-			v->u.road.frame = start_frame;
+			v->state = (byte)dir;
+			v->frame = start_frame;
 		}
 		if (new_dir != v->direction) {
 			v->direction = new_dir;
@@ -1517,7 +1519,7 @@
 		uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
 
 		RoadBits tram;
-		if (v->u.road.roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && CountBits(tram = GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true)) == 1) {
+		if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && CountBits(tram = GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true)) == 1) {
 			/*
 			 * The tram is turning around with one tram 'roadbit'. This means that
 			 * it is using the 'big' corner 'drive data'. However, to support the
@@ -1549,7 +1551,7 @@
 			return false;
 		}
 
-		const RoadDriveEntry *rdp = _road_drive_data[v->u.road.roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
+		const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
 
 		int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
 		int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
@@ -1563,8 +1565,8 @@
 			return false;
 		}
 
-		v->u.road.state = dir;
-		v->u.road.frame = turn_around_start_frame;
+		v->state = dir;
+		v->frame = turn_around_start_frame;
 
 		if (new_dir != v->direction) {
 			v->direction = new_dir;
@@ -1580,7 +1582,7 @@
 	 * it's on a depot tile, check if it's time to activate the next vehicle in
 	 * the chain yet. */
 	if (v->Next() != NULL && IsRoadDepotTile(v->tile)) {
-		if (v->u.road.frame == v->u.road.cached_veh_length + RVC_DEPOT_START_FRAME) {
+		if (v->frame == v->cached_veh_length + RVC_DEPOT_START_FRAME) {
 			RoadVehLeaveDepot(v->Next(), false);
 		}
 	}
@@ -1591,7 +1593,7 @@
 
 	Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
 
-	if (IsRoadVehFront(v) && !IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
+	if (IsRoadVehFront(v) && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
 		/* Vehicle is not in a road stop.
 		 * Check for another vehicle to overtake */
 		RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
@@ -1599,8 +1601,8 @@
 		if (u != NULL) {
 			u = u->First();
 			/* There is a vehicle in front overtake it if possible */
-			if (v->u.road.overtaking == 0) RoadVehCheckOvertake(v, u);
-			if (v->u.road.overtaking == 0) v->cur_speed = u->cur_speed;
+			if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
+			if (v->overtaking == 0) v->cur_speed = u->cur_speed;
 			return false;
 		}
 	}
@@ -1609,7 +1611,7 @@
 	if (new_dir != old_dir) {
 		v->direction = new_dir;
 		v->cur_speed -= (v->cur_speed >> 2);
-		if (old_dir != v->u.road.state) {
+		if (old_dir != v->state) {
 			/* The vehicle is in a road stop */
 			v->UpdateDeltaXY(v->direction);
 			SetRoadVehPosition(v, v->x_pos, v->y_pos);
@@ -1625,13 +1627,13 @@
 	 * and it's the correct type of stop (bus or truck) and the frame equals the stop frame...
 	 * (the station test and stop type test ensure that other vehicles, using the road stop as
 	 * a through route, do not stop) */
-	if (IsRoadVehFront(v) && ((IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
-			_road_veh_data_1[v->u.road.state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->u.road.frame) ||
-			(IsInsideMM(v->u.road.state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
+	if (IsRoadVehFront(v) && ((IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
+			_road_veh_data_1[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) ||
+			(IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
 			v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
 			v->owner == GetTileOwner(v->tile) &&
 			GetRoadStopType(v->tile) == (IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
-			v->u.road.frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
+			v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
 
 		RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
 		Station *st = GetStationByTile(v->tile);
@@ -1650,15 +1652,15 @@
 				if (IsDriveThroughStopTile(next_tile) && (GetRoadStopType(next_tile) == type) && GetStationIndex(v->tile) == GetStationIndex(next_tile)) {
 					RoadStop *rs_n = GetRoadStopByTile(next_tile, type);
 
-					if (rs_n->IsFreeBay(HasBit(v->u.road.state, RVS_USING_SECOND_BAY)) && rs_n->num_vehicles < RoadStop::MAX_VEHICLES) {
+					if (rs_n->IsFreeBay(HasBit(v->state, RVS_USING_SECOND_BAY)) && rs_n->num_vehicles < RoadStop::MAX_VEHICLES) {
 						/* Bay in next stop along is free - use it */
 						ClearSlot(v);
 						rs_n->num_vehicles++;
-						v->u.road.slot = rs_n;
+						v->slot = rs_n;
 						v->dest_tile = rs_n->xy;
-						v->u.road.slot_age = 14;
+						v->slot_age = 14;
 
-						v->u.road.frame++;
+						v->frame++;
 						RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
 						return true;
 					}
@@ -1687,10 +1689,10 @@
 
 		if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
 
-		if (rs == v->u.road.slot) {
+		if (rs == v->slot) {
 			/* We are leaving the correct station */
 			ClearSlot(v);
-		} else if (v->u.road.slot != NULL) {
+		} else if (v->slot != NULL) {
 			/* We are leaving the wrong station
 			 * XXX The question is .. what to do? Actually we shouldn't be here
 			 * but I guess we need to clear the slot */
@@ -1698,8 +1700,8 @@
 			if (v->tile != v->dest_tile) {
 				DEBUG(ms, 2, " current tile 0x%X is not destination tile 0x%X. Route problem", v->tile, v->dest_tile);
 			}
-			if (v->dest_tile != v->u.road.slot->xy) {
-				DEBUG(ms, 2, " stop tile 0x%X is not destination tile 0x%X. Multistop desync", v->u.road.slot->xy, v->dest_tile);
+			if (v->dest_tile != v->slot->xy) {
+				DEBUG(ms, 2, " stop tile 0x%X is not destination tile 0x%X. Multistop desync", v->slot->xy, v->dest_tile);
 			}
 			if (!v->current_order.IsType(OT_GOTO_STATION)) {
 				DEBUG(ms, 2, " current order type (%d) is not OT_GOTO_STATION", v->current_order.GetType());
@@ -1732,7 +1734,7 @@
 
 	/* Move to next frame unless vehicle arrived at a stop position
 	 * in a depot or entered a tunnel/bridge */
-	if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->u.road.frame++;
+	if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++;
 
 	v->UpdateDeltaXY(v->direction);
 	RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y));
@@ -1744,7 +1746,7 @@
 	/* decrease counters */
 	v->tick_counter++;
 	v->current_order_time++;
-	if (v->u.road.reverse_ctr != 0) v->u.road.reverse_ctr--;
+	if (v->reverse_ctr != 0) v->reverse_ctr--;
 
 	/* handle crashed */
 	if (v->vehstatus & VS_CRASHED) {
@@ -1824,7 +1826,7 @@
 static void CheckIfRoadVehNeedsService(RoadVehicle *v)
 {
 	/* If we already got a slot at a stop, use that FIRST, and go to a depot later */
-	if (v->u.road.slot != NULL || _settings_game.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
+	if (v->slot != NULL || _settings_game.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
 	if (v->IsInDepot()) {
 		VehicleServiceInDepot(v);
 		return;
@@ -1860,7 +1862,7 @@
 	if (!IsRoadVehFront(this)) return;
 
 	if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
-	if (this->u.road.blocked_ctr == 0) CheckVehicleBreakdown(this);
+	if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
 
 	AgeVehicle(this);
 	CheckIfRoadVehNeedsService(this);
@@ -1868,14 +1870,14 @@
 	CheckOrders(this);
 
 	/* Current slot has expired */
-	if (this->current_order.IsType(OT_GOTO_STATION) && this->u.road.slot != NULL && this->u.road.slot_age-- == 0) {
+	if (this->current_order.IsType(OT_GOTO_STATION) && this->slot != NULL && this->slot_age-- == 0) {
 		DEBUG(ms, 3, "Slot expired for vehicle %d (index %d) at stop 0x%X",
-			this->unitnumber, this->index, this->u.road.slot->xy);
+			this->unitnumber, this->index, this->slot->xy);
 		ClearSlot(this);
 	}
 
 	/* update destination */
-	if (!(this->vehstatus & VS_STOPPED) && this->current_order.IsType(OT_GOTO_STATION) && !(this->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) && this->u.road.slot == NULL && !(this->vehstatus & VS_CRASHED)) {
+	if (!(this->vehstatus & VS_STOPPED) && this->current_order.IsType(OT_GOTO_STATION) && !(this->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) && this->slot == NULL && !(this->vehstatus & VS_CRASHED)) {
 		Station *st = Station::Get(this->current_order.GetDestination());
 		RoadStop *rs = st->GetPrimaryRoadStop(this);
 		RoadStop *best = NULL;
@@ -1921,9 +1923,9 @@
 					best->num_vehicles++;
 					DEBUG(ms, 3, "Assigned to stop 0x%X", best->xy);
 
-					this->u.road.slot = best;
+					this->slot = best;
 					this->dest_tile = best->xy;
-					this->u.road.slot_age = 14;
+					this->slot_age = 14;
 				} else {
 					DEBUG(ms, 3, "Could not find a suitable stop");
 				}
@@ -1965,11 +1967,11 @@
 	}
 
 	/* Drive through road stops / wormholes (tunnels) */
-	if (this->u.road.state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
+	if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
 
 	/* If vehicle's state is a valid track direction (vehicle is not turning around) return it,
 	 * otherwise transform it into a valid track direction */
-	return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->u.road.state)) ? (this->u.road.state - 6) : this->u.road.state);
+	return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
 }
 
 
--- a/src/roadveh_gui.cpp
+++ b/src/roadveh_gui.cpp
@@ -130,7 +130,7 @@
 	int highlight_w = 0;
 
 	for (int dx = 0; v != NULL && dx < max_length ; v = v->Next()) {
-		int width = v->u.road.cached_veh_length;
+		int width = ((RoadVehicle *)v)->cached_veh_length;
 
 		if (dx + width > 0 && dx <= max_length) {
 			SpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -914,7 +914,7 @@
 			if (v->type == VEH_TRAIN) {
 				v->u.rail.track = TRACK_BIT_WORMHOLE;
 			} else {
-				v->u.road.state = RVSB_WORMHOLE;
+				((RoadVehicle *)v)->state = RVSB_WORMHOLE;
 			}
 		}
 	}
@@ -1049,15 +1049,18 @@
 		Vehicle *v;
 		FOR_ALL_VEHICLES(v) {
 			if (v->type == VEH_ROAD) {
-				v->vehstatus &= ~0x40;
-				v->u.road.slot = NULL;
-				v->u.road.slot_age = 0;
+				RoadVehicle *rv = (RoadVehicle *)v;
+				rv->vehstatus &= ~0x40;
+				rv->slot = NULL;
+				rv->slot_age = 0;
 			}
 		}
 	} else {
 		Vehicle *v;
 		FOR_ALL_VEHICLES(v) {
-			if (v->type == VEH_ROAD && v->u.road.slot != NULL) v->u.road.slot->num_vehicles++;
+			if (v->type != VEH_ROAD) continue;
+			RoadVehicle *rv = (RoadVehicle *)v;
+			if (rv->slot != NULL) rv->slot->num_vehicles++;
 		}
 	}
 
@@ -1373,8 +1376,10 @@
 		/* 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 && (v->u.road.state == 250 || v->u.road.state == 251)) {
-				SetBit(v->u.road.state, RVS_IS_STOPPING);
+			if (v->type != VEH_ROAD) continue;
+			RoadVehicle *rv = (RoadVehicle *)v;
+			if (rv->state == 250 || rv->state == 251) {
+				SetBit(rv->state, RVS_IS_STOPPING);
 			}
 		}
 	}
--- a/src/saveload/oldloader_sl.cpp
+++ b/src/saveload/oldloader_sl.cpp
@@ -175,10 +175,11 @@
 		v->name = CopyFromOldName(_old_vehicle_names[v->index]);
 
 		/* We haven't used this bit for stations for ages */
-		if (v->type == VEH_ROAD &&
-				v->u.road.state != RVSB_IN_DEPOT &&
-				v->u.road.state != RVSB_WORMHOLE) {
-			ClrBit(v->u.road.state, RVS_IS_STOPPING);
+		if (v->type == VEH_ROAD) {
+			RoadVehicle *rv = (RoadVehicle *)v;
+			if (rv->state != RVSB_IN_DEPOT && rv->state != RVSB_WORMHOLE) {
+				ClrBit(rv->state, RVS_IS_STOPPING);
+			}
 		}
 
 		/* The subtype should be 0, but it sometimes isn't :( */
@@ -1089,13 +1090,13 @@
 };
 
 static const OldChunks vehicle_road_chunk[] = {
-	OCL_SVAR(  OC_UINT8, VehicleRoad, state ),
-	OCL_SVAR(  OC_UINT8, VehicleRoad, frame ),
-	OCL_SVAR( OC_UINT16, VehicleRoad, blocked_ctr ),
-	OCL_SVAR(  OC_UINT8, VehicleRoad, overtaking ),
-	OCL_SVAR(  OC_UINT8, VehicleRoad, overtaking_ctr ),
-	OCL_SVAR( OC_UINT16, VehicleRoad, crashed_ctr ),
-	OCL_SVAR(  OC_UINT8, VehicleRoad, reverse_ctr ),
+	OCL_SVAR(  OC_UINT8, RoadVehicle, state ),
+	OCL_SVAR(  OC_UINT8, RoadVehicle, frame ),
+	OCL_SVAR( OC_UINT16, RoadVehicle, blocked_ctr ),
+	OCL_SVAR(  OC_UINT8, RoadVehicle, overtaking ),
+	OCL_SVAR(  OC_UINT8, RoadVehicle, overtaking_ctr ),
+	OCL_SVAR( OC_UINT16, RoadVehicle, crashed_ctr ),
+	OCL_SVAR(  OC_UINT8, RoadVehicle, reverse_ctr ),
 
 	OCL_NULL( 1 ), ///< Junk
 
@@ -1157,7 +1158,7 @@
 		switch (v->type) {
 			default: NOT_REACHED();
 			case VEH_TRAIN   : res = LoadChunk(ls, &v->u.rail,     vehicle_train_chunk);    break;
-			case VEH_ROAD    : res = LoadChunk(ls, &v->u.road,     vehicle_road_chunk);     break;
+			case VEH_ROAD    : res = LoadChunk(ls, v, vehicle_road_chunk);     break;
 			case VEH_SHIP    : res = LoadChunk(ls, v, vehicle_ship_chunk);     break;
 			case VEH_AIRCRAFT: res = LoadChunk(ls, v, vehicle_air_chunk);      break;
 			case VEH_EFFECT  : res = LoadChunk(ls, v, vehicle_effect_chunk);   break;
--- a/src/saveload/vehicle_sl.cpp
+++ b/src/saveload/vehicle_sl.cpp
@@ -253,7 +253,7 @@
 		if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID;
 		v->first = NULL;
 		if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
-		if (v->type == VEH_ROAD)  v->u.road.first_engine = INVALID_ENGINE;
+		if (v->type == VEH_ROAD)  ((RoadVehicle *)v)->first_engine = INVALID_ENGINE;
 
 		v->cargo.InvalidateCache();
 	}
@@ -344,9 +344,11 @@
 
 	FOR_ALL_VEHICLES(v) {
 		switch (v->type) {
-			case VEH_ROAD:
-				v->u.road.roadtype = HasBit(EngInfo(v->First()->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
-				v->u.road.compatible_roadtypes = RoadTypeToRoadTypes(v->u.road.roadtype);
+			case VEH_ROAD: {
+				RoadVehicle *rv = (RoadVehicle *)v;
+				rv->roadtype = HasBit(EngInfo(v->First()->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
+				rv->compatible_roadtypes = RoadTypeToRoadTypes(rv->roadtype);
+			}
 				/* FALL THROUGH */
 			case VEH_TRAIN:
 			case VEH_SHIP:
@@ -542,19 +544,19 @@
 	static const SaveLoad _roadveh_desc[] = {
 		SLE_WRITEBYTE(Vehicle, type, VEH_ROAD),
 		SLE_VEH_INCLUDEX(),
-		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, state),                SLE_UINT8),
-		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, frame),                SLE_UINT8),
-		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, blocked_ctr),          SLE_UINT16),
-		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking),           SLE_UINT8),
-		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking_ctr),       SLE_UINT8),
-		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, crashed_ctr),          SLE_UINT16),
-		    SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, reverse_ctr),          SLE_UINT8),
+		     SLE_VAR(RoadVehicle, state,                SLE_UINT8),
+		     SLE_VAR(RoadVehicle, frame,                SLE_UINT8),
+		     SLE_VAR(RoadVehicle, blocked_ctr,          SLE_UINT16),
+		     SLE_VAR(RoadVehicle, overtaking,           SLE_UINT8),
+		     SLE_VAR(RoadVehicle, overtaking_ctr,       SLE_UINT8),
+		     SLE_VAR(RoadVehicle, crashed_ctr,          SLE_UINT16),
+		     SLE_VAR(RoadVehicle, reverse_ctr,          SLE_UINT8),
 
-		SLE_CONDREFX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot),                 REF_ROADSTOPS,                6, SL_MAX_VERSION),
-		SLE_CONDNULL(1,                                                            6, SL_MAX_VERSION),
-		SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot_age),             SLE_UINT8,                    6, SL_MAX_VERSION),
+		 SLE_CONDREF(RoadVehicle, slot,                 REF_ROADSTOPS,                6, SL_MAX_VERSION),
+		SLE_CONDNULL(1,                                                               6, SL_MAX_VERSION),
+		 SLE_CONDVAR(RoadVehicle, slot_age,             SLE_UINT8,                    6, SL_MAX_VERSION),
 		/* reserve extra space in savegame here. (currently 16 bytes) */
-		SLE_CONDNULL(16,                                                           2, SL_MAX_VERSION),
+		SLE_CONDNULL(16,                                                              2, SL_MAX_VERSION),
 
 		     SLE_END()
 	};
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -114,7 +114,7 @@
 
 	for (; rs != NULL; rs = rs->next) {
 		/* The vehicle cannot go to this roadstop (different roadtype) */
-		if ((GetRoadTypes(rs->xy) & v->u.road.compatible_roadtypes) == ROADTYPES_NONE) continue;
+		if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue;
 		/* The vehicle is articulated and can therefor not go the a standard road stop */
 		if (IsStandardRoadStopTile(rs->xy) && RoadVehHasArticPart(v)) continue;
 
@@ -462,7 +462,7 @@
 			if (v->type != VEH_ROAD) continue;
 			RoadVehicle *rv = (RoadVehicle *)v;
 
-			if (rv->u.road.slot == this) ClearSlot(rv);
+			if (rv->slot == this) ClearSlot(rv);
 		}
 	}
 	assert(num_vehicles == 0);
@@ -542,7 +542,7 @@
 {
 	for (RoadStop *rs = this->next; rs != NULL; rs = rs->next) {
 		/* The vehicle cannot go to this roadstop (different roadtype) */
-		if ((GetRoadTypes(rs->xy) & v->u.road.compatible_roadtypes) == ROADTYPES_NONE) continue;
+		if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue;
 		/* The vehicle is articulated and can therefor not go the a standard road stop */
 		if (IsStandardRoadStopTile(rs->xy) && RoadVehHasArticPart(v)) continue;
 
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -1488,7 +1488,7 @@
 
 static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
 {
-	if (v->type == VEH_ROAD) ClrBit(v->u.road.state, RVS_IN_DT_ROAD_STOP);
+	if (v->type == VEH_ROAD) ClrBit(((RoadVehicle *)v)->state, RVS_IN_DT_ROAD_STOP);
 
 	return NULL;
 }
@@ -2649,30 +2649,31 @@
 			}
 		}
 	} else if (v->type == VEH_ROAD) {
-		if (v->u.road.state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)v->u.road.state) && v->u.road.frame == 0) {
+		RoadVehicle *rv = (RoadVehicle *)v;
+		if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
 			if (IsRoadStop(tile) && IsRoadVehFront(v)) {
 				/* Attempt to allocate a parking bay in a road stop */
 				RoadStop *rs = GetRoadStopByTile(tile, GetRoadStopType(tile));
 
 				if (IsDriveThroughStopTile(tile)) {
-					if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
+					if (!rv->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
 
 					/* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */
-					byte side = ((DirToDiagDir(v->direction) == ReverseDiagDir(GetRoadStopDir(tile))) == (v->u.road.overtaking == 0)) ? 0 : 1;
+					byte side = ((DirToDiagDir(rv->direction) == ReverseDiagDir(GetRoadStopDir(tile))) == (rv->overtaking == 0)) ? 0 : 1;
 
 					if (!rs->IsFreeBay(side)) return VETSB_CANNOT_ENTER;
 
 					/* Check if the vehicle is stopping at this road stop */
-					if (GetRoadStopType(tile) == (IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
-							v->current_order.GetDestination() == GetStationIndex(tile)) {
-						SetBit(v->u.road.state, RVS_IS_STOPPING);
+					if (GetRoadStopType(tile) == (IsCargoInClass(rv->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
+							rv->current_order.GetDestination() == GetStationIndex(tile)) {
+						SetBit(rv->state, RVS_IS_STOPPING);
 						rs->AllocateDriveThroughBay(side);
 					}
 
 					/* Indicate if vehicle is using second bay. */
-					if (side == 1) SetBit(v->u.road.state, RVS_USING_SECOND_BAY);
+					if (side == 1) SetBit(rv->state, RVS_USING_SECOND_BAY);
 					/* Indicate a drive-through stop */
-					SetBit(v->u.road.state, RVS_IN_DT_ROAD_STOP);
+					SetBit(rv->state, RVS_IN_DT_ROAD_STOP);
 					return VETSB_CONTINUE;
 				}
 
@@ -2680,11 +2681,11 @@
 				 * Check if station is busy or if there are no free bays or whether it is a articulated vehicle. */
 				if (rs->IsEntranceBusy() || !rs->HasFreeBay() || RoadVehHasArticPart(v)) return VETSB_CANNOT_ENTER;
 
-				SetBit(v->u.road.state, RVS_IN_ROAD_STOP);
+				SetBit(rv->state, RVS_IN_ROAD_STOP);
 
 				/* Allocate a bay and update the road state */
 				uint bay_nr = rs->AllocateBay();
-				SB(v->u.road.state, RVS_USING_SECOND_BAY, 1, bay_nr);
+				SB(rv->state, RVS_USING_SECOND_BAY, 1, bay_nr);
 
 				/* Mark the station entrace as busy */
 				rs->SetEntranceBusy(true);
--- a/src/tunnelbridge_cmd.cpp
+++ b/src/tunnelbridge_cmd.cpp
@@ -16,6 +16,7 @@
 #include "variables.h"
 #include "train.h"
 #include "ship.h"
+#include "roadveh.h"
 #include "water_map.h"
 #include "yapf/yapf.h"
 #include "newgrf_sound.h"
@@ -1412,16 +1413,17 @@
 				return VETSB_ENTERED_WORMHOLE;
 			}
 		} else if (v->type == VEH_ROAD) {
+			RoadVehicle *rv = (RoadVehicle *)v;
 			fc = (x & 0xF) + (y << 4);
 			vdir = DirToDiagDir(v->direction);
 
 			/* Enter tunnel? */
-			if (v->u.road.state != RVSB_WORMHOLE && dir == vdir) {
+			if (rv->state != RVSB_WORMHOLE && dir == vdir) {
 				if (fc == _tunnel_fractcoord_4[dir] ||
 						fc == _tunnel_fractcoord_5[dir]) {
-					v->tile = tile;
-					v->u.road.state = RVSB_WORMHOLE;
-					v->vehstatus |= VS_HIDDEN;
+					rv->tile = tile;
+					rv->state = RVSB_WORMHOLE;
+					rv->vehstatus |= VS_HIDDEN;
 					return VETSB_ENTERED_WORMHOLE;
 				} else {
 					return VETSB_CONTINUE;
@@ -1434,10 +1436,10 @@
 						fc == _tunnel_fractcoord_7[dir]
 					) &&
 					z == 0) {
-				v->tile = tile;
-				v->u.road.state = _road_exit_tunnel_state[dir];
-				v->u.road.frame = _road_exit_tunnel_frame[dir];
-				v->vehstatus &= ~VS_HIDDEN;
+				rv->tile = tile;
+				rv->state = _road_exit_tunnel_state[dir];
+				rv->frame = _road_exit_tunnel_frame[dir];
+				rv->vehstatus &= ~VS_HIDDEN;
 				return VETSB_ENTERED_WORMHOLE;
 			}
 		}
@@ -1467,11 +1469,11 @@
 					break;
 
 				case VEH_ROAD:
-					v->u.road.state = RVSB_WORMHOLE;
+					((RoadVehicle *)v)->state = RVSB_WORMHOLE;
 					break;
 
 				case VEH_SHIP:
-					static_cast<Ship*>(v)->state = TRACK_BIT_WORMHOLE;
+					((Ship *)v)->state = TRACK_BIT_WORMHOLE;
 					break;
 
 				default: NOT_REACHED();
@@ -1487,20 +1489,22 @@
 					}
 					break;
 
-				case VEH_ROAD:
-					if (v->u.road.state == RVSB_WORMHOLE) {
-						v->u.road.state = _road_exit_tunnel_state[dir];
-						v->u.road.frame = 0;
+				case VEH_ROAD: {
+					RoadVehicle *rv = (RoadVehicle *)v;
+					if (rv->state == RVSB_WORMHOLE) {
+						rv->state = _road_exit_tunnel_state[dir];
+						rv->frame = 0;
 						return VETSB_ENTERED_WORMHOLE;
 					}
-					break;
+				} break;
 
-				case VEH_SHIP:
-					if (static_cast<Ship*>(v)->state == TRACK_BIT_WORMHOLE) {
-						static_cast<Ship*>(v)->state = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
+				case VEH_SHIP: {
+					Ship *ship = (Ship *)v;
+					if (ship->state == TRACK_BIT_WORMHOLE) {
+						ship->state = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
 						return VETSB_ENTERED_WORMHOLE;
 					}
-					break;
+				} break;
 
 				default: NOT_REACHED();
 			}
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -1426,7 +1426,7 @@
 	if (v->type == VEH_TRAIN) {
 		return GetEngineColourMap(v->engine_type, v->owner, v->u.rail.first_engine, v);
 	} else if (v->type == VEH_ROAD) {
-		return GetEngineColourMap(v->engine_type, v->owner, v->u.road.first_engine, v);
+		return GetEngineColourMap(v->engine_type, v->owner, ((RoadVehicle *)v)->first_engine, v);
 	}
 
 	return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
--- a/src/vehicle_base.h
+++ b/src/vehicle_base.h
@@ -8,7 +8,6 @@
 #include "vehicle_type.h"
 #include "track_type.h"
 #include "rail_type.h"
-#include "road_type.h"
 #include "cargo_type.h"
 #include "direction_type.h"
 #include "gfx_type.h"
@@ -25,41 +24,6 @@
 #include "order_func.h"
 #include "transport_type.h"
 
-/** Road vehicle states */
-enum RoadVehicleStates {
-	/*
-	 * Lower 4 bits are used for vehicle track direction. (Trackdirs)
-	 * When in a road stop (bit 5 or bit 6 set) these bits give the
-	 * track direction of the entry to the road stop.
-	 * As the entry direction will always be a diagonal
-	 * direction (X_NE, Y_SE, X_SW or Y_NW) only bits 0 and 3
-	 * are needed to hold this direction. Bit 1 is then used to show
-	 * that the vehicle is using the second road stop bay.
-	 * Bit 2 is then used for drive-through stops to show the vehicle
-	 * is stopping at this road stop.
-	 */
-
-	/* Numeric values */
-	RVSB_IN_DEPOT                = 0xFE,                      ///< The vehicle is in a depot
-	RVSB_WORMHOLE                = 0xFF,                      ///< The vehicle is in a tunnel and/or bridge
-
-	/* Bit numbers */
-	RVS_USING_SECOND_BAY         =    1,                      ///< Only used while in a road stop
-	RVS_IS_STOPPING              =    2,                      ///< Only used for drive-through stops. Vehicle will stop here
-	RVS_DRIVE_SIDE               =    4,                      ///< Only used when retrieving move data
-	RVS_IN_ROAD_STOP             =    5,                      ///< The vehicle is in a road stop
-	RVS_IN_DT_ROAD_STOP          =    6,                      ///< The vehicle is in a drive-through road stop
-
-	/* Bit sets of the above specified bits */
-	RVSB_IN_ROAD_STOP            = 1 << RVS_IN_ROAD_STOP,     ///< The vehicle is in a road stop
-	RVSB_IN_ROAD_STOP_END        = RVSB_IN_ROAD_STOP + TRACKDIR_END,
-	RVSB_IN_DT_ROAD_STOP         = 1 << RVS_IN_DT_ROAD_STOP,  ///< The vehicle is in a drive-through road stop
-	RVSB_IN_DT_ROAD_STOP_END     = RVSB_IN_DT_ROAD_STOP + TRACKDIR_END,
-
-	RVSB_TRACKDIR_MASK           = 0x0F,                      ///< The mask used to extract track dirs
-	RVSB_ROAD_STOP_TRACKDIR_MASK = 0x09                       ///< Only bits 0 and 3 are used to encode the trackdir for road stops
-};
-
 enum VehStatus {
 	VS_HIDDEN          = 0x01,
 	VS_STOPPED         = 0x02,
@@ -149,23 +113,6 @@
 	VRF_TRAIN_STUCK    = 8,
 };
 
-struct VehicleRoad {
-	byte state;             ///< @see RoadVehicleStates
-	byte frame;
-	uint16 blocked_ctr;
-	byte overtaking;
-	byte overtaking_ctr;
-	uint16 crashed_ctr;
-	byte reverse_ctr;
-	struct RoadStop *slot;
-	byte slot_age;
-	EngineID first_engine;
-	byte cached_veh_length;
-
-	RoadType roadtype;
-	RoadTypes compatible_roadtypes;
-};
-
 typedef Pool<Vehicle, VehicleID, 512, 64000> VehiclePool;
 extern VehiclePool _vehicle_pool;
 
@@ -295,7 +242,6 @@
 
 	union {
 		VehicleRail rail;
-		VehicleRoad road;
 	} u;
 
 	/* cached oftenly queried NewGRF values */
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -639,9 +639,9 @@
 			break;
 
 		case VEH_ROAD: {
-			const Vehicle *u;
-			for (u = *a; u != NULL; u = u->Next()) r += u->u.road.cached_veh_length;
-			for (u = *b; u != NULL; u = u->Next()) r -= u->u.road.cached_veh_length;
+			const RoadVehicle *u;
+			for (u = (RoadVehicle *)*a; u != NULL; u = u->Next()) r += u->cached_veh_length;
+			for (u = (RoadVehicle *)*b; u != NULL; u = u->Next()) r -= u->cached_veh_length;
 		} break;
 
 		default: NOT_REACHED();
--- a/src/water_cmd.cpp
+++ b/src/water_cmd.cpp
@@ -822,7 +822,7 @@
 
 				case VEH_ROAD:
 					if (IsRoadVehFront(v)) pass += 1; // driver
-					v->u.road.crashed_ctr = 2000; // max 2220, disappear pretty fast
+					((RoadVehicle *)v)->crashed_ctr = 2000; // max 2220, disappear pretty fast
 					InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 					break;
 
--- a/src/yapf/follow_track.hpp
+++ b/src/yapf/follow_track.hpp
@@ -7,6 +7,7 @@
 
 #include "yapf.hpp"
 #include "../depot_map.h"
+#include "../roadveh.h"
 
 /** Track follower helper template class (can serve pathfinders and vehicle
  *  controllers). See 6 different typedefs below for 3 different transport
@@ -74,7 +75,7 @@
 	FORCEINLINE static TransportType TT() {return Ttr_type_;}
 	FORCEINLINE static bool IsWaterTT() {return TT() == TRANSPORT_WATER;}
 	FORCEINLINE static bool IsRailTT() {return TT() == TRANSPORT_RAIL;}
-	FORCEINLINE bool IsTram() {return IsRoadTT() && HasBit(m_veh->u.road.compatible_roadtypes, ROADTYPE_TRAM);}
+	FORCEINLINE bool IsTram() {return IsRoadTT() && HasBit(((RoadVehicle *)m_veh)->compatible_roadtypes, ROADTYPE_TRAM);}
 	FORCEINLINE static bool IsRoadTT() {return TT() == TRANSPORT_ROAD;}
 	FORCEINLINE static bool Allow90degTurns() {return T90deg_turns_allowed_;}
 	FORCEINLINE static bool DoTrackMasking() {return IsRailTT() && Tmask_reserved_tracks;}
@@ -205,7 +206,7 @@
 		if (IsRailTT() && IsPlainRailTile(m_new_tile)) {
 			m_new_td_bits = (TrackdirBits)(GetTrackBits(m_new_tile) * 0x101);
 		} else {
-			m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), m_veh != NULL ? m_veh->u.road.compatible_roadtypes : 0));
+			m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), m_veh != NULL ? ((RoadVehicle *)m_veh)->compatible_roadtypes : 0));
 
 			if (IsTram() && m_new_td_bits == 0) {
 				/* GetTileTrackStatus() returns 0 for single tram bits.
--- a/src/yapf/yapf_road.cpp
+++ b/src/yapf/yapf_road.cpp
@@ -4,6 +4,7 @@
 
 #include "../stdafx.h"
 #include "../depot_base.h"
+#include "../roadveh.h"
 
 #include "yapf.hpp"
 #include "yapf_node_road.hpp"
@@ -298,13 +299,13 @@
 		/* our source tile will be the next vehicle tile (should be the given one) */
 		TileIndex src_tile = tile;
 		/* get available trackdirs on the start tile */
-		TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes));
+		TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, ((RoadVehicle *)v)->compatible_roadtypes));
 		/* select reachable trackdirs only */
 		src_trackdirs &= DiagdirReachesTrackdirs(enterdir);
 
 		/* get available trackdirs on the destination tile */
 		TileIndex dest_tile = v->dest_tile;
-		TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(dest_tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes));
+		TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(dest_tile, TRANSPORT_ROAD, ((RoadVehicle *)v)->compatible_roadtypes));
 
 		/* set origin and destination nodes */
 		Yapf().SetOrigin(src_tile, src_trackdirs);
@@ -348,7 +349,7 @@
 
 		/* set destination tile, trackdir
 		 *   get available trackdirs on the destination tile */
-		TrackdirBits dst_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes));
+		TrackdirBits dst_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, TRANSPORT_ROAD, ((RoadVehicle *)v)->compatible_roadtypes));
 		Yapf().SetDestination(dst_tile, dst_td_bits);
 
 		/* if path not found - return distance = UINT_MAX */
@@ -373,7 +374,7 @@
 		/* set origin (tile, trackdir) */
 		TileIndex src_tile = v->tile;
 		Trackdir src_td = v->GetVehicleTrackdir();
-		if ((TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes)) & TrackdirToTrackdirBits(src_td)) == 0) {
+		if ((TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, ((RoadVehicle *)v)->compatible_roadtypes)) & TrackdirToTrackdirBits(src_td)) == 0) {
 			/* sometimes the roadveh is not on the road (it resides on non-existing track)
 			 * how should we handle that situation? */
 			return false;
@@ -470,7 +471,7 @@
 {
 	TileIndex tile = v->tile;
 	Trackdir trackdir = v->GetVehicleTrackdir();
-	if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes)) & TrackdirToTrackdirBits(trackdir)) == 0) {
+	if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, ((RoadVehicle *)v)->compatible_roadtypes)) & TrackdirToTrackdirBits(trackdir)) == 0) {
 		return NULL;
 	}