changeset 6193:0d05fec9d384 draft

(svn r8973) -Feature/Codechange: Changed the internal unit for aircraft velocities to from 8mph to 1km/h (peter1138), also give aircraft realsitic velocities (so that 1km/h is 1km/h independent of vehicle type) (peter1138). Introduce a flag to reduce aircraft speed in holding patterns to some realistic velocity. Use this flag for the city airport for the time being and make use of the different entry points for this airport type.
author celestar <celestar@openttd.org>
date Fri, 02 Mar 2007 12:01:24 +0000
parents 44da08e7d3d1
children bf3c126349b4
files src/aircraft_cmd.cpp src/aircraft_gui.cpp src/airport.h src/airport_movement.h src/build_vehicle_gui.cpp src/engine.h src/engine_gui.cpp src/newgrf.cpp src/openttd.cpp src/saveload.cpp src/table/engines.h
diffstat 11 files changed, 156 insertions(+), 100 deletions(-) [+]
line wrap: on
line diff
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -862,21 +862,35 @@
 	}
 }
 
-/** Special velocities for aircraft
+/**
+ * Special velocities for aircraft
  */
 enum AircraftSpeedLimits {
-	SPEED_LIMIT_NONE   =  0,  ///< No environmental speed limit. Speed limit is type dependent
-	SPEED_LIMIT_TAXI   = 12,  ///< Maximum speed of an aircraft while taxiing
-	SPEED_LIMIT_BROKEN = 27,  ///< Maximum speed of an aircraft that is broken
+	SPEED_LIMIT_TAXI     =     50,  ///< Maximum speed of an aircraft while taxiing
+	SPEED_LIMIT_APPROACH =    230,  ///< Maximum speed of an aircraft on finals
+	SPEED_LIMIT_BROKEN   =    320,  ///< Maximum speed of an aircraft that is broken
+	SPEED_LIMIT_HOLD     =    425,  ///< Maximum speed of an aircraft that flies the holding pattern
+	SPEED_LIMIT_NONE     = 0xFFFF   ///< No environmental speed limit. Speed limit is type dependent
 };
 
-static bool UpdateAircraftSpeed(Vehicle *v, uint speed_limit)
+/**
+ * Sets the new speed for an aircraft
+ * @param v The vehicle for which the speed should be obtained
+ * @param speed_limit The maximum speed the vehicle may have.
+ * @param hard_limit If true, the limit is directly enforced, otherwise the plane is slowed down gradually
+ * @return The number of position updates needed within the tick
+ */
+static int UpdateAircraftSpeed(Vehicle *v, uint speed_limit = SPEED_LIMIT_NONE, bool hard_limit = true)
 {
-	uint spd = v->acceleration * 2;
+	uint spd = v->acceleration * 16;
 	byte t;
 
+	speed_limit = min(speed_limit, v->max_speed);
+
 	v->subspeed = (t=v->subspeed) + (byte)spd;
-	if (speed_limit == SPEED_LIMIT_NONE) speed_limit = v->max_speed;
+
+	if (!hard_limit && v->cur_speed > speed_limit) speed_limit = v->cur_speed - (v->cur_speed / 48);
+
 	spd = min(v->cur_speed + (spd >> 8) + (v->subspeed < t), speed_limit);
 
 	/* adjust speed for broken vehicles */
@@ -891,13 +905,9 @@
 
 	if (!(v->direction & 1)) spd = spd * 3 / 4;
 
-	if (spd == 0) return false;
-
-	if ((byte)++spd == 0) return true;
-
-	v->progress = (t = v->progress) - (byte)spd;
-
-	return t < v->progress;
+	spd += v->progress;
+	v->progress = (byte)spd;
+	return spd >> 8;
 }
 
 /**
@@ -922,20 +932,28 @@
 		case DIR_NE:
 		case DIR_E:
 		case DIR_SE:
-			base_altitude += 15;
+			base_altitude += 10;
 			break;
 
 		default: break;
 	}
 
 	/* Make faster planes fly higher so that they can overtake slower ones */
-	base_altitude += min(30 * (v->max_speed / 37), 90);
+	base_altitude += min(20 * (v->max_speed / 200), 90);
 
 	return base_altitude;
 }
 
