00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "debug.h"
00014 #include "cmd_helper.h"
00015 #include "command_func.h"
00016 #include "company_func.h"
00017 #include "news_func.h"
00018 #include "vehicle_gui.h"
00019 #include "strings_func.h"
00020 #include "window_func.h"
00021 #include "timetable.h"
00022 #include "vehicle_func.h"
00023 #include "depot_base.h"
00024 #include "core/pool_func.hpp"
00025 #include "core/random_func.hpp"
00026 #include "aircraft.h"
00027 #include "roadveh.h"
00028 #include "station_base.h"
00029 #include "waypoint_base.h"
00030 #include "company_base.h"
00031 #include "order_backup.h"
00032
00033 #include "table/strings.h"
00034
00035
00036
00037
00038 assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
00039 assert_compile(sizeof(DestinationID) >= sizeof(StationID));
00040
00041 OrderPool _order_pool("Order");
00042 INSTANTIATE_POOL_METHODS(Order)
00043 OrderListPool _orderlist_pool("OrderList");
00044 INSTANTIATE_POOL_METHODS(OrderList)
00045
00047 Order::~Order()
00048 {
00049 if (CleaningPool()) return;
00050
00051
00052
00053 if (this->IsType(OT_GOTO_STATION) || this->IsType(OT_GOTO_WAYPOINT)) {
00054 BaseStation *bs = BaseStation::GetIfValid(this->GetDestination());
00055 if (bs != NULL && bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0);
00056 }
00057 }
00058
00063 void Order::Free()
00064 {
00065 this->type = OT_NOTHING;
00066 this->flags = 0;
00067 this->dest = 0;
00068 this->next = NULL;
00069 }
00070
00075 void Order::MakeGoToStation(StationID destination)
00076 {
00077 this->type = OT_GOTO_STATION;
00078 this->flags = 0;
00079 this->dest = destination;
00080 }
00081
00091 void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoID cargo, byte subtype)
00092 {
00093 this->type = OT_GOTO_DEPOT;
00094 this->SetDepotOrderType(order);
00095 this->SetDepotActionType(action);
00096 this->SetNonStopType(non_stop_type);
00097 this->dest = destination;
00098 this->SetRefit(cargo, subtype);
00099 }
00100
00105 void Order::MakeGoToWaypoint(StationID destination)
00106 {
00107 this->type = OT_GOTO_WAYPOINT;
00108 this->flags = 0;
00109 this->dest = destination;
00110 }
00111
00116 void Order::MakeLoading(bool ordered)
00117 {
00118 this->type = OT_LOADING;
00119 if (!ordered) this->flags = 0;
00120 }
00121
00125 void Order::MakeLeaveStation()
00126 {
00127 this->type = OT_LEAVESTATION;
00128 this->flags = 0;
00129 }
00130
00134 void Order::MakeDummy()
00135 {
00136 this->type = OT_DUMMY;
00137 this->flags = 0;
00138 }
00139
00144 void Order::MakeConditional(VehicleOrderID order)
00145 {
00146 this->type = OT_CONDITIONAL;
00147 this->flags = order;
00148 this->dest = 0;
00149 }
00150
00155 void Order::MakeImplicit(StationID destination)
00156 {
00157 this->type = OT_IMPLICIT;
00158 this->dest = destination;
00159 }
00160
00167 void Order::SetRefit(CargoID cargo, byte subtype)
00168 {
00169 this->refit_cargo = cargo;
00170 this->refit_subtype = subtype;
00171 }
00172
00178 bool Order::Equals(const Order &other) const
00179 {
00180
00181
00182
00183
00184
00185 if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
00186 ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
00187 (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
00188 return this->GetDepotOrderType() == other.GetDepotOrderType() &&
00189 (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
00190 }
00191
00192 return this->type == other.type && this->flags == other.flags && this->dest == other.dest;
00193 }
00194
00201 uint32 Order::Pack() const
00202 {
00203 return this->dest << 16 | this->flags << 8 | this->type;
00204 }
00205
00211 uint16 Order::MapOldOrder() const
00212 {
00213 uint16 order = this->GetType();
00214 switch (this->type) {
00215 case OT_GOTO_STATION:
00216 if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
00217 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
00218 if (this->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) SetBit(order, 7);
00219 order |= GB(this->GetDestination(), 0, 8) << 8;
00220 break;
00221 case OT_GOTO_DEPOT:
00222 if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
00223 SetBit(order, 7);
00224 order |= GB(this->GetDestination(), 0, 8) << 8;
00225 break;
00226 case OT_LOADING:
00227 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
00228 break;
00229 }
00230 return order;
00231 }
00232
00237 Order::Order(uint32 packed)
00238 {
00239 this->type = (OrderType)GB(packed, 0, 8);
00240 this->flags = GB(packed, 8, 8);
00241 this->dest = GB(packed, 16, 16);
00242 this->next = NULL;
00243 this->refit_cargo = CT_NO_REFIT;
00244 this->refit_subtype = 0;
00245 this->wait_time = 0;
00246 this->travel_time = 0;
00247 }
00248
00254 void InvalidateVehicleOrder(const Vehicle *v, int data)
00255 {
00256 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
00257
00258 if (data != 0) {
00259
00260 InvalidateWindowData(WC_VEHICLE_ORDERS, v->index, data);
00261 InvalidateWindowData(WC_VEHICLE_TIMETABLE, v->index, data);
00262 return;
00263 }
00264
00265 SetWindowDirty(WC_VEHICLE_ORDERS, v->index);
00266 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00267 }
00268
00276 void Order::AssignOrder(const Order &other)
00277 {
00278 this->type = other.type;
00279 this->flags = other.flags;
00280 this->dest = other.dest;
00281
00282 this->refit_cargo = other.refit_cargo;
00283 this->refit_subtype = other.refit_subtype;
00284
00285 this->wait_time = other.wait_time;
00286 this->travel_time = other.travel_time;
00287 }
00288
00294 void OrderList::Initialize(Order *chain, Vehicle *v)
00295 {
00296 this->first = chain;
00297 this->first_shared = v;
00298
00299 this->num_orders = 0;
00300 this->num_manual_orders = 0;
00301 this->num_vehicles = 1;
00302 this->timetable_duration = 0;
00303
00304 for (Order *o = this->first; o != NULL; o = o->next) {
00305 ++this->num_orders;
00306 if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
00307 this->timetable_duration += o->wait_time + o->travel_time;
00308 }
00309
00310 for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) {
00311 ++this->num_vehicles;
00312 this->first_shared = u;
00313 }
00314
00315 for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles;
00316 }
00317
00323 void OrderList::FreeChain(bool keep_orderlist)
00324 {
00325 Order *next;
00326 for (Order *o = this->first; o != NULL; o = next) {
00327 next = o->next;
00328 delete o;
00329 }
00330
00331 if (keep_orderlist) {
00332 this->first = NULL;
00333 this->num_orders = 0;
00334 this->num_manual_orders = 0;
00335 this->timetable_duration = 0;
00336 } else {
00337 delete this;
00338 }
00339 }
00340
00346 Order *OrderList::GetOrderAt(int index) const
00347 {
00348 if (index < 0) return NULL;
00349
00350 Order *order = this->first;
00351
00352 while (order != NULL && index-- > 0) {
00353 order = order->next;
00354 }
00355 return order;
00356 }
00357
00367 const Order *OrderList::GetBestLoadableNext(const Vehicle *v, const Order *o2, const Order *o1) const
00368 {
00369 SmallMap<CargoID, uint> capacities;
00370 v->GetConsistFreeCapacities(capacities);
00371 uint loadable1 = 0;
00372 uint loadable2 = 0;
00373 StationID st1 = o1->GetDestination();
00374 StationID st2 = o2->GetDestination();
00375 const Station *cur_station = Station::Get(v->last_station_visited);
00376 for (SmallPair<CargoID, uint> *i = capacities.Begin(); i != capacities.End(); ++i) {
00377 const StationCargoPacketMap *loadable_packets = cur_station->goods[i->first].cargo.Packets();
00378 uint loadable_cargo = 0;
00379 std::pair<StationCargoPacketMap::const_iterator, StationCargoPacketMap::const_iterator> p =
00380 loadable_packets->equal_range(st1);
00381 for (StationCargoPacketMap::const_iterator j = p.first; j != p.second; ++j) {
00382 loadable_cargo = (*j)->Count();
00383 }
00384 loadable1 += min(i->second, loadable_cargo);
00385
00386 loadable_cargo = 0;
00387 p = loadable_packets->equal_range(st2);
00388 for (StationCargoPacketMap::const_iterator j = p.first; j != p.second; ++j) {
00389 loadable_cargo = (*j)->Count();
00390 }
00391 loadable2 += min(i->second, loadable_cargo);
00392 }
00393 if (loadable1 == loadable2) return RandomRange(2) == 0 ? o1 : o2;
00394 return loadable1 > loadable2 ? o1 : o2;
00395 }
00396
00408 const Order *OrderList::GetNextStoppingOrder(const Vehicle *v, const Order *next, uint hops, bool is_loading) const
00409 {
00410 if (hops > this->GetNumOrders() || next == NULL) return NULL;
00411
00412 if (next->IsType(OT_CONDITIONAL)) {
00413 if (is_loading && next->GetConditionVariable() == OCV_LOAD_PERCENTAGE) {
00414
00415
00416
00417 const Order *skip_to = this->GetNextStoppingOrder(v,
00418 this->GetOrderAt(next->GetConditionSkipToOrder()),
00419 hops + 1);
00420 const Order *advance = this->GetNextStoppingOrder(v,
00421 this->GetNext(next), hops + 1);
00422 if (advance == NULL) {
00423 return skip_to;
00424 } else if (skip_to == NULL) {
00425 return advance;
00426 } else {
00427 return this->GetBestLoadableNext(v, skip_to, advance);
00428 }
00429 } else {
00430
00431
00432
00433 VehicleOrderID skip_to = ProcessConditionalOrder(next, v);
00434 if (skip_to != INVALID_VEH_ORDER_ID) {
00435 return this->GetNextStoppingOrder(v,
00436 this->GetOrderAt(skip_to), hops + 1);
00437 } else {
00438 return this->GetNextStoppingOrder(v,
00439 this->GetNext(next), hops + 1);
00440 }
00441 }
00442 }
00443
00444 if (next->IsType(OT_GOTO_DEPOT)) {
00445 if (next->GetDepotActionType() == ODATFB_HALT) return NULL;
00446 if (next->IsRefit()) return next;
00447 }
00448
00449 if (!next->CanLoadOrUnload()) {
00450 return this->GetNextStoppingOrder(v, this->GetNext(next), hops + 1);
00451 }
00452
00453 return next;
00454 }
00455
00463 StationID OrderList::GetNextStoppingStation(const Vehicle *v) const
00464 {
00465
00466 const Order *next = this->GetOrderAt(v->cur_implicit_order_index);
00467 if (next == NULL) {
00468 next = this->GetFirstOrder();
00469 if (next == NULL) return INVALID_STATION;
00470 } else {
00471 next = this->GetNext(next);
00472 }
00473
00474 uint hops = 0;
00475 do {
00476 next = this->GetNextStoppingOrder(v, next, ++hops, true);
00477
00478 if (next == NULL || (next->GetDestination() == v->last_station_visited &&
00479 (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) == 0)) {
00480 return INVALID_STATION;
00481 }
00482 } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
00483
00484 return next->GetDestination();
00485 }
00486
00492 void OrderList::InsertOrderAt(Order *new_order, int index)
00493 {
00494 if (this->first == NULL) {
00495 this->first = new_order;
00496 } else {
00497 if (index == 0) {
00498
00499 new_order->next = this->first;
00500 this->first = new_order;
00501 } else if (index >= this->num_orders) {
00502
00503 this->GetLastOrder()->next = new_order;
00504 } else {
00505
00506 Order *order = this->GetOrderAt(index - 1);
00507 new_order->next = order->next;
00508 order->next = new_order;
00509 }
00510 }
00511 ++this->num_orders;
00512 if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
00513 this->timetable_duration += new_order->wait_time + new_order->travel_time;
00514
00515
00516
00517 if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) {
00518 BaseStation *bs = BaseStation::Get(new_order->GetDestination());
00519 if (bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0);
00520 }
00521
00522 }
00523
00524
00529 void OrderList::DeleteOrderAt(int index)
00530 {
00531 if (index >= this->num_orders) return;
00532
00533 Order *to_remove;
00534
00535 if (index == 0) {
00536 to_remove = this->first;
00537 this->first = to_remove->next;
00538 } else {
00539 Order *prev = GetOrderAt(index - 1);
00540 to_remove = prev->next;
00541 prev->next = to_remove->next;
00542 }
00543 --this->num_orders;
00544 if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
00545 this->timetable_duration -= (to_remove->wait_time + to_remove->travel_time);
00546 delete to_remove;
00547 }
00548
00554 void OrderList::MoveOrder(int from, int to)
00555 {
00556 if (from >= this->num_orders || to >= this->num_orders || from == to) return;
00557
00558 Order *moving_one;
00559
00560
00561 if (from == 0) {
00562 moving_one = this->first;
00563 this->first = moving_one->next;
00564 } else {
00565 Order *one_before = GetOrderAt(from - 1);
00566 moving_one = one_before->next;
00567 one_before->next = moving_one->next;
00568 }
00569
00570
00571 if (to == 0) {
00572 moving_one->next = this->first;
00573 this->first = moving_one;
00574 } else {
00575 Order *one_before = GetOrderAt(to - 1);
00576 moving_one->next = one_before->next;
00577 one_before->next = moving_one;
00578 }
00579 }
00580
00586 void OrderList::RemoveVehicle(Vehicle *v)
00587 {
00588 --this->num_vehicles;
00589 if (v == this->first_shared) this->first_shared = v->NextShared();
00590 }
00591
00596 bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const
00597 {
00598 for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) {
00599 if (v_shared == v) return true;
00600 }
00601
00602 return false;
00603 }
00604
00610 int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
00611 {
00612 int count = 0;
00613 for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++;
00614 return count;
00615 }
00616
00621 bool OrderList::IsCompleteTimetable() const
00622 {
00623 for (Order *o = this->first; o != NULL; o = o->next) {
00624
00625 if (o->IsType(OT_IMPLICIT)) continue;
00626 if (!o->IsCompletelyTimetabled()) return false;
00627 }
00628 return true;
00629 }
00630
00634 void OrderList::DebugCheckSanity() const
00635 {
00636 VehicleOrderID check_num_orders = 0;
00637 VehicleOrderID check_num_manual_orders = 0;
00638 uint check_num_vehicles = 0;
00639 Ticks check_timetable_duration = 0;
00640
00641 DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
00642
00643 for (const Order *o = this->first; o != NULL; o = o->next) {
00644 ++check_num_orders;
00645 if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
00646 check_timetable_duration += o->wait_time + o->travel_time;
00647 }
00648 assert(this->num_orders == check_num_orders);
00649 assert(this->num_manual_orders == check_num_manual_orders);
00650 assert(this->timetable_duration == check_timetable_duration);
00651
00652 for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
00653 ++check_num_vehicles;
00654 assert(v->orders.list == this);
00655 }
00656 assert(this->num_vehicles == check_num_vehicles);
00657 DEBUG(misc, 6, "... detected %u orders (%u manual), %u vehicles, %i ticks",
00658 (uint)this->num_orders, (uint)this->num_manual_orders,
00659 this->num_vehicles, this->timetable_duration);
00660 }
00661
00669 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
00670 {
00671 return o->IsType(OT_GOTO_STATION) ||
00672 (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
00673 }
00674
00681 static void DeleteOrderWarnings(const Vehicle *v)
00682 {
00683 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
00684 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
00685 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
00686 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
00687 }
00688
00695 TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
00696 {
00697 switch (this->GetType()) {
00698 case OT_GOTO_WAYPOINT:
00699 case OT_GOTO_STATION:
00700 case OT_IMPLICIT:
00701 if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination())->airport.tile;
00702 return BaseStation::Get(this->GetDestination())->xy;
00703
00704 case OT_GOTO_DEPOT:
00705 if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE;
00706 return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
00707
00708 default:
00709 return INVALID_TILE;
00710 }
00711 }
00712
00722 uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
00723 {
00724 if (cur->IsType(OT_CONDITIONAL)) {
00725 if (conditional_depth > v->GetNumOrders()) return 0;
00726
00727 conditional_depth++;
00728
00729 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
00730 int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
00731 return max(dist1, dist2);
00732 }
00733
00734 TileIndex prev_tile = prev->GetLocation(v, true);
00735 TileIndex cur_tile = cur->GetLocation(v, true);
00736 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
00737 return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
00738 }
00739
00753 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00754 {
00755 VehicleID veh = GB(p1, 0, 20);
00756 VehicleOrderID sel_ord = GB(p1, 20, 8);
00757 Order new_order(p2);
00758
00759 Vehicle *v = Vehicle::GetIfValid(veh);
00760 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00761
00762 CommandCost ret = CheckOwnership(v->owner);
00763 if (ret.Failed()) return ret;
00764
00765
00766
00767 switch (new_order.GetType()) {
00768 case OT_GOTO_STATION: {
00769 const Station *st = Station::GetIfValid(new_order.GetDestination());
00770 if (st == NULL) return CMD_ERROR;
00771
00772 if (st->owner != OWNER_NONE) {
00773 CommandCost ret = CheckOwnership(st->owner);
00774 if (ret.Failed()) return ret;
00775 }
00776
00777 if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00778 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
00779 if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
00780 }
00781
00782
00783 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
00784
00785
00786 switch (new_order.GetLoadType()) {
00787 case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
00788 default: return CMD_ERROR;
00789 }
00790 switch (new_order.GetUnloadType()) {
00791 case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
00792 default: return CMD_ERROR;
00793 }
00794
00795
00796 switch (new_order.GetStopLocation()) {
00797 case OSL_PLATFORM_NEAR_END:
00798 case OSL_PLATFORM_MIDDLE:
00799 if (v->type != VEH_TRAIN) return CMD_ERROR;
00800
00801 case OSL_PLATFORM_FAR_END:
00802 break;
00803
00804 default:
00805 return CMD_ERROR;
00806 }
00807
00808 break;
00809 }
00810
00811 case OT_GOTO_DEPOT: {
00812 if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
00813 if (v->type == VEH_AIRCRAFT) {
00814 const Station *st = Station::GetIfValid(new_order.GetDestination());
00815
00816 if (st == NULL) return CMD_ERROR;
00817
00818 CommandCost ret = CheckOwnership(st->owner);
00819 if (ret.Failed()) return ret;
00820
00821 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
00822 return CMD_ERROR;
00823 }
00824 } else {
00825 const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
00826
00827 if (dp == NULL) return CMD_ERROR;
00828
00829 CommandCost ret = CheckOwnership(GetTileOwner(dp->xy));
00830 if (ret.Failed()) return ret;
00831
00832 switch (v->type) {
00833 case VEH_TRAIN:
00834 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
00835 break;
00836
00837 case VEH_ROAD:
00838 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
00839 break;
00840
00841 case VEH_SHIP:
00842 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
00843 break;
00844
00845 default: return CMD_ERROR;
00846 }
00847 }
00848 }
00849
00850 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
00851 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
00852 if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
00853 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
00854 break;
00855 }
00856
00857 case OT_GOTO_WAYPOINT: {
00858 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
00859 if (wp == NULL) return CMD_ERROR;
00860
00861 switch (v->type) {
00862 default: return CMD_ERROR;
00863
00864 case VEH_TRAIN: {
00865 if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00866
00867 CommandCost ret = CheckOwnership(wp->owner);
00868 if (ret.Failed()) return ret;
00869 break;
00870 }
00871
00872 case VEH_SHIP:
00873 if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00874 if (wp->owner != OWNER_NONE) {
00875 CommandCost ret = CheckOwnership(wp->owner);
00876 if (ret.Failed()) return ret;
00877 }
00878 break;
00879 }
00880
00881
00882
00883
00884 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
00885 break;
00886 }
00887
00888 case OT_CONDITIONAL: {
00889 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
00890 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR;
00891 if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR;
00892
00893 OrderConditionComparator occ = new_order.GetConditionComparator();
00894 if (occ >= OCC_END) return CMD_ERROR;
00895 switch (new_order.GetConditionVariable()) {
00896 case OCV_REQUIRES_SERVICE:
00897 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
00898 break;
00899
00900 case OCV_UNCONDITIONALLY:
00901 if (occ != OCC_EQUALS) return CMD_ERROR;
00902 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
00903 break;
00904
00905 case OCV_LOAD_PERCENTAGE:
00906 case OCV_RELIABILITY:
00907 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
00908
00909 default:
00910 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
00911 break;
00912 }
00913 break;
00914 }
00915
00916 default: return CMD_ERROR;
00917 }
00918
00919 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
00920
00921 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS);
00922 if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00923 if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00924
00925 if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) {
00926
00927 const Order *prev = NULL;
00928 uint n = 0;
00929
00930
00931
00932
00933 const Order *o;
00934 FOR_VEHICLE_ORDERS(v, o) {
00935 switch (o->GetType()) {
00936 case OT_GOTO_STATION:
00937 case OT_GOTO_DEPOT:
00938 case OT_GOTO_WAYPOINT:
00939 prev = o;
00940 break;
00941
00942 default: break;
00943 }
00944 if (++n == sel_ord && prev != NULL) break;
00945 }
00946 if (prev != NULL) {
00947 uint dist = GetOrderDistance(prev, &new_order, v);
00948 if (dist >= 130) {
00949 return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION);
00950 }
00951 }
00952 }
00953
00954 if (flags & DC_EXEC) {
00955 Order *new_o = new Order();
00956 new_o->AssignOrder(new_order);
00957 InsertOrder(v, new_o, sel_ord);
00958 }
00959
00960 return CommandCost();
00961 }
00962
00969 void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
00970 {
00971
00972 if (v->orders.list == NULL) {
00973 v->orders.list = new OrderList(new_o, v);
00974 } else {
00975 v->orders.list->InsertOrderAt(new_o, sel_ord);
00976 }
00977
00978 Vehicle *u = v->FirstShared();
00979 DeleteOrderWarnings(u);
00980 for (; u != NULL; u = u->NextShared()) {
00981 assert(v->orders.list == u->orders.list);
00982
00983
00984
00985
00986
00987 if (sel_ord <= u->cur_real_order_index) {
00988 uint cur = u->cur_real_order_index + 1;
00989
00990 if (cur < u->GetNumOrders()) {
00991 u->cur_real_order_index = cur;
00992 }
00993 }
00994 if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
00995
00996
00997
00998 uint16 &gv_flags = u->GetGroundVehicleFlags();
00999 SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
01000 }
01001 if (sel_ord <= u->cur_implicit_order_index) {
01002 uint cur = u->cur_implicit_order_index + 1;
01003
01004 if (cur < u->GetNumOrders()) {
01005 u->cur_implicit_order_index = cur;
01006 }
01007 }
01008
01009 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
01010 }
01011
01012
01013 VehicleOrderID cur_order_id = 0;
01014 Order *order;
01015 FOR_VEHICLE_ORDERS(v, order) {
01016 if (order->IsType(OT_CONDITIONAL)) {
01017 VehicleOrderID order_id = order->GetConditionSkipToOrder();
01018 if (order_id >= sel_ord) {
01019 order->SetConditionSkipToOrder(order_id + 1);
01020 }
01021 if (order_id == cur_order_id) {
01022 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
01023 }
01024 }
01025 cur_order_id++;
01026 }
01027
01028
01029 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
01030 }
01031
01037 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
01038 {
01039 if (flags & DC_EXEC) {
01040 DeleteVehicleOrders(dst);
01041 InvalidateVehicleOrder(dst, -1);
01042
01043 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01044 }
01045 return CommandCost();
01046 }
01047
01057 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01058 {
01059 VehicleID veh_id = GB(p1, 0, 20);
01060 VehicleOrderID sel_ord = GB(p2, 0, 8);
01061
01062 Vehicle *v = Vehicle::GetIfValid(veh_id);
01063
01064 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01065
01066 CommandCost ret = CheckOwnership(v->owner);
01067 if (ret.Failed()) return ret;
01068
01069
01070 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
01071
01072 if (v->GetOrder(sel_ord) == NULL) return CMD_ERROR;
01073
01074 if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
01075 return CommandCost();
01076 }
01077
01082 static void CancelLoadingDueToDeletedOrder(Vehicle *v)
01083 {
01084 assert(v->current_order.IsType(OT_LOADING));
01085
01086
01087 v->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
01088
01089
01090 if (v->current_order.GetLoadType() & OLFB_FULL_LOAD) v->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE);
01091 }
01092
01098 void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
01099 {
01100 v->orders.list->DeleteOrderAt(sel_ord);
01101
01102 Vehicle *u = v->FirstShared();
01103 DeleteOrderWarnings(u);
01104 for (; u != NULL; u = u->NextShared()) {
01105 assert(v->orders.list == u->orders.list);
01106
01107 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
01108 CancelLoadingDueToDeletedOrder(u);
01109 }
01110
01111 if (sel_ord < u->cur_real_order_index) {
01112 u->cur_real_order_index--;
01113 } else if (sel_ord == u->cur_real_order_index) {
01114 u->UpdateRealOrderIndex();
01115 }
01116
01117 if (sel_ord < u->cur_implicit_order_index) {
01118 u->cur_implicit_order_index--;
01119 } else if (sel_ord == u->cur_implicit_order_index) {
01120
01121 if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
01122
01123
01124 while (u->cur_implicit_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_implicit_order_index)->IsType(OT_IMPLICIT)) {
01125 u->cur_implicit_order_index++;
01126 if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
01127 }
01128 }
01129
01130
01131 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
01132 }
01133
01134
01135 VehicleOrderID cur_order_id = 0;
01136 Order *order = NULL;
01137 FOR_VEHICLE_ORDERS(v, order) {
01138 if (order->IsType(OT_CONDITIONAL)) {
01139 VehicleOrderID order_id = order->GetConditionSkipToOrder();
01140 if (order_id >= sel_ord) {
01141 order_id = max(order_id - 1, 0);
01142 }
01143 if (order_id == cur_order_id) {
01144 order_id = (order_id + 1) % v->GetNumOrders();
01145 }
01146 order->SetConditionSkipToOrder(order_id);
01147 }
01148 cur_order_id++;
01149 }
01150
01151 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
01152 }
01153
01163 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01164 {
01165 VehicleID veh_id = GB(p1, 0, 20);
01166 VehicleOrderID sel_ord = GB(p2, 0, 8);
01167
01168 Vehicle *v = Vehicle::GetIfValid(veh_id);
01169
01170 if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
01171
01172 CommandCost ret = CheckOwnership(v->owner);
01173 if (ret.Failed()) return ret;
01174
01175 if (flags & DC_EXEC) {
01176 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
01177
01178 v->cur_implicit_order_index = v->cur_real_order_index = sel_ord;
01179 v->UpdateRealOrderIndex();
01180
01181 InvalidateVehicleOrder(v, -2);
01182 }
01183
01184
01185 if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
01186 if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
01187
01188 return CommandCost();
01189 }
01190
01204 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01205 {
01206 VehicleID veh = GB(p1, 0, 20);
01207 VehicleOrderID moving_order = GB(p2, 0, 16);
01208 VehicleOrderID target_order = GB(p2, 16, 16);
01209
01210 Vehicle *v = Vehicle::GetIfValid(veh);
01211 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01212
01213 CommandCost ret = CheckOwnership(v->owner);
01214 if (ret.Failed()) return ret;
01215
01216
01217 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
01218 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
01219
01220 Order *moving_one = v->GetOrder(moving_order);
01221
01222 if (moving_one == NULL) return CMD_ERROR;
01223
01224 if (flags & DC_EXEC) {
01225 v->orders.list->MoveOrder(moving_order, target_order);
01226
01227
01228 Vehicle *u = v->FirstShared();
01229
01230 DeleteOrderWarnings(u);
01231
01232 for (; u != NULL; u = u->NextShared()) {
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249 if (u->cur_real_order_index == moving_order) {
01250 u->cur_real_order_index = target_order;
01251 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
01252 u->cur_real_order_index--;
01253 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
01254 u->cur_real_order_index++;
01255 }
01256
01257 if (u->cur_implicit_order_index == moving_order) {
01258 u->cur_implicit_order_index = target_order;
01259 } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
01260 u->cur_implicit_order_index--;
01261 } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
01262 u->cur_implicit_order_index++;
01263 }
01264
01265 assert(v->orders.list == u->orders.list);
01266
01267 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
01268 }
01269
01270
01271 Order *order;
01272 FOR_VEHICLE_ORDERS(v, order) {
01273 if (order->IsType(OT_CONDITIONAL)) {
01274 VehicleOrderID order_id = order->GetConditionSkipToOrder();
01275 if (order_id == moving_order) {
01276 order_id = target_order;
01277 } else if (order_id > moving_order && order_id <= target_order) {
01278 order_id--;
01279 } else if (order_id < moving_order && order_id >= target_order) {
01280 order_id++;
01281 }
01282 order->SetConditionSkipToOrder(order_id);
01283 }
01284 }
01285
01286
01287 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
01288 }
01289
01290 return CommandCost();
01291 }
01292
01308 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01309 {
01310 VehicleOrderID sel_ord = GB(p1, 20, 8);
01311 VehicleID veh = GB(p1, 0, 20);
01312 ModifyOrderFlags mof = Extract<ModifyOrderFlags, 0, 4>(p2);
01313 uint16 data = GB(p2, 4, 11);
01314
01315 if (mof >= MOF_END) return CMD_ERROR;
01316
01317 Vehicle *v = Vehicle::GetIfValid(veh);
01318 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01319
01320 CommandCost ret = CheckOwnership(v->owner);
01321 if (ret.Failed()) return ret;
01322
01323
01324 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
01325
01326 Order *order = v->GetOrder(sel_ord);
01327 switch (order->GetType()) {
01328 case OT_GOTO_STATION:
01329 if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE) return CMD_ERROR;
01330 break;
01331
01332 case OT_GOTO_DEPOT:
01333 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
01334 break;
01335
01336 case OT_GOTO_WAYPOINT:
01337 if (mof != MOF_NON_STOP) return CMD_ERROR;
01338 break;
01339
01340 case OT_CONDITIONAL:
01341 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
01342 break;
01343
01344 default:
01345 return CMD_ERROR;
01346 }
01347
01348 switch (mof) {
01349 default: NOT_REACHED();
01350
01351 case MOF_NON_STOP:
01352 if (!v->IsGroundVehicle()) return CMD_ERROR;
01353 if (data >= ONSF_END) return CMD_ERROR;
01354 if (data == order->GetNonStopType()) return CMD_ERROR;
01355 break;
01356
01357 case MOF_STOP_LOCATION:
01358 if (v->type != VEH_TRAIN) return CMD_ERROR;
01359 if (data >= OSL_END) return CMD_ERROR;
01360 break;
01361
01362 case MOF_UNLOAD:
01363 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
01364
01365 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
01366 if (data == order->GetUnloadType()) return CMD_ERROR;
01367 break;
01368
01369 case MOF_LOAD:
01370 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
01371 if (data == order->GetLoadType()) return CMD_ERROR;
01372 break;
01373
01374 case MOF_DEPOT_ACTION:
01375 if (data >= DA_END) return CMD_ERROR;
01376 break;
01377
01378 case MOF_COND_VARIABLE:
01379 if (data >= OCV_END) return CMD_ERROR;
01380 break;
01381
01382 case MOF_COND_COMPARATOR:
01383 if (data >= OCC_END) return CMD_ERROR;
01384 switch (order->GetConditionVariable()) {
01385 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01386
01387 case OCV_REQUIRES_SERVICE:
01388 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
01389 break;
01390
01391 default:
01392 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
01393 break;
01394 }
01395 break;
01396
01397 case MOF_COND_VALUE:
01398 switch (order->GetConditionVariable()) {
01399 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01400
01401 case OCV_LOAD_PERCENTAGE:
01402 case OCV_RELIABILITY:
01403 if (data > 100) return CMD_ERROR;
01404 break;
01405
01406 default:
01407 if (data > 2047) return CMD_ERROR;
01408 break;
01409 }
01410 break;
01411
01412 case MOF_COND_DESTINATION:
01413 if (data >= v->GetNumOrders()) return CMD_ERROR;
01414 break;
01415 }
01416
01417 if (flags & DC_EXEC) {
01418 switch (mof) {
01419 case MOF_NON_STOP:
01420 order->SetNonStopType((OrderNonStopFlags)data);
01421 if (data & ONSF_NO_STOP_AT_DESTINATION_STATION) order->SetRefit(CT_NO_REFIT);
01422 break;
01423
01424 case MOF_STOP_LOCATION:
01425 order->SetStopLocation((OrderStopLocation)data);
01426 break;
01427
01428 case MOF_UNLOAD:
01429 order->SetUnloadType((OrderUnloadFlags)data);
01430 break;
01431
01432 case MOF_LOAD:
01433 order->SetLoadType((OrderLoadFlags)data);
01434 if (data & OLFB_NO_LOAD) order->SetRefit(CT_NO_REFIT);
01435 break;
01436
01437 case MOF_DEPOT_ACTION: {
01438 switch (data) {
01439 case DA_ALWAYS_GO:
01440 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01441 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01442 break;
01443
01444 case DA_SERVICE:
01445 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
01446 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01447 order->SetRefit(CT_NO_REFIT);
01448 break;
01449
01450 case DA_STOP:
01451 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01452 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
01453 order->SetRefit(CT_NO_REFIT);
01454 break;
01455
01456 default:
01457 NOT_REACHED();
01458 }
01459 break;
01460 }
01461
01462 case MOF_COND_VARIABLE: {
01463 order->SetConditionVariable((OrderConditionVariable)data);
01464
01465 OrderConditionComparator occ = order->GetConditionComparator();
01466 switch (order->GetConditionVariable()) {
01467 case OCV_UNCONDITIONALLY:
01468 order->SetConditionComparator(OCC_EQUALS);
01469 order->SetConditionValue(0);
01470 break;
01471
01472 case OCV_REQUIRES_SERVICE:
01473 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
01474 break;
01475
01476 case OCV_LOAD_PERCENTAGE:
01477 case OCV_RELIABILITY:
01478 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
01479
01480 default:
01481 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
01482 break;
01483 }
01484 break;
01485 }
01486
01487 case MOF_COND_COMPARATOR:
01488 order->SetConditionComparator((OrderConditionComparator)data);
01489 break;
01490
01491 case MOF_COND_VALUE:
01492 order->SetConditionValue(data);
01493 break;
01494
01495 case MOF_COND_DESTINATION:
01496 order->SetConditionSkipToOrder(data);
01497 break;
01498
01499 default: NOT_REACHED();
01500 }
01501
01502
01503 Vehicle *u = v->FirstShared();
01504 DeleteOrderWarnings(u);
01505 for (; u != NULL; u = u->NextShared()) {
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515 if (sel_ord == u->cur_real_order_index &&
01516 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
01517 u->current_order.GetLoadType() != order->GetLoadType()) {
01518 u->current_order.SetLoadType(order->GetLoadType());
01519 }
01520 InvalidateVehicleOrder(u, -2);
01521 }
01522 }
01523
01524 return CommandCost();
01525 }
01526
01533 bool CheckAircraftOrderDistance(const Aircraft *v, const Order *first)
01534 {
01535 if (first == NULL || v->acache.cached_max_range == 0) return true;
01536
01537
01538
01539 for (const Order *o = first; o != NULL; o = o->next) {
01540 switch (o->GetType()) {
01541 case OT_GOTO_STATION:
01542 case OT_GOTO_DEPOT:
01543 case OT_GOTO_WAYPOINT:
01544
01545 if (GetOrderDistance(o, o->next != NULL ? o->next : first, v) > v->acache.cached_max_range_sqr) return false;
01546 break;
01547
01548 default: break;
01549 }
01550 }
01551
01552 return true;
01553 }
01554
01566 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01567 {
01568 VehicleID veh_src = GB(p2, 0, 20);
01569 VehicleID veh_dst = GB(p1, 0, 20);
01570
01571 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
01572 if (dst == NULL || !dst->IsPrimaryVehicle()) return CMD_ERROR;
01573
01574 CommandCost ret = CheckOwnership(dst->owner);
01575 if (ret.Failed()) return ret;
01576
01577 switch (GB(p1, 30, 2)) {
01578 case CO_SHARE: {
01579 Vehicle *src = Vehicle::GetIfValid(veh_src);
01580
01581
01582 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01583
01584 CommandCost ret = CheckOwnership(src->owner);
01585 if (ret.Failed()) return ret;
01586
01587
01588 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
01589 return CMD_ERROR;
01590 }
01591
01592
01593 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
01594
01595 const Order *order;
01596
01597 FOR_VEHICLE_ORDERS(src, order) {
01598 if (OrderGoesToStation(dst, order) &&
01599 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01600 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01601 }
01602 }
01603
01604
01605 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src->GetFirstOrder())) {
01606 return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
01607 }
01608
01609 if (src->orders.list == NULL && !OrderList::CanAllocateItem()) {
01610 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01611 }
01612
01613 if (flags & DC_EXEC) {
01614
01615
01616
01617 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
01618
01619 dst->orders.list = src->orders.list;
01620
01621
01622 dst->AddToShared(src);
01623
01624 InvalidateVehicleOrder(dst, -1);
01625 InvalidateVehicleOrder(src, -2);
01626
01627 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01628 }
01629 break;
01630 }
01631
01632 case CO_COPY: {
01633 Vehicle *src = Vehicle::GetIfValid(veh_src);
01634
01635
01636 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01637
01638 CommandCost ret = CheckOwnership(src->owner);
01639 if (ret.Failed()) return ret;
01640
01641
01642
01643 const Order *order;
01644 FOR_VEHICLE_ORDERS(src, order) {
01645 if (OrderGoesToStation(dst, order) &&
01646 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01647 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01648 }
01649 }
01650
01651
01652 if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src->GetFirstOrder())) {
01653 return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
01654 }
01655
01656
01657 int delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
01658 if (!Order::CanAllocateItem(delta) ||
01659 ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
01660 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01661 }
01662
01663 if (flags & DC_EXEC) {
01664 const Order *order;
01665 Order *first = NULL;
01666 Order **order_dst;
01667
01668
01669
01670
01671 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
01672
01673 order_dst = &first;
01674 FOR_VEHICLE_ORDERS(src, order) {
01675 *order_dst = new Order();
01676 (*order_dst)->AssignOrder(*order);
01677 order_dst = &(*order_dst)->next;
01678 }
01679 if (dst->orders.list == NULL) {
01680 dst->orders.list = new OrderList(first, dst);
01681 } else {
01682 assert(dst->orders.list->GetFirstOrder() == NULL);
01683 assert(!dst->orders.list->IsShared());
01684 delete dst->orders.list;
01685 assert(OrderList::CanAllocateItem());
01686 dst->orders.list = new OrderList(first, dst);
01687 }
01688
01689 InvalidateVehicleOrder(dst, -1);
01690
01691 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01692 }
01693 break;
01694 }
01695
01696 case CO_UNSHARE: return DecloneOrder(dst, flags);
01697 default: return CMD_ERROR;
01698 }
01699
01700 return CommandCost();
01701 }
01702
01715 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01716 {
01717 VehicleID veh = GB(p1, 0, 20);
01718 VehicleOrderID order_number = GB(p2, 16, 8);
01719 CargoID cargo = GB(p2, 0, 8);
01720 byte subtype = GB(p2, 8, 8);
01721
01722 if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT && cargo != CT_AUTO_REFIT) return CMD_ERROR;
01723
01724 const Vehicle *v = Vehicle::GetIfValid(veh);
01725 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01726
01727 CommandCost ret = CheckOwnership(v->owner);
01728 if (ret.Failed()) return ret;
01729
01730 Order *order = v->GetOrder(order_number);
01731 if (order == NULL) return CMD_ERROR;
01732
01733
01734 if (cargo == CT_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
01735
01736 if (flags & DC_EXEC) {
01737 order->SetRefit(cargo, subtype);
01738
01739
01740 if (cargo != CT_NO_REFIT) {
01741 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01742 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01743 }
01744
01745 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
01746
01747 InvalidateVehicleOrder(u, -2);
01748
01749
01750 if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
01751 u->current_order.SetRefit(cargo, subtype);
01752 }
01753 }
01754 }
01755
01756 return CommandCost();
01757 }
01758
01759
01765 void CheckOrders(const Vehicle *v)
01766 {
01767
01768 if (_settings_client.gui.order_review_system == 0) return;
01769
01770
01771 if (v->vehstatus & VS_CRASHED) return;
01772
01773
01774 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
01775
01776
01777 if (v->FirstShared() != v) return;
01778
01779
01780 if (v->owner == _local_company && v->day_counter % 20 == 0) {
01781 int n_st, problem_type = -1;
01782 const Order *order;
01783 int message = 0;
01784
01785
01786 n_st = 0;
01787
01788 FOR_VEHICLE_ORDERS(v, order) {
01789
01790 if (order->IsType(OT_DUMMY)) {
01791 problem_type = 1;
01792 break;
01793 }
01794
01795 if (order->IsType(OT_GOTO_STATION)) {
01796 const Station *st = Station::Get(order->GetDestination());
01797
01798 n_st++;
01799 if (!CanVehicleUseStation(v, st)) problem_type = 3;
01800 }
01801 }
01802
01803
01804 if (v->GetNumOrders() > 1) {
01805 const Order *last = v->GetLastOrder();
01806
01807 if (v->orders.list->GetFirstOrder()->Equals(*last)) {
01808 problem_type = 2;
01809 }
01810 }
01811
01812
01813 if (n_st < 2 && problem_type == -1) problem_type = 0;
01814
01815 #ifndef NDEBUG
01816 if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
01817 #endif
01818
01819
01820 if (problem_type < 0) return;
01821
01822 message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
01823
01824
01825 SetDParam(0, v->index);
01826 AddVehicleNewsItem(
01827 message,
01828 NS_ADVICE,
01829 v->index
01830 );
01831 }
01832 }
01833
01839 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01840 {
01841 Vehicle *v;
01842
01843
01844
01845
01846
01847
01848 FOR_ALL_VEHICLES(v) {
01849 Order *order;
01850
01851 order = &v->current_order;
01852 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01853 v->current_order.GetDestination() == destination) {
01854 order->MakeDummy();
01855 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01856 }
01857
01858
01859 int id = -1;
01860 FOR_VEHICLE_ORDERS(v, order) {
01861 id++;
01862 restart:
01863
01864 OrderType ot = order->GetType();
01865 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
01866 if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
01867 if (ot == type && order->GetDestination() == destination) {
01868
01869
01870
01871 if (order->IsType(OT_IMPLICIT)) {
01872 order = order->next;
01873 DeleteOrder(v, id);
01874 if (order != NULL) goto restart;
01875 break;
01876 }
01877
01878 order->MakeDummy();
01879 for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
01880
01881 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
01882 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
01883 }
01884 }
01885 }
01886 }
01887
01888 OrderBackup::RemoveOrder(type, destination);
01889 }
01890
01895 bool Vehicle::HasDepotOrder() const
01896 {
01897 const Order *order;
01898
01899 FOR_VEHICLE_ORDERS(this, order) {
01900 if (order->IsType(OT_GOTO_DEPOT)) return true;
01901 }
01902
01903 return false;
01904 }
01905
01915 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
01916 {
01917 DeleteOrderWarnings(v);
01918
01919 if (v->IsOrderListShared()) {
01920
01921 v->RemoveFromShared();
01922 v->orders.list = NULL;
01923 } else if (v->orders.list != NULL) {
01924
01925 v->orders.list->FreeChain(keep_orderlist);
01926 if (!keep_orderlist) v->orders.list = NULL;
01927 }
01928
01929 if (reset_order_indices) {
01930 v->cur_implicit_order_index = v->cur_real_order_index = 0;
01931 if (v->current_order.IsType(OT_LOADING)) {
01932 CancelLoadingDueToDeletedOrder(v);
01933 }
01934 }
01935 }
01936
01944 uint16 GetServiceIntervalClamped(uint interval, CompanyID company_id)
01945 {
01946 return (Company::Get(company_id)->settings.vehicle.servint_ispercent) ? Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
01947 }
01948
01957 static bool CheckForValidOrders(const Vehicle *v)
01958 {
01959 const Order *order;
01960
01961 FOR_VEHICLE_ORDERS(v, order) {
01962 switch (order->GetType()) {
01963 case OT_GOTO_STATION:
01964 case OT_GOTO_DEPOT:
01965 case OT_GOTO_WAYPOINT:
01966 return true;
01967
01968 default:
01969 break;
01970 }
01971 }
01972
01973 return false;
01974 }
01975
01979 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
01980 {
01981 switch (occ) {
01982 case OCC_EQUALS: return variable == value;
01983 case OCC_NOT_EQUALS: return variable != value;
01984 case OCC_LESS_THAN: return variable < value;
01985 case OCC_LESS_EQUALS: return variable <= value;
01986 case OCC_MORE_THAN: return variable > value;
01987 case OCC_MORE_EQUALS: return variable >= value;
01988 case OCC_IS_TRUE: return variable != 0;
01989 case OCC_IS_FALSE: return variable == 0;
01990 default: NOT_REACHED();
01991 }
01992 }
01993
02000 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
02001 {
02002 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
02003
02004 bool skip_order = false;
02005 OrderConditionComparator occ = order->GetConditionComparator();
02006 uint16 value = order->GetConditionValue();
02007
02008 switch (order->GetConditionVariable()) {
02009 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
02010 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
02011 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
02012 case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
02013 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
02014 case OCV_UNCONDITIONALLY: skip_order = true; break;
02015 case OCV_REMAINING_LIFETIME: skip_order = OrderConditionCompare(occ, max(v->max_age - v->age + DAYS_IN_LEAP_YEAR - 1, 0) / DAYS_IN_LEAP_YEAR, value); break;
02016 default: NOT_REACHED();
02017 }
02018
02019 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
02020 }
02021
02029 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
02030 {
02031 if (conditional_depth > v->GetNumOrders()) return false;
02032
02033 switch (order->GetType()) {
02034 case OT_GOTO_STATION:
02035 v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
02036 return true;
02037
02038 case OT_GOTO_DEPOT:
02039 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
02040 assert(!pbs_look_ahead);
02041 UpdateVehicleTimetable(v, true);
02042 v->IncrementRealOrderIndex();
02043 break;
02044 }
02045
02046 if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
02047
02048 TileIndex location;
02049 DestinationID destination;
02050 bool reverse;
02051
02052 if (v->FindClosestDepot(&location, &destination, &reverse)) {
02053
02054 if (pbs_look_ahead && reverse) return false;
02055
02056 v->dest_tile = location;
02057 v->current_order.MakeGoToDepot(destination, v->current_order.GetDepotOrderType(), v->current_order.GetNonStopType(), (OrderDepotActionFlags)(v->current_order.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT), v->current_order.GetRefitCargo(), v->current_order.GetRefitSubtype());
02058
02059
02060 if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
02061
02062 if (v->type == VEH_AIRCRAFT) {
02063 Aircraft *a = Aircraft::From(v);
02064 if (a->state == FLYING && a->targetairport != destination) {
02065
02066 extern void AircraftNextAirportPos_and_Order(Aircraft *a);
02067 AircraftNextAirportPos_and_Order(a);
02068 }
02069 }
02070 return true;
02071 }
02072
02073
02074 if (pbs_look_ahead) return false;
02075
02076 UpdateVehicleTimetable(v, true);
02077 v->IncrementRealOrderIndex();
02078 } else {
02079 if (v->type != VEH_AIRCRAFT) {
02080 v->dest_tile = Depot::Get(order->GetDestination())->xy;
02081 }
02082 return true;
02083 }
02084 break;
02085
02086 case OT_GOTO_WAYPOINT:
02087 v->dest_tile = Waypoint::Get(order->GetDestination())->xy;
02088 return true;
02089
02090 case OT_CONDITIONAL: {
02091 assert(!pbs_look_ahead);
02092 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
02093 if (next_order != INVALID_VEH_ORDER_ID) {
02094
02095
02096 UpdateVehicleTimetable(v, false);
02097 v->cur_implicit_order_index = v->cur_real_order_index = next_order;
02098 v->UpdateRealOrderIndex();
02099 v->current_order_time += v->GetOrder(v->cur_real_order_index)->travel_time;
02100
02101
02102
02103 if (v->IsGroundVehicle()) {
02104 uint16 &gv_flags = v->GetGroundVehicleFlags();
02105 SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
02106 }
02107 } else {
02108 UpdateVehicleTimetable(v, true);
02109 v->IncrementRealOrderIndex();
02110 }
02111 break;
02112 }
02113
02114 default:
02115 v->dest_tile = 0;
02116 return false;
02117 }
02118
02119 assert(v->cur_implicit_order_index < v->GetNumOrders());
02120 assert(v->cur_real_order_index < v->GetNumOrders());
02121
02122
02123 order = v->GetOrder(v->cur_real_order_index);
02124 if (order != NULL && order->IsType(OT_IMPLICIT)) {
02125 assert(v->GetNumManualOrders() == 0);
02126 order = NULL;
02127 }
02128
02129 if (order == NULL) {
02130 v->current_order.Free();
02131 v->dest_tile = 0;
02132 return false;
02133 }
02134
02135 v->current_order = *order;
02136 return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
02137 }
02138
02146 bool ProcessOrders(Vehicle *v)
02147 {
02148 switch (v->current_order.GetType()) {
02149 case OT_GOTO_DEPOT:
02150
02151 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
02152 break;
02153
02154 case OT_LOADING:
02155 return false;
02156
02157 case OT_LEAVESTATION:
02158 if (v->type != VEH_AIRCRAFT) return false;
02159 break;
02160
02161 default: break;
02162 }
02163
02171 bool may_reverse = v->current_order.IsType(OT_NOTHING);
02172
02173
02174 if (((v->current_order.IsType(OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) || v->current_order.IsType(OT_GOTO_WAYPOINT)) &&
02175 IsTileType(v->tile, MP_STATION) &&
02176 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
02177 v->DeleteUnreachedImplicitOrders();
02178
02179
02180
02181
02182 v->last_station_visited = v->current_order.GetDestination();
02183 UpdateVehicleTimetable(v, true);
02184 v->IncrementImplicitOrderIndex();
02185 }
02186
02187
02188 assert(v->cur_implicit_order_index == 0 || v->cur_implicit_order_index < v->GetNumOrders());
02189 v->UpdateRealOrderIndex();
02190
02191 const Order *order = v->GetOrder(v->cur_real_order_index);
02192 if (order != NULL && order->IsType(OT_IMPLICIT)) {
02193 assert(v->GetNumManualOrders() == 0);
02194 order = NULL;
02195 }
02196
02197
02198 if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
02199 if (v->type == VEH_AIRCRAFT) {
02200
02201 extern void HandleMissingAircraftOrders(Aircraft *v);
02202 HandleMissingAircraftOrders(Aircraft::From(v));
02203 return false;
02204 }
02205
02206 v->current_order.Free();
02207 v->dest_tile = 0;
02208 return false;
02209 }
02210
02211
02212 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
02213 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
02214 return false;
02215 }
02216
02217
02218 v->current_order = *order;
02219
02220 InvalidateVehicleOrder(v, -2);
02221 switch (v->type) {
02222 default:
02223 NOT_REACHED();
02224
02225 case VEH_ROAD:
02226 case VEH_TRAIN:
02227 break;
02228
02229 case VEH_AIRCRAFT:
02230 case VEH_SHIP:
02231 SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
02232 break;
02233 }
02234
02235 return UpdateOrderDest(v, order) && may_reverse;
02236 }
02237
02245 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
02246 {
02247 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
02248
02249 return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
02250 v->last_station_visited != station &&
02251
02252 !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
02253 }
02254
02255 bool Order::CanLoadOrUnload() const
02256 {
02257 return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
02258 (this->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0 &&
02259 ((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
02260 (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
02261 }
02262
02269 bool Order::CanLeaveWithCargo(bool has_cargo) const
02270 {
02271 return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
02272 (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
02273 }