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::MakeImplicit(StationID destination)
00141 {
00142 this->type = OT_IMPLICIT;
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_IMPLICIT)) ++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_IMPLICIT)) ++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_IMPLICIT)) --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_IMPLICIT)) 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_IMPLICIT)) ++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_IMPLICIT:
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_implicit_order_index && u->IsGroundVehicle()) {
00834
00835
00836
00837 uint16 &gv_flags = u->GetGroundVehicleFlags();
00838 SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
00839 }
00840 if (sel_ord <= u->cur_implicit_order_index) {
00841 uint cur = u->cur_implicit_order_index + 1;
00842
00843 if (cur < u->GetNumOrders()) {
00844 u->cur_implicit_order_index = cur;
00845 }
00846 }
00847
00848 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
00849 }
00850
00851
00852 VehicleOrderID cur_order_id = 0;
00853 Order *order;
00854 FOR_VEHICLE_ORDERS(v, order) {
00855 if (order->IsType(OT_CONDITIONAL)) {
00856 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00857 if (order_id >= sel_ord) {
00858 order->SetConditionSkipToOrder(order_id + 1);
00859 }
00860 if (order_id == cur_order_id) {
00861 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00862 }
00863 }
00864 cur_order_id++;
00865 }
00866
00867
00868 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00869 }
00870
00876 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
00877 {
00878 if (flags & DC_EXEC) {
00879 DeleteVehicleOrders(dst);
00880 InvalidateVehicleOrder(dst, -1);
00881 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
00882 }
00883 return CommandCost();
00884 }
00885
00895 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00896 {
00897 VehicleID veh_id = GB(p1, 0, 20);
00898 VehicleOrderID sel_ord = GB(p2, 0, 8);
00899
00900 Vehicle *v = Vehicle::GetIfValid(veh_id);
00901
00902 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00903
00904 CommandCost ret = CheckOwnership(v->owner);
00905 if (ret.Failed()) return ret;
00906
00907
00908 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
00909
00910 if (v->GetOrder(sel_ord) == NULL) return CMD_ERROR;
00911
00912 if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
00913 return CommandCost();
00914 }
00915
00920 static void CancelLoadingDueToDeletedOrder(Vehicle *v)
00921 {
00922 assert(v->current_order.IsType(OT_LOADING));
00923
00924
00925 v->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
00926
00927
00928 if (v->current_order.GetLoadType() & OLFB_FULL_LOAD) v->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE);
00929 }
00930
00936 void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
00937 {
00938 v->orders.list->DeleteOrderAt(sel_ord);
00939
00940 Vehicle *u = v->FirstShared();
00941 DeleteOrderWarnings(u);
00942 for (; u != NULL; u = u->NextShared()) {
00943 assert(v->orders.list == u->orders.list);
00944
00945 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
00946 CancelLoadingDueToDeletedOrder(u);
00947 }
00948
00949 if (sel_ord < u->cur_real_order_index) {
00950 u->cur_real_order_index--;
00951 } else if (sel_ord == u->cur_real_order_index) {
00952 u->UpdateRealOrderIndex();
00953 }
00954
00955 if (sel_ord < u->cur_implicit_order_index) {
00956 u->cur_implicit_order_index--;
00957 } else if (sel_ord == u->cur_implicit_order_index) {
00958
00959 if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
00960
00961
00962 while (u->cur_implicit_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_implicit_order_index)->IsType(OT_IMPLICIT)) {
00963 u->cur_implicit_order_index++;
00964 if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
00965 }
00966 }
00967
00968
00969 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
00970 }
00971
00972
00973 VehicleOrderID cur_order_id = 0;
00974 Order *order = NULL;
00975 FOR_VEHICLE_ORDERS(v, order) {
00976 if (order->IsType(OT_CONDITIONAL)) {
00977 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00978 if (order_id >= sel_ord) {
00979 order_id = max(order_id - 1, 0);
00980 }
00981 if (order_id == cur_order_id) {
00982 order_id = (order_id + 1) % v->GetNumOrders();
00983 }
00984 order->SetConditionSkipToOrder(order_id);
00985 }
00986 cur_order_id++;
00987 }
00988
00989 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00990 }
00991
01001 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01002 {
01003 VehicleID veh_id = GB(p1, 0, 20);
01004 VehicleOrderID sel_ord = GB(p2, 0, 8);
01005
01006 Vehicle *v = Vehicle::GetIfValid(veh_id);
01007
01008 if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
01009
01010 CommandCost ret = CheckOwnership(v->owner);
01011 if (ret.Failed()) return ret;
01012
01013 if (flags & DC_EXEC) {
01014 v->cur_implicit_order_index = v->cur_real_order_index = sel_ord;
01015 v->UpdateRealOrderIndex();
01016
01017 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
01018
01019 InvalidateVehicleOrder(v, -2);
01020 }
01021
01022
01023 if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
01024 if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
01025
01026 return CommandCost();
01027 }
01028
01042 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01043 {
01044 VehicleID veh = GB(p1, 0, 20);
01045 VehicleOrderID moving_order = GB(p2, 0, 16);
01046 VehicleOrderID target_order = GB(p2, 16, 16);
01047
01048 Vehicle *v = Vehicle::GetIfValid(veh);
01049 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01050
01051 CommandCost ret = CheckOwnership(v->owner);
01052 if (ret.Failed()) return ret;
01053
01054
01055 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
01056 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
01057
01058 Order *moving_one = v->GetOrder(moving_order);
01059
01060 if (moving_one == NULL) return CMD_ERROR;
01061
01062 if (flags & DC_EXEC) {
01063 v->orders.list->MoveOrder(moving_order, target_order);
01064
01065
01066 Vehicle *u = v->FirstShared();
01067
01068 DeleteOrderWarnings(u);
01069
01070 for (; u != NULL; u = u->NextShared()) {
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087 if (u->cur_real_order_index == moving_order) {
01088 u->cur_real_order_index = target_order;
01089 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
01090 u->cur_real_order_index--;
01091 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
01092 u->cur_real_order_index++;
01093 }
01094
01095 if (u->cur_implicit_order_index == moving_order) {
01096 u->cur_implicit_order_index = target_order;
01097 } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
01098 u->cur_implicit_order_index--;
01099 } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
01100 u->cur_implicit_order_index++;
01101 }
01102
01103 assert(v->orders.list == u->orders.list);
01104
01105 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
01106 }
01107
01108
01109 Order *order;
01110 FOR_VEHICLE_ORDERS(v, order) {
01111 if (order->IsType(OT_CONDITIONAL)) {
01112 VehicleOrderID order_id = order->GetConditionSkipToOrder();
01113 if (order_id == moving_order) {
01114 order_id = target_order;
01115 } else if (order_id > moving_order && order_id <= target_order) {
01116 order_id--;
01117 } else if (order_id < moving_order && order_id >= target_order) {
01118 order_id++;
01119 }
01120 order->SetConditionSkipToOrder(order_id);
01121 }
01122 }
01123
01124
01125 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
01126 }
01127
01128 return CommandCost();
01129 }
01130
01146 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01147 {
01148 VehicleOrderID sel_ord = GB(p1, 20, 8);
01149 VehicleID veh = GB(p1, 0, 20);
01150 ModifyOrderFlags mof = Extract<ModifyOrderFlags, 0, 4>(p2);
01151 uint16 data = GB(p2, 4, 11);
01152
01153 if (mof >= MOF_END) return CMD_ERROR;
01154
01155 Vehicle *v = Vehicle::GetIfValid(veh);
01156 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01157
01158 CommandCost ret = CheckOwnership(v->owner);
01159 if (ret.Failed()) return ret;
01160
01161
01162 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
01163
01164 Order *order = v->GetOrder(sel_ord);
01165 switch (order->GetType()) {
01166 case OT_GOTO_STATION:
01167 if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE) return CMD_ERROR;
01168 break;
01169
01170 case OT_GOTO_DEPOT:
01171 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
01172 break;
01173
01174 case OT_GOTO_WAYPOINT:
01175 if (mof != MOF_NON_STOP) return CMD_ERROR;
01176 break;
01177
01178 case OT_CONDITIONAL:
01179 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
01180 break;
01181
01182 default:
01183 return CMD_ERROR;
01184 }
01185
01186 switch (mof) {
01187 default: NOT_REACHED();
01188
01189 case MOF_NON_STOP:
01190 if (!v->IsGroundVehicle()) return CMD_ERROR;
01191 if (data >= ONSF_END) return CMD_ERROR;
01192 if (data == order->GetNonStopType()) return CMD_ERROR;
01193 break;
01194
01195 case MOF_STOP_LOCATION:
01196 if (v->type != VEH_TRAIN) return CMD_ERROR;
01197 if (data >= OSL_END) return CMD_ERROR;
01198 break;
01199
01200 case MOF_UNLOAD:
01201 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
01202
01203 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
01204 if (data == order->GetUnloadType()) return CMD_ERROR;
01205 break;
01206
01207 case MOF_LOAD:
01208 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
01209 if (data == order->GetLoadType()) return CMD_ERROR;
01210 break;
01211
01212 case MOF_DEPOT_ACTION:
01213 if (data >= DA_END) return CMD_ERROR;
01214 break;
01215
01216 case MOF_COND_VARIABLE:
01217 if (data >= OCV_END) return CMD_ERROR;
01218 break;
01219
01220 case MOF_COND_COMPARATOR:
01221 if (data >= OCC_END) return CMD_ERROR;
01222 switch (order->GetConditionVariable()) {
01223 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01224
01225 case OCV_REQUIRES_SERVICE:
01226 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
01227 break;
01228
01229 default:
01230 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
01231 break;
01232 }
01233 break;
01234
01235 case MOF_COND_VALUE:
01236 switch (order->GetConditionVariable()) {
01237 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01238
01239 case OCV_LOAD_PERCENTAGE:
01240 case OCV_RELIABILITY:
01241 if (data > 100) return CMD_ERROR;
01242 break;
01243
01244 default:
01245 if (data > 2047) return CMD_ERROR;
01246 break;
01247 }
01248 break;
01249
01250 case MOF_COND_DESTINATION:
01251 if (data >= v->GetNumOrders()) return CMD_ERROR;
01252 break;
01253 }
01254
01255 if (flags & DC_EXEC) {
01256 switch (mof) {
01257 case MOF_NON_STOP:
01258 order->SetNonStopType((OrderNonStopFlags)data);
01259 break;
01260
01261 case MOF_STOP_LOCATION:
01262 order->SetStopLocation((OrderStopLocation)data);
01263 break;
01264
01265 case MOF_UNLOAD:
01266 order->SetUnloadType((OrderUnloadFlags)data);
01267 break;
01268
01269 case MOF_LOAD:
01270 order->SetLoadType((OrderLoadFlags)data);
01271 break;
01272
01273 case MOF_DEPOT_ACTION: {
01274 switch (data) {
01275 case DA_ALWAYS_GO:
01276 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01277 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01278 break;
01279
01280 case DA_SERVICE:
01281 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
01282 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01283 order->SetRefit(CT_NO_REFIT);
01284 break;
01285
01286 case DA_STOP:
01287 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01288 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
01289 order->SetRefit(CT_NO_REFIT);
01290 break;
01291
01292 default:
01293 NOT_REACHED();
01294 }
01295 break;
01296 }
01297
01298 case MOF_COND_VARIABLE: {
01299 order->SetConditionVariable((OrderConditionVariable)data);
01300
01301 OrderConditionComparator occ = order->GetConditionComparator();
01302 switch (order->GetConditionVariable()) {
01303 case OCV_UNCONDITIONALLY:
01304 order->SetConditionComparator(OCC_EQUALS);
01305 order->SetConditionValue(0);
01306 break;
01307
01308 case OCV_REQUIRES_SERVICE:
01309 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
01310 break;
01311
01312 case OCV_LOAD_PERCENTAGE:
01313 case OCV_RELIABILITY:
01314 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
01315
01316 default:
01317 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
01318 break;
01319 }
01320 break;
01321 }
01322
01323 case MOF_COND_COMPARATOR:
01324 order->SetConditionComparator((OrderConditionComparator)data);
01325 break;
01326
01327 case MOF_COND_VALUE:
01328 order->SetConditionValue(data);
01329 break;
01330
01331 case MOF_COND_DESTINATION:
01332 order->SetConditionSkipToOrder(data);
01333 break;
01334
01335 default: NOT_REACHED();
01336 }
01337
01338
01339 Vehicle *u = v->FirstShared();
01340 DeleteOrderWarnings(u);
01341 for (; u != NULL; u = u->NextShared()) {
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351 if (sel_ord == u->cur_real_order_index &&
01352 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
01353 u->current_order.GetLoadType() != order->GetLoadType()) {
01354 u->current_order.SetLoadType(order->GetLoadType());
01355 }
01356 InvalidateVehicleOrder(u, -2);
01357 }
01358 }
01359
01360 return CommandCost();
01361 }
01362
01374 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01375 {
01376 VehicleID veh_src = GB(p2, 0, 20);
01377 VehicleID veh_dst = GB(p1, 0, 20);
01378
01379 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
01380 if (dst == NULL || !dst->IsPrimaryVehicle()) return CMD_ERROR;
01381
01382 CommandCost ret = CheckOwnership(dst->owner);
01383 if (ret.Failed()) return ret;
01384
01385 switch (GB(p1, 30, 2)) {
01386 case CO_SHARE: {
01387 Vehicle *src = Vehicle::GetIfValid(veh_src);
01388
01389
01390 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01391
01392 CommandCost ret = CheckOwnership(src->owner);
01393 if (ret.Failed()) return ret;
01394
01395
01396 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
01397 return CMD_ERROR;
01398 }
01399
01400
01401 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
01402
01403 const Order *order;
01404
01405 FOR_VEHICLE_ORDERS(src, order) {
01406 if (OrderGoesToStation(dst, order) &&
01407 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01408 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01409 }
01410 }
01411
01412 if (src->orders.list == NULL && !OrderList::CanAllocateItem()) {
01413 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01414 }
01415
01416 if (flags & DC_EXEC) {
01417
01418
01419
01420 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
01421
01422 dst->orders.list = src->orders.list;
01423
01424
01425 dst->AddToShared(src);
01426
01427 InvalidateVehicleOrder(dst, -1);
01428 InvalidateVehicleOrder(src, -2);
01429
01430 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01431 }
01432 break;
01433 }
01434
01435 case CO_COPY: {
01436 Vehicle *src = Vehicle::GetIfValid(veh_src);
01437
01438
01439 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01440
01441 CommandCost ret = CheckOwnership(src->owner);
01442 if (ret.Failed()) return ret;
01443
01444
01445
01446 const Order *order;
01447 FOR_VEHICLE_ORDERS(src, order) {
01448 if (OrderGoesToStation(dst, order) &&
01449 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01450 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01451 }
01452 }
01453
01454
01455 int delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
01456 if (!Order::CanAllocateItem(delta) ||
01457 ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
01458 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01459 }
01460
01461 if (flags & DC_EXEC) {
01462 const Order *order;
01463 Order *first = NULL;
01464 Order **order_dst;
01465
01466
01467
01468
01469 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
01470
01471 order_dst = &first;
01472 FOR_VEHICLE_ORDERS(src, order) {
01473 *order_dst = new Order();
01474 (*order_dst)->AssignOrder(*order);
01475 order_dst = &(*order_dst)->next;
01476 }
01477 if (dst->orders.list == NULL) {
01478 dst->orders.list = new OrderList(first, dst);
01479 } else {
01480 assert(dst->orders.list->GetFirstOrder() == NULL);
01481 assert(!dst->orders.list->IsShared());
01482 delete dst->orders.list;
01483 dst->orders.list = new OrderList(first, dst);
01484 }
01485
01486 InvalidateVehicleOrder(dst, -1);
01487
01488 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01489 }
01490 break;
01491 }
01492
01493 case CO_UNSHARE: return DecloneOrder(dst, flags);
01494 default: return CMD_ERROR;
01495 }
01496
01497 return CommandCost();
01498 }
01499
01512 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01513 {
01514 VehicleID veh = GB(p1, 0, 20);
01515 VehicleOrderID order_number = GB(p2, 16, 8);
01516 CargoID cargo = GB(p2, 0, 8);
01517 byte subtype = GB(p2, 8, 8);
01518
01519 if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT) return CMD_ERROR;
01520
01521 const Vehicle *v = Vehicle::GetIfValid(veh);
01522 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01523
01524 CommandCost ret = CheckOwnership(v->owner);
01525 if (ret.Failed()) return ret;
01526
01527 Order *order = v->GetOrder(order_number);
01528 if (order == NULL) return CMD_ERROR;
01529
01530 if (flags & DC_EXEC) {
01531 order->SetRefit(cargo, subtype);
01532
01533
01534 if (cargo != CT_NO_REFIT) {
01535 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01536 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01537 }
01538
01539 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
01540
01541 InvalidateVehicleOrder(u, -2);
01542
01543
01544 if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
01545 u->current_order.SetRefit(cargo, subtype);
01546 }
01547 }
01548 }
01549
01550 return CommandCost();
01551 }
01552
01553
01559 void CheckOrders(const Vehicle *v)
01560 {
01561
01562 if (_settings_client.gui.order_review_system == 0) return;
01563
01564
01565 if (v->vehstatus & VS_CRASHED) return;
01566
01567
01568 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
01569
01570
01571 if (v->FirstShared() != v) return;
01572
01573
01574 if (v->owner == _local_company && v->day_counter % 20 == 0) {
01575 int n_st, problem_type = -1;
01576 const Order *order;
01577 int message = 0;
01578
01579
01580 n_st = 0;
01581
01582 FOR_VEHICLE_ORDERS(v, order) {
01583
01584 if (order->IsType(OT_DUMMY)) {
01585 problem_type = 1;
01586 break;
01587 }
01588
01589 if (order->IsType(OT_GOTO_STATION)) {
01590 const Station *st = Station::Get(order->GetDestination());
01591
01592 n_st++;
01593 if (!CanVehicleUseStation(v, st)) problem_type = 3;
01594 }
01595 }
01596
01597
01598 if (v->GetNumOrders() > 1) {
01599 const Order *last = v->GetLastOrder();
01600
01601 if (v->orders.list->GetFirstOrder()->Equals(*last)) {
01602 problem_type = 2;
01603 }
01604 }
01605
01606
01607 if (n_st < 2 && problem_type == -1) problem_type = 0;
01608
01609 #ifndef NDEBUG
01610 if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
01611 #endif
01612
01613
01614 if (problem_type < 0) return;
01615
01616 message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
01617
01618
01619 SetDParam(0, v->index);
01620 AddVehicleNewsItem(
01621 message,
01622 NS_ADVICE,
01623 v->index
01624 );
01625 }
01626 }
01627
01633 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01634 {
01635 Vehicle *v;
01636
01637
01638
01639
01640
01641
01642 FOR_ALL_VEHICLES(v) {
01643 Order *order;
01644
01645 order = &v->current_order;
01646 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01647 v->current_order.GetDestination() == destination) {
01648 order->MakeDummy();
01649 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01650 }
01651
01652
01653 int id = -1;
01654 FOR_VEHICLE_ORDERS(v, order) {
01655 id++;
01656 restart:
01657
01658 OrderType ot = order->GetType();
01659 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
01660 if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
01661 if (ot == type && order->GetDestination() == destination) {
01662
01663
01664
01665 if (order->IsType(OT_IMPLICIT)) {
01666 order = order->next;
01667 DeleteOrder(v, id);
01668 if (order != NULL) goto restart;
01669 break;
01670 }
01671
01672 order->MakeDummy();
01673 for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
01674
01675 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
01676 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
01677 }
01678 }
01679 }
01680 }
01681 }
01682
01687 bool Vehicle::HasDepotOrder() const
01688 {
01689 const Order *order;
01690
01691 FOR_VEHICLE_ORDERS(this, order) {
01692 if (order->IsType(OT_GOTO_DEPOT)) return true;
01693 }
01694
01695 return false;
01696 }
01697
01707 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
01708 {
01709 DeleteOrderWarnings(v);
01710
01711 if (v->IsOrderListShared()) {
01712
01713 v->RemoveFromShared();
01714 v->orders.list = NULL;
01715 } else if (v->orders.list != NULL) {
01716
01717 v->orders.list->FreeChain(keep_orderlist);
01718 if (!keep_orderlist) v->orders.list = NULL;
01719 }
01720
01721 if (reset_order_indices) {
01722 v->cur_implicit_order_index = v->cur_real_order_index = 0;
01723 if (v->current_order.IsType(OT_LOADING)) {
01724 CancelLoadingDueToDeletedOrder(v);
01725 }
01726 }
01727 }
01728
01736 uint16 GetServiceIntervalClamped(uint interval, CompanyID company_id)
01737 {
01738 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);
01739 }
01740
01749 static bool CheckForValidOrders(const Vehicle *v)
01750 {
01751 const Order *order;
01752
01753 FOR_VEHICLE_ORDERS(v, order) {
01754 switch (order->GetType()) {
01755 case OT_GOTO_STATION:
01756 case OT_GOTO_DEPOT:
01757 case OT_GOTO_WAYPOINT:
01758 return true;
01759
01760 default:
01761 break;
01762 }
01763 }
01764
01765 return false;
01766 }
01767
01771 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
01772 {
01773 switch (occ) {
01774 case OCC_EQUALS: return variable == value;
01775 case OCC_NOT_EQUALS: return variable != value;
01776 case OCC_LESS_THAN: return variable < value;
01777 case OCC_LESS_EQUALS: return variable <= value;
01778 case OCC_MORE_THAN: return variable > value;
01779 case OCC_MORE_EQUALS: return variable >= value;
01780 case OCC_IS_TRUE: return variable != 0;
01781 case OCC_IS_FALSE: return variable == 0;
01782 default: NOT_REACHED();
01783 }
01784 }
01785
01792 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
01793 {
01794 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
01795
01796 bool skip_order = false;
01797 OrderConditionComparator occ = order->GetConditionComparator();
01798 uint16 value = order->GetConditionValue();
01799
01800 switch (order->GetConditionVariable()) {
01801 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
01802 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
01803 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
01804 case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
01805 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
01806 case OCV_UNCONDITIONALLY: skip_order = true; break;
01807 default: NOT_REACHED();
01808 }
01809
01810 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
01811 }
01812
01820 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
01821 {
01822 if (conditional_depth > v->GetNumOrders()) return false;
01823
01824 switch (order->GetType()) {
01825 case OT_GOTO_STATION:
01826 v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
01827 return true;
01828
01829 case OT_GOTO_DEPOT:
01830 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
01831 assert(!pbs_look_ahead);
01832 UpdateVehicleTimetable(v, true);
01833 v->IncrementRealOrderIndex();
01834 break;
01835 }
01836
01837 if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
01838
01839 TileIndex location;
01840 DestinationID destination;
01841 bool reverse;
01842
01843 if (v->FindClosestDepot(&location, &destination, &reverse)) {
01844
01845 if (pbs_look_ahead && reverse) return false;
01846
01847 v->dest_tile = location;
01848 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());
01849
01850
01851 if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01852
01853 if (v->type == VEH_AIRCRAFT) {
01854 Aircraft *a = Aircraft::From(v);
01855 if (a->state == FLYING && a->targetairport != destination) {
01856
01857 extern void AircraftNextAirportPos_and_Order(Aircraft *a);
01858 AircraftNextAirportPos_and_Order(a);
01859 }
01860 }
01861 return true;
01862 }
01863
01864
01865 if (pbs_look_ahead) return false;
01866
01867 UpdateVehicleTimetable(v, true);
01868 v->IncrementRealOrderIndex();
01869 } else {
01870 if (v->type != VEH_AIRCRAFT) {
01871 v->dest_tile = Depot::Get(order->GetDestination())->xy;
01872 }
01873 return true;
01874 }
01875 break;
01876
01877 case OT_GOTO_WAYPOINT:
01878 v->dest_tile = Waypoint::Get(order->GetDestination())->xy;
01879 return true;
01880
01881 case OT_CONDITIONAL: {
01882 assert(!pbs_look_ahead);
01883 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
01884 if (next_order != INVALID_VEH_ORDER_ID) {
01885
01886
01887 UpdateVehicleTimetable(v, false);
01888 v->cur_implicit_order_index = v->cur_real_order_index = next_order;
01889 v->UpdateRealOrderIndex();
01890 v->current_order_time += v->GetOrder(v->cur_real_order_index)->travel_time;
01891
01892
01893
01894 if (v->IsGroundVehicle()) {
01895 uint16 &gv_flags = v->GetGroundVehicleFlags();
01896 SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
01897 }
01898 } else {
01899 UpdateVehicleTimetable(v, true);
01900 v->IncrementRealOrderIndex();
01901 }
01902 break;
01903 }
01904
01905 default:
01906 v->dest_tile = 0;
01907 return false;
01908 }
01909
01910 assert(v->cur_implicit_order_index < v->GetNumOrders());
01911 assert(v->cur_real_order_index < v->GetNumOrders());
01912
01913
01914 order = v->GetOrder(v->cur_real_order_index);
01915 if (order != NULL && order->IsType(OT_IMPLICIT)) {
01916 assert(v->GetNumManualOrders() == 0);
01917 order = NULL;
01918 }
01919
01920 if (order == NULL) {
01921 v->current_order.Free();
01922 v->dest_tile = 0;
01923 return false;
01924 }
01925
01926 v->current_order = *order;
01927 return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
01928 }
01929
01937 bool ProcessOrders(Vehicle *v)
01938 {
01939 switch (v->current_order.GetType()) {
01940 case OT_GOTO_DEPOT:
01941
01942 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
01943 break;
01944
01945 case OT_LOADING:
01946 return false;
01947
01948 case OT_LEAVESTATION:
01949 if (v->type != VEH_AIRCRAFT) return false;
01950 break;
01951
01952 default: break;
01953 }
01954
01962 bool may_reverse = v->current_order.IsType(OT_NOTHING);
01963
01964
01965 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)) &&
01966 IsTileType(v->tile, MP_STATION) &&
01967 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
01968 v->DeleteUnreachedImplicitOrders();
01969
01970
01971
01972
01973 v->last_station_visited = v->current_order.GetDestination();
01974 UpdateVehicleTimetable(v, true);
01975 v->IncrementImplicitOrderIndex();
01976 }
01977
01978
01979 assert(v->cur_implicit_order_index == 0 || v->cur_implicit_order_index < v->GetNumOrders());
01980 v->UpdateRealOrderIndex();
01981
01982 const Order *order = v->GetOrder(v->cur_real_order_index);
01983 if (order != NULL && order->IsType(OT_IMPLICIT)) {
01984 assert(v->GetNumManualOrders() == 0);
01985 order = NULL;
01986 }
01987
01988
01989 if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
01990 if (v->type == VEH_AIRCRAFT) {
01991
01992 extern void HandleMissingAircraftOrders(Aircraft *v);
01993 HandleMissingAircraftOrders(Aircraft::From(v));
01994 return false;
01995 }
01996
01997 v->current_order.Free();
01998 v->dest_tile = 0;
01999 return false;
02000 }
02001
02002
02003 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
02004 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
02005 return false;
02006 }
02007
02008
02009 v->current_order = *order;
02010
02011 InvalidateVehicleOrder(v, -2);
02012 switch (v->type) {
02013 default:
02014 NOT_REACHED();
02015
02016 case VEH_ROAD:
02017 case VEH_TRAIN:
02018 break;
02019
02020 case VEH_AIRCRAFT:
02021 case VEH_SHIP:
02022 SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
02023 break;
02024 }
02025
02026 return UpdateOrderDest(v, order) && may_reverse;
02027 }
02028
02036 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
02037 {
02038 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
02039
02040 return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
02041 v->last_station_visited != station &&
02042
02043 !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
02044 }
02045
02046 void InitializeOrders()
02047 {
02048 _order_pool.CleanPool();
02049 _orderlist_pool.CleanPool();
02050 }