+/**
+ * Controls the movement of an aircraft. This function actually moves the vehicle
+ * on the map and takes care of minor things like sound playback.
+ * @todo    De-mystify the cur_speed values for helicopter rotors.
+ * @param v The vehicle that is moved. Must be the first vehicle of the chain
+ * @return  Whether the position requested by the State Machine has been reached
+ */
 static bool AircraftController(Vehicle *v)
 {
+	int count;
 	const Station *st = GetStation(v->u.air.targetairport);
 
 	/* prevent going to 0,0 if airport is deleted. */
@@ -958,7 +976,8 @@
 			if (--u->cur_speed == 32) SndPlayVehicleFx(SND_18_HELICOPTER, v);
 		} else {
 			u->cur_speed = 32;
-			if (UpdateAircraftSpeed(v, SPEED_LIMIT_NONE)) {
+			count = UpdateAircraftSpeed(v);
+			if (count > 0) {
 				v->tile = 0;
 
 				/* Reached altitude? */
@@ -966,7 +985,7 @@
 					v->cur_speed = 0;
 					return true;
 				}
-				SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos+1);
+				SetAircraftPosition(v, v->x_pos, v->y_pos, min(v->z_pos + count, 184));
 			}
 		}
 		return false;
@@ -974,7 +993,8 @@
 
 	/* Helicopter landing. */
 	if (amd->flag & AMED_HELI_LOWER) {
-		if (UpdateAircraftSpeed(v, SPEED_LIMIT_NONE)) {
+		count = UpdateAircraftSpeed(v);
+		if (count > 0) {
 			if (st->airport_tile == 0) {
 				/* FIXME - AircraftController -> if station no longer exists, do not land
 				 * helicopter will circle until sign disappears, then go to next order
@@ -988,7 +1008,7 @@
 			v->tile = st->airport_tile;
 
 			/* Find altitude of landing position. */
-			uint z = GetSlopeZ(x, y) + 1 + afc->delta_z;
+			int z = GetSlopeZ(x, y) + 1 + afc->delta_z;
 
 			if (z == v->z_pos) {
 				Vehicle *u = v->next->next;
@@ -997,9 +1017,9 @@
 				if (u->cur_speed >= 80) return true;
 				u->cur_speed += 4;
 			} else if (v->z_pos > z) {
-				SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos-1);
+				SetAircraftPosition(v, v->x_pos, v->y_pos, max(v->z_pos - count, z));
 			} else {
-				SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos+1);
+				SetAircraftPosition(v, v->x_pos, v->y_pos, min(v->z_pos + count, z));
 			}
 		}
 		return false;
@@ -1009,8 +1029,7 @@
 	uint dist = myabs(x + amd->x - v->x_pos) +  myabs(y + amd->y - v->y_pos);
 
 	/* Need exact position? */
-	if (!(amd->flag & AMED_EXACTPOS) && dist <= (amd->flag & AMED_SLOWTURN ? 8U : 4U))
-		return true;
+	if (!(amd->flag & AMED_EXACTPOS) && dist <= (amd->flag & AMED_SLOWTURN ? 8U : 4U)) return true;
 
 	/* At final pos? */
 	if (dist == 0) {
@@ -1032,71 +1051,82 @@
 		return false;
 	}
 
-	if (!UpdateAircraftSpeed(v, ((amd->flag & AMED_NOSPDCLAMP) == 0) ? SPEED_LIMIT_TAXI : SPEED_LIMIT_NONE)) return false;
+	uint speed_limit = SPEED_LIMIT_TAXI;
+	bool hard_limit = true;
+
+	if (amd->flag & AMED_NOSPDCLAMP)   speed_limit = SPEED_LIMIT_NONE;
+	if (amd->flag & AMED_HOLD)       { speed_limit = SPEED_LIMIT_HOLD;     hard_limit = false; }
+	if (amd->flag & AMED_LAND)       { speed_limit = SPEED_LIMIT_APPROACH; hard_limit = false; }
+	if (amd->flag & AMED_BRAKE)      { speed_limit = SPEED_LIMIT_TAXI;     hard_limit = false; }
+
+	count = UpdateAircraftSpeed(v, speed_limit, hard_limit);
+	if (count == 0) return false;
 
 	if (v->load_unload_time_rem != 0) v->load_unload_time_rem--;
 
-	/* Turn. Do it slowly if in the air. */
-	Direction newdir = GetDirectionTowards(v, x + amd->x, y + amd->y);
-	if (newdir != v->direction) {
-		if (amd->flag & AMED_SLOWTURN) {
-			if (v->load_unload_time_rem == 0) v->load_unload_time_rem = 8;
+	do {
+		/* Turn. Do it slowly if in the air. */
+		Direction newdir = GetDirectionTowards(v, x + amd->x, y + amd->y);
+		if (newdir != v->direction) {
 			v->direction = newdir;
-		} else {
-			v->cur_speed >>= 1;
-			v->direction = newdir;
+			if (amd->flag & AMED_SLOWTURN) {
+				if (v->load_unload_time_rem == 0) v->load_unload_time_rem = 8;
+			} else {
+				v->cur_speed >>= 1;
+			}
 		}
-	}
-
-	/* Move vehicle. */
-	GetNewVehiclePosResult gp = GetNewVehiclePos(v);
-	v->tile = gp.new_tile;
 
-	/* If vehicle is in the air, use tile coordinate 0. */
-	if (amd->flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) v->tile = 0;
-
-	/* Adjust Z for land or takeoff? */
-	uint z = v->z_pos;
+		/* Move vehicle. */
+		GetNewVehiclePosResult gp = GetNewVehiclePos(v);
+		v->tile = gp.new_tile;
+		/* If vehicle is in the air, use tile coordinate 0. */
+		// if (amd->flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) v->tile = 0;
 
-	if (amd->flag & AMED_TAKEOFF) {
-		z = min(z + 2, GetAircraftFlyingAltitude(v));
-	}
+		/* Adjust Z for land or takeoff? */
+		uint z = v->z_pos;
 
-	if (amd->flag & AMED_LAND) {
-		if (st->airport_tile == 0) {
-			v->u.air.state = FLYING;
-			AircraftNextAirportPos_and_Order(v);
-			/* get aircraft back on running altitude */
-			SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v));
-			return false;
+		if (amd->flag & AMED_TAKEOFF) {
+			z = min(z + 2, GetAircraftFlyingAltitude(v));
 		}
 
-		uint curz = GetSlopeZ(x, y) + 1;
-
-		if (curz > z) {
-			z++;
-		} else {
-			int t = max(1U, dist - 4);
+		if ((amd->flag & AMED_HOLD) && (z > 150)) z--;
 
-			z -= ((z - curz) + t - 1) / t;
-			if (z < curz) z = curz;
-		}
-	}
+		if (amd->flag & AMED_LAND) {
+			if (st->airport_tile == 0) {
+				/* Airport has been removed, abort the landing procedure */
+				v->u.air.state = FLYING;
+				AircraftNextAirportPos_and_Order(v);
+				/* get aircraft back on running altitude */
+				SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v));
+				continue;
+			}
 
-	/* We've landed. Decrase speed when we're reaching end of runway. */
-	if (amd->flag & AMED_BRAKE) {
-		uint curz = GetSlopeZ(x, y) + 1;
+			uint curz = GetSlopeZ(x, y) + 1;
 
-		if (z > curz) {
-			z--;
-		} else if (z < curz) {
-			z++;
+			if (curz > z) {
+				z++;
+			} else {
+				int t = max(1U, dist - 4);
+
+				z -= ((z - curz) + t - 1) / t;
+				if (z < curz) z = curz;
+			}
 		}
 
-		if (dist < 64 && v->cur_speed > 12) v->cur_speed -= 4;
-	}
+		/* We've landed. Decrase speed when we're reaching end of runway. */
+		if (amd->flag & AMED_BRAKE) {
+			uint curz = GetSlopeZ(x, y) + 1;
 
-	SetAircraftPosition(v, gp.x, gp.y, z);
+			if (z > curz) {
+				z--;
+			} else if (z < curz) {
+				z++;
+			}
+
+		}
+
+		SetAircraftPosition(v, gp.x, gp.y, z);
+	} while (--count != 0);
 	return false;
 }
 
