857 if (!PlayVehicleSound(v, VSE_START)) { |
860 if (!PlayVehicleSound(v, VSE_START)) { |
858 SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v); |
861 SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v); |
859 } |
862 } |
860 } |
863 } |
861 |
864 |
862 /** Special velocities for aircraft |
865 /** |
|
866 * Special velocities for aircraft |
863 */ |
867 */ |
864 enum AircraftSpeedLimits { |
868 enum AircraftSpeedLimits { |
865 SPEED_LIMIT_NONE = 0, ///< No environmental speed limit. Speed limit is type dependent |
869 SPEED_LIMIT_TAXI = 50, ///< Maximum speed of an aircraft while taxiing |
866 SPEED_LIMIT_TAXI = 12, ///< Maximum speed of an aircraft while taxiing |
870 SPEED_LIMIT_APPROACH = 230, ///< Maximum speed of an aircraft on finals |
867 SPEED_LIMIT_BROKEN = 27, ///< Maximum speed of an aircraft that is broken |
871 SPEED_LIMIT_BROKEN = 320, ///< Maximum speed of an aircraft that is broken |
|
872 SPEED_LIMIT_HOLD = 425, ///< Maximum speed of an aircraft that flies the holding pattern |
|
873 SPEED_LIMIT_NONE = 0xFFFF ///< No environmental speed limit. Speed limit is type dependent |
868 }; |
874 }; |
869 |
875 |
870 static bool UpdateAircraftSpeed(Vehicle *v, uint speed_limit) |
876 /** |
871 { |
877 * Sets the new speed for an aircraft |
872 uint spd = v->acceleration * 2; |
878 * @param v The vehicle for which the speed should be obtained |
|
879 * @param speed_limit The maximum speed the vehicle may have. |
|
880 * @param hard_limit If true, the limit is directly enforced, otherwise the plane is slowed down gradually |
|
881 * @return The number of position updates needed within the tick |
|
882 */ |
|
883 static int UpdateAircraftSpeed(Vehicle *v, uint speed_limit = SPEED_LIMIT_NONE, bool hard_limit = true) |
|
884 { |
|
885 uint spd = v->acceleration * 16; |
873 byte t; |
886 byte t; |
874 |
887 |
|
888 speed_limit = min(speed_limit, v->max_speed); |
|
889 |
875 v->subspeed = (t=v->subspeed) + (byte)spd; |
890 v->subspeed = (t=v->subspeed) + (byte)spd; |
876 if (speed_limit == SPEED_LIMIT_NONE) speed_limit = v->max_speed; |
891 |
|
892 if (!hard_limit && v->cur_speed > speed_limit) speed_limit = v->cur_speed - (v->cur_speed / 48); |
|
893 |
877 spd = min(v->cur_speed + (spd >> 8) + (v->subspeed < t), speed_limit); |
894 spd = min(v->cur_speed + (spd >> 8) + (v->subspeed < t), speed_limit); |
878 |
895 |
879 /* adjust speed for broken vehicles */ |
896 /* adjust speed for broken vehicles */ |
880 if (v->vehstatus & VS_AIRCRAFT_BROKEN) spd = min(spd, SPEED_LIMIT_BROKEN); |
897 if (v->vehstatus & VS_AIRCRAFT_BROKEN) spd = min(spd, SPEED_LIMIT_BROKEN); |
881 |
898 |
917 switch (v->direction) { |
930 switch (v->direction) { |
918 case DIR_N: |
931 case DIR_N: |
919 case DIR_NE: |
932 case DIR_NE: |
920 case DIR_E: |
933 case DIR_E: |
921 case DIR_SE: |
934 case DIR_SE: |
922 base_altitude += 15; |
935 base_altitude += 10; |
923 break; |
936 break; |
924 |
937 |
925 default: break; |
938 default: break; |
926 } |
939 } |
927 |
940 |
928 /* Make faster planes fly higher so that they can overtake slower ones */ |
941 /* Make faster planes fly higher so that they can overtake slower ones */ |
929 base_altitude += min(30 * (v->max_speed / 37), 90); |
942 base_altitude += min(20 * (v->max_speed / 200), 90); |
930 |
943 |
931 return base_altitude; |
944 return base_altitude; |
932 } |
945 } |
933 |
946 |
|
947 /** |
|
948 * Controls the movement of an aircraft. This function actually moves the vehicle |
|
949 * on the map and takes care of minor things like sound playback. |
|
950 * @todo De-mystify the cur_speed values for helicopter rotors. |
|
951 * @param v The vehicle that is moved. Must be the first vehicle of the chain |
|
952 * @return Whether the position requested by the State Machine has been reached |
|
953 */ |
934 static bool AircraftController(Vehicle *v) |
954 static bool AircraftController(Vehicle *v) |
935 { |
955 { |
|
956 int count; |
936 const Station *st = GetStation(v->u.air.targetairport); |
957 const Station *st = GetStation(v->u.air.targetairport); |
937 |
958 |
938 /* prevent going to 0,0 if airport is deleted. */ |
959 /* prevent going to 0,0 if airport is deleted. */ |
939 TileIndex tile = st->airport_tile; |
960 TileIndex tile = st->airport_tile; |
940 if (tile == 0) tile = st->xy; |
961 if (tile == 0) tile = st->xy; |
953 if (u->cur_speed > 32) { |
974 if (u->cur_speed > 32) { |
954 v->cur_speed = 0; |
975 v->cur_speed = 0; |
955 if (--u->cur_speed == 32) SndPlayVehicleFx(SND_18_HELICOPTER, v); |
976 if (--u->cur_speed == 32) SndPlayVehicleFx(SND_18_HELICOPTER, v); |
956 } else { |
977 } else { |
957 u->cur_speed = 32; |
978 u->cur_speed = 32; |
958 if (UpdateAircraftSpeed(v, SPEED_LIMIT_NONE)) { |
979 count = UpdateAircraftSpeed(v); |
|
980 if (count > 0) { |
959 v->tile = 0; |
981 v->tile = 0; |
960 |
982 |
961 /* Reached altitude? */ |
983 /* Reached altitude? */ |
962 if (v->z_pos >= 184) { |
984 if (v->z_pos >= 184) { |
963 v->cur_speed = 0; |
985 v->cur_speed = 0; |
964 return true; |
986 return true; |
965 } |
987 } |
966 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos+1); |
988 SetAircraftPosition(v, v->x_pos, v->y_pos, min(v->z_pos + count, 184)); |
967 } |
989 } |
968 } |
990 } |
969 return false; |
991 return false; |
970 } |
992 } |
971 |
993 |
972 /* Helicopter landing. */ |
994 /* Helicopter landing. */ |
973 if (amd->flag & AMED_HELI_LOWER) { |
995 if (amd->flag & AMED_HELI_LOWER) { |
974 if (UpdateAircraftSpeed(v, SPEED_LIMIT_NONE)) { |
996 count = UpdateAircraftSpeed(v); |
|
997 if (count > 0) { |
975 if (st->airport_tile == 0) { |
998 if (st->airport_tile == 0) { |
976 /* FIXME - AircraftController -> if station no longer exists, do not land |
999 /* FIXME - AircraftController -> if station no longer exists, do not land |
977 * helicopter will circle until sign disappears, then go to next order |
1000 * helicopter will circle until sign disappears, then go to next order |
978 * what to do when it is the only order left, right now it just stays in 1 place */ |
1001 * what to do when it is the only order left, right now it just stays in 1 place */ |
979 v->u.air.state = FLYING; |
1002 v->u.air.state = FLYING; |
983 |
1006 |
984 /* Vehicle is now at the airport. */ |
1007 /* Vehicle is now at the airport. */ |
985 v->tile = st->airport_tile; |
1008 v->tile = st->airport_tile; |
986 |
1009 |
987 /* Find altitude of landing position. */ |
1010 /* Find altitude of landing position. */ |
988 uint z = GetSlopeZ(x, y) + 1 + afc->delta_z; |
1011 int z = GetSlopeZ(x, y) + 1 + afc->delta_z; |
989 |
1012 |
990 if (z == v->z_pos) { |
1013 if (z == v->z_pos) { |
991 Vehicle *u = v->next->next; |
1014 Vehicle *u = v->next->next; |
992 |
1015 |
993 /* Increase speed of rotors. When speed is 80, we've landed. */ |
1016 /* Increase speed of rotors. When speed is 80, we've landed. */ |
994 if (u->cur_speed >= 80) return true; |
1017 if (u->cur_speed >= 80) return true; |
995 u->cur_speed += 4; |
1018 u->cur_speed += 4; |
996 } else if (v->z_pos > z) { |
1019 } else if (v->z_pos > z) { |
997 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos-1); |
1020 SetAircraftPosition(v, v->x_pos, v->y_pos, max(v->z_pos - count, z)); |
998 } else { |
1021 } else { |
999 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos+1); |
1022 SetAircraftPosition(v, v->x_pos, v->y_pos, min(v->z_pos + count, z)); |
1000 } |
1023 } |
1001 } |
1024 } |
1002 return false; |
1025 return false; |
1003 } |
1026 } |
1004 |
1027 |
1005 /* Get distance from destination pos to current pos. */ |
1028 /* Get distance from destination pos to current pos. */ |
1006 uint dist = myabs(x + amd->x - v->x_pos) + myabs(y + amd->y - v->y_pos); |
1029 uint dist = myabs(x + amd->x - v->x_pos) + myabs(y + amd->y - v->y_pos); |
1007 |
1030 |
1008 /* Need exact position? */ |
1031 /* Need exact position? */ |
1009 if (!(amd->flag & AMED_EXACTPOS) && dist <= (amd->flag & AMED_SLOWTURN ? 8U : 4U)) |
1032 if (!(amd->flag & AMED_EXACTPOS) && dist <= (amd->flag & AMED_SLOWTURN ? 8U : 4U)) return true; |
1010 return true; |
|
1011 |
1033 |
1012 /* At final pos? */ |
1034 /* At final pos? */ |
1013 if (dist == 0) { |
1035 if (dist == 0) { |
1014 /* Change direction smoothly to final direction. */ |
1036 /* Change direction smoothly to final direction. */ |
1015 DirDiff dirdiff = DirDifference(amd->direction, v->direction); |
1037 DirDiff dirdiff = DirDifference(amd->direction, v->direction); |
1027 |
1049 |
1028 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); |
1050 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); |
1029 return false; |
1051 return false; |
1030 } |
1052 } |
1031 |
1053 |
1032 if (!UpdateAircraftSpeed(v, ((amd->flag & AMED_NOSPDCLAMP) == 0) ? SPEED_LIMIT_TAXI : SPEED_LIMIT_NONE)) return false; |
1054 uint speed_limit = SPEED_LIMIT_TAXI; |
|
1055 bool hard_limit = true; |
|
1056 |
|
1057 if (amd->flag & AMED_NOSPDCLAMP) speed_limit = SPEED_LIMIT_NONE; |
|
1058 if (amd->flag & AMED_HOLD) { speed_limit = SPEED_LIMIT_HOLD; hard_limit = false; } |
|
1059 if (amd->flag & AMED_LAND) { speed_limit = SPEED_LIMIT_APPROACH; hard_limit = false; } |
|
1060 if (amd->flag & AMED_BRAKE) { speed_limit = SPEED_LIMIT_TAXI; hard_limit = false; } |
|
1061 |
|
1062 count = UpdateAircraftSpeed(v, speed_limit, hard_limit); |
|
1063 if (count == 0) return false; |
1033 |
1064 |
1034 if (v->load_unload_time_rem != 0) v->load_unload_time_rem--; |
1065 if (v->load_unload_time_rem != 0) v->load_unload_time_rem--; |
1035 |
1066 |
1036 /* Turn. Do it slowly if in the air. */ |
1067 do { |
1037 Direction newdir = GetDirectionTowards(v, x + amd->x, y + amd->y); |
1068 /* Turn. Do it slowly if in the air. */ |
1038 if (newdir != v->direction) { |
1069 Direction newdir = GetDirectionTowards(v, x + amd->x, y + amd->y); |
1039 if (amd->flag & AMED_SLOWTURN) { |
1070 if (newdir != v->direction) { |
1040 if (v->load_unload_time_rem == 0) v->load_unload_time_rem = 8; |
|
1041 v->direction = newdir; |
1071 v->direction = newdir; |
1042 } else { |
1072 if (amd->flag & AMED_SLOWTURN) { |
1043 v->cur_speed >>= 1; |
1073 if (v->load_unload_time_rem == 0) v->load_unload_time_rem = 8; |
1044 v->direction = newdir; |
1074 } else { |
1045 } |
1075 v->cur_speed >>= 1; |
1046 } |
1076 } |
1047 |
1077 } |
1048 /* Move vehicle. */ |
1078 |
1049 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
1079 /* Move vehicle. */ |
1050 v->tile = gp.new_tile; |
1080 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
1051 |
1081 v->tile = gp.new_tile; |
1052 /* If vehicle is in the air, use tile coordinate 0. */ |
1082 /* If vehicle is in the air, use tile coordinate 0. */ |
1053 if (amd->flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) v->tile = 0; |
1083 // if (amd->flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) v->tile = 0; |
1054 |
1084 |
1055 /* Adjust Z for land or takeoff? */ |
1085 /* Adjust Z for land or takeoff? */ |
1056 uint z = v->z_pos; |
1086 uint z = v->z_pos; |
1057 |
1087 |
1058 if (amd->flag & AMED_TAKEOFF) { |
1088 if (amd->flag & AMED_TAKEOFF) { |
1059 z = min(z + 2, GetAircraftFlyingAltitude(v)); |
1089 z = min(z + 2, GetAircraftFlyingAltitude(v)); |
1060 } |
1090 } |
1061 |
1091 |
1062 if (amd->flag & AMED_LAND) { |
1092 if ((amd->flag & AMED_HOLD) && (z > 150)) z--; |
1063 if (st->airport_tile == 0) { |
1093 |
1064 v->u.air.state = FLYING; |
1094 if (amd->flag & AMED_LAND) { |
1065 AircraftNextAirportPos_and_Order(v); |
1095 if (st->airport_tile == 0) { |
1066 /* get aircraft back on running altitude */ |
1096 /* Airport has been removed, abort the landing procedure */ |
1067 SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v)); |
1097 v->u.air.state = FLYING; |
1068 return false; |
1098 AircraftNextAirportPos_and_Order(v); |
1069 } |
1099 /* get aircraft back on running altitude */ |
1070 |
1100 SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v)); |
1071 uint curz = GetSlopeZ(x, y) + 1; |
1101 continue; |
1072 |
1102 } |
1073 if (curz > z) { |
1103 |
1074 z++; |
1104 uint curz = GetSlopeZ(x, y) + 1; |
1075 } else { |
1105 |
1076 int t = max(1U, dist - 4); |
1106 if (curz > z) { |
1077 |
1107 z++; |
1078 z -= ((z - curz) + t - 1) / t; |
1108 } else { |
1079 if (z < curz) z = curz; |
1109 int t = max(1U, dist - 4); |
1080 } |
1110 |
1081 } |
1111 z -= ((z - curz) + t - 1) / t; |
1082 |
1112 if (z < curz) z = curz; |
1083 /* We've landed. Decrase speed when we're reaching end of runway. */ |
1113 } |
1084 if (amd->flag & AMED_BRAKE) { |
1114 } |
1085 uint curz = GetSlopeZ(x, y) + 1; |
1115 |
1086 |
1116 /* We've landed. Decrase speed when we're reaching end of runway. */ |
1087 if (z > curz) { |
1117 if (amd->flag & AMED_BRAKE) { |
1088 z--; |
1118 uint curz = GetSlopeZ(x, y) + 1; |
1089 } else if (z < curz) { |
1119 |
1090 z++; |
1120 if (z > curz) { |
1091 } |
1121 z--; |
1092 |
1122 } else if (z < curz) { |
1093 if (dist < 64 && v->cur_speed > 12) v->cur_speed -= 4; |
1123 z++; |
1094 } |
1124 } |
1095 |
1125 |
1096 SetAircraftPosition(v, gp.x, gp.y, z); |
1126 } |
|
1127 |
|
1128 SetAircraftPosition(v, gp.x, gp.y, z); |
|
1129 } while (--count != 0); |
1097 return false; |
1130 return false; |
1098 } |
1131 } |
1099 |
1132 |
1100 |
1133 |
1101 static void HandleCrashedAircraft(Vehicle *v) |
1134 static void HandleCrashedAircraft(Vehicle *v) |
1213 |
1246 |
1214 if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; |
1247 if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; |
1215 |
1248 |
1216 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
1249 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
1217 |
1250 |
1218 if (order == NULL) { |
1251 if (order == NULL|| (order->type == OT_DUMMY && !CheckForValidOrders(v))) { |
1219 v->current_order.type = OT_NOTHING; |
1252 /* |
1220 v->current_order.flags = 0; |
1253 * We do not have an order. This can be divided into two cases: |
|
1254 * 1) we are heading to an invalid station. In this case we must |
|
1255 * find another airport to go to. If there is nowhere to go, |
|
1256 * we will destroy the aircraft as it otherwise will enter |
|
1257 * the holding pattern for the first airport, which can cause |
|
1258 * the plane to go into an undefined state when building an |
|
1259 * airport with the same StationID. |
|
1260 * 2) we are (still) heading to a (still) valid airport, then we |
|
1261 * can continue going there. This can happen when you are |
|
1262 * changing the aircraft's orders while in-flight or in for |
|
1263 * example a depot. However, when we have a current order to |
|
1264 * go to a depot, we have to keep that order so the aircraft |
|
1265 * actually stops. |
|
1266 */ |
|
1267 const Station *st = GetStation(v->u.air.targetairport); |
|
1268 if (!st->IsValid() || st->airport_tile == 0) { |
|
1269 int32 ret; |
|
1270 PlayerID old_player = _current_player; |
|
1271 |
|
1272 _current_player = v->owner; |
|
1273 ret = DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_SEND_AIRCRAFT_TO_HANGAR); |
|
1274 _current_player = old_player; |
|
1275 |
|
1276 if (CmdFailed(ret)) CrashAirplane(v); |
|
1277 } else if (v->current_order.type != OT_GOTO_DEPOT) { |
|
1278 v->current_order.type = OT_NOTHING; |
|
1279 v->current_order.flags = 0; |
|
1280 } |
1221 return; |
1281 return; |
1222 } |
1282 } |
1223 |
|
1224 if (order->type == OT_DUMMY && !CheckForValidOrders(v)) CrashAirplane(v); |
|
1225 |
1283 |
1226 if (order->type == v->current_order.type && |
1284 if (order->type == v->current_order.type && |
1227 order->flags == v->current_order.flags && |
1285 order->flags == v->current_order.flags && |
1228 order->dest == v->current_order.dest) |
1286 order->dest == v->current_order.dest) |
1229 return; |
1287 return; |
1257 if (mode != 0) return; |
1315 if (mode != 0) return; |
1258 if (--v->load_unload_time_rem != 0) return; |
1316 if (--v->load_unload_time_rem != 0) return; |
1259 |
1317 |
1260 if (CanFillVehicle(v) && ( |
1318 if (CanFillVehicle(v) && ( |
1261 v->current_order.flags & OF_FULL_LOAD || |
1319 v->current_order.flags & OF_FULL_LOAD || |
1262 (_patches.gradual_loading && !HASBIT(v->load_status, LS_LOADING_FINISHED)) |
1320 (_patches.gradual_loading && !HASBIT(v->vehicle_flags, VF_LOADING_FINISHED)) |
1263 )) { |
1321 )) { |
1264 SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_INC); |
1322 SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_INC); |
1265 if (LoadUnloadVehicle(v, false)) { |
1323 if (LoadUnloadVehicle(v, false)) { |
1266 InvalidateWindow(WC_AIRCRAFT_LIST, v->owner); |
1324 InvalidateWindow(WC_AIRCRAFT_LIST, v->owner); |
1267 MarkAircraftDirty(v); |
1325 MarkAircraftDirty(v); |