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 "aircraft.h"
00026 #include "roadveh.h"
00027 #include "station_base.h"
00028 #include "waypoint_base.h"
00029 #include "company_base.h"
00030
00031 #include "table/strings.h"
00032
00033
00034
00035
00036 assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
00037 assert_compile(sizeof(DestinationID) >= sizeof(StationID));
00038
00039 OrderPool _order_pool("Order");
00040 INSTANTIATE_POOL_METHODS(Order)
00041 OrderListPool _orderlist_pool("OrderList");
00042 INSTANTIATE_POOL_METHODS(OrderList)
00043
00048 void Order::Free()
00049 {
00050 this->type = OT_NOTHING;
00051 this->flags = 0;
00052 this->dest = 0;
00053 this->next = NULL;
00054 }
00055
00060 void Order::MakeGoToStation(StationID destination)
00061 {
00062 this->type = OT_GOTO_STATION;
00063 this->flags = 0;
00064 this->dest = destination;
00065 }
00066
00076 void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoID cargo, byte subtype)
00077 {
00078 this->type = OT_GOTO_DEPOT;
00079 this->SetDepotOrderType(order);
00080 this->SetDepotActionType(action);
00081 this->SetNonStopType(non_stop_type);
00082 this->dest = destination;
00083 this->SetRefit(cargo, subtype);
00084 }
00085
00090 void Order::MakeGoToWaypoint(StationID destination)
00091 {
00092 this->type = OT_GOTO_WAYPOINT;
00093 this->flags = 0;
00094 this->dest = destination;
00095 }
00096
00101 void Order::MakeLoading(bool ordered)
00102 {
00103 this->type = OT_LOADING;
00104 if (!ordered) this->flags = 0;
00105 }
00106
00110 void Order::MakeLeaveStation()
00111 {
00112 this->type = OT_LEAVESTATION;
00113 this->flags = 0;
00114 }
00115
00119 void Order::MakeDummy()
00120 {
00121 this->type = OT_DUMMY;
00122 this->flags = 0;
00123 }
00124
00129 void Order::MakeConditional(VehicleOrderID order)
00130 {
00131 this->type = OT_CONDITIONAL;
00132 this->flags = order;
00133 this->dest = 0;
00134 }
00135
00140 void Order::MakeAutomatic(StationID destination)
00141 {
00142 this->type = OT_AUTOMATIC;
00143 this->dest = destination;
00144 }
00145
00152 void Order::SetRefit(CargoID cargo, byte subtype)
00153 {
00154 this->refit_cargo = cargo;
00155 this->refit_subtype = subtype;
00156 }
00157
00163 bool Order::Equals(const Order &other) const
00164 {
00165
00166
00167
00168
00169
00170 if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
00171 ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
00172 (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
00173 return this->GetDepotOrderType() == other.GetDepotOrderType() &&
00174 (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
00175 }
00176
00177 return this->type == other.type && this->flags == other.flags && this->dest == other.dest;
00178 }
00179
00186 uint32 Order::Pack() const
00187 {
00188 return this->dest << 16 | this->flags << 8 | this->type;
00189 }
00190
00196 uint16 Order::MapOldOrder() const
00197 {
00198 uint16 order = this->GetType();
00199 switch (this->type) {
00200 case OT_GOTO_STATION:
00201 if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
00202 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
00203 if (this->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) SetBit(order, 7);
00204 order |= GB(this->GetDestination(), 0, 8) << 8;
00205 break;
00206 case OT_GOTO_DEPOT:
00207 if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
00208 SetBit(order, 7);
00209 order |= GB(this->GetDestination(), 0, 8) << 8;
00210 break;
00211 case OT_LOADING:
00212 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
00213 break;
00214 }
00215 return order;
00216 }
00217
00222 Order::Order(uint32 packed)
00223 {
00224 this->type = (OrderType)GB(packed, 0, 8);
00225 this->flags = GB(packed, 8, 8);
00226 this->dest = GB(packed, 16, 16);
00227 this->next = NULL;
00228 this->refit_cargo = CT_NO_REFIT;
00229 this->refit_subtype = 0;
00230 this->wait_time = 0;
00231 this->travel_time = 0;
00232 }
00233
00239 void InvalidateVehicleOrder(const Vehicle *v, int data)
00240 {
00241 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
00242
00243 if (data != 0) {
00244
00245 InvalidateWindowData(WC_VEHICLE_ORDERS, v->index, data);
00246 InvalidateWindowData(WC_VEHICLE_TIMETABLE, v->index, data);
00247 return;
00248 }
00249
00250 SetWindowDirty(WC_VEHICLE_ORDERS, v->index);
00251 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00252 }
00253
00261 void Order::AssignOrder(const Order &other)
00262 {
00263 this->type = other.type;
00264 this->flags = other.flags;
00265 this->dest = other.dest;
00266
00267 this->refit_cargo = other.refit_cargo;
00268 this->refit_subtype = other.refit_subtype;
00269
00270 this->wait_time = other.wait_time;
00271 this->travel_time = other.travel_time;
00272 }
00273
00279 void OrderList::Initialize(Order *chain, Vehicle *v)
00280 {
00281 this->first = chain;
00282 this->first_shared = v;
00283
00284 this->num_orders = 0;
00285 this->num_manual_orders = 0;
00286 this->num_vehicles = 1;
00287 this->timetable_duration = 0;
00288
00289 for (Order *o = this->first; o != NULL; o = o->next) {
00290 ++this->num_orders;
00291 if (!o->IsType(OT_AUTOMATIC)) ++this->num_manual_orders;
00292 this->timetable_duration += o->wait_time + o->travel_time;
00293 }
00294
00295 for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) {
00296 ++this->num_vehicles;
00297 this->first_shared = u;
00298 }
00299
00300 for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles;
00301 }
00302
00308 void OrderList::FreeChain(bool keep_orderlist)
00309 {
00310 Order *next;
00311 for (Order *o = this->first; o != NULL; o = next) {
00312 next = o->next;
00313 delete o;
00314 }
00315
00316 if (keep_orderlist) {
00317 this->first = NULL;
00318 this->num_orders = 0;
00319 this->num_manual_orders = 0;
00320 this->timetable_duration = 0;
00321 } else {
00322 delete this;
00323 }
00324 }
00325
00331 Order *OrderList::GetOrderAt(int index) const
00332 {
00333 if (index < 0) return NULL;
00334
00335 Order *order = this->first;
00336
00337 while (order != NULL && index-- > 0) {
00338 order = order->next;
00339 }
00340 return order;
00341 }
00342
00348 void OrderList::InsertOrderAt(Order *new_order, int index)
00349 {
00350 if (this->first == NULL) {
00351 this->first = new_order;
00352 } else {
00353 if (index == 0) {
00354
00355 new_order->next = this->first;
00356 this->first = new_order;
00357 } else if (index >= this->num_orders) {
00358
00359 this->GetLastOrder()->next = new_order;
00360 } else {
00361
00362 Order *order = this->GetOrderAt(index - 1);
00363 new_order->next = order->next;
00364 order->next = new_order;
00365 }
00366 }
00367 ++this->num_orders;
00368 if (!new_order->IsType(OT_AUTOMATIC)) ++this->num_manual_orders;
00369 this->timetable_duration += new_order->wait_time + new_order->travel_time;
00370 }
00371
00372
00377 void OrderList::DeleteOrderAt(int index)
00378 {
00379 if (index >= this->num_orders) return;
00380
00381 Order *to_remove;
00382
00383 if (index == 0) {
00384 to_remove = this->first;
00385 this->first = to_remove->next;
00386 } else {
00387 Order *prev = GetOrderAt(index - 1);
00388 to_remove = prev->next;
00389 prev->next = to_remove->next;
00390 }
00391 --this->num_orders;
00392 if (!to_remove->IsType(OT_AUTOMATIC)) --this->num_manual_orders;
00393 this->timetable_duration -= (to_remove->wait_time + to_remove->travel_time);
00394 delete to_remove;
00395 }
00396
00402 void OrderList::MoveOrder(int from, int to)
00403 {
00404 if (from >= this->num_orders || to >= this->num_orders || from == to) return;
00405
00406 Order *moving_one;
00407
00408
00409 if (from == 0) {
00410 moving_one = this->first;
00411 this->first = moving_one->next;
00412 } else {
00413 Order *one_before = GetOrderAt(from - 1);
00414 moving_one = one_before->next;
00415 one_before->next = moving_one->next;
00416 }
00417
00418
00419 if (to == 0) {
00420 moving_one->next = this->first;
00421 this->first = moving_one;
00422 } else {
00423 Order *one_before = GetOrderAt(to - 1);
00424 moving_one->next = one_before->next;
00425 one_before->next = moving_one;
00426 }
00427 }
00428
00434 void OrderList::RemoveVehicle(Vehicle *v)
00435 {
00436 --this->num_vehicles;
00437 if (v == this->first_shared) this->first_shared = v->NextShared();
00438 }
00439
00444 bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const
00445 {
00446 for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) {
00447 if (v_shared == v) return true;
00448 }
00449
00450 return false;
00451 }
00452
00458 int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
00459 {
00460 int count = 0;
00461 for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++;
00462 return count;
00463 }
00464
00469 bool OrderList::IsCompleteTimetable() const
00470 {
00471 for (Order *o = this->first; o != NULL; o = o->next) {
00472
00473 if (o->IsType(OT_AUTOMATIC)) continue;
00474 if (!o->IsCompletelyTimetabled()) return false;
00475 }
00476 return true;
00477 }
00478
00482 void OrderList::DebugCheckSanity() const
00483 {
00484 VehicleOrderID check_num_orders = 0;
00485 VehicleOrderID check_num_manual_orders = 0;
00486 uint check_num_vehicles = 0;
00487 Ticks check_timetable_duration = 0;
00488
00489 DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
00490
00491 for (const Order *o = this->first; o != NULL; o = o->next) {
00492 ++check_num_orders;
00493 if (!o->IsType(OT_AUTOMATIC)) ++check_num_manual_orders;
00494 check_timetable_duration += o->wait_time + o->travel_time;
00495 }
00496 assert(this->num_orders == check_num_orders);
00497 assert(this->num_manual_orders == check_num_manual_orders);
00498 assert(this->timetable_duration == check_timetable_duration);
00499
00500 for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
00501 ++check_num_vehicles;
00502 assert(v->orders.list == this);
00503 }
00504 assert(this->num_vehicles == check_num_vehicles);
00505 DEBUG(misc, 6, "... detected %u orders (%u manual), %u vehicles, %i ticks",
00506 (uint)this->num_orders, (uint)this->num_manual_orders,
00507 this->num_vehicles, this->timetable_duration);
00508 }
00509
00517 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
00518 {
00519 return o->IsType(OT_GOTO_STATION) ||
00520 (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
00521 }
00522
00529 static void DeleteOrderWarnings(const Vehicle *v)
00530 {
00531 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
00532 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
00533 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
00534 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
00535 }
00536
00542 TileIndex Order::GetLocation(const Vehicle *v) const
00543 {
00544 switch (this->GetType()) {
00545 case OT_GOTO_WAYPOINT:
00546 case OT_GOTO_STATION:
00547 case OT_AUTOMATIC:
00548 return BaseStation::Get(this->GetDestination())->xy;
00549
00550 case OT_GOTO_DEPOT:
00551 if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE;
00552 return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
00553
00554 default:
00555 return INVALID_TILE;
00556 }
00557 }
00558
00559 static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0)
00560 {
00561 assert(v->type == VEH_SHIP);
00562
00563 if (cur->IsType(OT_CONDITIONAL)) {
00564 if (conditional_depth > v->GetNumOrders()) return 0;
00565
00566 conditional_depth++;
00567
00568 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
00569 int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
00570 return max(dist1, dist2);
00571 }
00572
00573 TileIndex prev_tile = prev->GetLocation(v);
00574 TileIndex cur_tile = cur->GetLocation(v);
00575 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
00576 return DistanceManhattan(prev_tile, cur_tile);
00577 }
00578
00592 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00593 {
00594 VehicleID veh = GB(p1, 0, 20);
00595 VehicleOrderID sel_ord = GB(p1, 20, 8);
00596 Order new_order(p2);
00597
00598 Vehicle *v = Vehicle::GetIfValid(veh);
00599 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00600
00601 CommandCost ret = CheckOwnership(v->owner);
00602 if (ret.Failed()) return ret;
00603
00604
00605
00606 switch (new_order.GetType()) {
00607 case OT_GOTO_STATION: {
00608 const Station *st = Station::GetIfValid(new_order.GetDestination());
00609 if (st == NULL) return CMD_ERROR;
00610
00611 if (st->owner != OWNER_NONE) {
00612 CommandCost ret = CheckOwnership(st->owner);
00613 if (ret.Failed()) return ret;
00614 }
00615
00616 if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00617 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
00618 if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
00619 }
00620
00621
00622 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
00623
00624
00625 switch (new_order.GetLoadType()) {
00626 case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
00627 default: return CMD_ERROR;
00628 }
00629 switch (new_order.GetUnloadType()) {
00630 case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
00631 default: return CMD_ERROR;
00632 }
00633
00634
00635 switch (new_order.GetStopLocation()) {
00636 case OSL_PLATFORM_NEAR_END:
00637 case OSL_PLATFORM_MIDDLE:
00638 if (v->type != VEH_TRAIN) return CMD_ERROR;
00639
00640 case OSL_PLATFORM_FAR_END:
00641 break;
00642
00643 default:
00644 return CMD_ERROR;
00645 }
00646
00647 break;
00648 }
00649
00650 case OT_GOTO_DEPOT: {
00651 if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
00652 if (v->type == VEH_AIRCRAFT) {
00653 const Station *st = Station::GetIfValid(new_order.GetDestination());
00654
00655 if (st == NULL) return CMD_ERROR;
00656
00657 CommandCost ret = CheckOwnership(st->owner);
00658 if (ret.Failed()) return ret;
00659
00660 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
00661 return CMD_ERROR;
00662 }
00663 } else {
00664 const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
00665
00666 if (dp == NULL) return CMD_ERROR;
00667
00668 CommandCost ret = CheckOwnership(GetTileOwner(dp->xy));
00669 if (ret.Failed()) return ret;
00670
00671 switch (v->type) {
00672 case VEH_TRAIN:
00673 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
00674 break;
00675
00676 case VEH_ROAD:
00677 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
00678 break;
00679
00680 case VEH_SHIP:
00681 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
00682 break;
00683
00684 default: return CMD_ERROR;
00685 }
00686 }
00687 }
00688
00689 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
00690 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
00691 if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
00692 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
00693 break;
00694 }
00695
00696 case OT_GOTO_WAYPOINT: {
00697 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
00698 if (wp == NULL) return CMD_ERROR;
00699
00700 switch (v->type) {
00701 default: return CMD_ERROR;
00702
00703 case VEH_TRAIN: {
00704 if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00705
00706 CommandCost ret = CheckOwnership(wp->owner);
00707 if (ret.Failed()) return ret;
00708 break;
00709 }
00710
00711 case VEH_SHIP:
00712 if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00713 if (wp->owner != OWNER_NONE) {
00714 CommandCost ret = CheckOwnership(wp->owner);
00715 if (ret.Failed()) return ret;
00716 }
00717 break;
00718 }
00719
00720
00721
00722
00723 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
00724 break;
00725 }
00726
00727 case OT_CONDITIONAL: {
00728 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
00729 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR;
00730 if (new_order.GetConditionVariable() > OCV_END) return CMD_ERROR;
00731
00732 OrderConditionComparator occ = new_order.GetConditionComparator();
00733 if (occ > OCC_END) return CMD_ERROR;
00734 switch (new_order.GetConditionVariable()) {
00735 case OCV_REQUIRES_SERVICE:
00736 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
00737 break;
00738
00739 case OCV_UNCONDITIONALLY:
00740 if (occ != OCC_EQUALS) return CMD_ERROR;
00741 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
00742 break;
00743
00744 case OCV_LOAD_PERCENTAGE:
00745 case OCV_RELIABILITY:
00746 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
00747
00748 default:
00749 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
00750 break;
00751 }
00752 break;
00753 }
00754
00755 default: return CMD_ERROR;
00756 }
00757
00758 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
00759
00760 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS);
00761 if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00762 if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00763
00764 if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) {
00765
00766 const Order *prev = NULL;
00767 uint n = 0;
00768
00769
00770
00771
00772 const Order *o;
00773 FOR_VEHICLE_ORDERS(v, o) {
00774 switch (o->GetType()) {
00775 case OT_GOTO_STATION:
00776 case OT_GOTO_DEPOT:
00777 case OT_GOTO_WAYPOINT:
00778 prev = o;
00779 break;
00780
00781 default: break;
00782 }
00783 if (++n == sel_ord && prev != NULL) break;
00784 }
00785 if (prev != NULL) {
00786 uint dist = GetOrderDistance(prev, &new_order, v);
00787 if (dist >= 130) {
00788 return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION);
00789 }
00790 }
00791 }
00792
00793 if (flags & DC_EXEC) {
00794 Order *new_o = new Order();
00795 new_o->AssignOrder(new_order);
00796 InsertOrder(v, new_o, sel_ord);
00797 }
00798
00799 return CommandCost();
00800 }
00801
00808 void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
00809 {
00810
00811 if (v->orders.list == NULL) {
00812 v->orders.list = new OrderList(new_o, v);
00813 } else {
00814 v->orders.list->InsertOrderAt(new_o, sel_ord);
00815 }
00816
00817 Vehicle *u = v->FirstShared();
00818 DeleteOrderWarnings(u);
00819 for (; u != NULL; u = u->NextShared()) {
00820 assert(v->orders.list == u->orders.list);
00821
00822
00823
00824
00825
00826 if (sel_ord <= u->cur_real_order_index) {
00827 uint cur = u->cur_real_order_index + 1;
00828
00829 if (cur < u->GetNumOrders()) {
00830 u->cur_real_order_index = cur;
00831 }
00832 }
00833 if (sel_ord <= u->cur_auto_order_index) {
00834 uint cur = u->cur_auto_order_index + 1;
00835
00836 if (cur < u->GetNumOrders()) {
00837 u->cur_auto_order_index = cur;
00838 }
00839 }
00840
00841 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
00842 }
00843
00844
00845 VehicleOrderID cur_order_id = 0;
00846 Order *order;
00847 FOR_VEHICLE_ORDERS(v, order) {
00848 if (order->IsType(OT_CONDITIONAL)) {
00849 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00850 if (order_id >= sel_ord) {
00851 order->SetConditionSkipToOrder(order_id + 1);
00852 }
00853 if (order_id == cur_order_id) {
00854 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00855 }
00856 }
00857 cur_order_id++;
00858 }
00859
00860
00861 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00862 }
00863
00869 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
00870 {
00871 if (flags & DC_EXEC) {
00872 DeleteVehicleOrders(dst);
00873 InvalidateVehicleOrder(dst, -1);
00874 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
00875 }
00876 return CommandCost();
00877 }
00878
00888 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00889 {
00890 VehicleID veh_id = GB(p1, 0, 20);
00891 VehicleOrderID sel_ord = GB(p2, 0, 8);
00892
00893 Vehicle *v = Vehicle::GetIfValid(veh_id);
00894
00895 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00896
00897 CommandCost ret = CheckOwnership(v->owner);
00898 if (ret.Failed()) return ret;
00899
00900
00901 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
00902
00903 if (v->GetOrder(sel_ord) == NULL) return CMD_ERROR;
00904
00905 if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
00906 return CommandCost();
00907 }
00908
00913 static void CancelLoadingDueToDeletedOrder(Vehicle *v)
00914 {
00915 assert(v->current_order.IsType(OT_LOADING));
00916
00917
00918 v->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
00919
00920
00921 if (v->current_order.GetLoadType() & OLFB_FULL_LOAD) v->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE);
00922 }
00923
00929 void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
00930 {
00931 v->orders.list->DeleteOrderAt(sel_ord);
00932
00933 Vehicle *u = v->FirstShared();
00934 DeleteOrderWarnings(u);
00935 for (; u != NULL; u = u->NextShared()) {
00936 assert(v->orders.list == u->orders.list);
00937
00938 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
00939 CancelLoadingDueToDeletedOrder(u);
00940 }
00941
00942 if (sel_ord < u->cur_real_order_index) {
00943 u->cur_real_order_index--;
00944 } else if (sel_ord == u->cur_real_order_index) {
00945 u->UpdateRealOrderIndex();
00946 }
00947
00948 if (sel_ord < u->cur_auto_order_index) {
00949 u->cur_auto_order_index--;
00950 } else if (sel_ord == u->cur_auto_order_index) {
00951
00952 if (u->cur_auto_order_index >= u->GetNumOrders()) u->cur_auto_order_index = 0;
00953
00954
00955 while (u->cur_auto_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_auto_order_index)->IsType(OT_AUTOMATIC)) {
00956 u->cur_auto_order_index++;
00957 if (u->cur_auto_order_index >= u->GetNumOrders()) u->cur_auto_order_index = 0;
00958 }
00959 }
00960
00961
00962 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
00963 }
00964
00965
00966 VehicleOrderID cur_order_id = 0;
00967 Order *order = NULL;
00968 FOR_VEHICLE_ORDERS(v, order) {
00969 if (order->IsType(OT_CONDITIONAL)) {
00970 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00971 if (order_id >= sel_ord) {
00972 order->SetConditionSkipToOrder(max(order_id - 1, 0));
00973 }
00974 if (order_id == cur_order_id) {
00975 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00976 }
00977 }
00978 cur_order_id++;
00979 }
00980
00981 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00982 }
00983
00993 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00994 {
00995 VehicleID veh_id = GB(p1, 0, 20);
00996 VehicleOrderID sel_ord = GB(p2, 0, 8);
00997
00998 Vehicle *v = Vehicle::GetIfValid(veh_id);
00999
01000 if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_auto_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
01001
01002 CommandCost ret = CheckOwnership(v->owner);
01003 if (ret.Failed()) return ret;
01004
01005 if (flags & DC_EXEC) {
01006 v->cur_auto_order_index = v->cur_real_order_index = sel_ord;
01007 v->UpdateRealOrderIndex();
01008
01009 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
01010
01011 InvalidateVehicleOrder(v, -2);
01012 }
01013
01014
01015 if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
01016 if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
01017
01018 return CommandCost();
01019 }
01020
01034 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01035 {
01036 VehicleID veh = GB(p1, 0, 20);
01037 VehicleOrderID moving_order = GB(p2, 0, 16);
01038 VehicleOrderID target_order = GB(p2, 16, 16);
01039
01040 Vehicle *v = Vehicle::GetIfValid(veh);
01041 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01042
01043 CommandCost ret = CheckOwnership(v->owner);
01044 if (ret.Failed()) return ret;
01045
01046
01047 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
01048 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
01049
01050 Order *moving_one = v->GetOrder(moving_order);
01051
01052 if (moving_one == NULL) return CMD_ERROR;
01053
01054 if (flags & DC_EXEC) {
01055 v->orders.list->MoveOrder(moving_order, target_order);
01056
01057
01058 Vehicle *u = v->FirstShared();
01059
01060 DeleteOrderWarnings(u);
01061
01062 for (; u != NULL; u = u->NextShared()) {
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079 if (u->cur_real_order_index == moving_order) {
01080 u->cur_real_order_index = target_order;
01081 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
01082 u->cur_real_order_index--;
01083 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
01084 u->cur_real_order_index++;
01085 }
01086
01087 if (u->cur_auto_order_index == moving_order) {
01088 u->cur_auto_order_index = target_order;
01089 } else if (u->cur_auto_order_index > moving_order && u->cur_auto_order_index <= target_order) {
01090 u->cur_auto_order_index--;
01091 } else if (u->cur_auto_order_index < moving_order && u->cur_auto_order_index >= target_order) {
01092 u->cur_auto_order_index++;
01093 }
01094
01095 assert(v->orders.list == u->orders.list);
01096
01097 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
01098 }
01099
01100
01101 Order *order;
01102 FOR_VEHICLE_ORDERS(v, order) {
01103 if (order->IsType(OT_CONDITIONAL)) {
01104 VehicleOrderID order_id = order->GetConditionSkipToOrder();
01105 if (order_id == moving_order) {
01106 order_id = target_order;
01107 } else if (order_id > moving_order && order_id <= target_order) {
01108 order_id--;
01109 } else if (order_id < moving_order && order_id >= target_order) {
01110 order_id++;
01111 }
01112 order->SetConditionSkipToOrder(order_id);
01113 }
01114 }
01115
01116
01117 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
01118 }
01119
01120 return CommandCost();
01121 }
01122
01138 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01139 {
01140 VehicleOrderID sel_ord = GB(p1, 20, 8);
01141 VehicleID veh = GB(p1, 0, 20);
01142 ModifyOrderFlags mof = Extract<ModifyOrderFlags, 0, 4>(p2);
01143 uint16 data = GB(p2, 4, 11);
01144
01145 if (mof >= MOF_END) return CMD_ERROR;
01146
01147 Vehicle *v = Vehicle::GetIfValid(veh);
01148 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01149
01150 CommandCost ret = CheckOwnership(v->owner);
01151 if (ret.Failed()) return ret;
01152
01153
01154 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
01155
01156 Order *order = v->GetOrder(sel_ord);
01157 switch (order->GetType()) {
01158 case OT_GOTO_STATION:
01159 if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE) return CMD_ERROR;
01160 break;
01161
01162 case OT_GOTO_DEPOT:
01163 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
01164 break;
01165
01166 case OT_GOTO_WAYPOINT:
01167 if (mof != MOF_NON_STOP) return CMD_ERROR;
01168 break;
01169
01170 case OT_CONDITIONAL:
01171 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
01172 break;
01173
01174 default:
01175 return CMD_ERROR;
01176 }
01177
01178 switch (mof) {
01179 default: NOT_REACHED();
01180
01181 case MOF_NON_STOP:
01182 if (!v->IsGroundVehicle()) return CMD_ERROR;
01183 if (data >= ONSF_END) return CMD_ERROR;
01184 if (data == order->GetNonStopType()) return CMD_ERROR;
01185 break;
01186
01187 case MOF_STOP_LOCATION:
01188 if (v->type != VEH_TRAIN) return CMD_ERROR;
01189 if (data >= OSL_END) return CMD_ERROR;
01190 break;
01191
01192 case MOF_UNLOAD:
01193 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
01194
01195 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
01196 if (data == order->GetUnloadType()) return CMD_ERROR;
01197 break;
01198
01199 case MOF_LOAD:
01200 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
01201 if (data == order->GetLoadType()) return CMD_ERROR;
01202 break;
01203
01204 case MOF_DEPOT_ACTION:
01205 if (data >= DA_END) return CMD_ERROR;
01206 break;
01207
01208 case MOF_COND_VARIABLE:
01209 if (data >= OCV_END) return CMD_ERROR;
01210 break;
01211
01212 case MOF_COND_COMPARATOR:
01213 if (data >= OCC_END) return CMD_ERROR;
01214 switch (order->GetConditionVariable()) {
01215 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01216
01217 case OCV_REQUIRES_SERVICE:
01218 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
01219 break;
01220
01221 default:
01222 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
01223 break;
01224 }
01225 break;
01226
01227 case MOF_COND_VALUE:
01228 switch (order->GetConditionVariable()) {
01229 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01230
01231 case OCV_LOAD_PERCENTAGE:
01232 case OCV_RELIABILITY:
01233 if (data > 100) return CMD_ERROR;
01234 break;
01235
01236 default:
01237 if (data > 2047) return CMD_ERROR;
01238 break;
01239 }
01240 break;
01241
01242 case MOF_COND_DESTINATION:
01243 if (data >= v->GetNumOrders()) return CMD_ERROR;
01244 break;
01245 }
01246
01247 if (flags & DC_EXEC) {
01248 switch (mof) {
01249 case MOF_NON_STOP:
01250 order->SetNonStopType((OrderNonStopFlags)data);
01251 break;
01252
01253 case MOF_STOP_LOCATION:
01254 order->SetStopLocation((OrderStopLocation)data);
01255 break;
01256
01257 case MOF_UNLOAD:
01258 order->SetUnloadType((OrderUnloadFlags)data);
01259 break;
01260
01261 case MOF_LOAD:
01262 order->SetLoadType((OrderLoadFlags)data);
01263 break;
01264
01265 case MOF_DEPOT_ACTION: {
01266 switch (data) {
01267 case DA_ALWAYS_GO:
01268 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01269 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01270 break;
01271
01272 case DA_SERVICE:
01273 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
01274 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01275 break;
01276
01277 case DA_STOP:
01278 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01279 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
01280 break;
01281
01282 default:
01283 NOT_REACHED();
01284 }
01285 break;
01286 }
01287
01288 case MOF_COND_VARIABLE: {
01289 order->SetConditionVariable((OrderConditionVariable)data);
01290
01291 OrderConditionComparator occ = order->GetConditionComparator();
01292 switch (order->GetConditionVariable()) {
01293 case OCV_UNCONDITIONALLY:
01294 order->SetConditionComparator(OCC_EQUALS);
01295 order->SetConditionValue(0);
01296 break;
01297
01298 case OCV_REQUIRES_SERVICE:
01299 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
01300 break;
01301
01302 case OCV_LOAD_PERCENTAGE:
01303 case OCV_RELIABILITY:
01304 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
01305
01306 default:
01307 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
01308 break;
01309 }
01310 break;
01311 }
01312
01313 case MOF_COND_COMPARATOR:
01314 order->SetConditionComparator((OrderConditionComparator)data);
01315 break;
01316
01317 case MOF_COND_VALUE:
01318 order->SetConditionValue(data);
01319 break;
01320
01321 case MOF_COND_DESTINATION:
01322 order->SetConditionSkipToOrder(data);
01323 break;
01324
01325 default: NOT_REACHED();
01326 }
01327
01328
01329 Vehicle *u = v->FirstShared();
01330 DeleteOrderWarnings(u);
01331 for (; u != NULL; u = u->NextShared()) {
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341 if (sel_ord == u->cur_real_order_index &&
01342 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
01343 u->current_order.GetLoadType() != order->GetLoadType()) {
01344 u->current_order.SetLoadType(order->GetLoadType());
01345 }
01346 InvalidateVehicleOrder(u, -2);
01347 }
01348 }
01349
01350 return CommandCost();
01351 }
01352
01364 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01365 {
01366 VehicleID veh_src = GB(p2, 0, 20);
01367 VehicleID veh_dst = GB(p1, 0, 20);
01368
01369 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
01370 if (dst == NULL || !dst->IsPrimaryVehicle()) return CMD_ERROR;
01371
01372 CommandCost ret = CheckOwnership(dst->owner);
01373 if (ret.Failed()) return ret;
01374
01375 switch (GB(p1, 30, 2)) {
01376 case CO_SHARE: {
01377 Vehicle *src = Vehicle::GetIfValid(veh_src);
01378
01379
01380 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01381
01382 CommandCost ret = CheckOwnership(src->owner);
01383 if (ret.Failed()) return ret;
01384
01385
01386 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
01387 return CMD_ERROR;
01388 }
01389
01390
01391 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
01392
01393 const Order *order;
01394
01395 FOR_VEHICLE_ORDERS(src, order) {
01396 if (OrderGoesToStation(dst, order) &&
01397 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01398 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01399 }
01400 }
01401
01402 if (src->orders.list == NULL && !OrderList::CanAllocateItem()) {
01403 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01404 }
01405
01406 if (flags & DC_EXEC) {
01407
01408
01409
01410 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
01411
01412 dst->orders.list = src->orders.list;
01413
01414
01415 dst->AddToShared(src);
01416
01417 InvalidateVehicleOrder(dst, -1);
01418 InvalidateVehicleOrder(src, -2);
01419
01420 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01421 }
01422 break;
01423 }
01424
01425 case CO_COPY: {
01426 Vehicle *src = Vehicle::GetIfValid(veh_src);
01427
01428
01429 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01430
01431 CommandCost ret = CheckOwnership(src->owner);
01432 if (ret.Failed()) return ret;
01433
01434
01435
01436 const Order *order;
01437 FOR_VEHICLE_ORDERS(src, order) {
01438 if (OrderGoesToStation(dst, order) &&
01439 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01440 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01441 }
01442 }
01443
01444
01445 int delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
01446 if (!Order::CanAllocateItem(delta) ||
01447 ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
01448 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01449 }
01450
01451 if (flags & DC_EXEC) {
01452 const Order *order;
01453 Order *first = NULL;
01454 Order **order_dst;
01455
01456
01457
01458
01459 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
01460
01461 order_dst = &first;
01462 FOR_VEHICLE_ORDERS(src, order) {
01463 *order_dst = new Order();
01464 (*order_dst)->AssignOrder(*order);
01465 order_dst = &(*order_dst)->next;
01466 }
01467 if (dst->orders.list == NULL) {
01468 dst->orders.list = new OrderList(first, dst);
01469 } else {
01470 assert(dst->orders.list->GetFirstOrder() == NULL);
01471 assert(!dst->orders.list->IsShared());
01472 delete dst->orders.list;
01473 dst->orders.list = new OrderList(first, dst);
01474 }
01475
01476 InvalidateVehicleOrder(dst, -1);
01477
01478 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01479 }
01480 break;
01481 }
01482
01483 case CO_UNSHARE: return DecloneOrder(dst, flags);
01484 default: return CMD_ERROR;
01485 }
01486
01487 return CommandCost();
01488 }
01489
01502 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01503 {
01504 VehicleID veh = GB(p1, 0, 20);
01505 VehicleOrderID order_number = GB(p2, 16, 8);
01506 CargoID cargo = GB(p2, 0, 8);
01507 byte subtype = GB(p2, 8, 8);
01508
01509 if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT) return CMD_ERROR;
01510
01511 const Vehicle *v = Vehicle::GetIfValid(veh);
01512 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01513
01514 CommandCost ret = CheckOwnership(v->owner);
01515 if (ret.Failed()) return ret;
01516
01517 Order *order = v->GetOrder(order_number);
01518 if (order == NULL) return CMD_ERROR;
01519
01520 if (flags & DC_EXEC) {
01521 order->SetRefit(cargo, subtype);
01522
01523 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
01524
01525 InvalidateVehicleOrder(u, -2);
01526
01527
01528 if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
01529 u->current_order.SetRefit(cargo, subtype);
01530 }
01531 }
01532 }
01533
01534 return CommandCost();
01535 }
01536
01537
01543 void CheckOrders(const Vehicle *v)
01544 {
01545
01546 if (_settings_client.gui.order_review_system == 0) return;
01547
01548
01549 if (v->vehstatus & VS_CRASHED) return;
01550
01551
01552 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
01553
01554
01555 if (v->FirstShared() != v) return;
01556
01557
01558 if (v->owner == _local_company && v->day_counter % 20 == 0) {
01559 int n_st, problem_type = -1;
01560 const Order *order;
01561 int message = 0;
01562
01563
01564 n_st = 0;
01565
01566 FOR_VEHICLE_ORDERS(v, order) {
01567
01568 if (order->IsType(OT_DUMMY)) {
01569 problem_type = 1;
01570 break;
01571 }
01572
01573 if (order->IsType(OT_GOTO_STATION)) {
01574 const Station *st = Station::Get(order->GetDestination());
01575
01576 n_st++;
01577 if (!CanVehicleUseStation(v, st)) problem_type = 3;
01578 }
01579 }
01580
01581
01582 if (v->GetNumOrders() > 1) {
01583 const Order *last = v->GetLastOrder();
01584
01585 if (v->orders.list->GetFirstOrder()->Equals(*last)) {
01586 problem_type = 2;
01587 }
01588 }
01589
01590
01591 if (n_st < 2 && problem_type == -1) problem_type = 0;
01592
01593 #ifndef NDEBUG
01594 if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
01595 #endif
01596
01597
01598 if (problem_type < 0) return;
01599
01600 message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
01601
01602
01603 SetDParam(0, v->index);
01604 AddVehicleNewsItem(
01605 message,
01606 NS_ADVICE,
01607 v->index
01608 );
01609 }
01610 }
01611
01617 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01618 {
01619 Vehicle *v;
01620
01621
01622
01623
01624
01625
01626 FOR_ALL_VEHICLES(v) {
01627 Order *order;
01628
01629 order = &v->current_order;
01630 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01631 v->current_order.GetDestination() == destination) {
01632 order->MakeDummy();
01633 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01634 }
01635
01636
01637 int id = -1;
01638 FOR_VEHICLE_ORDERS(v, order) {
01639 id++;
01640 restart:
01641
01642 OrderType ot = order->GetType();
01643 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
01644 if (ot == OT_AUTOMATIC || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
01645 if (ot == type && order->GetDestination() == destination) {
01646
01647
01648
01649 if (order->IsType(OT_AUTOMATIC)) {
01650 order = order->next;
01651 DeleteOrder(v, id);
01652 if (order != NULL) goto restart;
01653 break;
01654 }
01655
01656 order->MakeDummy();
01657 for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
01658
01659 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
01660 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
01661 }
01662 }
01663 }
01664 }
01665 }
01666
01671 bool Vehicle::HasDepotOrder() const
01672 {
01673 const Order *order;
01674
01675 FOR_VEHICLE_ORDERS(this, order) {
01676 if (order->IsType(OT_GOTO_DEPOT)) return true;
01677 }
01678
01679 return false;
01680 }
01681
01691 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
01692 {
01693 DeleteOrderWarnings(v);
01694
01695 if (v->IsOrderListShared()) {
01696
01697 v->RemoveFromShared();
01698 v->orders.list = NULL;
01699 } else if (v->orders.list != NULL) {
01700
01701 v->orders.list->FreeChain(keep_orderlist);
01702 if (!keep_orderlist) v->orders.list = NULL;
01703 }
01704
01705 if (reset_order_indices) {
01706 v->cur_auto_order_index = v->cur_real_order_index = 0;
01707 if (v->current_order.IsType(OT_LOADING)) {
01708 CancelLoadingDueToDeletedOrder(v);
01709 }
01710 }
01711 }
01712
01720 uint16 GetServiceIntervalClamped(uint interval, CompanyID company_id)
01721 {
01722 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);
01723 }
01724
01733 static bool CheckForValidOrders(const Vehicle *v)
01734 {
01735 const Order *order;
01736
01737 FOR_VEHICLE_ORDERS(v, order) {
01738 switch (order->GetType()) {
01739 case OT_GOTO_STATION:
01740 case OT_GOTO_DEPOT:
01741 case OT_GOTO_WAYPOINT:
01742 return true;
01743
01744 default:
01745 break;
01746 }
01747 }
01748
01749 return false;
01750 }
01751
01755 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
01756 {
01757 switch (occ) {
01758 case OCC_EQUALS: return variable == value;
01759 case OCC_NOT_EQUALS: return variable != value;
01760 case OCC_LESS_THAN: return variable < value;
01761 case OCC_LESS_EQUALS: return variable <= value;
01762 case OCC_MORE_THAN: return variable > value;
01763 case OCC_MORE_EQUALS: return variable >= value;
01764 case OCC_IS_TRUE: return variable != 0;
01765 case OCC_IS_FALSE: return variable == 0;
01766 default: NOT_REACHED();
01767 }
01768 }
01769
01776 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
01777 {
01778 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
01779
01780 bool skip_order = false;
01781 OrderConditionComparator occ = order->GetConditionComparator();
01782 uint16 value = order->GetConditionValue();
01783
01784 switch (order->GetConditionVariable()) {
01785 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
01786 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
01787 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
01788 case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
01789 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
01790 case OCV_UNCONDITIONALLY: skip_order = true; break;
01791 default: NOT_REACHED();
01792 }
01793
01794 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
01795 }
01796
01803 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
01804 {
01805 if (conditional_depth > v->GetNumOrders()) return false;
01806
01807 switch (order->GetType()) {
01808 case OT_GOTO_STATION:
01809 v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
01810 return true;
01811
01812 case OT_GOTO_DEPOT:
01813 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
01814 UpdateVehicleTimetable(v, true);
01815 v->IncrementRealOrderIndex();
01816 break;
01817 }
01818
01819 if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
01820
01821 TileIndex location;
01822 DestinationID destination;
01823 bool reverse;
01824
01825 if (v->FindClosestDepot(&location, &destination, &reverse)) {
01826 v->dest_tile = location;
01827 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());
01828
01829
01830 if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01831
01832 if (v->type == VEH_AIRCRAFT) {
01833 Aircraft *a = Aircraft::From(v);
01834 if (a->state == FLYING && a->targetairport != destination) {
01835
01836 extern void AircraftNextAirportPos_and_Order(Aircraft *a);
01837 AircraftNextAirportPos_and_Order(a);
01838 }
01839 }
01840 return true;
01841 }
01842
01843 UpdateVehicleTimetable(v, true);
01844 v->IncrementRealOrderIndex();
01845 } else {
01846 if (v->type != VEH_AIRCRAFT) {
01847 v->dest_tile = Depot::Get(order->GetDestination())->xy;
01848 }
01849 return true;
01850 }
01851 break;
01852
01853 case OT_GOTO_WAYPOINT:
01854 v->dest_tile = Waypoint::Get(order->GetDestination())->xy;
01855 return true;
01856
01857 case OT_CONDITIONAL: {
01858 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
01859 if (next_order != INVALID_VEH_ORDER_ID) {
01860
01861
01862 UpdateVehicleTimetable(v, false);
01863 v->cur_auto_order_index = v->cur_real_order_index = next_order;
01864 v->UpdateRealOrderIndex();
01865 v->current_order_time += v->GetOrder(v->cur_real_order_index)->travel_time;
01866 } else {
01867 UpdateVehicleTimetable(v, true);
01868 v->IncrementRealOrderIndex();
01869 }
01870 break;
01871 }
01872
01873 default:
01874 v->dest_tile = 0;
01875 return false;
01876 }
01877
01878 assert(v->cur_auto_order_index < v->GetNumOrders());
01879 assert(v->cur_real_order_index < v->GetNumOrders());
01880
01881
01882 order = v->GetOrder(v->cur_real_order_index);
01883 if (order != NULL && order->IsType(OT_AUTOMATIC)) {
01884 assert(v->GetNumManualOrders() == 0);
01885 order = NULL;
01886 }
01887
01888 if (order == NULL) {
01889 v->current_order.Free();
01890 v->dest_tile = 0;
01891 return false;
01892 }
01893
01894 v->current_order = *order;
01895 return UpdateOrderDest(v, order, conditional_depth + 1);
01896 }
01897
01905 bool ProcessOrders(Vehicle *v)
01906 {
01907 switch (v->current_order.GetType()) {
01908 case OT_GOTO_DEPOT:
01909
01910 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
01911 break;
01912
01913 case OT_LOADING:
01914 return false;
01915
01916 case OT_LEAVESTATION:
01917 if (v->type != VEH_AIRCRAFT) return false;
01918 break;
01919
01920 default: break;
01921 }
01922
01930 bool may_reverse = v->current_order.IsType(OT_NOTHING);
01931
01932
01933 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)) &&
01934 IsTileType(v->tile, MP_STATION) &&
01935 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
01936 v->DeleteUnreachedAutoOrders();
01937
01938
01939
01940
01941 v->last_station_visited = v->current_order.GetDestination();
01942 UpdateVehicleTimetable(v, true);
01943 v->IncrementAutoOrderIndex();
01944 }
01945
01946
01947 assert(v->cur_auto_order_index == 0 || v->cur_auto_order_index < v->GetNumOrders());
01948 v->UpdateRealOrderIndex();
01949
01950 const Order *order = v->GetOrder(v->cur_real_order_index);
01951 if (order != NULL && order->IsType(OT_AUTOMATIC)) {
01952 assert(v->GetNumManualOrders() == 0);
01953 order = NULL;
01954 }
01955
01956
01957 if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
01958 if (v->type == VEH_AIRCRAFT) {
01959
01960 extern void HandleMissingAircraftOrders(Aircraft *v);
01961 HandleMissingAircraftOrders(Aircraft::From(v));
01962 return false;
01963 }
01964
01965 v->current_order.Free();
01966 v->dest_tile = 0;
01967 return false;
01968 }
01969
01970
01971 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
01972 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
01973 return false;
01974 }
01975
01976
01977 v->current_order = *order;
01978
01979 InvalidateVehicleOrder(v, -2);
01980 switch (v->type) {
01981 default:
01982 NOT_REACHED();
01983
01984 case VEH_ROAD:
01985 case VEH_TRAIN:
01986 break;
01987
01988 case VEH_AIRCRAFT:
01989 case VEH_SHIP:
01990 SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
01991 break;
01992 }
01993
01994 return UpdateOrderDest(v, order) && may_reverse;
01995 }
01996
02004 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
02005 {
02006 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
02007
02008 return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
02009 v->last_station_visited != station &&
02010
02011 !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
02012 }
02013
02014 void InitializeOrders()
02015 {
02016 _order_pool.CleanPool();
02017 _orderlist_pool.CleanPool();
02018 }