00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "debug.h"
00014 #include "cmd_helper.h"
00015 #include "command_func.h"
00016 #include "company_func.h"
00017 #include "news_func.h"
00018 #include "vehicle_gui.h"
00019 #include "strings_func.h"
00020 #include "window_func.h"
00021 #include "timetable.h"
00022 #include "vehicle_func.h"
00023 #include "depot_base.h"
00024 #include "core/pool_func.hpp"
00025 #include "core/random_func.hpp"
00026 #include "aircraft.h"
00027 #include "roadveh.h"
00028 #include "station_base.h"
00029 #include "waypoint_base.h"
00030 #include "company_base.h"
00031
00032 #include "table/strings.h"
00033
00034
00035
00036
00037 assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
00038 assert_compile(sizeof(DestinationID) >= sizeof(StationID));
00039
00040 OrderPool _order_pool("Order");
00041 INSTANTIATE_POOL_METHODS(Order)
00042 OrderListPool _orderlist_pool("OrderList");
00043 INSTANTIATE_POOL_METHODS(OrderList)
00044
00049 void Order::Free()
00050 {
00051 this->type = OT_NOTHING;
00052 this->flags = 0;
00053 this->dest = 0;
00054 this->next = NULL;
00055 }
00056
00061 void Order::MakeGoToStation(StationID destination)
00062 {
00063 this->type = OT_GOTO_STATION;
00064 this->flags = 0;
00065 this->dest = destination;
00066 }
00067
00077 void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoID cargo, byte subtype)
00078 {
00079 this->type = OT_GOTO_DEPOT;
00080 this->SetDepotOrderType(order);
00081 this->SetDepotActionType(action);
00082 this->SetNonStopType(non_stop_type);
00083 this->dest = destination;
00084 this->SetRefit(cargo, subtype);
00085 }
00086
00091 void Order::MakeGoToWaypoint(StationID destination)
00092 {
00093 this->type = OT_GOTO_WAYPOINT;
00094 this->flags = 0;
00095 this->dest = destination;
00096 }
00097
00102 void Order::MakeLoading(bool ordered)
00103 {
00104 this->type = OT_LOADING;
00105 if (!ordered) this->flags = 0;
00106 }
00107
00111 void Order::MakeLeaveStation()
00112 {
00113 this->type = OT_LEAVESTATION;
00114 this->flags = 0;
00115 }
00116
00120 void Order::MakeDummy()
00121 {
00122 this->type = OT_DUMMY;
00123 this->flags = 0;
00124 }
00125
00130 void Order::MakeConditional(VehicleOrderID order)
00131 {
00132 this->type = OT_CONDITIONAL;
00133 this->flags = order;
00134 this->dest = 0;
00135 }
00136
00141 void Order::MakeImplicit(StationID destination)
00142 {
00143 this->type = OT_IMPLICIT;
00144 this->dest = destination;
00145 }
00146
00153 void Order::SetRefit(CargoID cargo, byte subtype)
00154 {
00155 this->refit_cargo = cargo;
00156 this->refit_subtype = subtype;
00157 }
00158
00164 bool Order::Equals(const Order &other) const
00165 {
00166
00167
00168
00169
00170
00171 if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
00172 ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
00173 (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
00174 return this->GetDepotOrderType() == other.GetDepotOrderType() &&
00175 (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
00176 }
00177
00178 return this->type == other.type && this->flags == other.flags && this->dest == other.dest;
00179 }
00180
00187 uint32 Order::Pack() const
00188 {
00189 return this->dest << 16 | this->flags << 8 | this->type;
00190 }
00191
00197 uint16 Order::MapOldOrder() const
00198 {
00199 uint16 order = this->GetType();
00200 switch (this->type) {
00201 case OT_GOTO_STATION:
00202 if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
00203 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
00204 if (this->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) SetBit(order, 7);
00205 order |= GB(this->GetDestination(), 0, 8) << 8;
00206 break;
00207 case OT_GOTO_DEPOT:
00208 if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
00209 SetBit(order, 7);
00210 order |= GB(this->GetDestination(), 0, 8) << 8;
00211 break;
00212 case OT_LOADING:
00213 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
00214 break;
00215 }
00216 return order;
00217 }
00218
00223 Order::Order(uint32 packed)
00224 {
00225 this->type = (OrderType)GB(packed, 0, 8);
00226 this->flags = GB(packed, 8, 8);
00227 this->dest = GB(packed, 16, 16);
00228 this->next = NULL;
00229 this->refit_cargo = CT_NO_REFIT;
00230 this->refit_subtype = 0;
00231 this->wait_time = 0;
00232 this->travel_time = 0;
00233 }
00234
00240 void InvalidateVehicleOrder(const Vehicle *v, int data)
00241 {
00242 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
00243
00244 if (data != 0) {
00245
00246 InvalidateWindowData(WC_VEHICLE_ORDERS, v->index, data);
00247 InvalidateWindowData(WC_VEHICLE_TIMETABLE, v->index, data);
00248 return;
00249 }
00250
00251 SetWindowDirty(WC_VEHICLE_ORDERS, v->index);
00252 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00253 }
00254
00262 void Order::AssignOrder(const Order &other)
00263 {
00264 this->type = other.type;
00265 this->flags = other.flags;
00266 this->dest = other.dest;
00267
00268 this->refit_cargo = other.refit_cargo;
00269 this->refit_subtype = other.refit_subtype;
00270
00271 this->wait_time = other.wait_time;
00272 this->travel_time = other.travel_time;
00273 }
00274
00280 void OrderList::Initialize(Order *chain, Vehicle *v)
00281 {
00282 this->first = chain;
00283 this->first_shared = v;
00284
00285 this->num_orders = 0;
00286 this->num_manual_orders = 0;
00287 this->num_vehicles = 1;
00288 this->timetable_duration = 0;
00289
00290 for (Order *o = this->first; o != NULL; o = o->next) {
00291 ++this->num_orders;
00292 if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
00293 this->timetable_duration += o->wait_time + o->travel_time;
00294 }
00295
00296 for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) {
00297 ++this->num_vehicles;
00298 this->first_shared = u;
00299 }
00300
00301 for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles;
00302 }
00303
00309 void OrderList::FreeChain(bool keep_orderlist)
00310 {
00311 Order *next;
00312 for (Order *o = this->first; o != NULL; o = next) {
00313 next = o->next;
00314 delete o;
00315 }
00316
00317 if (keep_orderlist) {
00318 this->first = NULL;
00319 this->num_orders = 0;
00320 this->num_manual_orders = 0;
00321 this->timetable_duration = 0;
00322 } else {
00323 delete this;
00324 }
00325 }
00326
00332 Order *OrderList::GetOrderAt(int index) const
00333 {
00334 if (index < 0) return NULL;
00335
00336 Order *order = this->first;
00337
00338 while (order != NULL && index-- > 0) {
00339 order = order->next;
00340 }
00341 return order;
00342 }
00343
00353 const Order *OrderList::GetBestLoadableNext(const Vehicle *v, const Order *o2, const Order *o1) const
00354 {
00355 SmallMap<CargoID, uint> capacities;
00356 v->GetConsistFreeCapacities(capacities);
00357 uint loadable1 = 0;
00358 uint loadable2 = 0;
00359 StationID st1 = o1->GetDestination();
00360 StationID st2 = o2->GetDestination();
00361 const Station *cur_station = Station::Get(v->last_station_visited);
00362 for (SmallPair<CargoID, uint> *i = capacities.Begin(); i != capacities.End(); ++i) {
00363 const StationCargoPacketMap *loadable_packets = cur_station->goods[i->first].cargo.Packets();
00364 uint loadable_cargo = 0;
00365 std::pair<StationCargoPacketMap::const_iterator, StationCargoPacketMap::const_iterator> p =
00366 loadable_packets->equal_range(st1);
00367 for (StationCargoPacketMap::const_iterator j = p.first; j != p.second; ++j) {
00368 loadable_cargo = (*j)->Count();
00369 }
00370 loadable1 += min(i->second, loadable_cargo);
00371
00372 loadable_cargo = 0;
00373 p = loadable_packets->equal_range(st2);
00374 for (StationCargoPacketMap::const_iterator j = p.first; j != p.second; ++j) {
00375 loadable_cargo = (*j)->Count();
00376 }
00377 loadable2 += min(i->second, loadable_cargo);
00378 }
00379 if (loadable1 == loadable2) return RandomRange(2) == 0 ? o1 : o2;
00380 return loadable1 > loadable2 ? o1 : o2;
00381 }
00382
00394 const Order *OrderList::GetNextStoppingOrder(const Vehicle *v, const Order *next, uint hops, bool is_loading) const
00395 {
00396 if (hops > this->GetNumOrders() || next == NULL) return NULL;
00397
00398 if (next->IsType(OT_CONDITIONAL)) {
00399 if (is_loading && next->GetConditionVariable() == OCV_LOAD_PERCENTAGE) {
00400
00401
00402
00403 const Order *skip_to = this->GetNextStoppingOrder(v,
00404 this->GetOrderAt(next->GetConditionSkipToOrder()),
00405 hops + 1);
00406 const Order *advance = this->GetNextStoppingOrder(v,
00407 this->GetNext(next), hops + 1);
00408 if (advance == NULL) {
00409 return skip_to;
00410 } else if (skip_to == NULL) {
00411 return advance;
00412 } else {
00413 return this->GetBestLoadableNext(v, skip_to, advance);
00414 }
00415 } else {
00416
00417
00418
00419 VehicleOrderID skip_to = ProcessConditionalOrder(next, v);
00420 if (skip_to != INVALID_VEH_ORDER_ID) {
00421 return this->GetNextStoppingOrder(v,
00422 this->GetOrderAt(skip_to), hops + 1);
00423 } else {
00424 return this->GetNextStoppingOrder(v,
00425 this->GetNext(next), hops + 1);
00426 }
00427 }
00428 }
00429
00430 if (next->IsType(OT_GOTO_DEPOT)) {
00431 if (next->GetDepotActionType() == ODATFB_HALT) return NULL;
00432 if (next->IsRefit()) return next;
00433 }
00434
00435 if (!next->CanLoadOrUnload()) {
00436 return this->GetNextStoppingOrder(v, this->GetNext(next), hops + 1);
00437 }
00438
00439 return next;
00440 }
00441
00449 StationID OrderList::GetNextStoppingStation(const Vehicle *v) const
00450 {
00451
00452 const Order *next = this->GetOrderAt(v->cur_implicit_order_index);
00453 if (next == NULL) {
00454 next = this->GetFirstOrder();
00455 if (next == NULL) return INVALID_STATION;
00456 } else {
00457 next = this->GetNext(next);
00458 }
00459
00460 uint hops = 0;
00461 do {
00462 next = this->GetNextStoppingOrder(v, next, ++hops, true);
00463
00464 if (next == NULL || (next->GetDestination() == v->last_station_visited &&
00465 (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) == 0)) {
00466 return INVALID_STATION;
00467 }
00468 } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited);
00469
00470 return next->GetDestination();
00471 }
00472
00478 void OrderList::InsertOrderAt(Order *new_order, int index)
00479 {
00480 if (this->first == NULL) {
00481 this->first = new_order;
00482 } else {
00483 if (index == 0) {
00484
00485 new_order->next = this->first;
00486 this->first = new_order;
00487 } else if (index >= this->num_orders) {
00488
00489 this->GetLastOrder()->next = new_order;
00490 } else {
00491
00492 Order *order = this->GetOrderAt(index - 1);
00493 new_order->next = order->next;
00494 order->next = new_order;
00495 }
00496 }
00497 ++this->num_orders;
00498 if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
00499 this->timetable_duration += new_order->wait_time + new_order->travel_time;
00500 }
00501
00502
00507 void OrderList::DeleteOrderAt(int index)
00508 {
00509 if (index >= this->num_orders) return;
00510
00511 Order *to_remove;
00512
00513 if (index == 0) {
00514 to_remove = this->first;
00515 this->first = to_remove->next;
00516 } else {
00517 Order *prev = GetOrderAt(index - 1);
00518 to_remove = prev->next;
00519 prev->next = to_remove->next;
00520 }
00521 --this->num_orders;
00522 if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
00523 this->timetable_duration -= (to_remove->wait_time + to_remove->travel_time);
00524 delete to_remove;
00525 }
00526
00532 void OrderList::MoveOrder(int from, int to)
00533 {
00534 if (from >= this->num_orders || to >= this->num_orders || from == to) return;
00535
00536 Order *moving_one;
00537
00538
00539 if (from == 0) {
00540 moving_one = this->first;
00541 this->first = moving_one->next;
00542 } else {
00543 Order *one_before = GetOrderAt(from - 1);
00544 moving_one = one_before->next;
00545 one_before->next = moving_one->next;
00546 }
00547
00548
00549 if (to == 0) {
00550 moving_one->next = this->first;
00551 this->first = moving_one;
00552 } else {
00553 Order *one_before = GetOrderAt(to - 1);
00554 moving_one->next = one_before->next;
00555 one_before->next = moving_one;
00556 }
00557 }
00558
00564 void OrderList::RemoveVehicle(Vehicle *v)
00565 {
00566 --this->num_vehicles;
00567 if (v == this->first_shared) this->first_shared = v->NextShared();
00568 }
00569
00574 bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const
00575 {
00576 for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) {
00577 if (v_shared == v) return true;
00578 }
00579
00580 return false;
00581 }
00582
00588 int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
00589 {
00590 int count = 0;
00591 for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++;
00592 return count;
00593 }
00594
00599 bool OrderList::IsCompleteTimetable() const
00600 {
00601 for (Order *o = this->first; o != NULL; o = o->next) {
00602
00603 if (o->IsType(OT_IMPLICIT)) continue;
00604 if (!o->IsCompletelyTimetabled()) return false;
00605 }
00606 return true;
00607 }
00608
00612 void OrderList::DebugCheckSanity() const
00613 {
00614 VehicleOrderID check_num_orders = 0;
00615 VehicleOrderID check_num_manual_orders = 0;
00616 uint check_num_vehicles = 0;
00617 Ticks check_timetable_duration = 0;
00618
00619 DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
00620
00621 for (const Order *o = this->first; o != NULL; o = o->next) {
00622 ++check_num_orders;
00623 if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
00624 check_timetable_duration += o->wait_time + o->travel_time;
00625 }
00626 assert(this->num_orders == check_num_orders);
00627 assert(this->num_manual_orders == check_num_manual_orders);
00628 assert(this->timetable_duration == check_timetable_duration);
00629
00630 for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
00631 ++check_num_vehicles;
00632 assert(v->orders.list == this);
00633 }
00634 assert(this->num_vehicles == check_num_vehicles);
00635 DEBUG(misc, 6, "... detected %u orders (%u manual), %u vehicles, %i ticks",
00636 (uint)this->num_orders, (uint)this->num_manual_orders,
00637 this->num_vehicles, this->timetable_duration);
00638 }
00639
00647 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
00648 {
00649 return o->IsType(OT_GOTO_STATION) ||
00650 (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
00651 }
00652
00659 static void DeleteOrderWarnings(const Vehicle *v)
00660 {
00661 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
00662 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
00663 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
00664 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
00665 }
00666
00672 TileIndex Order::GetLocation(const Vehicle *v) const
00673 {
00674 switch (this->GetType()) {
00675 case OT_GOTO_WAYPOINT:
00676 case OT_GOTO_STATION:
00677 case OT_IMPLICIT:
00678 return BaseStation::Get(this->GetDestination())->xy;
00679
00680 case OT_GOTO_DEPOT:
00681 if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE;
00682 return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
00683
00684 default:
00685 return INVALID_TILE;
00686 }
00687 }
00688
00689 static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0)
00690 {
00691 assert(v->type == VEH_SHIP);
00692
00693 if (cur->IsType(OT_CONDITIONAL)) {
00694 if (conditional_depth > v->GetNumOrders()) return 0;
00695
00696 conditional_depth++;
00697
00698 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
00699 int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
00700 return max(dist1, dist2);
00701 }
00702
00703 TileIndex prev_tile = prev->GetLocation(v);
00704 TileIndex cur_tile = cur->GetLocation(v);
00705 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
00706 return DistanceManhattan(prev_tile, cur_tile);
00707 }
00708
00722 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00723 {
00724 VehicleID veh = GB(p1, 0, 20);
00725 VehicleOrderID sel_ord = GB(p1, 20, 8);
00726 Order new_order(p2);
00727
00728 Vehicle *v = Vehicle::GetIfValid(veh);
00729 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00730
00731 CommandCost ret = CheckOwnership(v->owner);
00732 if (ret.Failed()) return ret;
00733
00734
00735
00736 switch (new_order.GetType()) {
00737 case OT_GOTO_STATION: {
00738 const Station *st = Station::GetIfValid(new_order.GetDestination());
00739 if (st == NULL) return CMD_ERROR;
00740
00741 if (st->owner != OWNER_NONE) {
00742 CommandCost ret = CheckOwnership(st->owner);
00743 if (ret.Failed()) return ret;
00744 }
00745
00746 if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00747 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
00748 if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
00749 }
00750
00751
00752 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
00753
00754
00755 switch (new_order.GetLoadType()) {
00756 case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
00757 default: return CMD_ERROR;
00758 }
00759 switch (new_order.GetUnloadType()) {
00760 case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
00761 default: return CMD_ERROR;
00762 }
00763
00764
00765 switch (new_order.GetStopLocation()) {
00766 case OSL_PLATFORM_NEAR_END:
00767 case OSL_PLATFORM_MIDDLE:
00768 if (v->type != VEH_TRAIN) return CMD_ERROR;
00769
00770 case OSL_PLATFORM_FAR_END:
00771 break;
00772
00773 default:
00774 return CMD_ERROR;
00775 }
00776
00777 break;
00778 }
00779
00780 case OT_GOTO_DEPOT: {
00781 if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
00782 if (v->type == VEH_AIRCRAFT) {
00783 const Station *st = Station::GetIfValid(new_order.GetDestination());
00784
00785 if (st == NULL) return CMD_ERROR;
00786
00787 CommandCost ret = CheckOwnership(st->owner);
00788 if (ret.Failed()) return ret;
00789
00790 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
00791 return CMD_ERROR;
00792 }
00793 } else {
00794 const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
00795
00796 if (dp == NULL) return CMD_ERROR;
00797
00798 CommandCost ret = CheckOwnership(GetTileOwner(dp->xy));
00799 if (ret.Failed()) return ret;
00800
00801 switch (v->type) {
00802 case VEH_TRAIN:
00803 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
00804 break;
00805
00806 case VEH_ROAD:
00807 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
00808 break;
00809
00810 case VEH_SHIP:
00811 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
00812 break;
00813
00814 default: return CMD_ERROR;
00815 }
00816 }
00817 }
00818
00819 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
00820 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
00821 if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
00822 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
00823 break;
00824 }
00825
00826 case OT_GOTO_WAYPOINT: {
00827 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
00828 if (wp == NULL) return CMD_ERROR;
00829
00830 switch (v->type) {
00831 default: return CMD_ERROR;
00832
00833 case VEH_TRAIN: {
00834 if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00835
00836 CommandCost ret = CheckOwnership(wp->owner);
00837 if (ret.Failed()) return ret;
00838 break;
00839 }
00840
00841 case VEH_SHIP:
00842 if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00843 if (wp->owner != OWNER_NONE) {
00844 CommandCost ret = CheckOwnership(wp->owner);
00845 if (ret.Failed()) return ret;
00846 }
00847 break;
00848 }
00849
00850
00851
00852
00853 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
00854 break;
00855 }
00856
00857 case OT_CONDITIONAL: {
00858 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
00859 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR;
00860 if (new_order.GetConditionVariable() > OCV_END) return CMD_ERROR;
00861
00862 OrderConditionComparator occ = new_order.GetConditionComparator();
00863 if (occ > OCC_END) return CMD_ERROR;
00864 switch (new_order.GetConditionVariable()) {
00865 case OCV_REQUIRES_SERVICE:
00866 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
00867 break;
00868
00869 case OCV_UNCONDITIONALLY:
00870 if (occ != OCC_EQUALS) return CMD_ERROR;
00871 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
00872 break;
00873
00874 case OCV_LOAD_PERCENTAGE:
00875 case OCV_RELIABILITY:
00876 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
00877
00878 default:
00879 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
00880 break;
00881 }
00882 break;
00883 }
00884
00885 default: return CMD_ERROR;
00886 }
00887
00888 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
00889
00890 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS);
00891 if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00892 if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00893
00894 if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) {
00895
00896 const Order *prev = NULL;
00897 uint n = 0;
00898
00899
00900
00901
00902 const Order *o;
00903 FOR_VEHICLE_ORDERS(v, o) {
00904 switch (o->GetType()) {
00905 case OT_GOTO_STATION:
00906 case OT_GOTO_DEPOT:
00907 case OT_GOTO_WAYPOINT:
00908 prev = o;
00909 break;
00910
00911 default: break;
00912 }
00913 if (++n == sel_ord && prev != NULL) break;
00914 }
00915 if (prev != NULL) {
00916 uint dist = GetOrderDistance(prev, &new_order, v);
00917 if (dist >= 130) {
00918 return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION);
00919 }
00920 }
00921 }
00922
00923 if (flags & DC_EXEC) {
00924 Order *new_o = new Order();
00925 new_o->AssignOrder(new_order);
00926 InsertOrder(v, new_o, sel_ord);
00927 }
00928
00929 return CommandCost();
00930 }
00931
00938 void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
00939 {
00940
00941 if (v->orders.list == NULL) {
00942 v->orders.list = new OrderList(new_o, v);
00943 } else {
00944 v->orders.list->InsertOrderAt(new_o, sel_ord);
00945 }
00946
00947 Vehicle *u = v->FirstShared();
00948 DeleteOrderWarnings(u);
00949 for (; u != NULL; u = u->NextShared()) {
00950 assert(v->orders.list == u->orders.list);
00951
00952
00953
00954
00955
00956 if (sel_ord <= u->cur_real_order_index) {
00957 uint cur = u->cur_real_order_index + 1;
00958
00959 if (cur < u->GetNumOrders()) {
00960 u->cur_real_order_index = cur;
00961 }
00962 }
00963 if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) {
00964
00965
00966
00967 uint16 &gv_flags = u->GetGroundVehicleFlags();
00968 SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
00969 }
00970 if (sel_ord <= u->cur_implicit_order_index) {
00971 uint cur = u->cur_implicit_order_index + 1;
00972
00973 if (cur < u->GetNumOrders()) {
00974 u->cur_implicit_order_index = cur;
00975 }
00976 }
00977
00978 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
00979 }
00980
00981
00982 VehicleOrderID cur_order_id = 0;
00983 Order *order;
00984 FOR_VEHICLE_ORDERS(v, order) {
00985 if (order->IsType(OT_CONDITIONAL)) {
00986 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00987 if (order_id >= sel_ord) {
00988 order->SetConditionSkipToOrder(order_id + 1);
00989 }
00990 if (order_id == cur_order_id) {
00991 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00992 }
00993 }
00994 cur_order_id++;
00995 }
00996
00997
00998 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00999 }
01000
01006 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
01007 {
01008 if (flags & DC_EXEC) {
01009 DeleteVehicleOrders(dst);
01010 InvalidateVehicleOrder(dst, -1);
01011
01012 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01013 }
01014 return CommandCost();
01015 }
01016
01026 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01027 {
01028 VehicleID veh_id = GB(p1, 0, 20);
01029 VehicleOrderID sel_ord = GB(p2, 0, 8);
01030
01031 Vehicle *v = Vehicle::GetIfValid(veh_id);
01032
01033 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01034
01035 CommandCost ret = CheckOwnership(v->owner);
01036 if (ret.Failed()) return ret;
01037
01038
01039 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
01040
01041 if (v->GetOrder(sel_ord) == NULL) return CMD_ERROR;
01042
01043 if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
01044 return CommandCost();
01045 }
01046
01051 static void CancelLoadingDueToDeletedOrder(Vehicle *v)
01052 {
01053 assert(v->current_order.IsType(OT_LOADING));
01054
01055
01056 v->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
01057
01058
01059 if (v->current_order.GetLoadType() & OLFB_FULL_LOAD) v->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE);
01060 }
01061
01067 void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
01068 {
01069 v->orders.list->DeleteOrderAt(sel_ord);
01070
01071 Vehicle *u = v->FirstShared();
01072 DeleteOrderWarnings(u);
01073 for (; u != NULL; u = u->NextShared()) {
01074 assert(v->orders.list == u->orders.list);
01075
01076 if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
01077 CancelLoadingDueToDeletedOrder(u);
01078 }
01079
01080 if (sel_ord < u->cur_real_order_index) {
01081 u->cur_real_order_index--;
01082 } else if (sel_ord == u->cur_real_order_index) {
01083 u->UpdateRealOrderIndex();
01084 }
01085
01086 if (sel_ord < u->cur_implicit_order_index) {
01087 u->cur_implicit_order_index--;
01088 } else if (sel_ord == u->cur_implicit_order_index) {
01089
01090 if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
01091
01092
01093 while (u->cur_implicit_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_implicit_order_index)->IsType(OT_IMPLICIT)) {
01094 u->cur_implicit_order_index++;
01095 if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
01096 }
01097 }
01098
01099
01100 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
01101 }
01102
01103
01104 VehicleOrderID cur_order_id = 0;
01105 Order *order = NULL;
01106 FOR_VEHICLE_ORDERS(v, order) {
01107 if (order->IsType(OT_CONDITIONAL)) {
01108 VehicleOrderID order_id = order->GetConditionSkipToOrder();
01109 if (order_id >= sel_ord) {
01110 order_id = max(order_id - 1, 0);
01111 }
01112 if (order_id == cur_order_id) {
01113 order_id = (order_id + 1) % v->GetNumOrders();
01114 }
01115 order->SetConditionSkipToOrder(order_id);
01116 }
01117 cur_order_id++;
01118 }
01119
01120 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
01121 }
01122
01132 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01133 {
01134 VehicleID veh_id = GB(p1, 0, 20);
01135 VehicleOrderID sel_ord = GB(p2, 0, 8);
01136
01137 Vehicle *v = Vehicle::GetIfValid(veh_id);
01138
01139 if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
01140
01141 CommandCost ret = CheckOwnership(v->owner);
01142 if (ret.Failed()) return ret;
01143
01144 if (flags & DC_EXEC) {
01145 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
01146
01147 v->cur_implicit_order_index = v->cur_real_order_index = sel_ord;
01148 v->UpdateRealOrderIndex();
01149
01150 InvalidateVehicleOrder(v, -2);
01151 }
01152
01153
01154 if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
01155 if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
01156
01157 return CommandCost();
01158 }
01159
01173 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01174 {
01175 VehicleID veh = GB(p1, 0, 20);
01176 VehicleOrderID moving_order = GB(p2, 0, 16);
01177 VehicleOrderID target_order = GB(p2, 16, 16);
01178
01179 Vehicle *v = Vehicle::GetIfValid(veh);
01180 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01181
01182 CommandCost ret = CheckOwnership(v->owner);
01183 if (ret.Failed()) return ret;
01184
01185
01186 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
01187 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
01188
01189 Order *moving_one = v->GetOrder(moving_order);
01190
01191 if (moving_one == NULL) return CMD_ERROR;
01192
01193 if (flags & DC_EXEC) {
01194 v->orders.list->MoveOrder(moving_order, target_order);
01195
01196
01197 Vehicle *u = v->FirstShared();
01198
01199 DeleteOrderWarnings(u);
01200
01201 for (; u != NULL; u = u->NextShared()) {
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218 if (u->cur_real_order_index == moving_order) {
01219 u->cur_real_order_index = target_order;
01220 } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) {
01221 u->cur_real_order_index--;
01222 } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) {
01223 u->cur_real_order_index++;
01224 }
01225
01226 if (u->cur_implicit_order_index == moving_order) {
01227 u->cur_implicit_order_index = target_order;
01228 } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) {
01229 u->cur_implicit_order_index--;
01230 } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
01231 u->cur_implicit_order_index++;
01232 }
01233
01234 assert(v->orders.list == u->orders.list);
01235
01236 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
01237 }
01238
01239
01240 Order *order;
01241 FOR_VEHICLE_ORDERS(v, order) {
01242 if (order->IsType(OT_CONDITIONAL)) {
01243 VehicleOrderID order_id = order->GetConditionSkipToOrder();
01244 if (order_id == moving_order) {
01245 order_id = target_order;
01246 } else if (order_id > moving_order && order_id <= target_order) {
01247 order_id--;
01248 } else if (order_id < moving_order && order_id >= target_order) {
01249 order_id++;
01250 }
01251 order->SetConditionSkipToOrder(order_id);
01252 }
01253 }
01254
01255
01256 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
01257 }
01258
01259 return CommandCost();
01260 }
01261
01277 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01278 {
01279 VehicleOrderID sel_ord = GB(p1, 20, 8);
01280 VehicleID veh = GB(p1, 0, 20);
01281 ModifyOrderFlags mof = Extract<ModifyOrderFlags, 0, 4>(p2);
01282 uint16 data = GB(p2, 4, 11);
01283
01284 if (mof >= MOF_END) return CMD_ERROR;
01285
01286 Vehicle *v = Vehicle::GetIfValid(veh);
01287 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01288
01289 CommandCost ret = CheckOwnership(v->owner);
01290 if (ret.Failed()) return ret;
01291
01292
01293 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
01294
01295 Order *order = v->GetOrder(sel_ord);
01296 switch (order->GetType()) {
01297 case OT_GOTO_STATION:
01298 if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE) return CMD_ERROR;
01299 break;
01300
01301 case OT_GOTO_DEPOT:
01302 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
01303 break;
01304
01305 case OT_GOTO_WAYPOINT:
01306 if (mof != MOF_NON_STOP) return CMD_ERROR;
01307 break;
01308
01309 case OT_CONDITIONAL:
01310 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
01311 break;
01312
01313 default:
01314 return CMD_ERROR;
01315 }
01316
01317 switch (mof) {
01318 default: NOT_REACHED();
01319
01320 case MOF_NON_STOP:
01321 if (!v->IsGroundVehicle()) return CMD_ERROR;
01322 if (data >= ONSF_END) return CMD_ERROR;
01323 if (data == order->GetNonStopType()) return CMD_ERROR;
01324 break;
01325
01326 case MOF_STOP_LOCATION:
01327 if (v->type != VEH_TRAIN) return CMD_ERROR;
01328 if (data >= OSL_END) return CMD_ERROR;
01329 break;
01330
01331 case MOF_UNLOAD:
01332 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
01333
01334 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
01335 if (data == order->GetUnloadType()) return CMD_ERROR;
01336 break;
01337
01338 case MOF_LOAD:
01339 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
01340 if (data == order->GetLoadType()) return CMD_ERROR;
01341 break;
01342
01343 case MOF_DEPOT_ACTION:
01344 if (data >= DA_END) return CMD_ERROR;
01345 break;
01346
01347 case MOF_COND_VARIABLE:
01348 if (data >= OCV_END) return CMD_ERROR;
01349 break;
01350
01351 case MOF_COND_COMPARATOR:
01352 if (data >= OCC_END) return CMD_ERROR;
01353 switch (order->GetConditionVariable()) {
01354 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01355
01356 case OCV_REQUIRES_SERVICE:
01357 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
01358 break;
01359
01360 default:
01361 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
01362 break;
01363 }
01364 break;
01365
01366 case MOF_COND_VALUE:
01367 switch (order->GetConditionVariable()) {
01368 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01369
01370 case OCV_LOAD_PERCENTAGE:
01371 case OCV_RELIABILITY:
01372 if (data > 100) return CMD_ERROR;
01373 break;
01374
01375 default:
01376 if (data > 2047) return CMD_ERROR;
01377 break;
01378 }
01379 break;
01380
01381 case MOF_COND_DESTINATION:
01382 if (data >= v->GetNumOrders()) return CMD_ERROR;
01383 break;
01384 }
01385
01386 if (flags & DC_EXEC) {
01387 switch (mof) {
01388 case MOF_NON_STOP:
01389 order->SetNonStopType((OrderNonStopFlags)data);
01390 break;
01391
01392 case MOF_STOP_LOCATION:
01393 order->SetStopLocation((OrderStopLocation)data);
01394 break;
01395
01396 case MOF_UNLOAD:
01397 order->SetUnloadType((OrderUnloadFlags)data);
01398 break;
01399
01400 case MOF_LOAD:
01401 order->SetLoadType((OrderLoadFlags)data);
01402 break;
01403
01404 case MOF_DEPOT_ACTION: {
01405 switch (data) {
01406 case DA_ALWAYS_GO:
01407 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01408 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01409 break;
01410
01411 case DA_SERVICE:
01412 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
01413 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01414 break;
01415
01416 case DA_STOP:
01417 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01418 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
01419 break;
01420
01421 default:
01422 NOT_REACHED();
01423 }
01424 break;
01425 }
01426
01427 case MOF_COND_VARIABLE: {
01428 order->SetConditionVariable((OrderConditionVariable)data);
01429
01430 OrderConditionComparator occ = order->GetConditionComparator();
01431 switch (order->GetConditionVariable()) {
01432 case OCV_UNCONDITIONALLY:
01433 order->SetConditionComparator(OCC_EQUALS);
01434 order->SetConditionValue(0);
01435 break;
01436
01437 case OCV_REQUIRES_SERVICE:
01438 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
01439 break;
01440
01441 case OCV_LOAD_PERCENTAGE:
01442 case OCV_RELIABILITY:
01443 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
01444
01445 default:
01446 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
01447 break;
01448 }
01449 break;
01450 }
01451
01452 case MOF_COND_COMPARATOR:
01453 order->SetConditionComparator((OrderConditionComparator)data);
01454 break;
01455
01456 case MOF_COND_VALUE:
01457 order->SetConditionValue(data);
01458 break;
01459
01460 case MOF_COND_DESTINATION:
01461 order->SetConditionSkipToOrder(data);
01462 break;
01463
01464 default: NOT_REACHED();
01465 }
01466
01467
01468 Vehicle *u = v->FirstShared();
01469 DeleteOrderWarnings(u);
01470 for (; u != NULL; u = u->NextShared()) {
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480 if (sel_ord == u->cur_real_order_index &&
01481 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
01482 u->current_order.GetLoadType() != order->GetLoadType()) {
01483 u->current_order.SetLoadType(order->GetLoadType());
01484 }
01485 InvalidateVehicleOrder(u, -2);
01486 }
01487 }
01488
01489 return CommandCost();
01490 }
01491
01503 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01504 {
01505 VehicleID veh_src = GB(p2, 0, 20);
01506 VehicleID veh_dst = GB(p1, 0, 20);
01507
01508 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
01509 if (dst == NULL || !dst->IsPrimaryVehicle()) return CMD_ERROR;
01510
01511 CommandCost ret = CheckOwnership(dst->owner);
01512 if (ret.Failed()) return ret;
01513
01514 switch (GB(p1, 30, 2)) {
01515 case CO_SHARE: {
01516 Vehicle *src = Vehicle::GetIfValid(veh_src);
01517
01518
01519 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01520
01521 CommandCost ret = CheckOwnership(src->owner);
01522 if (ret.Failed()) return ret;
01523
01524
01525 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
01526 return CMD_ERROR;
01527 }
01528
01529
01530 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
01531
01532 const Order *order;
01533
01534 FOR_VEHICLE_ORDERS(src, order) {
01535 if (OrderGoesToStation(dst, order) &&
01536 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01537 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01538 }
01539 }
01540
01541 if (src->orders.list == NULL && !OrderList::CanAllocateItem()) {
01542 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01543 }
01544
01545 if (flags & DC_EXEC) {
01546
01547
01548
01549 DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders());
01550
01551 dst->orders.list = src->orders.list;
01552
01553
01554 dst->AddToShared(src);
01555
01556 InvalidateVehicleOrder(dst, -1);
01557 InvalidateVehicleOrder(src, -2);
01558
01559 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01560 }
01561 break;
01562 }
01563
01564 case CO_COPY: {
01565 Vehicle *src = Vehicle::GetIfValid(veh_src);
01566
01567
01568 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01569
01570 CommandCost ret = CheckOwnership(src->owner);
01571 if (ret.Failed()) return ret;
01572
01573
01574
01575 const Order *order;
01576 FOR_VEHICLE_ORDERS(src, order) {
01577 if (OrderGoesToStation(dst, order) &&
01578 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01579 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01580 }
01581 }
01582
01583
01584 int delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
01585 if (!Order::CanAllocateItem(delta) ||
01586 ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
01587 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01588 }
01589
01590 if (flags & DC_EXEC) {
01591 const Order *order;
01592 Order *first = NULL;
01593 Order **order_dst;
01594
01595
01596
01597
01598 DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders());
01599
01600 order_dst = &first;
01601 FOR_VEHICLE_ORDERS(src, order) {
01602 *order_dst = new Order();
01603 (*order_dst)->AssignOrder(*order);
01604 order_dst = &(*order_dst)->next;
01605 }
01606 if (dst->orders.list == NULL) {
01607 dst->orders.list = new OrderList(first, dst);
01608 } else {
01609 assert(dst->orders.list->GetFirstOrder() == NULL);
01610 assert(!dst->orders.list->IsShared());
01611 delete dst->orders.list;
01612 assert(OrderList::CanAllocateItem());
01613 dst->orders.list = new OrderList(first, dst);
01614 }
01615
01616 InvalidateVehicleOrder(dst, -1);
01617
01618 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01619 }
01620 break;
01621 }
01622
01623 case CO_UNSHARE: return DecloneOrder(dst, flags);
01624 default: return CMD_ERROR;
01625 }
01626
01627 return CommandCost();
01628 }
01629
01642 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01643 {
01644 VehicleID veh = GB(p1, 0, 20);
01645 VehicleOrderID order_number = GB(p2, 16, 8);
01646 CargoID cargo = GB(p2, 0, 8);
01647 byte subtype = GB(p2, 8, 8);
01648
01649 if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT) return CMD_ERROR;
01650
01651 const Vehicle *v = Vehicle::GetIfValid(veh);
01652 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01653
01654 CommandCost ret = CheckOwnership(v->owner);
01655 if (ret.Failed()) return ret;
01656
01657 Order *order = v->GetOrder(order_number);
01658 if (order == NULL) return CMD_ERROR;
01659
01660 if (flags & DC_EXEC) {
01661 order->SetRefit(cargo, subtype);
01662
01663 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
01664
01665 InvalidateVehicleOrder(u, -2);
01666
01667
01668 if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
01669 u->current_order.SetRefit(cargo, subtype);
01670 }
01671 }
01672 }
01673
01674 return CommandCost();
01675 }
01676
01677
01683 void CheckOrders(const Vehicle *v)
01684 {
01685
01686 if (_settings_client.gui.order_review_system == 0) return;
01687
01688
01689 if (v->vehstatus & VS_CRASHED) return;
01690
01691
01692 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
01693
01694
01695 if (v->FirstShared() != v) return;
01696
01697
01698 if (v->owner == _local_company && v->day_counter % 20 == 0) {
01699 int n_st, problem_type = -1;
01700 const Order *order;
01701 int message = 0;
01702
01703
01704 n_st = 0;
01705
01706 FOR_VEHICLE_ORDERS(v, order) {
01707
01708 if (order->IsType(OT_DUMMY)) {
01709 problem_type = 1;
01710 break;
01711 }
01712
01713 if (order->IsType(OT_GOTO_STATION)) {
01714 const Station *st = Station::Get(order->GetDestination());
01715
01716 n_st++;
01717 if (!CanVehicleUseStation(v, st)) problem_type = 3;
01718 }
01719 }
01720
01721
01722 if (v->GetNumOrders() > 1) {
01723 const Order *last = v->GetLastOrder();
01724
01725 if (v->orders.list->GetFirstOrder()->Equals(*last)) {
01726 problem_type = 2;
01727 }
01728 }
01729
01730
01731 if (n_st < 2 && problem_type == -1) problem_type = 0;
01732
01733 #ifndef NDEBUG
01734 if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
01735 #endif
01736
01737
01738 if (problem_type < 0) return;
01739
01740 message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
01741
01742
01743 SetDParam(0, v->index);
01744 AddVehicleNewsItem(
01745 message,
01746 NS_ADVICE,
01747 v->index
01748 );
01749 }
01750 }
01751
01757 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01758 {
01759 Vehicle *v;
01760
01761
01762
01763
01764
01765
01766 FOR_ALL_VEHICLES(v) {
01767 Order *order;
01768
01769 order = &v->current_order;
01770 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01771 v->current_order.GetDestination() == destination) {
01772 order->MakeDummy();
01773 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01774 }
01775
01776
01777 int id = -1;
01778 FOR_VEHICLE_ORDERS(v, order) {
01779 id++;
01780 restart:
01781
01782 OrderType ot = order->GetType();
01783 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
01784 if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
01785 if (ot == type && order->GetDestination() == destination) {
01786
01787
01788
01789 if (order->IsType(OT_IMPLICIT)) {
01790 order = order->next;
01791 DeleteOrder(v, id);
01792 if (order != NULL) goto restart;
01793 break;
01794 }
01795
01796 order->MakeDummy();
01797 for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
01798
01799 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
01800 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
01801 }
01802 }
01803 }
01804 }
01805 }
01806
01811 bool Vehicle::HasDepotOrder() const
01812 {
01813 const Order *order;
01814
01815 FOR_VEHICLE_ORDERS(this, order) {
01816 if (order->IsType(OT_GOTO_DEPOT)) return true;
01817 }
01818
01819 return false;
01820 }
01821
01831 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
01832 {
01833 DeleteOrderWarnings(v);
01834
01835 if (v->IsOrderListShared()) {
01836
01837 v->RemoveFromShared();
01838 v->orders.list = NULL;
01839 } else if (v->orders.list != NULL) {
01840
01841 v->orders.list->FreeChain(keep_orderlist);
01842 if (!keep_orderlist) v->orders.list = NULL;
01843 }
01844
01845 if (reset_order_indices) {
01846 v->cur_implicit_order_index = v->cur_real_order_index = 0;
01847 if (v->current_order.IsType(OT_LOADING)) {
01848 CancelLoadingDueToDeletedOrder(v);
01849 }
01850 }
01851 }
01852
01860 uint16 GetServiceIntervalClamped(uint interval, CompanyID company_id)
01861 {
01862 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);
01863 }
01864
01873 static bool CheckForValidOrders(const Vehicle *v)
01874 {
01875 const Order *order;
01876
01877 FOR_VEHICLE_ORDERS(v, order) {
01878 switch (order->GetType()) {
01879 case OT_GOTO_STATION:
01880 case OT_GOTO_DEPOT:
01881 case OT_GOTO_WAYPOINT:
01882 return true;
01883
01884 default:
01885 break;
01886 }
01887 }
01888
01889 return false;
01890 }
01891
01895 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
01896 {
01897 switch (occ) {
01898 case OCC_EQUALS: return variable == value;
01899 case OCC_NOT_EQUALS: return variable != value;
01900 case OCC_LESS_THAN: return variable < value;
01901 case OCC_LESS_EQUALS: return variable <= value;
01902 case OCC_MORE_THAN: return variable > value;
01903 case OCC_MORE_EQUALS: return variable >= value;
01904 case OCC_IS_TRUE: return variable != 0;
01905 case OCC_IS_FALSE: return variable == 0;
01906 default: NOT_REACHED();
01907 }
01908 }
01909
01916 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
01917 {
01918 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
01919
01920 bool skip_order = false;
01921 OrderConditionComparator occ = order->GetConditionComparator();
01922 uint16 value = order->GetConditionValue();
01923
01924 switch (order->GetConditionVariable()) {
01925 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
01926 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
01927 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
01928 case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
01929 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
01930 case OCV_UNCONDITIONALLY: skip_order = true; break;
01931 default: NOT_REACHED();
01932 }
01933
01934 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
01935 }
01936
01943 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
01944 {
01945 if (conditional_depth > v->GetNumOrders()) return false;
01946
01947 switch (order->GetType()) {
01948 case OT_GOTO_STATION:
01949 v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
01950 return true;
01951
01952 case OT_GOTO_DEPOT:
01953 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
01954 UpdateVehicleTimetable(v, true);
01955 v->IncrementRealOrderIndex();
01956 break;
01957 }
01958
01959 if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
01960
01961 TileIndex location;
01962 DestinationID destination;
01963 bool reverse;
01964
01965 if (v->FindClosestDepot(&location, &destination, &reverse)) {
01966 v->dest_tile = location;
01967 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());
01968
01969
01970 if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01971
01972 if (v->type == VEH_AIRCRAFT) {
01973 Aircraft *a = Aircraft::From(v);
01974 if (a->state == FLYING && a->targetairport != destination) {
01975
01976 extern void AircraftNextAirportPos_and_Order(Aircraft *a);
01977 AircraftNextAirportPos_and_Order(a);
01978 }
01979 }
01980 return true;
01981 }
01982
01983 UpdateVehicleTimetable(v, true);
01984 v->IncrementRealOrderIndex();
01985 } else {
01986 if (v->type != VEH_AIRCRAFT) {
01987 v->dest_tile = Depot::Get(order->GetDestination())->xy;
01988 }
01989 return true;
01990 }
01991 break;
01992
01993 case OT_GOTO_WAYPOINT:
01994 v->dest_tile = Waypoint::Get(order->GetDestination())->xy;
01995 return true;
01996
01997 case OT_CONDITIONAL: {
01998 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
01999 if (next_order != INVALID_VEH_ORDER_ID) {
02000
02001
02002 UpdateVehicleTimetable(v, false);
02003 v->cur_implicit_order_index = v->cur_real_order_index = next_order;
02004 v->UpdateRealOrderIndex();
02005 v->current_order_time += v->GetOrder(v->cur_real_order_index)->travel_time;
02006
02007
02008
02009 if (v->IsGroundVehicle()) {
02010 uint16 &gv_flags = v->GetGroundVehicleFlags();
02011 SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
02012 }
02013 } else {
02014 UpdateVehicleTimetable(v, true);
02015 v->IncrementRealOrderIndex();
02016 }
02017 break;
02018 }
02019
02020 default:
02021 v->dest_tile = 0;
02022 return false;
02023 }
02024
02025 assert(v->cur_implicit_order_index < v->GetNumOrders());
02026 assert(v->cur_real_order_index < v->GetNumOrders());
02027
02028
02029 order = v->GetOrder(v->cur_real_order_index);
02030 if (order != NULL && order->IsType(OT_IMPLICIT)) {
02031 assert(v->GetNumManualOrders() == 0);
02032 order = NULL;
02033 }
02034
02035 if (order == NULL) {
02036 v->current_order.Free();
02037 v->dest_tile = 0;
02038 return false;
02039 }
02040
02041 v->current_order = *order;
02042 return UpdateOrderDest(v, order, conditional_depth + 1);
02043 }
02044
02052 bool ProcessOrders(Vehicle *v)
02053 {
02054 switch (v->current_order.GetType()) {
02055 case OT_GOTO_DEPOT:
02056
02057 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
02058 break;
02059
02060 case OT_LOADING:
02061 return false;
02062
02063 case OT_LEAVESTATION:
02064 if (v->type != VEH_AIRCRAFT) return false;
02065 break;
02066
02067 default: break;
02068 }
02069
02077 bool may_reverse = v->current_order.IsType(OT_NOTHING);
02078
02079
02080 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)) &&
02081 IsTileType(v->tile, MP_STATION) &&
02082 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
02083 v->DeleteUnreachedImplicitOrders();
02084
02085
02086
02087
02088 v->last_station_visited = v->current_order.GetDestination();
02089 UpdateVehicleTimetable(v, true);
02090 v->IncrementImplicitOrderIndex();
02091 }
02092
02093
02094 assert(v->cur_implicit_order_index == 0 || v->cur_implicit_order_index < v->GetNumOrders());
02095 v->UpdateRealOrderIndex();
02096
02097 const Order *order = v->GetOrder(v->cur_real_order_index);
02098 if (order != NULL && order->IsType(OT_IMPLICIT)) {
02099 assert(v->GetNumManualOrders() == 0);
02100 order = NULL;
02101 }
02102
02103
02104 if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
02105 if (v->type == VEH_AIRCRAFT) {
02106
02107 extern void HandleMissingAircraftOrders(Aircraft *v);
02108 HandleMissingAircraftOrders(Aircraft::From(v));
02109 return false;
02110 }
02111
02112 v->current_order.Free();
02113 v->dest_tile = 0;
02114 return false;
02115 }
02116
02117
02118 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
02119 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
02120 return false;
02121 }
02122
02123
02124 v->current_order = *order;
02125
02126 InvalidateVehicleOrder(v, -2);
02127 switch (v->type) {
02128 default:
02129 NOT_REACHED();
02130
02131 case VEH_ROAD:
02132 case VEH_TRAIN:
02133 break;
02134
02135 case VEH_AIRCRAFT:
02136 case VEH_SHIP:
02137 SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
02138 break;
02139 }
02140
02141 return UpdateOrderDest(v, order) && may_reverse;
02142 }
02143
02151 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
02152 {
02153 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
02154
02155 return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
02156 v->last_station_visited != station &&
02157
02158 !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
02159 }
02160
02161 bool Order::CanLoadOrUnload() const
02162 {
02163 return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) &&
02164 (this->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0 &&
02165 ((this->GetLoadType() & OLFB_NO_LOAD) == 0 ||
02166 (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0);
02167 }
02168
02175 bool Order::CanLeaveWithCargo(bool has_cargo) const
02176 {
02177 return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo &&
02178 (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0);
02179 }