53 case LANDING: |
53 case LANDING: |
54 case HELILANDING: |
54 case HELILANDING: |
55 case FLYING: x = MKIT(24, 24, -1, -1); break; |
55 case FLYING: x = MKIT(24, 24, -1, -1); break; |
56 default: x = MKIT( 2, 2, -1, -1); break; |
56 default: x = MKIT( 2, 2, -1, -1); break; |
57 } |
57 } |
58 this->z_height = 5; |
58 this->z_extent = 5; |
59 break; |
59 break; |
60 case AIR_SHADOW: this->z_height = 1; x = MKIT(2, 2, 0, 0); break; |
60 case AIR_SHADOW: this->z_extent = 1; x = MKIT(2, 2, 0, 0); break; |
61 case AIR_ROTOR: this->z_height = 1; x = MKIT(2, 2, -1, -1); break; |
61 case AIR_ROTOR: this->z_extent = 1; x = MKIT(2, 2, -1, -1); break; |
62 } |
62 } |
63 #undef MKIT |
63 #undef MKIT |
64 |
64 |
65 this->x_offs = GB(x, 0, 8); |
65 this->x_offs = GB(x, 0, 8); |
66 this->y_offs = GB(x, 8, 8); |
66 this->y_offs = GB(x, 8, 8); |
67 this->sprite_width = GB(x, 16, 8); |
67 this->x_extent = GB(x, 16, 8); |
68 this->sprite_height = GB(x, 24, 8); |
68 this->y_extent = GB(x, 24, 8); |
69 } |
69 } |
70 |
70 |
71 |
71 |
72 /** this maps the terminal to its corresponding state and block flag |
72 /** this maps the terminal to its corresponding state and block flag |
73 * currently set for 10 terms, 4 helipads */ |
73 * currently set for 10 terms, 4 helipads */ |
568 |
568 |
569 Vehicle *v = GetVehicle(p1); |
569 Vehicle *v = GetVehicle(p1); |
570 |
570 |
571 if (v->type != VEH_AIRCRAFT || !CheckOwnership(v->owner) || v->IsInDepot()) return CMD_ERROR; |
571 if (v->type != VEH_AIRCRAFT || !CheckOwnership(v->owner) || v->IsInDepot()) return CMD_ERROR; |
572 |
572 |
573 if (v->current_order.type == OT_GOTO_DEPOT && !(p2 & DEPOT_LOCATE_HANGAR)) { |
573 if (v->current_order.IsType(OT_GOTO_DEPOT) && !(p2 & DEPOT_LOCATE_HANGAR)) { |
574 if (!!(p2 & DEPOT_SERVICE) == HasBit(v->current_order.flags, OF_HALT_IN_DEPOT)) { |
574 bool halt_in_depot = HasBit(v->current_order.GetDepotActionType(), OF_HALT_IN_DEPOT); |
|
575 if (!!(p2 & DEPOT_SERVICE) == halt_in_depot) { |
575 /* We called with a different DEPOT_SERVICE setting. |
576 /* We called with a different DEPOT_SERVICE setting. |
576 * Now we change the setting to apply the new one and let the vehicle head for the same hangar. |
577 * Now we change the setting to apply the new one and let the vehicle head for the same hangar. |
577 * Note: the if is (true for requesting service == true for ordered to stop in hangar) */ |
578 * Note: the if is (true for requesting service == true for ordered to stop in hangar) */ |
578 if (flags & DC_EXEC) { |
579 if (flags & DC_EXEC) { |
579 ClrBit(v->current_order.flags, OF_PART_OF_ORDERS); |
580 v->current_order.SetDepotOrderType(OFB_MANUAL_ORDER); |
580 ToggleBit(v->current_order.flags, OF_HALT_IN_DEPOT); |
581 v->current_order.SetDepotActionType(halt_in_depot ? OFB_NORMAL_ACTION : OFB_HALT_IN_DEPOT); |
581 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
582 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
582 } |
583 } |
583 return CommandCost(); |
584 return CommandCost(); |
584 } |
585 } |
585 |
586 |
586 if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of hangar orders |
587 if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of hangar orders |
587 if (flags & DC_EXEC) { |
588 if (flags & DC_EXEC) { |
588 if (v->current_order.flags & OFB_UNLOAD) v->cur_order_index++; |
589 /* If the orders to 'goto depot' are in the orders list (forced servicing), |
589 v->current_order.type = OT_DUMMY; |
590 * then skip to the next order; effectively cancelling this forced service */ |
590 v->current_order.flags = 0; |
591 if (v->current_order.GetDepotOrderType() & OFB_PART_OF_ORDERS) v->cur_order_index++; |
|
592 |
|
593 v->current_order.MakeDummy(); |
591 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
594 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
592 } |
595 } |
593 } else { |
596 } else { |
594 bool next_airport_has_hangar = true; |
597 bool next_airport_has_hangar = true; |
595 StationID next_airport_index = v->u.air.targetairport; |
598 StationID next_airport_index = v->u.air.targetairport; |
603 if (station == INVALID_STATION) return CMD_ERROR; |
606 if (station == INVALID_STATION) return CMD_ERROR; |
604 next_airport_index = station; |
607 next_airport_index = station; |
605 } |
608 } |
606 |
609 |
607 if (flags & DC_EXEC) { |
610 if (flags & DC_EXEC) { |
608 if (v->current_order.type == OT_LOADING) v->LeaveStation(); |
611 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation(); |
609 |
612 |
610 v->current_order.type = OT_GOTO_DEPOT; |
613 v->current_order.MakeGoToDepot(next_airport_index, false); |
611 v->current_order.flags = OFB_NON_STOP; |
614 if (!(p2 & DEPOT_SERVICE)) v->current_order.SetDepotActionType(OFB_HALT_IN_DEPOT); |
612 if (!(p2 & DEPOT_SERVICE)) SetBit(v->current_order.flags, OF_HALT_IN_DEPOT); |
|
613 v->current_order.refit_cargo = CT_INVALID; |
|
614 v->current_order.dest = next_airport_index; |
|
615 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
615 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
616 if (v->u.air.state == FLYING && !next_airport_has_hangar) { |
616 if (v->u.air.state == FLYING && !next_airport_has_hangar) { |
617 /* The aircraft is now heading for a different hangar than the next in the orders */ |
617 /* The aircraft is now heading for a different hangar than the next in the orders */ |
618 AircraftNextAirportPos_and_Order(v); |
618 AircraftNextAirportPos_and_Order(v); |
619 } |
619 } |
708 if (v->IsInDepot()) { |
708 if (v->IsInDepot()) { |
709 VehicleServiceInDepot(v); |
709 VehicleServiceInDepot(v); |
710 return; |
710 return; |
711 } |
711 } |
712 |
712 |
713 const Station *st = GetStation(v->current_order.dest); |
713 const Station *st = GetStation(v->current_order.GetDestination()); |
714 /* only goto depot if the target airport has terminals (eg. it is airport) */ |
714 /* only goto depot if the target airport has terminals (eg. it is airport) */ |
715 if (st->IsValid() && st->airport_tile != 0 && st->Airport()->terminals != NULL) { |
715 if (st->IsValid() && st->airport_tile != 0 && st->Airport()->terminals != NULL) { |
716 // printf("targetairport = %d, st->index = %d\n", v->u.air.targetairport, st->index); |
716 // printf("targetairport = %d, st->index = %d\n", v->u.air.targetairport, st->index); |
717 // v->u.air.targetairport = st->index; |
717 // v->u.air.targetairport = st->index; |
718 v->current_order.type = OT_GOTO_DEPOT; |
718 v->current_order.MakeGoToDepot(0, false); |
719 v->current_order.flags = OFB_NON_STOP; |
|
720 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
719 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
721 } else if (v->current_order.type == OT_GOTO_DEPOT) { |
720 } else if (v->current_order.IsType(OT_GOTO_DEPOT)) { |
722 v->current_order.type = OT_DUMMY; |
721 v->current_order.MakeDummy(); |
723 v->current_order.flags = 0; |
|
724 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
722 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); |
725 } |
723 } |
726 } |
724 } |
727 |
725 |
728 void Aircraft::OnNewDay() |
726 void Aircraft::OnNewDay() |
1059 tile = st->xy; |
1057 tile = st->xy; |
1060 |
1058 |
1061 /* Jump into our "holding pattern" state machine if possible */ |
1059 /* Jump into our "holding pattern" state machine if possible */ |
1062 if (v->u.air.pos >= afc->nofelements) { |
1060 if (v->u.air.pos >= afc->nofelements) { |
1063 v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, afc); |
1061 v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, afc); |
1064 } else if (v->u.air.targetairport != v->current_order.dest) { |
1062 } else if (v->u.air.targetairport != v->current_order.GetDestination()) { |
1065 /* If not possible, just get out of here fast */ |
1063 /* If not possible, just get out of here fast */ |
1066 v->u.air.state = FLYING; |
1064 v->u.air.state = FLYING; |
1067 UpdateAircraftCache(v); |
1065 UpdateAircraftCache(v); |
1068 AircraftNextAirportPos_and_Order(v); |
1066 AircraftNextAirportPos_and_Order(v); |
1069 /* get aircraft back on running altitude */ |
1067 /* get aircraft back on running altitude */ |
1360 EV_SMOKE |
1358 EV_SMOKE |
1361 ); |
1359 ); |
1362 } |
1360 } |
1363 } |
1361 } |
1364 |
1362 |
1365 static void ProcessAircraftOrder(Vehicle *v) |
1363 void HandleMissingAircraftOrders(Vehicle *v) |
1366 { |
1364 { |
1367 switch (v->current_order.type) { |
1365 /* |
1368 case OT_GOTO_DEPOT: |
1366 * We do not have an order. This can be divided into two cases: |
1369 if (!(v->current_order.flags & OFB_PART_OF_ORDERS)) return; |
1367 * 1) we are heading to an invalid station. In this case we must |
1370 if (v->current_order.flags & OFB_SERVICE_IF_NEEDED && |
1368 * find another airport to go to. If there is nowhere to go, |
1371 !VehicleNeedsService(v)) { |
1369 * we will destroy the aircraft as it otherwise will enter |
1372 UpdateVehicleTimetable(v, true); |
1370 * the holding pattern for the first airport, which can cause |
1373 v->cur_order_index++; |
1371 * the plane to go into an undefined state when building an |
1374 } |
1372 * airport with the same StationID. |
1375 break; |
1373 * 2) we are (still) heading to a (still) valid airport, then we |
1376 |
1374 * can continue going there. This can happen when you are |
1377 case OT_LOADING: return; |
1375 * changing the aircraft's orders while in-flight or in for |
1378 |
1376 * example a depot. However, when we have a current order to |
1379 default: break; |
1377 * go to a depot, we have to keep that order so the aircraft |
1380 } |
1378 * actually stops. |
1381 |
1379 */ |
1382 if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; |
1380 const Station *st = GetStation(v->u.air.targetairport); |
1383 |
1381 if (!st->IsValid() || st->airport_tile == 0) { |
1384 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
1382 CommandCost ret; |
1385 |
1383 PlayerID old_player = _current_player; |
1386 if (order == NULL|| (order->type == OT_DUMMY && !CheckForValidOrders(v))) { |
1384 |
1387 /* |
1385 _current_player = v->owner; |
1388 * We do not have an order. This can be divided into two cases: |
1386 ret = DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_SEND_AIRCRAFT_TO_HANGAR); |
1389 * 1) we are heading to an invalid station. In this case we must |
1387 _current_player = old_player; |
1390 * find another airport to go to. If there is nowhere to go, |
1388 |
1391 * we will destroy the aircraft as it otherwise will enter |
1389 if (CmdFailed(ret)) CrashAirplane(v); |
1392 * the holding pattern for the first airport, which can cause |
1390 } else if (!v->current_order.IsType(OT_GOTO_DEPOT)) { |
1393 * the plane to go into an undefined state when building an |
1391 v->current_order.Free(); |
1394 * airport with the same StationID. |
1392 } |
1395 * 2) we are (still) heading to a (still) valid airport, then we |
1393 } |
1396 * can continue going there. This can happen when you are |
1394 |
1397 * changing the aircraft's orders while in-flight or in for |
1395 |
1398 * example a depot. However, when we have a current order to |
1396 TileIndex Aircraft::GetOrderStationLocation(StationID station) |
1399 * go to a depot, we have to keep that order so the aircraft |
1397 { |
1400 * actually stops. |
1398 /* Orders are changed in flight, ensure going to the right station. */ |
1401 */ |
1399 if (this->u.air.state == FLYING) { |
1402 const Station *st = GetStation(v->u.air.targetairport); |
1400 AircraftNextAirportPos_and_Order(this); |
1403 if (!st->IsValid() || st->airport_tile == 0) { |
1401 } |
1404 CommandCost ret; |
1402 |
1405 PlayerID old_player = _current_player; |
1403 /* Aircraft do not use dest-tile */ |
1406 |
1404 return 0; |
1407 _current_player = v->owner; |
|
1408 ret = DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_SEND_AIRCRAFT_TO_HANGAR); |
|
1409 _current_player = old_player; |
|
1410 |
|
1411 if (CmdFailed(ret)) CrashAirplane(v); |
|
1412 } else if (v->current_order.type != OT_GOTO_DEPOT) { |
|
1413 v->current_order.Free(); |
|
1414 } |
|
1415 return; |
|
1416 } |
|
1417 |
|
1418 if (order->type == v->current_order.type && |
|
1419 order->flags == v->current_order.flags && |
|
1420 order->dest == v->current_order.dest) |
|
1421 return; |
|
1422 |
|
1423 v->current_order = *order; |
|
1424 |
|
1425 /* orders are changed in flight, ensure going to the right station */ |
|
1426 if (order->type == OT_GOTO_STATION && v->u.air.state == FLYING) { |
|
1427 AircraftNextAirportPos_and_Order(v); |
|
1428 } |
|
1429 |
|
1430 InvalidateVehicleOrder(v); |
|
1431 |
|
1432 InvalidateWindowClasses(WC_AIRCRAFT_LIST); |
|
1433 } |
1405 } |
1434 |
1406 |
1435 void Aircraft::MarkDirty() |
1407 void Aircraft::MarkDirty() |
1436 { |
1408 { |
1437 this->cur_image = this->GetImage(this->direction); |
1409 this->cur_image = this->GetImage(this->direction); |
1630 AircraftEventHandler_EnterHangar(v, apc); |
1602 AircraftEventHandler_EnterHangar(v, apc); |
1631 return; |
1603 return; |
1632 } |
1604 } |
1633 |
1605 |
1634 /* if we were sent to the depot, stay there */ |
1606 /* if we were sent to the depot, stay there */ |
1635 if (v->current_order.type == OT_GOTO_DEPOT && (v->vehstatus & VS_STOPPED)) { |
1607 if (v->current_order.IsType(OT_GOTO_DEPOT) && (v->vehstatus & VS_STOPPED)) { |
1636 v->current_order.Free(); |
1608 v->current_order.Free(); |
1637 return; |
1609 return; |
1638 } |
1610 } |
1639 |
1611 |
1640 if (v->current_order.type != OT_GOTO_STATION && |
1612 if (!v->current_order.IsType(OT_GOTO_STATION) && |
1641 v->current_order.type != OT_GOTO_DEPOT) |
1613 !v->current_order.IsType(OT_GOTO_DEPOT)) |
1642 return; |
1614 return; |
1643 |
1615 |
1644 /* if the block of the next position is busy, stay put */ |
1616 /* if the block of the next position is busy, stay put */ |
1645 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1617 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1646 |
1618 |
1647 /* We are already at the target airport, we need to find a terminal */ |
1619 /* We are already at the target airport, we need to find a terminal */ |
1648 if (v->current_order.dest == v->u.air.targetairport) { |
1620 if (v->current_order.GetDestination() == v->u.air.targetairport) { |
1649 /* FindFreeTerminal: |
1621 /* FindFreeTerminal: |
1650 * 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */ |
1622 * 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */ |
1651 if (v->subtype == AIR_HELICOPTER) { |
1623 if (v->subtype == AIR_HELICOPTER) { |
1652 if (!AirportFindFreeHelipad(v, apc)) return; // helicopter |
1624 if (!AirportFindFreeHelipad(v, apc)) return; // helicopter |
1653 } else { |
1625 } else { |
1687 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1659 if (AirportHasBlock(v, &apc->layout[v->u.air.pos], apc)) return; |
1688 |
1660 |
1689 /* airport-road is free. We either have to go to another airport, or to the hangar |
1661 /* airport-road is free. We either have to go to another airport, or to the hangar |
1690 * ---> start moving */ |
1662 * ---> start moving */ |
1691 |
1663 |
1692 switch (v->current_order.type) { |
1664 switch (v->current_order.GetType()) { |
1693 case OT_GOTO_STATION: // ready to fly to another airport |
1665 case OT_GOTO_STATION: // ready to fly to another airport |
1694 /* airplane goto state takeoff, helicopter to helitakeoff */ |
1666 /* airplane goto state takeoff, helicopter to helitakeoff */ |
1695 v->u.air.state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; |
1667 v->u.air.state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; |
1696 break; |
1668 break; |
1697 case OT_GOTO_DEPOT: // visit hangar for serivicing, sale, etc. |
1669 case OT_GOTO_DEPOT: // visit hangar for serivicing, sale, etc. |
1698 if (v->current_order.dest == v->u.air.targetairport) { |
1670 if (v->current_order.GetDestination() == v->u.air.targetairport) { |
1699 v->u.air.state = HANGAR; |
1671 v->u.air.state = HANGAR; |
1700 } else { |
1672 } else { |
1701 v->u.air.state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; |
1673 v->u.air.state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; |
1702 } |
1674 } |
1703 break; |
1675 break; |
1813 |
1785 |
1814 /* if going to terminal (OT_GOTO_STATION) choose one |
1786 /* if going to terminal (OT_GOTO_STATION) choose one |
1815 * 1. in case all terminals are busy AirportFindFreeTerminal() returns false or |
1787 * 1. in case all terminals are busy AirportFindFreeTerminal() returns false or |
1816 * 2. not going for terminal (but depot, no order), |
1788 * 2. not going for terminal (but depot, no order), |
1817 * --> get out of the way to the hangar. */ |
1789 * --> get out of the way to the hangar. */ |
1818 if (v->current_order.type == OT_GOTO_STATION) { |
1790 if (v->current_order.IsType(OT_GOTO_STATION)) { |
1819 if (AirportFindFreeTerminal(v, apc)) return; |
1791 if (AirportFindFreeTerminal(v, apc)) return; |
1820 } |
1792 } |
1821 v->u.air.state = HANGAR; |
1793 v->u.air.state = HANGAR; |
1822 |
1794 |
1823 } |
1795 } |
1832 * 2. not going for terminal (but depot, no order), |
1804 * 2. not going for terminal (but depot, no order), |
1833 * --> get out of the way to the hangar IF there are terminals on the airport. |
1805 * --> get out of the way to the hangar IF there are terminals on the airport. |
1834 * --> else TAKEOFF |
1806 * --> else TAKEOFF |
1835 * the reason behind this is that if an airport has a terminal, it also has a hangar. Airplanes |
1807 * the reason behind this is that if an airport has a terminal, it also has a hangar. Airplanes |
1836 * must go to a hangar. */ |
1808 * must go to a hangar. */ |
1837 if (v->current_order.type == OT_GOTO_STATION) { |
1809 if (v->current_order.IsType(OT_GOTO_STATION)) { |
1838 if (AirportFindFreeHelipad(v, apc)) return; |
1810 if (AirportFindFreeHelipad(v, apc)) return; |
1839 } |
1811 } |
1840 v->u.air.state = (apc->nof_depots != 0) ? HANGAR : HELITAKEOFF; |
1812 v->u.air.state = (apc->nof_depots != 0) ? HANGAR : HELITAKEOFF; |
1841 } |
1813 } |
1842 |
1814 |