@@ -2067,7 +2097,7 @@
 
 	AgeAircraftCargo(v);
 
-	for (uint i = 0; i != 6; i++) {
+	for (uint i = 0; i != 2; i++) {
 		AircraftEventHandler(v, i);
 		if (v->type != VEH_Aircraft) // In case it was deleted
 			break;
--- a/src/aircraft_gui.cpp
+++ b/src/aircraft_gui.cpp
@@ -84,7 +84,7 @@
 
 		/* Draw max speed */
 		{
-			SetDParam(0, v->max_speed * 128 / 10);
+			SetDParam(0, v->max_speed * 10 / 16);
 			DrawString(2, 25, STR_A00E_MAX_SPEED, 0);
 		}
 
@@ -263,14 +263,14 @@
 			switch (v->current_order.type) {
 			case OT_GOTO_STATION: {
 				SetDParam(0, v->current_order.dest);
-				SetDParam(1, v->cur_speed * 8);
+				SetDParam(1, v->cur_speed * 10 / 16);
 				str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
 			} break;
 
 			case OT_GOTO_DEPOT: {
 				/* Aircrafts always go to a station, even if you say depot */
 				SetDParam(0, v->current_order.dest);
-				SetDParam(1, v->cur_speed * 8);
+				SetDParam(1, v->cur_speed * 10 / 16);
 				if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
 					str = STR_HEADING_FOR_HANGAR + _patches.vehicle_speed;
 				} else {
@@ -285,7 +285,7 @@
 			default:
 				if (v->num_orders == 0) {
 					str = STR_NO_ORDERS + _patches.vehicle_speed;
-					SetDParam(0, v->cur_speed * 8);
+					SetDParam(0, v->cur_speed * 10 / 16);
 				} else {
 					str = STR_EMPTY;
 				}
--- a/src/airport.h
+++ b/src/airport.h
@@ -36,6 +36,7 @@
 	AMED_BRAKE      = 1 << 5,
 	AMED_HELI_RAISE = 1 << 6,
 	AMED_HELI_LOWER = 1 << 7,
+	AMED_HOLD       = 1 << 8
 };
 
 /* Movement States on Airports (headings target) */
@@ -114,7 +115,7 @@
 typedef struct AirportMovingData {
 	int16 x;
 	int16 y;
-	byte flag;
+	uint16 flag;
 	DirectionByte direction;
 } AirportMovingData;
 
--- a/src/airport_movement.h
+++ b/src/airport_movement.h
@@ -86,7 +86,7 @@
 };
 
 // City Airport (large) 6x6
-static const AirportMovingData _airport_moving_data_town[25] = {
+static const AirportMovingData _airport_moving_data_town[] = {
 	{   85,    3, AMED_EXACTPOS,                   {DIR_SE} }, // 00 In Hangar
 	{   85,   27, 0,                               {DIR_N} }, // 01 Taxi to right outside depot
 	{   26,   41, AMED_EXACTPOS,                   {DIR_SW} }, // 02 Terminal 1
@@ -100,18 +100,23 @@
 	{   89,   85, AMED_EXACTPOS,                   {DIR_NE} }, // 10 Taxi to start of runway (takeoff)
 	{    3,   85, AMED_NOSPDCLAMP,                 {DIR_N} }, // 11 Accelerate to end of runway
 	{  -79,   85, AMED_NOSPDCLAMP | AMED_TAKEOFF,  {DIR_N} }, // 12 Take off
-	{  177,   85, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 13 Fly to landing position in air
-	{   89,   85, AMED_NOSPDCLAMP | AMED_LAND,     {DIR_N} }, // 14 Going down for land
-	{    3,   85, AMED_NOSPDCLAMP | AMED_BRAKE,    {DIR_N} }, // 15 Just landed, brake until end of runway
-	{   20,   87, 0,                               {DIR_N} }, // 16 Just landed, turn around and taxi 1 square
+	{  177,   87, AMED_HOLD       | AMED_SLOWTURN, {DIR_N} }, // 13 Fly to landing position in air
+	{   89,   87, AMED_HOLD       | AMED_LAND,     {DIR_N} }, // 14 Going down for land
+	{   20,   87, AMED_NOSPDCLAMP | AMED_BRAKE,    {DIR_N} }, // 15 Just landed, brake until end of runway
+	{   20,   87, 0,                               {DIR_N} }, // 16 Just landed, turn around and taxi 1 square /* NOT USED */
 	{   36,   71, 0,                               {DIR_N} }, // 17 Taxi from runway to crossing
-	{  -31,  193, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 18 Fly around waiting for a landing spot (north-east)
-	{    1,    1, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 19 Fly around waiting for a landing spot (north-west)
-	{  257,    1, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 20 Fly around waiting for a landing spot (south-west)
-	{  273,   49, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 21 Fly around waiting for a landing spot (south)
+	{  160,   87, AMED_HOLD       | AMED_SLOWTURN, {DIR_N} }, // 18 Fly around waiting for a landing spot (north-east)
+	{  140,    1, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 19 Final approach fix
+	{  257,    1, AMED_HOLD       | AMED_SLOWTURN, {DIR_N} }, // 20 Fly around waiting for a landing spot (south-west)
+	{  273,   49, AMED_HOLD       | AMED_SLOWTURN, {DIR_N} }, // 21 Fly around waiting for a landing spot (south)
 	{   44,   63, AMED_HELI_RAISE,                 {DIR_N} }, // 22 Helicopter takeoff
 	{   28,   74, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 23 In position above landing spot helicopter
 	{   28,   74, AMED_HELI_LOWER,                 {DIR_N} }, // 24 Helicopter landing
+	{  145,    1, AMED_HOLD       | AMED_SLOWTURN, {DIR_N} }, // 25 Fly around waiting for a landing spot (north-west)
+	{  -32,    1, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 26 Initial approach fix (north)
+	{  300,  -48, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 27 Initial approach fix (south)
+	{  140,  -48, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 28 Intermediadate Approach fix (south), IAF (west)
+	{  -32,  120, AMED_NOSPDCLAMP | AMED_SLOWTURN, {DIR_N} }, // 29 Initial approach fix (east)
 };
 
 // Metropolitan Airport (metropolitan) - 2 runways
@@ -458,7 +463,7 @@
 
 static const TileIndexDiffC _airport_depots_city[] = { { 5, 0 } };
 static const byte _airport_terminal_city[] = { 1, 3 };
-static const byte _airport_entries_city[] = {19, 19, 19, 19};
+static const byte _airport_entries_city[] = {26, 29, 27, 28};
 static const AirportFTAbuildup _airport_fta_city[] = {
 	{  0, HANGAR, NOTHING_block, 1 }, { 0, TAKEOFF, OUT_WAY_block, 1 }, { 0, 0, 0, 1 },
 	{  1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, 0, 0, 7 }, // for all else, go to 7
@@ -477,11 +482,11 @@
 	// landing
 	{ 13, FLYING, NOTHING_block, 18 }, { 13, LANDING, 0, 14 }, { 13, HELILANDING, 0, 23 },
 	{ 14, LANDING, RUNWAY_IN_OUT_block, 15 },
-	{ 15, 0, RUNWAY_IN_OUT_block, 16 },
-	{ 16, 0, RUNWAY_IN_OUT_block, 17 },
+	{ 15, 0, RUNWAY_IN_OUT_block, 17 },
+	{ 16, 0, RUNWAY_IN_OUT_block, 17 }, /* not used, left for compatibility */
 	{ 17, ENDLANDING, IN_WAY_block, 7 },
 	// In Air
-	{ 18, 0, NOTHING_block, 19 },
+	{ 18, 0, NOTHING_block, 25 },
 	{ 19, 0, NOTHING_block, 20 },
 	{ 20, 0, NOTHING_block, 21 },
 	{ 21, 0, NOTHING_block, 13 },
@@ -489,6 +494,11 @@
 	{ 22, HELITAKEOFF, NOTHING_block, 0 },
 	{ 23, HELILANDING, IN_WAY_block, 24 },
 	{ 24, HELIENDLANDING, IN_WAY_block, 17 },
+	{ 25, 0, NOTHING_block, 20},
+	{ 26, 0, NOTHING_block, 19},
+	{ 27, 0, NOTHING_block, 28},
+	{ 28, 0, NOTHING_block, 19},
+	{ 29, 0, NOTHING_block, 26},
 	{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
 };
 
--- a/src/build_vehicle_gui.cpp
+++ b/src/build_vehicle_gui.cpp
@@ -494,7 +494,7 @@
 
 	/* Purchase cost - Max speed */
 	SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5);
-	SetDParam(1, avi->max_speed * 8);
+	SetDParam(1, avi->max_speed * 10 / 16);
 	DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, 0);
 	y += 10;
 
--- a/src/engine.h
+++ b/src/engine.h
@@ -68,7 +68,7 @@
 	byte subtype;
 	SoundFxByte sfx;
 	byte acceleration;
-	byte max_speed;
+	uint16 max_speed;
 	byte mail_capacity;
 	uint16 passenger_capacity;
 } AircraftVehicleInfo;
--- a/src/engine_gui.cpp
+++ b/src/engine_gui.cpp
@@ -175,7 +175,7 @@
 {
 	const AircraftVehicleInfo *avi = AircraftVehInfo(engine);
 	SetDParam(0, (_price.aircraft_base >> 3) * avi->base_cost >> 5);
-	SetDParam(1, avi->max_speed * 8);
+	SetDParam(1, avi->max_speed);
 	SetDParam(2, avi->passenger_capacity);
 	SetDParam(3, avi->mail_capacity);
 	SetDParam(4, avi->running_cost * _price.aircraft_running >> 8);
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -781,12 +781,12 @@
 			FOR_EACH_OBJECT avi[i].base_cost = grf_load_byte(&buf); // ?? is it base_cost?
 			break;
 
-		case 0x0C: /* Speed (1 unit is 8 mph) */
-			FOR_EACH_OBJECT avi[i].max_speed = grf_load_byte(&buf);
+		case 0x0C: /* Speed (1 unit is 8 mph, we translate to 1 unit is 1 km/h) */
+			FOR_EACH_OBJECT avi[i].max_speed = (grf_load_byte(&buf) * 129) / 10;
 			break;
 
 		case 0x0D: /* Acceleration */
-			FOR_EACH_OBJECT avi[i].acceleration = grf_load_byte(&buf);
+			FOR_EACH_OBJECT avi[i].acceleration = (grf_load_byte(&buf) * 129) / 10;
 			break;
 
 		case 0x0E: /* Running cost factor */
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -40,6 +40,7 @@
 #include "fileio.h"
 #include "hal.h"
 #include "airport.h"
+#include "aircraft.h"
 #include "console.h"
 #include "screenshot.h"
 #include "network/network.h"
@@ -1818,6 +1819,20 @@
 		}
 	}
 
+	if (CheckSavegameVersion(50)) {
+		Vehicle *v;
+		/* Aircraft units changed from 8 mph to 1 km/h */
+		FOR_ALL_VEHICLES(v) {
+			if (v->type == VEH_Aircraft && v->subtype <= AIR_AIRCRAFT) {
+				const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type);
+				v->cur_speed *= 129;
+				v->cur_speed /= 10;
+				v->max_speed = avi->max_speed;
+				v->acceleration = avi->acceleration;
+			}
+		}
+	}
+
 	if (CheckSavegameVersion(49)) FOR_ALL_PLAYERS(p) p->face = ConvertFromOldPlayerFace(p->face);
 
 	return true;
--- a/src/saveload.cpp
+++ b/src/saveload.cpp
@@ -28,7 +28,7 @@
 #include "variables.h"
 #include <setjmp.h>
 
-extern const uint16 SAVEGAME_VERSION = 49;
+extern const uint16 SAVEGAME_VERSION = 50;
 uint16 _sl_version;       ///< the major savegame version identifier
 byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
 
--- a/src/table/engines.h
+++ b/src/table/engines.h
@@ -519,7 +519,7 @@
  * @param h mail_capacity
  * @param i passenger_capacity
  */
-#define AVI(a, b, c, d, e, f, g, h, i) { a, b, c, d, {e}, f, g, h, i }
+#define AVI(a, b, c, d, e, f, g, h, i) { a, b, c, d, {e}, f, (g * 129) / 10, h, i }
 #define H AIR_HELI
 #define P AIR_CTOL
 #define J AIR_CTOL | AIR_FAST