29 #include "newgrf_text.h" |
29 #include "newgrf_text.h" |
30 #include "newgrf_sound.h" |
30 #include "newgrf_sound.h" |
31 #include "date.h" |
31 #include "date.h" |
32 #include "spritecache.h" |
32 #include "spritecache.h" |
33 |
33 |
34 // this maps the terminal to its corresponding state and block flag |
34 /** this maps the terminal to its corresponding state and block flag |
35 // currently set for 10 terms, 4 helipads |
35 * currently set for 10 terms, 4 helipads */ |
36 static const byte _airport_terminal_state[] = {2, 3, 4, 5, 6, 7, 19, 20, 0, 0, 8, 9, 21, 22}; |
36 static const byte _airport_terminal_state[] = {2, 3, 4, 5, 6, 7, 19, 20, 0, 0, 8, 9, 21, 22}; |
37 static const byte _airport_terminal_flag[] = {0, 1, 2, 3, 4, 5, 22, 23, 0, 0, 6, 7, 24, 25}; |
37 static const byte _airport_terminal_flag[] = {0, 1, 2, 3, 4, 5, 22, 23, 0, 0, 6, 7, 24, 25}; |
38 |
38 |
39 static bool AirportMove(Vehicle *v, const AirportFTAClass *apc); |
39 static bool AirportMove(Vehicle *v, const AirportFTAClass *apc); |
40 static bool AirportSetBlocks(Vehicle *v, const AirportFTA *current_pos, const AirportFTAClass *apc); |
40 static bool AirportSetBlocks(Vehicle *v, const AirportFTA *current_pos, const AirportFTAClass *apc); |
54 0x0EED, 0x0EF5, 0x0EFD, 0x0F35, |
54 0x0EED, 0x0EF5, 0x0EFD, 0x0F35, |
55 0x0E9D, 0x0EA5, 0x0EAD, 0x0EB5, |
55 0x0E9D, 0x0EA5, 0x0EAD, 0x0EB5, |
56 0x0EBD, 0x0EC5 |
56 0x0EBD, 0x0EC5 |
57 }; |
57 }; |
58 |
58 |
59 /* Helicopter rotor animation states */ |
59 /** Helicopter rotor animation states */ |
60 enum HelicopterRotorStates { |
60 enum HelicopterRotorStates { |
61 HRS_ROTOR_STOPPED, |
61 HRS_ROTOR_STOPPED, |
62 HRS_ROTOR_MOVING_1, |
62 HRS_ROTOR_MOVING_1, |
63 HRS_ROTOR_MOVING_2, |
63 HRS_ROTOR_MOVING_2, |
64 HRS_ROTOR_MOVING_3, |
64 HRS_ROTOR_MOVING_3, |
65 }; |
65 }; |
66 |
66 |
67 /* Find the nearest hangar to v |
67 /** Find the nearest hangar to v |
68 * INVALID_STATION is returned, if the player does not have any suitable |
68 * INVALID_STATION is returned, if the player does not have any suitable |
69 * airports (like helipads only) |
69 * airports (like helipads only) |
|
70 * @param v vehicle looking for a hangar |
|
71 * @return the StationID if one is found, otherwise, INVALID_STATION |
70 */ |
72 */ |
71 static StationID FindNearestHangar(const Vehicle *v) |
73 static StationID FindNearestHangar(const Vehicle *v) |
72 { |
74 { |
73 const Station *st; |
75 const Station *st; |
74 uint best = 0; |
76 uint best = 0; |
86 !_cheats.no_jetcrash.value |
88 !_cheats.no_jetcrash.value |
87 )) { |
89 )) { |
88 continue; |
90 continue; |
89 } |
91 } |
90 |
92 |
91 // v->tile can't be used here, when aircraft is flying v->tile is set to 0 |
93 /* v->tile can't be used here, when aircraft is flying v->tile is set to 0 */ |
92 uint distance = DistanceSquare(vtile, st->airport_tile); |
94 uint distance = DistanceSquare(vtile, st->airport_tile); |
93 if (distance < best || index == INVALID_STATION) { |
95 if (distance < best || index == INVALID_STATION) { |
94 best = distance; |
96 best = distance; |
95 index = st->index; |
97 index = st->index; |
96 } |
98 } |
97 } |
99 } |
98 return index; |
100 return index; |
99 } |
101 } |
100 |
102 |
101 #if 0 |
103 #if 0 |
102 // returns true if vehicle v have an airport in the schedule, that has a hangar |
104 /** Check if given vehicle has a goto hangar in his orders |
|
105 * @param v vehicle to inquiry |
|
106 * @return true if vehicle v has an airport in the schedule, that has a hangar */ |
103 static bool HaveHangarInOrderList(Vehicle *v) |
107 static bool HaveHangarInOrderList(Vehicle *v) |
104 { |
108 { |
105 const Order *order; |
109 const Order *order; |
106 |
110 |
107 FOR_VEHICLE_ORDERS(v, order) { |
111 FOR_VEHICLE_ORDERS(v, order) { |
108 const Station *st = GetStation(order->station); |
112 const Station *st = GetStation(order->station); |
109 if (st->owner == v->owner && st->facilities & FACIL_AIRPORT) { |
113 if (st->owner == v->owner && st->facilities & FACIL_AIRPORT) { |
110 // If an airport doesn't have a hangar, skip it |
114 /* If an airport doesn't have a hangar, skip it */ |
111 if (st->Airport()->nof_depots != 0) |
115 if (st->Airport()->nof_depots != 0) |
112 return true; |
116 return true; |
113 } |
117 } |
114 } |
118 } |
115 |
119 |
224 } |
228 } |
225 |
229 |
226 |
230 |
227 /** Build an aircraft. |
231 /** Build an aircraft. |
228 * @param tile tile of depot where aircraft is built |
232 * @param tile tile of depot where aircraft is built |
|
233 * @param flags for command |
229 * @param p1 aircraft type being built (engine) |
234 * @param p1 aircraft type being built (engine) |
230 * @param p2 bit 0 when set, the unitnumber will be 0, otherwise it will be a free number |
235 * @param p2 bit 0 when set, the unitnumber will be 0, otherwise it will be a free number |
|
236 * return result of operation. Could be cost, error |
231 */ |
237 */ |
232 int32 CmdBuildAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
238 int32 CmdBuildAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
233 { |
239 { |
234 if (!IsEngineBuildable(p1, VEH_Aircraft, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE); |
240 if (!IsEngineBuildable(p1, VEH_Aircraft, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE); |
235 |
241 |
236 const AircraftVehicleInfo *avi = AircraftVehInfo(p1); |
242 const AircraftVehicleInfo *avi = AircraftVehInfo(p1); |
237 int32 value = EstimateAircraftCost(avi); |
243 int32 value = EstimateAircraftCost(avi); |
238 |
244 |
239 // to just query the cost, it is not neccessary to have a valid tile (automation/AI) |
245 /* to just query the cost, it is not neccessary to have a valid tile (automation/AI) */ |
240 if (flags & DC_QUERY_COST) return value; |
246 if (flags & DC_QUERY_COST) return value; |
241 |
247 |
242 if (!IsHangarTile(tile) || !IsTileOwner(tile, _current_player)) return CMD_ERROR; |
248 if (!IsHangarTile(tile) || !IsTileOwner(tile, _current_player)) return CMD_ERROR; |
243 |
249 |
244 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
250 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
245 |
251 |
246 // Prevent building aircraft types at places which can't handle them |
252 /* Prevent building aircraft types at places which can't handle them */ |
247 const Station* st = GetStationByTile(tile); |
253 const Station* st = GetStationByTile(tile); |
248 const AirportFTAClass* apc = st->Airport(); |
254 const AirportFTAClass* apc = st->Airport(); |
249 if (!(apc->flags & (avi->subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS))) { |
255 if (!(apc->flags & (avi->subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS))) { |
250 return CMD_ERROR; |
256 return CMD_ERROR; |
251 } |
257 } |
460 return -(int32)v->value; |
468 return -(int32)v->value; |
461 } |
469 } |
462 |
470 |
463 /** Start/Stop an aircraft. |
471 /** Start/Stop an aircraft. |
464 * @param tile unused |
472 * @param tile unused |
|
473 * @param flags for command type |
465 * @param p1 aircraft ID to start/stop |
474 * @param p1 aircraft ID to start/stop |
466 * @param p2 unused |
475 * @param p2 unused |
|
476 * @return result of operation. Nothing if everything went well |
467 */ |
477 */ |
468 int32 CmdStartStopAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
478 int32 CmdStartStopAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
469 { |
479 { |
470 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
480 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
471 |
481 |
472 Vehicle *v = GetVehicle(p1); |
482 Vehicle *v = GetVehicle(p1); |
473 |
483 |
474 if (v->type != VEH_Aircraft || !CheckOwnership(v->owner)) return CMD_ERROR; |
484 if (v->type != VEH_Aircraft || !CheckOwnership(v->owner)) return CMD_ERROR; |
475 |
485 |
476 // cannot stop airplane when in flight, or when taking off / landing |
486 /* cannot stop airplane when in flight, or when taking off / landing */ |
477 if (v->u.air.state >= STARTTAKEOFF && v->u.air.state < TERM7) |
487 if (v->u.air.state >= STARTTAKEOFF && v->u.air.state < TERM7) |
478 return_cmd_error(STR_A017_AIRCRAFT_IS_IN_FLIGHT); |
488 return_cmd_error(STR_A017_AIRCRAFT_IS_IN_FLIGHT); |
479 |
489 |
480 /* Check if this aircraft can be started/stopped. The callback will fail or |
490 /* Check if this aircraft can be started/stopped. The callback will fail or |
481 * return 0xFF if it can. */ |
491 * return 0xFF if it can. */ |
499 return 0; |
509 return 0; |
500 } |
510 } |
501 |
511 |
502 /** Send an aircraft to the hangar. |
512 /** Send an aircraft to the hangar. |
503 * @param tile unused |
513 * @param tile unused |
|
514 * @param flags for command type |
504 * @param p1 vehicle ID to send to the hangar |
515 * @param p1 vehicle ID to send to the hangar |
505 * @param p2 various bitmasked elements |
516 * @param p2 various bitmasked elements |
506 * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h) |
517 * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h) |
507 * - p2 bit 8-10 - VLW flag (for mass goto depot) |
518 * - p2 bit 8-10 - VLW flag (for mass goto depot) |
|
519 * @return o if everything went well |
508 */ |
520 */ |
509 int32 CmdSendAircraftToHangar(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
521 int32 CmdSendAircraftToHangar(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
510 { |
522 { |
511 if (p2 & DEPOT_MASS_SEND) { |
523 if (p2 & DEPOT_MASS_SEND) { |
512 /* Mass goto depot requested */ |
524 /* Mass goto depot requested */ |
543 bool next_airport_has_hangar = true; |
555 bool next_airport_has_hangar = true; |
544 StationID next_airport_index = v->u.air.targetairport; |
556 StationID next_airport_index = v->u.air.targetairport; |
545 const Station *st = GetStation(next_airport_index); |
557 const Station *st = GetStation(next_airport_index); |
546 /* If the station is not a valid airport or if it has no hangars */ |
558 /* If the station is not a valid airport or if it has no hangars */ |
547 if (!st->IsValid() || st->airport_tile == 0 || st->Airport()->nof_depots == 0) { |
559 if (!st->IsValid() || st->airport_tile == 0 || st->Airport()->nof_depots == 0) { |
548 // the aircraft has to search for a hangar on its own |
560 /* the aircraft has to search for a hangar on its own */ |
549 StationID station = FindNearestHangar(v); |
561 StationID station = FindNearestHangar(v); |
550 |
562 |
551 next_airport_has_hangar = false; |
563 next_airport_has_hangar = false; |
552 if (station == INVALID_STATION) return CMD_ERROR; |
564 if (station == INVALID_STATION) return CMD_ERROR; |
553 next_airport_index = station; |
565 next_airport_index = station; |
571 } |
583 } |
572 |
584 |
573 |
585 |
574 /** Refits an aircraft to the specified cargo type. |
586 /** Refits an aircraft to the specified cargo type. |
575 * @param tile unused |
587 * @param tile unused |
|
588 * @param flags for command type |
576 * @param p1 vehicle ID of the aircraft to refit |
589 * @param p1 vehicle ID of the aircraft to refit |
577 * @param p2 various bitstuffed elements |
590 * @param p2 various bitstuffed elements |
578 * - p2 = (bit 0-7) - the new cargo type to refit to |
591 * - p2 = (bit 0-7) - the new cargo type to refit to |
579 * - p2 = (bit 8-15) - the new cargo subtype to refit to |
592 * - p2 = (bit 8-15) - the new cargo subtype to refit to |
|
593 * @return cost of refit or error |
580 */ |
594 */ |
581 int32 CmdRefitAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
595 int32 CmdRefitAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
582 { |
596 { |
583 byte new_subtype = GB(p2, 8, 8); |
597 byte new_subtype = GB(p2, 8, 8); |
584 |
598 |
860 |
874 |
861 v->subspeed = (t=v->subspeed) + (byte)spd; |
875 v->subspeed = (t=v->subspeed) + (byte)spd; |
862 if (speed_limit == SPEED_LIMIT_NONE) speed_limit = v->max_speed; |
876 if (speed_limit == SPEED_LIMIT_NONE) speed_limit = v->max_speed; |
863 spd = min(v->cur_speed + (spd >> 8) + (v->subspeed < t), speed_limit); |
877 spd = min(v->cur_speed + (spd >> 8) + (v->subspeed < t), speed_limit); |
864 |
878 |
865 // adjust speed for broken vehicles |
879 /* adjust speed for broken vehicles */ |
866 if (v->vehstatus & VS_AIRCRAFT_BROKEN) spd = min(spd, SPEED_LIMIT_BROKEN); |
880 if (v->vehstatus & VS_AIRCRAFT_BROKEN) spd = min(spd, SPEED_LIMIT_BROKEN); |
867 |
881 |
868 //updates statusbar only if speed have changed to save CPU time |
882 /* updates statusbar only if speed have changed to save CPU time */ |
869 if (spd != v->cur_speed) { |
883 if (spd != v->cur_speed) { |
870 v->cur_speed = spd; |
884 v->cur_speed = spd; |
871 if (_patches.vehicle_speed) |
885 if (_patches.vehicle_speed) |
872 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
886 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
873 } |
887 } |
919 |
933 |
920 static bool AircraftController(Vehicle *v) |
934 static bool AircraftController(Vehicle *v) |
921 { |
935 { |
922 const Station *st = GetStation(v->u.air.targetairport); |
936 const Station *st = GetStation(v->u.air.targetairport); |
923 |
937 |
924 // prevent going to 0,0 if airport is deleted. |
938 /* prevent going to 0,0 if airport is deleted. */ |
925 TileIndex tile = st->airport_tile; |
939 TileIndex tile = st->airport_tile; |
926 if (tile == 0) tile = st->xy; |
940 if (tile == 0) tile = st->xy; |
927 int x = TileX(tile) * TILE_SIZE; |
941 int x = TileX(tile) * TILE_SIZE; |
928 int y = TileY(tile) * TILE_SIZE; |
942 int y = TileY(tile) * TILE_SIZE; |
929 |
943 |
930 // get airport moving data |
944 /* get airport moving data */ |
931 const AirportFTAClass *afc = st->Airport(); |
945 const AirportFTAClass *afc = st->Airport(); |
932 const AirportMovingData *amd = afc->MovingData(v->u.air.pos); |
946 const AirportMovingData *amd = afc->MovingData(v->u.air.pos); |
933 |
947 |
934 // Helicopter raise |
948 /* Helicopter raise */ |
935 if (amd->flag & AMED_HELI_RAISE) { |
949 if (amd->flag & AMED_HELI_RAISE) { |
936 Vehicle *u = v->next->next; |
950 Vehicle *u = v->next->next; |
937 |
951 |
938 // Make sure the rotors don't rotate too fast |
952 /* Make sure the rotors don't rotate too fast */ |
939 if (u->cur_speed > 32) { |
953 if (u->cur_speed > 32) { |
940 v->cur_speed = 0; |
954 v->cur_speed = 0; |
941 if (--u->cur_speed == 32) SndPlayVehicleFx(SND_18_HELICOPTER, v); |
955 if (--u->cur_speed == 32) SndPlayVehicleFx(SND_18_HELICOPTER, v); |
942 } else { |
956 } else { |
943 u->cur_speed = 32; |
957 u->cur_speed = 32; |
944 if (UpdateAircraftSpeed(v, SPEED_LIMIT_NONE)) { |
958 if (UpdateAircraftSpeed(v, SPEED_LIMIT_NONE)) { |
945 v->tile = 0; |
959 v->tile = 0; |
946 |
960 |
947 // Reached altitude? |
961 /* Reached altitude? */ |
948 if (v->z_pos >= 184) { |
962 if (v->z_pos >= 184) { |
949 v->cur_speed = 0; |
963 v->cur_speed = 0; |
950 return true; |
964 return true; |
951 } |
965 } |
952 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos+1); |
966 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos+1); |
953 } |
967 } |
954 } |
968 } |
955 return false; |
969 return false; |
956 } |
970 } |
957 |
971 |
958 // Helicopter landing. |
972 /* Helicopter landing. */ |
959 if (amd->flag & AMED_HELI_LOWER) { |
973 if (amd->flag & AMED_HELI_LOWER) { |
960 if (UpdateAircraftSpeed(v, SPEED_LIMIT_NONE)) { |
974 if (UpdateAircraftSpeed(v, SPEED_LIMIT_NONE)) { |
961 if (st->airport_tile == 0) { |
975 if (st->airport_tile == 0) { |
962 // FIXME - AircraftController -> if station no longer exists, do not land |
976 /* FIXME - AircraftController -> if station no longer exists, do not land |
963 // helicopter will circle until sign disappears, then go to next order |
977 * helicopter will circle until sign disappears, then go to next order |
964 // * what to do when it is the only order left, right now it just stays in 1 place |
978 * what to do when it is the only order left, right now it just stays in 1 place */ |
965 v->u.air.state = FLYING; |
979 v->u.air.state = FLYING; |
966 AircraftNextAirportPos_and_Order(v); |
980 AircraftNextAirportPos_and_Order(v); |
967 return false; |
981 return false; |
968 } |
982 } |
969 |
983 |
970 // Vehicle is now at the airport. |
984 /* Vehicle is now at the airport. */ |
971 v->tile = st->airport_tile; |
985 v->tile = st->airport_tile; |
972 |
986 |
973 // Find altitude of landing position. |
987 /* Find altitude of landing position. */ |
974 uint z = GetSlopeZ(x, y) + 1 + afc->delta_z; |
988 uint z = GetSlopeZ(x, y) + 1 + afc->delta_z; |
975 |
989 |
976 if (z == v->z_pos) { |
990 if (z == v->z_pos) { |
977 Vehicle *u = v->next->next; |
991 Vehicle *u = v->next->next; |
978 |
992 |
979 // Increase speed of rotors. When speed is 80, we've landed. |
993 /* Increase speed of rotors. When speed is 80, we've landed. */ |
980 if (u->cur_speed >= 80) return true; |
994 if (u->cur_speed >= 80) return true; |
981 u->cur_speed += 4; |
995 u->cur_speed += 4; |
982 } else if (v->z_pos > z) { |
996 } else if (v->z_pos > z) { |
983 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos-1); |
997 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos-1); |
984 } else { |
998 } else { |
986 } |
1000 } |
987 } |
1001 } |
988 return false; |
1002 return false; |
989 } |
1003 } |
990 |
1004 |
991 // Get distance from destination pos to current pos. |
1005 /* Get distance from destination pos to current pos. */ |
992 uint dist = myabs(x + amd->x - v->x_pos) + myabs(y + amd->y - v->y_pos); |
1006 uint dist = myabs(x + amd->x - v->x_pos) + myabs(y + amd->y - v->y_pos); |
993 |
1007 |
994 // Need exact position? |
1008 /* Need exact position? */ |
995 if (!(amd->flag & AMED_EXACTPOS) && dist <= (amd->flag & AMED_SLOWTURN ? 8U : 4U)) |
1009 if (!(amd->flag & AMED_EXACTPOS) && dist <= (amd->flag & AMED_SLOWTURN ? 8U : 4U)) |
996 return true; |
1010 return true; |
997 |
1011 |
998 // At final pos? |
1012 /* At final pos? */ |
999 if (dist == 0) { |
1013 if (dist == 0) { |
1000 // Change direction smoothly to final direction. |
1014 /* Change direction smoothly to final direction. */ |
1001 DirDiff dirdiff = DirDifference(amd->direction, v->direction); |
1015 DirDiff dirdiff = DirDifference(amd->direction, v->direction); |
1002 // if distance is 0, and plane points in right direction, no point in calling |
1016 /* if distance is 0, and plane points in right direction, no point in calling |
1003 // UpdateAircraftSpeed(). So do it only afterwards |
1017 * UpdateAircraftSpeed(). So do it only afterwards */ |
1004 if (dirdiff == DIRDIFF_SAME) { |
1018 if (dirdiff == DIRDIFF_SAME) { |
1005 v->cur_speed = 0; |
1019 v->cur_speed = 0; |
1006 return true; |
1020 return true; |
1007 } |
1021 } |
1008 |
1022 |
1029 v->cur_speed >>= 1; |
1043 v->cur_speed >>= 1; |
1030 v->direction = newdir; |
1044 v->direction = newdir; |
1031 } |
1045 } |
1032 } |
1046 } |
1033 |
1047 |
1034 // Move vehicle. |
1048 /* Move vehicle. */ |
1035 GetNewVehiclePosResult gp; |
1049 GetNewVehiclePosResult gp; |
1036 GetNewVehiclePos(v, &gp); |
1050 GetNewVehiclePos(v, &gp); |
1037 v->tile = gp.new_tile; |
1051 v->tile = gp.new_tile; |
1038 |
1052 |
1039 // If vehicle is in the air, use tile coordinate 0. |
1053 /* If vehicle is in the air, use tile coordinate 0. */ |
1040 if (amd->flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) v->tile = 0; |
1054 if (amd->flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) v->tile = 0; |
1041 |
1055 |
1042 // Adjust Z for land or takeoff? |
1056 /* Adjust Z for land or takeoff? */ |
1043 uint z = v->z_pos; |
1057 uint z = v->z_pos; |
1044 |
1058 |
1045 if (amd->flag & AMED_TAKEOFF) { |
1059 if (amd->flag & AMED_TAKEOFF) { |
1046 z = min(z + 2, GetAircraftFlyingAltitude(v)); |
1060 z = min(z + 2, GetAircraftFlyingAltitude(v)); |
1047 } |
1061 } |
1048 |
1062 |
1049 if (amd->flag & AMED_LAND) { |
1063 if (amd->flag & AMED_LAND) { |
1050 if (st->airport_tile == 0) { |
1064 if (st->airport_tile == 0) { |
1051 v->u.air.state = FLYING; |
1065 v->u.air.state = FLYING; |
1052 AircraftNextAirportPos_and_Order(v); |
1066 AircraftNextAirportPos_and_Order(v); |
1053 // get aircraft back on running altitude |
1067 /* get aircraft back on running altitude */ |
1054 SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v)); |
1068 SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v)); |
1055 return false; |
1069 return false; |
1056 } |
1070 } |
1057 |
1071 |
1058 uint curz = GetSlopeZ(x, y) + 1; |
1072 uint curz = GetSlopeZ(x, y) + 1; |
1116 GB(r, 4, 4) + 4, |
1130 GB(r, 4, 4) + 4, |
1117 GB(r, 8, 4), |
1131 GB(r, 8, 4), |
1118 EV_EXPLOSION_SMALL); |
1132 EV_EXPLOSION_SMALL); |
1119 } |
1133 } |
1120 } else if (v->u.air.crashed_counter >= 10000) { |
1134 } else if (v->u.air.crashed_counter >= 10000) { |
1121 // remove rubble of crashed airplane |
1135 /* remove rubble of crashed airplane */ |
1122 |
1136 |
1123 // clear runway-in on all airports, set by crashing plane |
1137 /* clear runway-in on all airports, set by crashing plane |
1124 // small airports use AIRPORT_BUSY, city airports use RUNWAY_IN_OUT_block, etc. |
1138 * small airports use AIRPORT_BUSY, city airports use RUNWAY_IN_OUT_block, etc. |
1125 // but they all share the same number |
1139 * but they all share the same number */ |
1126 CLRBITS(st->airport_flags, RUNWAY_IN_block); |
1140 CLRBITS(st->airport_flags, RUNWAY_IN_block); |
1127 CLRBITS(st->airport_flags, RUNWAY_IN_OUT_block); // commuter airport |
1141 CLRBITS(st->airport_flags, RUNWAY_IN_OUT_block); // commuter airport |
1128 CLRBITS(st->airport_flags, RUNWAY_IN2_block); // intercontinental |
1142 CLRBITS(st->airport_flags, RUNWAY_IN2_block); // intercontinental |
1129 |
1143 |
1130 BeginVehicleMove(v); |
1144 BeginVehicleMove(v); |
1131 EndVehicleMove(v); |
1145 EndVehicleMove(v); |
1132 |
1146 |
1133 DoDeleteAircraft(v); |
1147 DoDeleteAircraft(v); |
1308 |
1322 |
1309 static void MaybeCrashAirplane(Vehicle *v) |
1323 static void MaybeCrashAirplane(Vehicle *v) |
1310 { |
1324 { |
1311 Station *st = GetStation(v->u.air.targetairport); |
1325 Station *st = GetStation(v->u.air.targetairport); |
1312 |
1326 |
1313 //FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports |
1327 /* FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports */ |
1314 uint16 prob = 0x10000 / 1500; |
1328 uint16 prob = 0x10000 / 1500; |
1315 if (st->Airport()->flags & AirportFTAClass::SHORT_STRIP && |
1329 if (st->Airport()->flags & AirportFTAClass::SHORT_STRIP && |
1316 AircraftVehInfo(v->engine_type)->subtype & AIR_FAST && |
1330 AircraftVehInfo(v->engine_type)->subtype & AIR_FAST && |
1317 !_cheats.no_jetcrash.value) { |
1331 !_cheats.no_jetcrash.value) { |
1318 prob = 0x10000 / 20; |
1332 prob = 0x10000 / 20; |
1319 } |
1333 } |
1320 |
1334 |
1321 if (GB(Random(), 0, 16) > prob) return; |
1335 if (GB(Random(), 0, 16) > prob) return; |
1322 |
1336 |
1323 // Crash the airplane. Remove all goods stored at the station. |
1337 /* Crash the airplane. Remove all goods stored at the station. */ |
1324 for (uint i = 0; i != NUM_CARGO; i++) { |
1338 for (uint i = 0; i != NUM_CARGO; i++) { |
1325 st->goods[i].rating = 1; |
1339 st->goods[i].rating = 1; |
1326 SB(st->goods[i].waiting_acceptance, 0, 12, 0); |
1340 SB(st->goods[i].waiting_acceptance, 0, 12, 0); |
1327 } |
1341 } |
1328 |
1342 |
1329 CrashAirplane(v); |
1343 CrashAirplane(v); |
1330 } |
1344 } |
1331 |
1345 |
1332 // we've landed and just arrived at a terminal |
1346 /** we've landed and just arrived at a terminal */ |
1333 static void AircraftEntersTerminal(Vehicle *v) |
1347 static void AircraftEntersTerminal(Vehicle *v) |
1334 { |
1348 { |
1335 if (v->current_order.type == OT_GOTO_DEPOT) return; |
1349 if (v->current_order.type == OT_GOTO_DEPOT) return; |
1336 |
1350 |
1337 Station *st = GetStation(v->u.air.targetairport); |
1351 Station *st = GetStation(v->u.air.targetairport); |
1470 { |
1484 { |
1471 VehicleEnterDepot(v); |
1485 VehicleEnterDepot(v); |
1472 v->u.air.state = apc->layout[v->u.air.pos].heading; |
1486 v->u.air.state = apc->layout[v->u.air.pos].heading; |
1473 } |
1487 } |
1474 |
1488 |
1475 // In an Airport Hangar |
1489 /** In an Airport Hangar */ |
1476 static void AircraftEventHandler_InHangar(Vehicle *v, const AirportFTAClass *apc) |
1490 static void AircraftEventHandler_InHangar(Vehicle *v, const AirportFTAClass *apc) |
1477 { |
1491 { |
1478 // if we just arrived, execute EnterHangar first |
1492 /* if we just arrived, execute EnterHangar first */ |
1479 if (v->u.air.previous_pos != v->u.air.pos) { |
1493 if (v->u.air.previous_pos != v->u.air.pos) { |
1480 AircraftEventHandler_EnterHangar(v, apc); |
1494 AircraftEventHandler_EnterHangar(v, apc); |
1481 return; |
1495 return; |
1482 } |
1496 } |
1483 |
1497 |
1484 // if we were sent to the depot, stay there |
1498 /* if we were sent to the depot, stay there */ |
1485 if (v->current_order.type == OT_GOTO_DEPOT && (v->vehstatus & VS_STOPPED)) { |
1499 if (v->current_order.type == OT_GOTO_DEPOT && (v->vehstatus & VS_STOPPED)) { |
1486 v->current_order.type = OT_NOTHING; |
1500 v->current_order.type = OT_NOTHING; |
1487 v->current_order.flags = 0; |
1501 v->current_order.flags = 0; |
1488 return; |
1502 return; |
1489 } |
1503 } |
1490 |
1504 |
1491 if (v->current_order.type != OT_GOTO_STATION && |
1505 if (v->current_order.type != OT_GOTO_STATION && |
1492 v->current_order.type != OT_GOTO_DEPOT) |
1506 v->current_order.type != OT_GOTO_DEPOT) |
1493 return; |
1507 return; |
1494 |
1508 |
1495 // if the block of the next position is busy, stay put |
1509 /* if the block of the next position is busy, stay put */ |
1496 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1510 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1497 |
1511 |
1498 // We are already at the target airport, we need to find a terminal |
1512 /* We are already at the target airport, we need to find a terminal */ |
1499 if (v->current_order.dest == v->u.air.targetairport) { |
1513 if (v->current_order.dest == v->u.air.targetairport) { |
1500 // FindFreeTerminal: |
1514 /* FindFreeTerminal: |
1501 // 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal |
1515 * 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */ |
1502 if (v->subtype == AIR_HELICOPTER) { |
1516 if (v->subtype == AIR_HELICOPTER) { |
1503 if (!AirportFindFreeHelipad(v, apc)) return; // helicopter |
1517 if (!AirportFindFreeHelipad(v, apc)) return; // helicopter |
1504 } else { |
1518 } else { |
1505 if (!AirportFindFreeTerminal(v, apc)) return; // airplane |
1519 if (!AirportFindFreeTerminal(v, apc)) return; // airplane |
1506 } |
1520 } |
1507 } else { // Else prepare for launch. |
1521 } else { // Else prepare for launch. |
1508 // airplane goto state takeoff, helicopter to helitakeoff |
1522 /* airplane goto state takeoff, helicopter to helitakeoff */ |
1509 v->u.air.state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; |
1523 v->u.air.state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; |
1510 } |
1524 } |
1511 AircraftLeaveHangar(v); |
1525 AircraftLeaveHangar(v); |
1512 AirportMove(v, apc); |
1526 AirportMove(v, apc); |
1513 } |
1527 } |
1514 |
1528 |
1515 // At one of the Airport's Terminals |
1529 /** At one of the Airport's Terminals */ |
1516 static void AircraftEventHandler_AtTerminal(Vehicle *v, const AirportFTAClass *apc) |
1530 static void AircraftEventHandler_AtTerminal(Vehicle *v, const AirportFTAClass *apc) |
1517 { |
1531 { |
1518 // if we just arrived, execute EnterTerminal first |
1532 /* if we just arrived, execute EnterTerminal first */ |
1519 if (v->u.air.previous_pos != v->u.air.pos) { |
1533 if (v->u.air.previous_pos != v->u.air.pos) { |
1520 AircraftEventHandler_EnterTerminal(v, apc); |
1534 AircraftEventHandler_EnterTerminal(v, apc); |
1521 // on an airport with helipads, a helicopter will always land there |
1535 /* on an airport with helipads, a helicopter will always land there |
1522 // and get serviced at the same time - patch setting |
1536 * and get serviced at the same time - patch setting */ |
1523 if (_patches.serviceathelipad) { |
1537 if (_patches.serviceathelipad) { |
1524 if (v->subtype == AIR_HELICOPTER && apc->helipads != NULL) { |
1538 if (v->subtype == AIR_HELICOPTER && apc->helipads != NULL) { |
1525 // an exerpt of ServiceAircraft, without the invisibility stuff |
1539 /* an exerpt of ServiceAircraft, without the invisibility stuff */ |
1526 v->date_of_last_service = _date; |
1540 v->date_of_last_service = _date; |
1527 v->breakdowns_since_last_service = 0; |
1541 v->breakdowns_since_last_service = 0; |
1528 v->reliability = GetEngine(v->engine_type)->reliability; |
1542 v->reliability = GetEngine(v->engine_type)->reliability; |
1529 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
1543 InvalidateWindow(WC_VEHICLE_DETAILS, v->index); |
1530 } |
1544 } |
1532 return; |
1546 return; |
1533 } |
1547 } |
1534 |
1548 |
1535 if (v->current_order.type == OT_NOTHING) return; |
1549 if (v->current_order.type == OT_NOTHING) return; |
1536 |
1550 |
1537 // if the block of the next position is busy, stay put |
1551 /* if the block of the next position is busy, stay put */ |
1538 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1552 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1539 |
1553 |
1540 // airport-road is free. We either have to go to another airport, or to the hangar |
1554 /* airport-road is free. We either have to go to another airport, or to the hangar |
1541 // ---> start moving |
1555 * ---> start moving */ |
1542 |
1556 |
1543 switch (v->current_order.type) { |
1557 switch (v->current_order.type) { |
1544 case OT_GOTO_STATION: // ready to fly to another airport |
1558 case OT_GOTO_STATION: // ready to fly to another airport |
1545 // airplane goto state takeoff, helicopter to helitakeoff |
1559 /* airplane goto state takeoff, helicopter to helitakeoff */ |
1546 v->u.air.state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; |
1560 v->u.air.state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; |
1547 break; |
1561 break; |
1548 case OT_GOTO_DEPOT: // visit hangar for serivicing, sale, etc. |
1562 case OT_GOTO_DEPOT: // visit hangar for serivicing, sale, etc. |
1549 if (v->current_order.dest == v->u.air.targetairport) { |
1563 if (v->current_order.dest == v->u.air.targetairport) { |
1550 v->u.air.state = HANGAR; |
1564 v->u.air.state = HANGAR; |
1578 } |
1592 } |
1579 |
1593 |
1580 static void AircraftEventHandler_EndTakeOff(Vehicle *v, const AirportFTAClass *apc) |
1594 static void AircraftEventHandler_EndTakeOff(Vehicle *v, const AirportFTAClass *apc) |
1581 { |
1595 { |
1582 v->u.air.state = FLYING; |
1596 v->u.air.state = FLYING; |
1583 // get the next position to go to, differs per airport |
1597 /* get the next position to go to, differs per airport */ |
1584 AircraftNextAirportPos_and_Order(v); |
1598 AircraftNextAirportPos_and_Order(v); |
1585 } |
1599 } |
1586 |
1600 |
1587 static void AircraftEventHandler_HeliTakeOff(Vehicle *v, const AirportFTAClass *apc) |
1601 static void AircraftEventHandler_HeliTakeOff(Vehicle *v, const AirportFTAClass *apc) |
1588 { |
1602 { |
1589 const Player* p = GetPlayer(v->owner); |
1603 const Player* p = GetPlayer(v->owner); |
1590 v->sprite_width = v->sprite_height = 24; // ??? no idea what this is |
1604 v->sprite_width = v->sprite_height = 24; // ??? no idea what this is |
1591 v->u.air.state = FLYING; |
1605 v->u.air.state = FLYING; |
1592 // get the next position to go to, differs per airport |
1606 /* get the next position to go to, differs per airport */ |
1593 AircraftNextAirportPos_and_Order(v); |
1607 AircraftNextAirportPos_and_Order(v); |
1594 |
1608 |
1595 // check if the aircraft needs to be replaced or renewed and send it to a hangar if needed |
1609 /* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed |
1596 // unless it is due for renewal but the engine is no longer available |
1610 * unless it is due for renewal but the engine is no longer available */ |
1597 if (v->owner == _local_player && ( |
1611 if (v->owner == _local_player && ( |
1598 EngineHasReplacementForPlayer(p, v->engine_type) || |
1612 EngineHasReplacementForPlayer(p, v->engine_type) || |
1599 ((p->engine_renew && v->age - v->max_age > p->engine_renew_months * 30) && |
1613 ((p->engine_renew && v->age - v->max_age > p->engine_renew_months * 30) && |
1600 HASBIT(GetEngine(v->engine_type)->player_avail, _local_player)) |
1614 HASBIT(GetEngine(v->engine_type)->player_avail, _local_player)) |
1601 )) { |
1615 )) { |
1607 |
1621 |
1608 static void AircraftEventHandler_Flying(Vehicle *v, const AirportFTAClass *apc) |
1622 static void AircraftEventHandler_Flying(Vehicle *v, const AirportFTAClass *apc) |
1609 { |
1623 { |
1610 Station *st = GetStation(v->u.air.targetairport); |
1624 Station *st = GetStation(v->u.air.targetairport); |
1611 |
1625 |
1612 // runway busy or not allowed to use this airstation, circle |
1626 /* runway busy or not allowed to use this airstation, circle */ |
1613 if (apc->flags & (v->subtype == AIR_HELICOPTER ? AirportFTAClass::HELICOPTERS : AirportFTAClass::AIRPLANES) && |
1627 if (apc->flags & (v->subtype == AIR_HELICOPTER ? AirportFTAClass::HELICOPTERS : AirportFTAClass::AIRPLANES) && |
1614 st->airport_tile != 0 && |
1628 st->airport_tile != 0 && |
1615 (st->owner == OWNER_NONE || st->owner == v->owner)) { |
1629 (st->owner == OWNER_NONE || st->owner == v->owner)) { |
1616 // {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41}, |
1630 // {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41}, |
1617 // if it is an airplane, look for LANDING, for helicopter HELILANDING |
1631 // if it is an airplane, look for LANDING, for helicopter HELILANDING |
1618 // it is possible to choose from multiple landing runways, so loop until a free one is found |
1632 // it is possible to choose from multiple landing runways, so loop until a free one is found |
1619 byte landingtype = (v->subtype == AIR_HELICOPTER) ? HELILANDING : LANDING; |
1633 byte landingtype = (v->subtype == AIR_HELICOPTER) ? HELILANDING : LANDING; |
1620 const AirportFTA *current = apc->layout[v->u.air.pos].next; |
1634 const AirportFTA *current = apc->layout[v->u.air.pos].next; |
1621 while (current != NULL) { |
1635 while (current != NULL) { |
1622 if (current->heading == landingtype) { |
1636 if (current->heading == landingtype) { |
1623 // save speed before, since if AirportHasBlock is false, it resets them to 0 |
1637 /* save speed before, since if AirportHasBlock is false, it resets them to 0 |
1624 // we don't want that for plane in air |
1638 * we don't want that for plane in air |
1625 // hack for speed thingie |
1639 * hack for speed thingie */ |
1626 uint16 tcur_speed = v->cur_speed; |
1640 uint16 tcur_speed = v->cur_speed; |
1627 uint16 tsubspeed = v->subspeed; |
1641 uint16 tsubspeed = v->subspeed; |
1628 if (!AirportHasBlock(v, current, apc)) { |
1642 if (!AirportHasBlock(v, current, apc)) { |
1629 v->u.air.state = landingtype; // LANDING / HELILANDING |
1643 v->u.air.state = landingtype; // LANDING / HELILANDING |
1630 // it's a bit dirty, but I need to set position to next position, otherwise |
1644 /* it's a bit dirty, but I need to set position to next position, otherwise |
1631 // if there are multiple runways, plane won't know which one it took (because |
1645 * if there are multiple runways, plane won't know which one it took (because |
1632 // they all have heading LANDING). And also occupy that block! |
1646 * they all have heading LANDING). And also occupy that block! */ |
1633 v->u.air.pos = current->next_position; |
1647 v->u.air.pos = current->next_position; |
1634 SETBITS(st->airport_flags, apc->layout[v->u.air.pos].block); |
1648 SETBITS(st->airport_flags, apc->layout[v->u.air.pos].block); |
1635 return; |
1649 return; |
1636 } |
1650 } |
1637 v->cur_speed = tcur_speed; |
1651 v->cur_speed = tcur_speed; |
1646 |
1660 |
1647 static void AircraftEventHandler_Landing(Vehicle *v, const AirportFTAClass *apc) |
1661 static void AircraftEventHandler_Landing(Vehicle *v, const AirportFTAClass *apc) |
1648 { |
1662 { |
1649 AircraftLandAirplane(v); // maybe crash airplane |
1663 AircraftLandAirplane(v); // maybe crash airplane |
1650 v->u.air.state = ENDLANDING; |
1664 v->u.air.state = ENDLANDING; |
1651 // check if the aircraft needs to be replaced or renewed and send it to a hangar if needed |
1665 /* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed */ |
1652 if (v->current_order.type != OT_GOTO_DEPOT && v->owner == _local_player) { |
1666 if (v->current_order.type != OT_GOTO_DEPOT && v->owner == _local_player) { |
1653 // only the vehicle owner needs to calculate the rest (locally) |
1667 /* only the vehicle owner needs to calculate the rest (locally) */ |
1654 const Player* p = GetPlayer(v->owner); |
1668 const Player* p = GetPlayer(v->owner); |
1655 if (EngineHasReplacementForPlayer(p, v->engine_type) || |
1669 if (EngineHasReplacementForPlayer(p, v->engine_type) || |
1656 (p->engine_renew && v->age - v->max_age > (p->engine_renew_months * 30))) { |
1670 (p->engine_renew && v->age - v->max_age > (p->engine_renew_months * 30))) { |
1657 // send the aircraft to the hangar at next airport |
1671 /* send the aircraft to the hangar at next airport */ |
1658 _current_player = _local_player; |
1672 _current_player = _local_player; |
1659 DoCommandP(v->tile, v->index, DEPOT_SERVICE, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_SHOW_NO_ERROR); |
1673 DoCommandP(v->tile, v->index, DEPOT_SERVICE, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_SHOW_NO_ERROR); |
1660 _current_player = OWNER_NONE; |
1674 _current_player = OWNER_NONE; |
1661 } |
1675 } |
1662 } |
1676 } |
1668 v->u.air.state = HELIENDLANDING; |
1682 v->u.air.state = HELIENDLANDING; |
1669 } |
1683 } |
1670 |
1684 |
1671 static void AircraftEventHandler_EndLanding(Vehicle *v, const AirportFTAClass *apc) |
1685 static void AircraftEventHandler_EndLanding(Vehicle *v, const AirportFTAClass *apc) |
1672 { |
1686 { |
1673 // next block busy, don't do a thing, just wait |
1687 /* next block busy, don't do a thing, just wait */ |
1674 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1688 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1675 |
1689 |
1676 // if going to terminal (OT_GOTO_STATION) choose one |
1690 /* if going to terminal (OT_GOTO_STATION) choose one |
1677 // 1. in case all terminals are busy AirportFindFreeTerminal() returns false or |
1691 * 1. in case all terminals are busy AirportFindFreeTerminal() returns false or |
1678 // 2. not going for terminal (but depot, no order), |
1692 * 2. not going for terminal (but depot, no order), |
1679 // --> get out of the way to the hangar. |
1693 * --> get out of the way to the hangar. */ |
1680 if (v->current_order.type == OT_GOTO_STATION) { |
1694 if (v->current_order.type == OT_GOTO_STATION) { |
1681 if (AirportFindFreeTerminal(v, apc)) return; |
1695 if (AirportFindFreeTerminal(v, apc)) return; |
1682 } |
1696 } |
1683 v->u.air.state = HANGAR; |
1697 v->u.air.state = HANGAR; |
1684 |
1698 |
1685 } |
1699 } |
1686 |
1700 |
1687 static void AircraftEventHandler_HeliEndLanding(Vehicle *v, const AirportFTAClass *apc) |
1701 static void AircraftEventHandler_HeliEndLanding(Vehicle *v, const AirportFTAClass *apc) |
1688 { |
1702 { |
1689 // next block busy, don't do a thing, just wait |
1703 /* next block busy, don't do a thing, just wait */ |
1690 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1704 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1691 |
1705 |
1692 // if going to helipad (OT_GOTO_STATION) choose one. If airport doesn't have helipads, choose terminal |
1706 /* if going to helipad (OT_GOTO_STATION) choose one. If airport doesn't have helipads, choose terminal |
1693 // 1. in case all terminals/helipads are busy (AirportFindFreeHelipad() returns false) or |
1707 * 1. in case all terminals/helipads are busy (AirportFindFreeHelipad() returns false) or |
1694 // 2. not going for terminal (but depot, no order), |
1708 * 2. not going for terminal (but depot, no order), |
1695 // --> get out of the way to the hangar IF there are terminals on the airport. |
1709 * --> get out of the way to the hangar IF there are terminals on the airport. |
1696 // --> else TAKEOFF |
1710 * --> else TAKEOFF |
1697 // the reason behind this is that if an airport has a terminal, it also has a hangar. Airplanes |
1711 * the reason behind this is that if an airport has a terminal, it also has a hangar. Airplanes |
1698 // must go to a hangar. |
1712 * must go to a hangar. */ |
1699 if (v->current_order.type == OT_GOTO_STATION) { |
1713 if (v->current_order.type == OT_GOTO_STATION) { |
1700 if (AirportFindFreeHelipad(v, apc)) return; |
1714 if (AirportFindFreeHelipad(v, apc)) return; |
1701 } |
1715 } |
1702 v->u.air.state = (apc->nof_depots != 0) ? HANGAR : HELITAKEOFF; |
1716 v->u.air.state = (apc->nof_depots != 0) ? HANGAR : HELITAKEOFF; |
1703 } |
1717 } |
1729 AircraftEventHandler_AtTerminal, // HELIPAD4 = 22 |
1743 AircraftEventHandler_AtTerminal, // HELIPAD4 = 22 |
1730 }; |
1744 }; |
1731 |
1745 |
1732 static void AirportClearBlock(const Vehicle *v, const AirportFTAClass *apc) |
1746 static void AirportClearBlock(const Vehicle *v, const AirportFTAClass *apc) |
1733 { |
1747 { |
1734 // we have left the previous block, and entered the new one. Free the previous block |
1748 /* we have left the previous block, and entered the new one. Free the previous block */ |
1735 if (apc->layout[v->u.air.previous_pos].block != apc->layout[v->u.air.pos].block) { |
1749 if (apc->layout[v->u.air.previous_pos].block != apc->layout[v->u.air.pos].block) { |
1736 Station *st = GetStation(v->u.air.targetairport); |
1750 Station *st = GetStation(v->u.air.targetairport); |
1737 |
1751 |
1738 CLRBITS(st->airport_flags, apc->layout[v->u.air.previous_pos].block); |
1752 CLRBITS(st->airport_flags, apc->layout[v->u.air.previous_pos].block); |
1739 } |
1753 } |
1740 } |
1754 } |
1741 |
1755 |
1742 static void AirportGoToNextPosition(Vehicle *v) |
1756 static void AirportGoToNextPosition(Vehicle *v) |
1743 { |
1757 { |
1744 // if aircraft is not in position, wait until it is |
1758 /* if aircraft is not in position, wait until it is */ |
1745 if (!AircraftController(v)) return; |
1759 if (!AircraftController(v)) return; |
1746 |
1760 |
1747 const AirportFTAClass *apc = GetStation(v->u.air.targetairport)->Airport(); |
1761 const AirportFTAClass *apc = GetStation(v->u.air.targetairport)->Airport(); |
1748 |
1762 |
1749 AirportClearBlock(v, apc); |
1763 AirportClearBlock(v, apc); |
1750 AirportMove(v, apc); // move aircraft to next position |
1764 AirportMove(v, apc); // move aircraft to next position |
1751 } |
1765 } |
1752 |
1766 |
1753 // gets pos from vehicle and next orders |
1767 /* gets pos from vehicle and next orders */ |
1754 static bool AirportMove(Vehicle *v, const AirportFTAClass *apc) |
1768 static bool AirportMove(Vehicle *v, const AirportFTAClass *apc) |
1755 { |
1769 { |
1756 // error handling |
1770 /* error handling */ |
1757 if (v->u.air.pos >= apc->nofelements) { |
1771 if (v->u.air.pos >= apc->nofelements) { |
1758 DEBUG(misc, 0, "[Ap] position %d is not valid for current airport. Max position is %d", v->u.air.pos, apc->nofelements-1); |
1772 DEBUG(misc, 0, "[Ap] position %d is not valid for current airport. Max position is %d", v->u.air.pos, apc->nofelements-1); |
1759 assert(v->u.air.pos < apc->nofelements); |
1773 assert(v->u.air.pos < apc->nofelements); |
1760 } |
1774 } |
1761 |
1775 |
1762 const AirportFTA *current = &apc->layout[v->u.air.pos]; |
1776 const AirportFTA *current = &apc->layout[v->u.air.pos]; |
1763 // we have arrived in an important state (eg terminal, hangar, etc.) |
1777 /* we have arrived in an important state (eg terminal, hangar, etc.) */ |
1764 if (current->heading == v->u.air.state) { |
1778 if (current->heading == v->u.air.state) { |
1765 byte prev_pos = v->u.air.pos; // location could be changed in state, so save it before-hand |
1779 byte prev_pos = v->u.air.pos; // location could be changed in state, so save it before-hand |
1766 _aircraft_state_handlers[v->u.air.state](v, apc); |
1780 _aircraft_state_handlers[v->u.air.state](v, apc); |
1767 if (v->u.air.state != FLYING) v->u.air.previous_pos = prev_pos; |
1781 if (v->u.air.state != FLYING) v->u.air.previous_pos = prev_pos; |
1768 return true; |
1782 return true; |
1769 } |
1783 } |
1770 |
1784 |
1771 v->u.air.previous_pos = v->u.air.pos; // save previous location |
1785 v->u.air.previous_pos = v->u.air.pos; // save previous location |
1772 |
1786 |
1773 // there is only one choice to move to |
1787 /* there is only one choice to move to */ |
1774 if (current->next == NULL) { |
1788 if (current->next == NULL) { |
1775 if (AirportSetBlocks(v, current, apc)) { |
1789 if (AirportSetBlocks(v, current, apc)) { |
1776 v->u.air.pos = current->next_position; |
1790 v->u.air.pos = current->next_position; |
1777 } // move to next position |
1791 } // move to next position |
1778 return false; |
1792 return false; |
1779 } |
1793 } |
1780 |
1794 |
1781 // there are more choices to choose from, choose the one that |
1795 /* there are more choices to choose from, choose the one that |
1782 // matches our heading |
1796 * matches our heading */ |
1783 do { |
1797 do { |
1784 if (v->u.air.state == current->heading || current->heading == TO_ALL) { |
1798 if (v->u.air.state == current->heading || current->heading == TO_ALL) { |
1785 if (AirportSetBlocks(v, current, apc)) { |
1799 if (AirportSetBlocks(v, current, apc)) { |
1786 v->u.air.pos = current->next_position; |
1800 v->u.air.pos = current->next_position; |
1787 } // move to next position |
1801 } // move to next position |
1793 DEBUG(misc, 0, "[Ap] cannot move further on Airport! (pos %d state %d) for vehicle %d", v->u.air.pos, v->u.air.state, v->index); |
1807 DEBUG(misc, 0, "[Ap] cannot move further on Airport! (pos %d state %d) for vehicle %d", v->u.air.pos, v->u.air.state, v->index); |
1794 assert(0); |
1808 assert(0); |
1795 return false; |
1809 return false; |
1796 } |
1810 } |
1797 |
1811 |
1798 // returns true if the road ahead is busy, eg. you must wait before proceeding |
1812 /* returns true if the road ahead is busy, eg. you must wait before proceeding */ |
1799 static bool AirportHasBlock(Vehicle *v, const AirportFTA *current_pos, const AirportFTAClass *apc) |
1813 static bool AirportHasBlock(Vehicle *v, const AirportFTA *current_pos, const AirportFTAClass *apc) |
1800 { |
1814 { |
1801 const AirportFTA *reference = &apc->layout[v->u.air.pos]; |
1815 const AirportFTA *reference = &apc->layout[v->u.air.pos]; |
1802 const AirportFTA *next = &apc->layout[current_pos->next_position]; |
1816 const AirportFTA *next = &apc->layout[current_pos->next_position]; |
1803 |
1817 |
1804 // same block, then of course we can move |
1818 /* same block, then of course we can move */ |
1805 if (apc->layout[current_pos->position].block != next->block) { |
1819 if (apc->layout[current_pos->position].block != next->block) { |
1806 const Station *st = GetStation(v->u.air.targetairport); |
1820 const Station *st = GetStation(v->u.air.targetairport); |
1807 uint64 airport_flags = next->block; |
1821 uint64 airport_flags = next->block; |
1808 |
1822 |
1809 // check additional possible extra blocks |
1823 /* check additional possible extra blocks */ |
1810 if (current_pos != reference && current_pos->block != NOTHING_block) { |
1824 if (current_pos != reference && current_pos->block != NOTHING_block) { |
1811 airport_flags |= current_pos->block; |
1825 airport_flags |= current_pos->block; |
1812 } |
1826 } |
1813 |
1827 |
1814 if (HASBITS(st->airport_flags, airport_flags)) { |
1828 if (HASBITS(st->airport_flags, airport_flags)) { |
1818 } |
1832 } |
1819 } |
1833 } |
1820 return false; |
1834 return false; |
1821 } |
1835 } |
1822 |
1836 |
1823 // returns true on success. Eg, next block was free and we have occupied it |
1837 /** |
|
1838 * ... |
|
1839 * @param v airplane that requires the operation |
|
1840 * @param currentpos of the vehicle in the list of blocks |
|
1841 * @param apc airport on which block is requsted to be set |
|
1842 * @returns true on success. Eg, next block was free and we have occupied it |
|
1843 */ |
1824 static bool AirportSetBlocks(Vehicle *v, const AirportFTA *current_pos, const AirportFTAClass *apc) |
1844 static bool AirportSetBlocks(Vehicle *v, const AirportFTA *current_pos, const AirportFTAClass *apc) |
1825 { |
1845 { |
1826 const AirportFTA *next = &apc->layout[current_pos->next_position]; |
1846 const AirportFTA *next = &apc->layout[current_pos->next_position]; |
1827 const AirportFTA *reference = &apc->layout[v->u.air.pos]; |
1847 const AirportFTA *reference = &apc->layout[v->u.air.pos]; |
1828 |
1848 |
1829 // if the next position is in another block, check it and wait until it is free |
1849 /* if the next position is in another block, check it and wait until it is free */ |
1830 if ((apc->layout[current_pos->position].block & next->block) != next->block) { |
1850 if ((apc->layout[current_pos->position].block & next->block) != next->block) { |
1831 uint64 airport_flags = next->block; |
1851 uint64 airport_flags = next->block; |
1832 //search for all all elements in the list with the same state, and blocks != N |
1852 /* search for all all elements in the list with the same state, and blocks != N |
1833 // this means more blocks should be checked/set |
1853 * this means more blocks should be checked/set */ |
1834 const AirportFTA *current = current_pos; |
1854 const AirportFTA *current = current_pos; |
1835 if (current == reference) current = current->next; |
1855 if (current == reference) current = current->next; |
1836 while (current != NULL) { |
1856 while (current != NULL) { |
1837 if (current->heading == current_pos->heading && current->block != 0) { |
1857 if (current->heading == current_pos->heading && current->block != 0) { |
1838 airport_flags |= current->block; |
1858 airport_flags |= current->block; |
1839 break; |
1859 break; |
1840 } |
1860 } |
1841 current = current->next; |
1861 current = current->next; |
1842 }; |
1862 }; |
1843 |
1863 |
1844 // if the block to be checked is in the next position, then exclude that from |
1864 /* if the block to be checked is in the next position, then exclude that from |
1845 // checking, because it has been set by the airplane before |
1865 * checking, because it has been set by the airplane before */ |
1846 if (current_pos->block == next->block) airport_flags ^= next->block; |
1866 if (current_pos->block == next->block) airport_flags ^= next->block; |
1847 |
1867 |
1848 Station* st = GetStation(v->u.air.targetairport); |
1868 Station* st = GetStation(v->u.air.targetairport); |
1849 if (HASBITS(st->airport_flags, airport_flags)) { |
1869 if (HASBITS(st->airport_flags, airport_flags)) { |
1850 v->cur_speed = 0; |
1870 v->cur_speed = 0; |
1899 const AirportFTA *temp = apc->layout[v->u.air.pos].next; |
1919 const AirportFTA *temp = apc->layout[v->u.air.pos].next; |
1900 |
1920 |
1901 while (temp != NULL) { |
1921 while (temp != NULL) { |
1902 if (temp->heading == 255) { |
1922 if (temp->heading == 255) { |
1903 if (!HASBITS(st->airport_flags, temp->block)) { |
1923 if (!HASBITS(st->airport_flags, temp->block)) { |
1904 //read which group do we want to go to? |
1924 /* read which group do we want to go to? |
1905 //(the first free group) |
1925 * (the first free group) */ |
1906 uint target_group = temp->next_position + 1; |
1926 uint target_group = temp->next_position + 1; |
1907 |
1927 |
1908 //at what terminal does the group start? |
1928 /* at what terminal does the group start? |
1909 //that means, sum up all terminals of |
1929 * that means, sum up all terminals of |
1910 //groups with lower number |
1930 * groups with lower number */ |
1911 uint group_start = 0; |
1931 uint group_start = 0; |
1912 for (uint i = 1; i < target_group; i++) { |
1932 for (uint i = 1; i < target_group; i++) { |
1913 group_start += apc->terminals[i]; |
1933 group_start += apc->terminals[i]; |
1914 } |
1934 } |
1915 |
1935 |
1939 } |
1959 } |
1940 |
1960 |
1941 |
1961 |
1942 static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *apc) |
1962 static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *apc) |
1943 { |
1963 { |
1944 // if an airport doesn't have helipads, use terminals |
1964 /* if an airport doesn't have helipads, use terminals */ |
1945 if (apc->helipads == NULL) return AirportFindFreeTerminal(v, apc); |
1965 if (apc->helipads == NULL) return AirportFindFreeTerminal(v, apc); |
1946 |
1966 |
1947 // if there are more helicoptergroups, pick one, just as in AirportFindFreeTerminal() |
1967 /* if there are more helicoptergroups, pick one, just as in AirportFindFreeTerminal() */ |
1948 if (apc->helipads[0] > 1) { |
1968 if (apc->helipads[0] > 1) { |
1949 const Station* st = GetStation(v->u.air.targetairport); |
1969 const Station* st = GetStation(v->u.air.targetairport); |
1950 const AirportFTA* temp = apc->layout[v->u.air.pos].next; |
1970 const AirportFTA* temp = apc->layout[v->u.air.pos].next; |
1951 |
1971 |
1952 while (temp != NULL) { |
1972 while (temp != NULL) { |
1953 if (temp->heading == 255) { |
1973 if (temp->heading == 255) { |
1954 if (!HASBITS(st->airport_flags, temp->block)) { |
1974 if (!HASBITS(st->airport_flags, temp->block)) { |
1955 |
1975 |
1956 //read which group do we want to go to? |
1976 /* read which group do we want to go to? |
1957 //(the first free group) |
1977 * (the first free group) */ |
1958 uint target_group = temp->next_position + 1; |
1978 uint target_group = temp->next_position + 1; |
1959 |
1979 |
1960 //at what terminal does the group start? |
1980 /* at what terminal does the group start? |
1961 //that means, sum up all terminals of |
1981 * that means, sum up all terminals of |
1962 //groups with lower number |
1982 * groups with lower number */ |
1963 uint group_start = 0; |
1983 uint group_start = 0; |
1964 for (uint i = 1; i < target_group; i++) { |
1984 for (uint i = 1; i < target_group; i++) { |
1965 group_start += apc->helipads[i]; |
1985 group_start += apc->helipads[i]; |
1966 } |
1986 } |
1967 |
1987 |
2026 break; |
2046 break; |
2027 } |
2047 } |
2028 } |
2048 } |
2029 |
2049 |
2030 |
2050 |
2031 // need to be called to load aircraft from old version |
2051 /** need to be called to load aircraft from old version */ |
2032 void UpdateOldAircraft(void) |
2052 void UpdateOldAircraft(void) |
2033 { |
2053 { |
2034 // set airport_flags to 0 for all airports just to be sure |
2054 /* set airport_flags to 0 for all airports just to be sure */ |
2035 Station *st; |
2055 Station *st; |
2036 FOR_ALL_STATIONS(st) { |
2056 FOR_ALL_STATIONS(st) { |
2037 st->airport_flags = 0; // reset airport |
2057 st->airport_flags = 0; // reset airport |
2038 } |
2058 } |
2039 |
2059 |
2040 Vehicle *v_oldstyle; |
2060 Vehicle *v_oldstyle; |
2041 FOR_ALL_VEHICLES(v_oldstyle) { |
2061 FOR_ALL_VEHICLES(v_oldstyle) { |
2042 // airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor) |
2062 /* airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor) |
2043 // skip those |
2063 * skip those */ |
2044 if (v_oldstyle->type == VEH_Aircraft && IsNormalAircraft(v_oldstyle)) { |
2064 if (v_oldstyle->type == VEH_Aircraft && IsNormalAircraft(v_oldstyle)) { |
2045 // airplane in terminal stopped doesn't hurt anyone, so goto next |
2065 /* airplane in terminal stopped doesn't hurt anyone, so goto next */ |
2046 if (v_oldstyle->vehstatus & VS_STOPPED && v_oldstyle->u.air.state == 0) { |
2066 if (v_oldstyle->vehstatus & VS_STOPPED && v_oldstyle->u.air.state == 0) { |
2047 v_oldstyle->u.air.state = HANGAR; |
2067 v_oldstyle->u.air.state = HANGAR; |
2048 continue; |
2068 continue; |
2049 } |
2069 } |
2050 |
2070 |
2054 AircraftNextAirportPos_and_Order(v_oldstyle); // move it to the entry point of the airport |
2074 AircraftNextAirportPos_and_Order(v_oldstyle); // move it to the entry point of the airport |
2055 GetNewVehiclePosResult gp; |
2075 GetNewVehiclePosResult gp; |
2056 GetNewVehiclePos(v_oldstyle, &gp); // get the position of the plane (to be used for setting) |
2076 GetNewVehiclePos(v_oldstyle, &gp); // get the position of the plane (to be used for setting) |
2057 v_oldstyle->tile = 0; // aircraft in air is tile=0 |
2077 v_oldstyle->tile = 0; // aircraft in air is tile=0 |
2058 |
2078 |
2059 // correct speed of helicopter-rotors |
2079 /* correct speed of helicopter-rotors */ |
2060 if (v_oldstyle->subtype == AIR_HELICOPTER) v_oldstyle->next->next->cur_speed = 32; |
2080 if (v_oldstyle->subtype == AIR_HELICOPTER) v_oldstyle->next->next->cur_speed = 32; |
2061 |
2081 |
2062 // set new position x,y,z |
2082 /* set new position x,y,z */ |
2063 SetAircraftPosition(v_oldstyle, gp.x, gp.y, GetAircraftFlyingAltitude(v_oldstyle)); |
2083 SetAircraftPosition(v_oldstyle, gp.x, gp.y, GetAircraftFlyingAltitude(v_oldstyle)); |
2064 } |
2084 } |
2065 } |
2085 } |
2066 } |
2086 } |
2067 |
2087 |
2068 void UpdateAirplanesOnNewStation(const Station *st) |
2088 void UpdateAirplanesOnNewStation(const Station *st) |
2069 { |
2089 { |
2070 // only 1 station is updated per function call, so it is enough to get entry_point once |
2090 /* only 1 station is updated per function call, so it is enough to get entry_point once */ |
2071 const AirportFTAClass *ap = st->Airport(); |
2091 const AirportFTAClass *ap = st->Airport(); |
2072 |
2092 |
2073 Vehicle *v; |
2093 Vehicle *v; |
2074 FOR_ALL_VEHICLES(v) { |
2094 FOR_ALL_VEHICLES(v) { |
2075 if (v->type == VEH_Aircraft && IsNormalAircraft(v)) { |
2095 if (v->type == VEH_Aircraft && IsNormalAircraft(v)) { |
2076 if (v->u.air.targetairport == st->index) { // if heading to this airport |
2096 if (v->u.air.targetairport == st->index) { // if heading to this airport |
2077 /* update position of airplane. If plane is not flying, landing, or taking off |
2097 /* update position of airplane. If plane is not flying, landing, or taking off |
2078 *you cannot delete airport, so it doesn't matter |
2098 *you cannot delete airport, so it doesn't matter */ |
2079 */ |
|
2080 if (v->u.air.state >= FLYING) { // circle around |
2099 if (v->u.air.state >= FLYING) { // circle around |
2081 v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, ap); |
2100 v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, ap); |
2082 v->u.air.state = FLYING; |
2101 v->u.air.state = FLYING; |
2083 // landing plane needs to be reset to flying height (only if in pause mode upgrade, |
2102 /* landing plane needs to be reset to flying height (only if in pause mode upgrade, |
2084 // in normal mode, plane is reset in AircraftController. It doesn't hurt for FLYING |
2103 * in normal mode, plane is reset in AircraftController. It doesn't hurt for FLYING */ |
2085 GetNewVehiclePosResult gp; |
2104 GetNewVehiclePosResult gp; |
2086 GetNewVehiclePos(v, &gp); |
2105 GetNewVehiclePos(v, &gp); |
2087 // set new position x,y,z |
2106 /* set new position x,y,z */ |
2088 SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v)); |
2107 SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlyingAltitude(v)); |
2089 } else { |
2108 } else { |
2090 assert(v->u.air.state == ENDTAKEOFF || v->u.air.state == HELITAKEOFF); |
2109 assert(v->u.air.state == ENDTAKEOFF || v->u.air.state == HELITAKEOFF); |
2091 byte takeofftype = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : ENDTAKEOFF; |
2110 byte takeofftype = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : ENDTAKEOFF; |
2092 // search in airportdata for that heading |
2111 /* search in airportdata for that heading |
2093 // easiest to do, since this doesn't happen a lot |
2112 * easiest to do, since this doesn't happen a lot */ |
2094 for (uint cnt = 0; cnt < ap->nofelements; cnt++) { |
2113 for (uint cnt = 0; cnt < ap->nofelements; cnt++) { |
2095 if (ap->layout[cnt].heading == takeofftype) { |
2114 if (ap->layout[cnt].heading == takeofftype) { |
2096 v->u.air.pos = ap->layout[cnt].position; |
2115 v->u.air.pos = ap->layout[cnt].position; |
2097 break; |
2116 break; |
2098 } |
2117 } |