860 if (!PlayVehicleSound(v, VSE_START)) { |
860 if (!PlayVehicleSound(v, VSE_START)) { |
861 SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v); |
861 SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v); |
862 } |
862 } |
863 } |
863 } |
864 |
864 |
865 /** Special velocities for aircraft |
865 /** |
|
866 * Special velocities for aircraft |
866 */ |
867 */ |
867 enum AircraftSpeedLimits { |
868 enum AircraftSpeedLimits { |
868 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 |
869 SPEED_LIMIT_TAXI = 12, ///< Maximum speed of an aircraft while taxiing |
870 SPEED_LIMIT_APPROACH = 230, ///< Maximum speed of an aircraft on finals |
870 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 |
871 }; |
874 }; |
872 |
875 |
873 static bool UpdateAircraftSpeed(Vehicle *v, uint speed_limit) |
876 /** |
874 { |
877 * Sets the new speed for an aircraft |
875 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; |
876 byte t; |
886 byte t; |
877 |
887 |
|
888 speed_limit = min(speed_limit, v->max_speed); |
|
889 |
878 v->subspeed = (t=v->subspeed) + (byte)spd; |
890 v->subspeed = (t=v->subspeed) + (byte)spd; |
879 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 |
880 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); |
881 |
895 |
882 /* adjust speed for broken vehicles */ |
896 /* adjust speed for broken vehicles */ |
883 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); |
884 |
898 |
920 switch (v->direction) { |
930 switch (v->direction) { |
921 case DIR_N: |
931 case DIR_N: |
922 case DIR_NE: |
932 case DIR_NE: |
923 case DIR_E: |
933 case DIR_E: |
924 case DIR_SE: |
934 case DIR_SE: |
925 base_altitude += 15; |
935 base_altitude += 10; |
926 break; |
936 break; |
927 |
937 |
928 default: break; |
938 default: break; |
929 } |
939 } |
930 |
940 |
931 /* 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 */ |
932 base_altitude += min(30 * (v->max_speed / 37), 90); |
942 base_altitude += min(20 * (v->max_speed / 200), 90); |
933 |
943 |
934 return base_altitude; |
944 return base_altitude; |
935 } |
945 } |
936 |
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 */ |
937 static bool AircraftController(Vehicle *v) |
954 static bool AircraftController(Vehicle *v) |
938 { |
955 { |
|
956 int count; |
939 const Station *st = GetStation(v->u.air.targetairport); |
957 const Station *st = GetStation(v->u.air.targetairport); |
940 |
958 |
941 /* prevent going to 0,0 if airport is deleted. */ |
959 /* prevent going to 0,0 if airport is deleted. */ |
942 TileIndex tile = st->airport_tile; |
960 TileIndex tile = st->airport_tile; |
943 if (tile == 0) tile = st->xy; |
961 if (tile == 0) tile = st->xy; |
956 if (u->cur_speed > 32) { |
974 if (u->cur_speed > 32) { |
957 v->cur_speed = 0; |
975 v->cur_speed = 0; |
958 if (--u->cur_speed == 32) SndPlayVehicleFx(SND_18_HELICOPTER, v); |
976 if (--u->cur_speed == 32) SndPlayVehicleFx(SND_18_HELICOPTER, v); |
959 } else { |
977 } else { |
960 u->cur_speed = 32; |
978 u->cur_speed = 32; |
961 if (UpdateAircraftSpeed(v, SPEED_LIMIT_NONE)) { |
979 count = UpdateAircraftSpeed(v); |
|
980 if (count > 0) { |
962 v->tile = 0; |
981 v->tile = 0; |
963 |
982 |
964 /* Reached altitude? */ |
983 /* Reached altitude? */ |
965 if (v->z_pos >= 184) { |
984 if (v->z_pos >= 184) { |
966 v->cur_speed = 0; |
985 v->cur_speed = 0; |
967 return true; |
986 return true; |
968 } |
987 } |
969 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)); |
970 } |
989 } |
971 } |
990 } |
972 return false; |
991 return false; |
973 } |
992 } |
974 |
993 |
975 /* Helicopter landing. */ |
994 /* Helicopter landing. */ |
976 if (amd->flag & AMED_HELI_LOWER) { |
995 if (amd->flag & AMED_HELI_LOWER) { |
977 if (UpdateAircraftSpeed(v, SPEED_LIMIT_NONE)) { |
996 count = UpdateAircraftSpeed(v); |
|
997 if (count > 0) { |
978 if (st->airport_tile == 0) { |
998 if (st->airport_tile == 0) { |
979 /* FIXME - AircraftController -> if station no longer exists, do not land |
999 /* FIXME - AircraftController -> if station no longer exists, do not land |
980 * helicopter will circle until sign disappears, then go to next order |
1000 * helicopter will circle until sign disappears, then go to next order |
981 * 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 */ |
982 v->u.air.state = FLYING; |
1002 v->u.air.state = FLYING; |
986 |
1006 |
987 /* Vehicle is now at the airport. */ |
1007 /* Vehicle is now at the airport. */ |
988 v->tile = st->airport_tile; |
1008 v->tile = st->airport_tile; |
989 |
1009 |
990 /* Find altitude of landing position. */ |
1010 /* Find altitude of landing position. */ |
991 uint z = GetSlopeZ(x, y) + 1 + afc->delta_z; |
1011 int z = GetSlopeZ(x, y) + 1 + afc->delta_z; |
992 |
1012 |
993 if (z == v->z_pos) { |
1013 if (z == v->z_pos) { |
994 Vehicle *u = v->next->next; |
1014 Vehicle *u = v->next->next; |
995 |
1015 |
996 /* Increase speed of rotors. When speed is 80, we've landed. */ |
1016 /* Increase speed of rotors. When speed is 80, we've landed. */ |
997 if (u->cur_speed >= 80) return true; |
1017 if (u->cur_speed >= 80) return true; |
998 u->cur_speed += 4; |
1018 u->cur_speed += 4; |
999 } else if (v->z_pos > z) { |
1019 } else if (v->z_pos > z) { |
1000 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)); |
1001 } else { |
1021 } else { |
1002 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)); |
1003 } |
1023 } |
1004 } |
1024 } |
1005 return false; |
1025 return false; |
1006 } |
1026 } |
1007 |
1027 |
1008 /* Get distance from destination pos to current pos. */ |
1028 /* Get distance from destination pos to current pos. */ |
1009 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); |
1010 |
1030 |
1011 /* Need exact position? */ |
1031 /* Need exact position? */ |
1012 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; |
1013 return true; |
|
1014 |
1033 |
1015 /* At final pos? */ |
1034 /* At final pos? */ |
1016 if (dist == 0) { |
1035 if (dist == 0) { |
1017 /* Change direction smoothly to final direction. */ |
1036 /* Change direction smoothly to final direction. */ |
1018 DirDiff dirdiff = DirDifference(amd->direction, v->direction); |
1037 DirDiff dirdiff = DirDifference(amd->direction, v->direction); |
1030 |
1049 |
1031 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); |
1050 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); |
1032 return false; |
1051 return false; |
1033 } |
1052 } |
1034 |
1053 |
1035 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; |
1036 |
1064 |
1037 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--; |
1038 |
1066 |
1039 /* Turn. Do it slowly if in the air. */ |
1067 do { |
1040 Direction newdir = GetDirectionTowards(v, x + amd->x, y + amd->y); |
1068 /* Turn. Do it slowly if in the air. */ |
1041 if (newdir != v->direction) { |
1069 Direction newdir = GetDirectionTowards(v, x + amd->x, y + amd->y); |
1042 if (amd->flag & AMED_SLOWTURN) { |
1070 if (newdir != v->direction) { |
1043 if (v->load_unload_time_rem == 0) v->load_unload_time_rem = 8; |
|
1044 v->direction = newdir; |
1071 v->direction = newdir; |
1045 } else { |
1072 if (amd->flag & AMED_SLOWTURN) { |
1046 v->cur_speed >>= 1; |
1073 if (v->load_unload_time_rem == 0) v->load_unload_time_rem = 8; |
1047 v->direction = newdir; |
1074 } else { |
1048 } |
1075 v->cur_speed >>= 1; |
1049 } |
1076 } |
1050 |
1077 } |
1051 /* Move vehicle. */ |
1078 |
1052 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
1079 /* Move vehicle. */ |
1053 v->tile = gp.new_tile; |
1080 GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
1054 |
1081 v->tile = gp.new_tile; |
1055 /* If vehicle is in the air, use tile coordinate 0. */ |
1082 /* If vehicle is in the air, use tile coordinate 0. */ |
1056 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; |
1057 |
1084 |
1058 /* Adjust Z for land or takeoff? */ |
1085 /* Adjust Z for land or takeoff? */ |
1059 uint z = v->z_pos; |
1086 uint z = v->z_pos; |
1060 |
1087 |
1061 if (amd->flag & AMED_TAKEOFF) { |
1088 if (amd->flag & AMED_TAKEOFF) { |
1062 z = min(z + 2, GetAircraftFlyingAltitude(v)); |
1089 z = min(z + 2, GetAircraftFlyingAltitude(v)); |
1063 } |
1090 } |
1064 |
1091 |
1065 if (amd->flag & AMED_LAND) { |
1092 if ((amd->flag & AMED_HOLD) && (z > 150)) z--; |
1066 if (st->airport_tile == 0) { |
1093 |
1067 v->u.air.state = FLYING; |
1094 if (amd->flag & AMED_LAND) { |
1068 AircraftNextAirportPos_and_Order(v); |
1095 if (st->airport_tile == 0) { |
1069 /* get aircraft back on running altitude */ |
1096 /* Airport has been removed, abort the landing procedure */ |
1070 SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v)); |
1097 v->u.air.state = FLYING; |
1071 return false; |
1098 AircraftNextAirportPos_and_Order(v); |
1072 } |
1099 /* get aircraft back on running altitude */ |
1073 |
1100 SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v)); |
1074 uint curz = GetSlopeZ(x, y) + 1; |
1101 continue; |
1075 |
1102 } |
1076 if (curz > z) { |
1103 |
1077 z++; |
1104 uint curz = GetSlopeZ(x, y) + 1; |
1078 } else { |
1105 |
1079 int t = max(1U, dist - 4); |
1106 if (curz > z) { |
1080 |
1107 z++; |
1081 z -= ((z - curz) + t - 1) / t; |
1108 } else { |
1082 if (z < curz) z = curz; |
1109 int t = max(1U, dist - 4); |
1083 } |
1110 |
1084 } |
1111 z -= ((z - curz) + t - 1) / t; |
1085 |
1112 if (z < curz) z = curz; |
1086 /* We've landed. Decrase speed when we're reaching end of runway. */ |
1113 } |
1087 if (amd->flag & AMED_BRAKE) { |
1114 } |
1088 uint curz = GetSlopeZ(x, y) + 1; |
1115 |
1089 |
1116 /* We've landed. Decrase speed when we're reaching end of runway. */ |
1090 if (z > curz) { |
1117 if (amd->flag & AMED_BRAKE) { |
1091 z--; |
1118 uint curz = GetSlopeZ(x, y) + 1; |
1092 } else if (z < curz) { |
1119 |
1093 z++; |
1120 if (z > curz) { |
1094 } |
1121 z--; |
1095 |
1122 } else if (z < curz) { |
1096 if (dist < 64 && v->cur_speed > 12) v->cur_speed -= 4; |
1123 z++; |
1097 } |
1124 } |
1098 |
1125 |
1099 SetAircraftPosition(v, gp.x, gp.y, z); |
1126 } |
|
1127 |
|
1128 SetAircraftPosition(v, gp.x, gp.y, z); |
|
1129 } while (--count != 0); |
1100 return false; |
1130 return false; |
1101 } |
1131 } |
1102 |
1132 |
1103 |
1133 |
1104 static void HandleCrashedAircraft(Vehicle *v) |
1134 static void HandleCrashedAircraft(Vehicle *v) |