72 uint best = 0; |
72 uint best = 0; |
73 StationID index = INVALID_STATION; |
73 StationID index = INVALID_STATION; |
74 TileIndex vtile = TileVirtXY(v->x_pos, v->y_pos); |
74 TileIndex vtile = TileVirtXY(v->x_pos, v->y_pos); |
75 |
75 |
76 FOR_ALL_STATIONS(st) { |
76 FOR_ALL_STATIONS(st) { |
77 if (st->owner == v->owner && st->facilities & FACIL_AIRPORT && |
77 if (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT)) continue; |
78 GetAirport(st->airport_type)->nof_depots > 0) { |
78 |
79 uint distance; |
79 const AirportFTAClass *afc = st->Airport(); |
80 |
80 if (afc->nof_depots == 0 || ( |
81 // don't crash the plane if we know it can't land at the airport |
81 /* don't crash the plane if we know it can't land at the airport */ |
82 if ((AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) && |
82 afc->flags & AirportFTAClass::SHORT_STRIP && |
83 (st->airport_type == AT_SMALL || st->airport_type == AT_COMMUTER) && |
83 AircraftVehInfo(v->engine_type)->subtype & AIR_FAST && |
84 !_cheats.no_jetcrash.value) |
84 !_cheats.no_jetcrash.value |
85 continue; |
85 )) { |
86 |
86 continue; |
87 // v->tile can't be used here, when aircraft is flying v->tile is set to 0 |
87 } |
88 distance = DistanceSquare(vtile, st->airport_tile); |
88 |
89 if (distance < best || index == INVALID_STATION) { |
89 // v->tile can't be used here, when aircraft is flying v->tile is set to 0 |
90 best = distance; |
90 uint distance = DistanceSquare(vtile, st->airport_tile); |
91 index = st->index; |
91 if (distance < best || index == INVALID_STATION) { |
92 } |
92 best = distance; |
|
93 index = st->index; |
93 } |
94 } |
94 } |
95 } |
95 return index; |
96 return index; |
96 } |
97 } |
97 |
98 |
103 |
104 |
104 FOR_VEHICLE_ORDERS(v, order) { |
105 FOR_VEHICLE_ORDERS(v, order) { |
105 const Station *st = GetStation(order->station); |
106 const Station *st = GetStation(order->station); |
106 if (st->owner == v->owner && st->facilities & FACIL_AIRPORT) { |
107 if (st->owner == v->owner && st->facilities & FACIL_AIRPORT) { |
107 // If an airport doesn't have a hangar, skip it |
108 // If an airport doesn't have a hangar, skip it |
108 if (GetAirport(st->airport_type)->nof_depots != 0) |
109 if (st->Airport()->nof_depots != 0) |
109 return true; |
110 return true; |
110 } |
111 } |
111 } |
112 } |
112 |
113 |
113 return false; |
114 return false; |
247 |
248 |
248 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
249 SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); |
249 |
250 |
250 // Prevent building aircraft types at places which can't handle them |
251 // Prevent building aircraft types at places which can't handle them |
251 const Station* st = GetStationByTile(tile); |
252 const Station* st = GetStationByTile(tile); |
252 const AirportFTAClass* apc = GetAirport(st->airport_type); |
253 const AirportFTAClass* apc = st->Airport(); |
253 if ((avi->subtype & AIR_CTOL ? HELICOPTERS_ONLY : AIRCRAFT_ONLY) == apc->acc_planes) { |
254 if (!(apc->flags & (avi->subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS))) { |
254 return CMD_ERROR; |
255 return CMD_ERROR; |
255 } |
256 } |
256 |
257 |
257 /* Allocate 2 or 3 vehicle structs, depending on type |
258 /* Allocate 2 or 3 vehicle structs, depending on type |
258 * vl[0] = aircraft, vl[1] = shadow, [vl[2] = rotor] */ |
259 * vl[0] = aircraft, vl[1] = shadow, [vl[2] = rotor] */ |
556 } else { |
557 } else { |
557 bool next_airport_has_hangar = true; |
558 bool next_airport_has_hangar = true; |
558 StationID next_airport_index = v->u.air.targetairport; |
559 StationID next_airport_index = v->u.air.targetairport; |
559 const Station *st = GetStation(next_airport_index); |
560 const Station *st = GetStation(next_airport_index); |
560 /* If the station is not a valid airport or if it has no hangars */ |
561 /* If the station is not a valid airport or if it has no hangars */ |
561 if (!st->IsValid() || st->airport_tile == 0 || GetAirport(st->airport_type)->nof_depots == 0) { |
562 if (!st->IsValid() || st->airport_tile == 0 || st->Airport()->nof_depots == 0) { |
562 StationID station; |
563 StationID station; |
563 |
564 |
564 // the aircraft has to search for a hangar on its own |
565 // the aircraft has to search for a hangar on its own |
565 station = FindNearestHangar(v); |
566 station = FindNearestHangar(v); |
566 |
567 |
693 return; |
694 return; |
694 } |
695 } |
695 |
696 |
696 st = GetStation(v->current_order.dest); |
697 st = GetStation(v->current_order.dest); |
697 // only goto depot if the target airport has terminals (eg. it is airport) |
698 // only goto depot if the target airport has terminals (eg. it is airport) |
698 if (st->IsValid() && st->airport_tile != 0 && GetAirport(st->airport_type)->terminals != NULL) { |
699 if (st->IsValid() && st->airport_tile != 0 && st->Airport()->terminals != NULL) { |
699 // printf("targetairport = %d, st->index = %d\n", v->u.air.targetairport, st->index); |
700 // printf("targetairport = %d, st->index = %d\n", v->u.air.targetairport, st->index); |
700 // v->u.air.targetairport = st->index; |
701 // v->u.air.targetairport = st->index; |
701 v->current_order.type = OT_GOTO_DEPOT; |
702 v->current_order.type = OT_GOTO_DEPOT; |
702 v->current_order.flags = OF_NON_STOP; |
703 v->current_order.flags = OF_NON_STOP; |
703 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
704 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); |
967 x = TileX(tile) * TILE_SIZE; |
968 x = TileX(tile) * TILE_SIZE; |
968 y = TileY(tile) * TILE_SIZE; |
969 y = TileY(tile) * TILE_SIZE; |
969 } |
970 } |
970 |
971 |
971 // get airport moving data |
972 // get airport moving data |
972 const AirportMovingData *amd = GetAirport(st->airport_type)->MovingData(v->u.air.pos); |
973 const AirportFTAClass *afc = st->Airport(); |
|
974 const AirportMovingData *amd = afc->MovingData(v->u.air.pos); |
973 |
975 |
974 // Helicopter raise |
976 // Helicopter raise |
975 if (amd->flag & AMED_HELI_RAISE) { |
977 if (amd->flag & AMED_HELI_RAISE) { |
976 u = v->next->next; |
978 u = v->next->next; |
977 |
979 |
1009 |
1011 |
1010 // Vehicle is now at the airport. |
1012 // Vehicle is now at the airport. |
1011 v->tile = st->airport_tile; |
1013 v->tile = st->airport_tile; |
1012 |
1014 |
1013 // Find altitude of landing position. |
1015 // Find altitude of landing position. |
1014 z = GetSlopeZ(x, y) + 1; |
1016 z = GetSlopeZ(x, y) + 1 + afc->delta_z; |
1015 if (st->airport_type == AT_OILRIG) z += 54; |
|
1016 if (st->airport_type == AT_HELIPORT) z += 60; |
|
1017 |
1017 |
1018 if (z == v->z_pos) { |
1018 if (z == v->z_pos) { |
1019 u = v->next->next; |
1019 u = v->next->next; |
1020 |
1020 |
1021 // Increase speed of rotors. When speed is 80, we've landed. |
1021 // Increase speed of rotors. When speed is 80, we've landed. |
1367 |
1367 |
1368 st = GetStation(v->u.air.targetairport); |
1368 st = GetStation(v->u.air.targetairport); |
1369 |
1369 |
1370 //FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports |
1370 //FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports |
1371 prob = 0x10000 / 1500; |
1371 prob = 0x10000 / 1500; |
1372 if (((st->airport_type == AT_SMALL) || (st->airport_type == AT_COMMUTER)) && (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) && !_cheats.no_jetcrash.value) { |
1372 if (st->Airport()->flags & AirportFTAClass::SHORT_STRIP && |
|
1373 AircraftVehInfo(v->engine_type)->subtype & AIR_FAST && |
|
1374 !_cheats.no_jetcrash.value) { |
1373 prob = 0x10000 / 20; |
1375 prob = 0x10000 / 20; |
1374 } |
1376 } |
1375 |
1377 |
1376 if (GB(Random(), 0, 16) > prob) return; |
1378 if (GB(Random(), 0, 16) > prob) return; |
1377 |
1379 |
1439 SndPlayVehicleFx(SND_17_SKID_PLANE, v); |
1441 SndPlayVehicleFx(SND_17_SKID_PLANE, v); |
1440 } |
1442 } |
1441 MaybeCrashAirplane(v); |
1443 MaybeCrashAirplane(v); |
1442 } |
1444 } |
1443 |
1445 |
|
1446 /** |
|
1447 * Find the entry point to an airport depending on direction which |
|
1448 * the airport is being approached from. Each airport can have up to |
|
1449 * four entry points for its approach system so that approaching |
|
1450 * aircraft do not fly through each other or are forced to do 180 |
|
1451 * degree turns during the approach. The arrivals are grouped into |
|
1452 * four sectors dependent on the DiagDirection from which the airport |
|
1453 * is approached. |
|
1454 * |
|
1455 * @param v The vehicle that is approaching the airport |
|
1456 * @param apc The Airport Class being approached. |
|
1457 * @returns The index of the entry point |
|
1458 */ |
|
1459 static byte AircraftGetEntryPoint(const Vehicle *v, const AirportFTAClass *apc) |
|
1460 { |
|
1461 assert(v != NULL); |
|
1462 assert(apc != NULL); |
|
1463 |
|
1464 const Station *st = GetStation(v->u.air.targetairport); |
|
1465 /* Make sure we don't go to 0,0 if the airport has been removed. */ |
|
1466 TileIndex tile = (st->airport_tile != 0) ? st->airport_tile : st->xy; |
|
1467 |
|
1468 int delta_x = v->x_pos - TileX(tile) * TILE_SIZE; |
|
1469 int delta_y = v->y_pos - TileY(tile) * TILE_SIZE; |
|
1470 |
|
1471 DiagDirection dir; |
|
1472 if (abs(delta_y) < abs(delta_x)) { |
|
1473 /* We are northeast or southwest of the airport */ |
|
1474 dir = delta_x < 0 ? DIAGDIR_NE : DIAGDIR_SW; |
|
1475 } else { |
|
1476 /* We are northwest or southeast of the airport */ |
|
1477 dir = delta_y < 0 ? DIAGDIR_NW : DIAGDIR_SE; |
|
1478 } |
|
1479 return apc->entry_points[dir]; |
|
1480 } |
|
1481 |
|
1482 |
1444 // set the right pos when heading to other airports after takeoff |
1483 // set the right pos when heading to other airports after takeoff |
1445 static void AircraftNextAirportPos_and_Order(Vehicle *v) |
1484 static void AircraftNextAirportPos_and_Order(Vehicle *v) |
1446 { |
1485 { |
1447 const Station* st; |
|
1448 const AirportFTAClass *apc; |
|
1449 |
|
1450 if (v->current_order.type == OT_GOTO_STATION || |
1486 if (v->current_order.type == OT_GOTO_STATION || |
1451 v->current_order.type == OT_GOTO_DEPOT) |
1487 v->current_order.type == OT_GOTO_DEPOT) |
1452 v->u.air.targetairport = v->current_order.dest; |
1488 v->u.air.targetairport = v->current_order.dest; |
1453 |
1489 |
1454 st = GetStation(v->u.air.targetairport); |
1490 const AirportFTAClass *apc = GetStation(v->u.air.targetairport)->Airport(); |
1455 apc = GetAirport(st->airport_type); |
1491 v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, apc); |
1456 v->u.air.pos = v->u.air.previous_pos = apc->entry_point; |
|
1457 } |
1492 } |
1458 |
1493 |
1459 static void AircraftLeaveHangar(Vehicle *v) |
1494 static void AircraftLeaveHangar(Vehicle *v) |
1460 { |
1495 { |
1461 v->cur_speed = 0; |
1496 v->cur_speed = 0; |
1635 byte landingtype; |
1670 byte landingtype; |
1636 AirportFTA *current; |
1671 AirportFTA *current; |
1637 uint16 tcur_speed, tsubspeed; |
1672 uint16 tcur_speed, tsubspeed; |
1638 |
1673 |
1639 st = GetStation(v->u.air.targetairport); |
1674 st = GetStation(v->u.air.targetairport); |
1640 // flying device is accepted at this station |
|
1641 // small airport --> no helicopters (AIRCRAFT_ONLY) |
|
1642 // all other airports --> all types of flying devices (ALL) |
|
1643 // heliport/oilrig, etc --> no airplanes (HELICOPTERS_ONLY) |
|
1644 // runway busy or not allowed to use this airstation, circle |
1675 // runway busy or not allowed to use this airstation, circle |
1645 if (v->subtype != apc->acc_planes && |
1676 if (apc->flags & (v->subtype == AIR_HELICOPTER ? AirportFTAClass::HELICOPTERS : AirportFTAClass::AIRPLANES) && |
1646 st->airport_tile != 0 && |
1677 st->airport_tile != 0 && |
1647 (st->owner == OWNER_NONE || st->owner == v->owner)) { |
1678 (st->owner == OWNER_NONE || st->owner == v->owner)) { |
1648 // {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41}, |
1679 // {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41}, |
1649 // if it is an airplane, look for LANDING, for helicopter HELILANDING |
1680 // if it is an airplane, look for LANDING, for helicopter HELILANDING |
1650 // it is possible to choose from multiple landing runways, so loop until a free one is found |
1681 // it is possible to choose from multiple landing runways, so loop until a free one is found |
1821 return false; |
1852 return false; |
1822 } |
1853 } |
1823 current = current->next; |
1854 current = current->next; |
1824 } while (current != NULL); |
1855 } while (current != NULL); |
1825 |
1856 |
1826 DEBUG(misc, 0, "[Ap] cannot move further on Airport! (pos %d state %d)", v->u.air.pos, v->u.air.state); |
1857 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); |
1827 DEBUG(misc, 0, "[Ap] airport entry point: %d, Vehicle: %d", apc->entry_point, v->index); |
|
1828 assert(0); |
1858 assert(0); |
1829 return false; |
1859 return false; |
1830 } |
1860 } |
1831 |
1861 |
1832 // returns true if the road ahead is busy, eg. you must wait before proceeding |
1862 // returns true if the road ahead is busy, eg. you must wait before proceeding |
1836 const AirportFTA *next = &apc->layout[current_pos->next_position]; |
1866 const AirportFTA *next = &apc->layout[current_pos->next_position]; |
1837 |
1867 |
1838 // same block, then of course we can move |
1868 // same block, then of course we can move |
1839 if (apc->layout[current_pos->position].block != next->block) { |
1869 if (apc->layout[current_pos->position].block != next->block) { |
1840 const Station *st = GetStation(v->u.air.targetairport); |
1870 const Station *st = GetStation(v->u.air.targetairport); |
1841 uint32 airport_flags = next->block; |
1871 uint64 airport_flags = next->block; |
1842 |
1872 |
1843 // check additional possible extra blocks |
1873 // check additional possible extra blocks |
1844 if (current_pos != reference && current_pos->block != NOTHING_block) { |
1874 if (current_pos != reference && current_pos->block != NOTHING_block) { |
1845 airport_flags |= current_pos->block; |
1875 airport_flags |= current_pos->block; |
1846 } |
1876 } |
1860 AirportFTA *next = &apc->layout[current_pos->next_position]; |
1890 AirportFTA *next = &apc->layout[current_pos->next_position]; |
1861 AirportFTA *reference = &apc->layout[v->u.air.pos]; |
1891 AirportFTA *reference = &apc->layout[v->u.air.pos]; |
1862 |
1892 |
1863 // if the next position is in another block, check it and wait until it is free |
1893 // if the next position is in another block, check it and wait until it is free |
1864 if ((apc->layout[current_pos->position].block & next->block) != next->block) { |
1894 if ((apc->layout[current_pos->position].block & next->block) != next->block) { |
1865 uint32 airport_flags = next->block; |
1895 uint64 airport_flags = next->block; |
1866 Station* st = GetStation(v->u.air.targetairport); |
1896 Station* st = GetStation(v->u.air.targetairport); |
1867 //search for all all elements in the list with the same state, and blocks != N |
1897 //search for all all elements in the list with the same state, and blocks != N |
1868 // this means more blocks should be checked/set |
1898 // this means more blocks should be checked/set |
1869 AirportFTA *current = current_pos; |
1899 AirportFTA *current = current_pos; |
1870 if (current == reference) current = current->next; |
1900 if (current == reference) current = current->next; |
2048 ProcessAircraftOrder(v); |
2078 ProcessAircraftOrder(v); |
2049 HandleAircraftLoading(v, loop); |
2079 HandleAircraftLoading(v, loop); |
2050 |
2080 |
2051 if (v->current_order.type >= OT_LOADING) return; |
2081 if (v->current_order.type >= OT_LOADING) return; |
2052 |
2082 |
2053 // pass the right airport structure to the functions |
2083 AirportGoToNextPosition(v, GetStation(v->u.air.targetairport)->Airport()); |
2054 // DEREF_STATION gets target airport (Station *st), its type is passed to GetAirport |
|
2055 // that returns the correct layout depending on type |
|
2056 AirportGoToNextPosition(v, GetAirport(GetStation(v->u.air.targetairport)->airport_type)); |
|
2057 } |
2084 } |
2058 |
2085 |
2059 void Aircraft_Tick(Vehicle *v) |
2086 void Aircraft_Tick(Vehicle *v) |
2060 { |
2087 { |
2061 int i; |
2088 int i; |
2117 GetNewVehiclePosResult gp; |
2144 GetNewVehiclePosResult gp; |
2118 Vehicle *v; |
2145 Vehicle *v; |
2119 byte takeofftype; |
2146 byte takeofftype; |
2120 uint16 cnt; |
2147 uint16 cnt; |
2121 // only 1 station is updated per function call, so it is enough to get entry_point once |
2148 // only 1 station is updated per function call, so it is enough to get entry_point once |
2122 const AirportFTAClass *ap = GetAirport(st->airport_type); |
2149 const AirportFTAClass *ap = st->Airport(); |
2123 FOR_ALL_VEHICLES(v) { |
2150 FOR_ALL_VEHICLES(v) { |
2124 if (v->type == VEH_Aircraft && IsNormalAircraft(v)) { |
2151 if (v->type == VEH_Aircraft && IsNormalAircraft(v)) { |
2125 if (v->u.air.targetairport == st->index) { // if heading to this airport |
2152 if (v->u.air.targetairport == st->index) { // if heading to this airport |
2126 /* update position of airplane. If plane is not flying, landing, or taking off |
2153 /* update position of airplane. If plane is not flying, landing, or taking off |
2127 *you cannot delete airport, so it doesn't matter |
2154 *you cannot delete airport, so it doesn't matter |
2128 */ |
2155 */ |
2129 if (v->u.air.state >= FLYING) { // circle around |
2156 if (v->u.air.state >= FLYING) { // circle around |
2130 v->u.air.pos = v->u.air.previous_pos = ap->entry_point; |
2157 v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, ap); |
2131 v->u.air.state = FLYING; |
2158 v->u.air.state = FLYING; |
2132 // landing plane needs to be reset to flying height (only if in pause mode upgrade, |
2159 // landing plane needs to be reset to flying height (only if in pause mode upgrade, |
2133 // in normal mode, plane is reset in AircraftController. It doesn't hurt for FLYING |
2160 // in normal mode, plane is reset in AircraftController. It doesn't hurt for FLYING |
2134 GetNewVehiclePos(v, &gp); |
2161 GetNewVehiclePos(v, &gp); |
2135 // set new position x,y,z |
2162 // set new position x,y,z |