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 "functions.h"
00021 #include "window_func.h"
00022 #include "timetable.h"
00023 #include "vehicle_func.h"
00024 #include "depot_base.h"
00025 #include "core/pool_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 TileIndex _backup_orders_tile;
00041 BackuppedOrders _backup_orders_data;
00042
00043 OrderPool _order_pool("Order");
00044 INSTANTIATE_POOL_METHODS(Order)
00045 OrderListPool _orderlist_pool("OrderList");
00046 INSTANTIATE_POOL_METHODS(OrderList)
00047
00048 void Order::Free()
00049 {
00050 this->type = OT_NOTHING;
00051 this->flags = 0;
00052 this->dest = 0;
00053 this->next = NULL;
00054 }
00055
00056 void Order::MakeGoToStation(StationID destination)
00057 {
00058 this->type = OT_GOTO_STATION;
00059 this->flags = 0;
00060 this->dest = destination;
00061 }
00062
00063 void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoID cargo, byte subtype)
00064 {
00065 this->type = OT_GOTO_DEPOT;
00066 this->SetDepotOrderType(order);
00067 this->SetDepotActionType(action);
00068 this->SetNonStopType(non_stop_type);
00069 this->dest = destination;
00070 this->SetRefit(cargo, subtype);
00071 }
00072
00073 void Order::MakeGoToWaypoint(StationID destination)
00074 {
00075 this->type = OT_GOTO_WAYPOINT;
00076 this->flags = 0;
00077 this->dest = destination;
00078 }
00079
00080 void Order::MakeLoading(bool ordered)
00081 {
00082 this->type = OT_LOADING;
00083 if (!ordered) this->flags = 0;
00084 }
00085
00086 void Order::MakeLeaveStation()
00087 {
00088 this->type = OT_LEAVESTATION;
00089 this->flags = 0;
00090 }
00091
00092 void Order::MakeDummy()
00093 {
00094 this->type = OT_DUMMY;
00095 this->flags = 0;
00096 }
00097
00098 void Order::MakeConditional(VehicleOrderID order)
00099 {
00100 this->type = OT_CONDITIONAL;
00101 this->flags = order;
00102 this->dest = 0;
00103 }
00104
00105 void Order::SetRefit(CargoID cargo, byte subtype)
00106 {
00107 this->refit_cargo = cargo;
00108 this->refit_subtype = subtype;
00109 }
00110
00111 bool Order::Equals(const Order &other) const
00112 {
00113
00114
00115
00116
00117
00118 if ((this->type == OT_GOTO_DEPOT && this->type == other.type) &&
00119 ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
00120 (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
00121 return
00122 this->GetDepotOrderType() == other.GetDepotOrderType() &&
00123 (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
00124 }
00125
00126 return
00127 this->type == other.type &&
00128 this->flags == other.flags &&
00129 this->dest == other.dest;
00130 }
00131
00132 uint32 Order::Pack() const
00133 {
00134 return this->dest << 16 | this->flags << 8 | this->type;
00135 }
00136
00137 uint16 Order::MapOldOrder() const
00138 {
00139 uint16 order = this->GetType();
00140 switch (this->type) {
00141 case OT_GOTO_STATION:
00142 if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
00143 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
00144 if (this->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) SetBit(order, 7);
00145 order |= GB(this->GetDestination(), 0, 8) << 8;
00146 break;
00147 case OT_GOTO_DEPOT:
00148 if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
00149 SetBit(order, 7);
00150 order |= GB(this->GetDestination(), 0, 8) << 8;
00151 break;
00152 case OT_LOADING:
00153 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
00154 break;
00155 }
00156 return order;
00157 }
00158
00159 Order::Order(uint32 packed)
00160 {
00161 this->type = (OrderType)GB(packed, 0, 8);
00162 this->flags = GB(packed, 8, 8);
00163 this->dest = GB(packed, 16, 16);
00164 this->next = NULL;
00165 this->refit_cargo = CT_NO_REFIT;
00166 this->refit_subtype = 0;
00167 this->wait_time = 0;
00168 this->travel_time = 0;
00169 }
00170
00176 void InvalidateVehicleOrder(const Vehicle *v, int data)
00177 {
00178 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
00179
00180 if (data != 0) {
00181
00182 InvalidateWindowData(WC_VEHICLE_ORDERS, v->index, data);
00183 InvalidateWindowData(WC_VEHICLE_TIMETABLE, v->index, data);
00184 return;
00185 }
00186
00187 SetWindowDirty(WC_VEHICLE_ORDERS, v->index);
00188 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00189 }
00190
00197 void Order::AssignOrder(const Order &other)
00198 {
00199 this->type = other.type;
00200 this->flags = other.flags;
00201 this->dest = other.dest;
00202
00203 this->refit_cargo = other.refit_cargo;
00204 this->refit_subtype = other.refit_subtype;
00205
00206 this->wait_time = other.wait_time;
00207 this->travel_time = other.travel_time;
00208 }
00209
00210 void OrderList::Initialize(Order *chain, Vehicle *v)
00211 {
00212 this->first = chain;
00213 this->first_shared = v;
00214
00215 this->num_orders = 0;
00216 this->num_vehicles = 1;
00217 this->timetable_duration = 0;
00218
00219 for (Order *o = this->first; o != NULL; o = o->next) {
00220 ++this->num_orders;
00221 this->timetable_duration += o->wait_time + o->travel_time;
00222 }
00223
00224 for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) {
00225 ++this->num_vehicles;
00226 this->first_shared = u;
00227 }
00228
00229 for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles;
00230 }
00231
00232 void OrderList::FreeChain(bool keep_orderlist)
00233 {
00234 Order *next;
00235 for (Order *o = this->first; o != NULL; o = next) {
00236 next = o->next;
00237 delete o;
00238 }
00239
00240 if (keep_orderlist) {
00241 this->first = NULL;
00242 this->num_orders = 0;
00243 this->timetable_duration = 0;
00244 } else {
00245 delete this;
00246 }
00247 }
00248
00249 Order *OrderList::GetOrderAt(int index) const
00250 {
00251 if (index < 0) return NULL;
00252
00253 Order *order = this->first;
00254
00255 while (order != NULL && index-- > 0)
00256 order = order->next;
00257
00258 return order;
00259 }
00260
00261 void OrderList::InsertOrderAt(Order *new_order, int index)
00262 {
00263 if (this->first == NULL) {
00264 this->first = new_order;
00265 } else {
00266 if (index == 0) {
00267
00268 new_order->next = this->first;
00269 this->first = new_order;
00270 } else if (index >= this->num_orders) {
00271
00272 this->GetLastOrder()->next = new_order;
00273 } else {
00274
00275 Order *order = this->GetOrderAt(index - 1);
00276 new_order->next = order->next;
00277 order->next = new_order;
00278 }
00279 }
00280 ++this->num_orders;
00281 this->timetable_duration += new_order->wait_time + new_order->travel_time;
00282 }
00283
00284
00285 void OrderList::DeleteOrderAt(int index)
00286 {
00287 if (index >= this->num_orders) return;
00288
00289 Order *to_remove;
00290
00291 if (index == 0) {
00292 to_remove = this->first;
00293 this->first = to_remove->next;
00294 } else {
00295 Order *prev = GetOrderAt(index - 1);
00296 to_remove = prev->next;
00297 prev->next = to_remove->next;
00298 }
00299 --this->num_orders;
00300 this->timetable_duration -= (to_remove->wait_time + to_remove->travel_time);
00301 delete to_remove;
00302 }
00303
00304 void OrderList::MoveOrder(int from, int to)
00305 {
00306 if (from >= this->num_orders || to >= this->num_orders || from == to) return;
00307
00308 Order *moving_one;
00309
00310
00311 if (from == 0) {
00312 moving_one = this->first;
00313 this->first = moving_one->next;
00314 } else {
00315 Order *one_before = GetOrderAt(from - 1);
00316 moving_one = one_before->next;
00317 one_before->next = moving_one->next;
00318 }
00319
00320
00321 if (to == 0) {
00322 moving_one->next = this->first;
00323 this->first = moving_one;
00324 } else {
00325 Order *one_before = GetOrderAt(to - 1);
00326 moving_one->next = one_before->next;
00327 one_before->next = moving_one;
00328 }
00329 }
00330
00331 void OrderList::RemoveVehicle(Vehicle *v)
00332 {
00333 --this->num_vehicles;
00334 if (v == this->first_shared) this->first_shared = v->NextShared();
00335 }
00336
00337 bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const
00338 {
00339 for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) {
00340 if (v_shared == v) return true;
00341 }
00342
00343 return false;
00344 }
00345
00346 int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
00347 {
00348 int count = 0;
00349 for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++;
00350 return count;
00351 }
00352
00353 bool OrderList::IsCompleteTimetable() const
00354 {
00355 for (Order *o = this->first; o != NULL; o = o->next) {
00356 if (!o->IsCompletelyTimetabled()) return false;
00357 }
00358 return true;
00359 }
00360
00361 void OrderList::DebugCheckSanity() const
00362 {
00363 VehicleOrderID check_num_orders = 0;
00364 uint check_num_vehicles = 0;
00365 Ticks check_timetable_duration = 0;
00366
00367 DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
00368
00369 for (const Order *o = this->first; o != NULL; o = o->next) {
00370 ++check_num_orders;
00371 check_timetable_duration += o->wait_time + o->travel_time;
00372 }
00373 assert(this->num_orders == check_num_orders);
00374 assert(this->timetable_duration == check_timetable_duration);
00375
00376 for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
00377 ++check_num_vehicles;
00378 assert(v->orders.list == this);
00379 }
00380 assert(this->num_vehicles == check_num_vehicles);
00381 DEBUG(misc, 6, "... detected %u orders, %u vehicles, %i ticks", (uint)this->num_orders,
00382 this->num_vehicles, this->timetable_duration);
00383 }
00384
00392 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
00393 {
00394 return o->IsType(OT_GOTO_STATION) ||
00395 (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
00396 }
00397
00404 static void DeleteOrderWarnings(const Vehicle *v)
00405 {
00406 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
00407 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
00408 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
00409 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
00410 }
00411
00417 TileIndex Order::GetLocation(const Vehicle *v) const
00418 {
00419 switch (this->GetType()) {
00420 case OT_GOTO_WAYPOINT:
00421 case OT_GOTO_STATION:
00422 return BaseStation::Get(this->GetDestination())->xy;
00423
00424 case OT_GOTO_DEPOT:
00425 if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE;
00426 return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
00427
00428 default:
00429 return INVALID_TILE;
00430 }
00431 }
00432
00433 static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0)
00434 {
00435 assert(v->type == VEH_SHIP);
00436
00437 if (cur->IsType(OT_CONDITIONAL)) {
00438 if (conditional_depth > v->GetNumOrders()) return 0;
00439
00440 conditional_depth++;
00441
00442 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
00443 int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
00444 return max(dist1, dist2);
00445 }
00446
00447 TileIndex prev_tile = prev->GetLocation(v);
00448 TileIndex cur_tile = cur->GetLocation(v);
00449 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
00450 return DistanceManhattan(prev_tile, cur_tile);
00451 }
00452
00465 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00466 {
00467 VehicleID veh = GB(p1, 0, 16);
00468 VehicleOrderID sel_ord = GB(p1, 16, 16);
00469 Order new_order(p2);
00470
00471 Vehicle *v = Vehicle::GetIfValid(veh);
00472 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner)) return CMD_ERROR;
00473
00474
00475
00476 switch (new_order.GetType()) {
00477 case OT_GOTO_STATION: {
00478 const Station *st = Station::GetIfValid(new_order.GetDestination());
00479 if (st == NULL) return CMD_ERROR;
00480
00481 if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) return CMD_ERROR;
00482
00483 if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00484 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
00485 if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
00486 }
00487
00488
00489 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00490
00491
00492 if ((new_order.GetLoadType() & OLFB_NO_LOAD) && (new_order.GetUnloadType() & OUFB_NO_UNLOAD)) return CMD_ERROR;
00493
00494
00495 switch (new_order.GetLoadType()) {
00496 case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
00497 default: return CMD_ERROR;
00498 }
00499 switch (new_order.GetUnloadType()) {
00500 case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
00501 default: return CMD_ERROR;
00502 }
00503
00504
00505 switch (new_order.GetStopLocation()) {
00506 case OSL_PLATFORM_NEAR_END:
00507 case OSL_PLATFORM_MIDDLE:
00508 if (v->type != VEH_TRAIN) return CMD_ERROR;
00509
00510 case OSL_PLATFORM_FAR_END:
00511 break;
00512
00513 default:
00514 return CMD_ERROR;
00515 }
00516
00517 break;
00518 }
00519
00520 case OT_GOTO_DEPOT: {
00521 if (new_order.GetDepotActionType() != ODATFB_NEAREST_DEPOT) {
00522 if (v->type == VEH_AIRCRAFT) {
00523 const Station *st = Station::GetIfValid(new_order.GetDestination());
00524
00525 if (st == NULL || !CheckOwnership(st->owner) ||
00526 !CanVehicleUseStation(v, st) ||
00527 st->GetAirportSpec()->nof_depots == 0) {
00528 return CMD_ERROR;
00529 }
00530 } else {
00531 const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
00532
00533 if (dp == NULL || !CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
00534
00535 switch (v->type) {
00536 case VEH_TRAIN:
00537 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
00538 break;
00539
00540 case VEH_ROAD:
00541 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
00542 break;
00543
00544 case VEH_SHIP:
00545 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
00546 break;
00547
00548 default: return CMD_ERROR;
00549 }
00550 }
00551 }
00552
00553 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00554 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
00555 if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
00556 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
00557 break;
00558 }
00559
00560 case OT_GOTO_WAYPOINT: {
00561 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
00562 if (wp == NULL) return CMD_ERROR;
00563
00564 switch (v->type) {
00565 default: return CMD_ERROR;
00566
00567 case VEH_TRAIN:
00568 if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00569 if (!CheckOwnership(wp->owner)) return CMD_ERROR;
00570 break;
00571
00572 case VEH_SHIP:
00573 if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00574 if (!CheckOwnership(wp->owner) && wp->owner != OWNER_NONE) return CMD_ERROR;
00575 break;
00576 }
00577
00578
00579
00580
00581 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
00582 break;
00583 }
00584
00585 case OT_CONDITIONAL: {
00586 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
00587 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR;
00588 if (new_order.GetConditionVariable() > OCV_END) return CMD_ERROR;
00589
00590 OrderConditionComparator occ = new_order.GetConditionComparator();
00591 if (occ > OCC_END) return CMD_ERROR;
00592 switch (new_order.GetConditionVariable()) {
00593 case OCV_REQUIRES_SERVICE:
00594 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
00595 break;
00596
00597 case OCV_UNCONDITIONALLY:
00598 if (occ != OCC_EQUALS) return CMD_ERROR;
00599 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
00600 break;
00601
00602 case OCV_LOAD_PERCENTAGE:
00603 case OCV_RELIABILITY:
00604 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
00605
00606 default:
00607 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
00608 break;
00609 }
00610 } break;
00611
00612 default: return CMD_ERROR;
00613 }
00614
00615 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
00616
00617 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS);
00618 if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00619 if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00620
00621 if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) {
00622
00623 const Order *prev = NULL;
00624 uint n = 0;
00625
00626
00627
00628
00629 const Order *o;
00630 FOR_VEHICLE_ORDERS(v, o) {
00631 switch (o->GetType()) {
00632 case OT_GOTO_STATION:
00633 case OT_GOTO_DEPOT:
00634 case OT_GOTO_WAYPOINT:
00635 prev = o;
00636 break;
00637
00638 default: break;
00639 }
00640 if (++n == sel_ord && prev != NULL) break;
00641 }
00642 if (prev != NULL) {
00643 uint dist = GetOrderDistance(prev, &new_order, v);
00644 if (dist >= 130) {
00645 return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION);
00646 }
00647 }
00648 }
00649
00650 if (flags & DC_EXEC) {
00651 Order *new_o = new Order();
00652 new_o->AssignOrder(new_order);
00653
00654
00655 if (v->orders.list == NULL) {
00656 v->orders.list = new OrderList(new_o, v);
00657 } else {
00658 v->orders.list->InsertOrderAt(new_o, sel_ord);
00659 }
00660
00661 Vehicle *u = v->FirstShared();
00662 DeleteOrderWarnings(u);
00663 for (; u != NULL; u = u->NextShared()) {
00664 assert(v->orders.list == u->orders.list);
00665
00666
00667
00668 if (sel_ord <= u->cur_order_index) {
00669 uint cur = u->cur_order_index + 1;
00670
00671 if (cur < u->GetNumOrders())
00672 u->cur_order_index = cur;
00673 }
00674
00675 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
00676 }
00677
00678
00679 VehicleOrderID cur_order_id = 0;
00680 Order *order;
00681 FOR_VEHICLE_ORDERS(v, order) {
00682 if (order->IsType(OT_CONDITIONAL)) {
00683 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00684 if (order_id >= sel_ord) {
00685 order->SetConditionSkipToOrder(order_id + 1);
00686 }
00687 if (order_id == cur_order_id) {
00688 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00689 }
00690 }
00691 cur_order_id++;
00692 }
00693
00694
00695 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00696 }
00697
00698 return CommandCost();
00699 }
00700
00705 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
00706 {
00707 if (flags & DC_EXEC) {
00708 DeleteVehicleOrders(dst);
00709 InvalidateVehicleOrder(dst, -1);
00710 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
00711 }
00712 return CommandCost();
00713 }
00714
00723 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00724 {
00725 VehicleID veh_id = p1;
00726 VehicleOrderID sel_ord = p2;
00727 Order *order;
00728
00729 Vehicle *v = Vehicle::GetIfValid(veh_id);
00730
00731 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner)) return CMD_ERROR;
00732
00733
00734 if (sel_ord >= v->GetNumOrders())
00735 return DecloneOrder(v, flags);
00736
00737 order = v->GetOrder(sel_ord);
00738 if (order == NULL) return CMD_ERROR;
00739
00740 if (flags & DC_EXEC) {
00741 v->orders.list->DeleteOrderAt(sel_ord);
00742
00743 Vehicle *u = v->FirstShared();
00744 DeleteOrderWarnings(u);
00745 for (; u != NULL; u = u->NextShared()) {
00746 if (sel_ord < u->cur_order_index)
00747 u->cur_order_index--;
00748
00749 assert(v->orders.list == u->orders.list);
00750
00751
00752
00753 if (sel_ord == u->cur_order_index && u->current_order.IsType(OT_LOADING)) {
00754 u->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
00755 }
00756
00757
00758 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
00759 }
00760
00761
00762 VehicleOrderID cur_order_id = 0;
00763 FOR_VEHICLE_ORDERS(v, order) {
00764 if (order->IsType(OT_CONDITIONAL)) {
00765 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00766 if (order_id >= sel_ord) {
00767 order->SetConditionSkipToOrder(max(order_id - 1, 0));
00768 }
00769 if (order_id == cur_order_id) {
00770 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00771 }
00772 }
00773 cur_order_id++;
00774 }
00775
00776 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00777 }
00778
00779 return CommandCost();
00780 }
00781
00790 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00791 {
00792 VehicleID veh_id = p1;
00793 VehicleOrderID sel_ord = p2;
00794
00795 Vehicle *v = Vehicle::GetIfValid(veh_id);
00796
00797 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner) || sel_ord == v->cur_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
00798
00799 if (flags & DC_EXEC) {
00800 v->cur_order_index = sel_ord;
00801
00802 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
00803
00804 InvalidateVehicleOrder(v, -2);
00805 }
00806
00807
00808 if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
00809 if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
00810
00811 return CommandCost();
00812 }
00813
00827 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00828 {
00829 VehicleID veh = p1;
00830 VehicleOrderID moving_order = GB(p2, 0, 16);
00831 VehicleOrderID target_order = GB(p2, 16, 16);
00832
00833 Vehicle *v = Vehicle::GetIfValid(veh);
00834 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner)) return CMD_ERROR;
00835
00836
00837 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
00838 moving_order == target_order || v->GetNumOrders() <= 1)
00839 return CMD_ERROR;
00840
00841 Order *moving_one = v->GetOrder(moving_order);
00842
00843 if (moving_one == NULL) return CMD_ERROR;
00844
00845 if (flags & DC_EXEC) {
00846 v->orders.list->MoveOrder(moving_order, target_order);
00847
00848
00849 Vehicle *u = v->FirstShared();
00850
00851 DeleteOrderWarnings(u);
00852
00853 for (; u != NULL; u = u->NextShared()) {
00854
00855 if (u->cur_order_index == moving_order) {
00856 u->cur_order_index = target_order;
00857 } else if (u->cur_order_index > moving_order && u->cur_order_index <= target_order) {
00858 u->cur_order_index--;
00859 } else if (u->cur_order_index < moving_order && u->cur_order_index >= target_order) {
00860 u->cur_order_index++;
00861 }
00862
00863 assert(v->orders.list == u->orders.list);
00864
00865 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
00866 }
00867
00868
00869 Order *order;
00870 FOR_VEHICLE_ORDERS(v, order) {
00871 if (order->IsType(OT_CONDITIONAL)) {
00872 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00873 if (order_id == moving_order) {
00874 order_id = target_order;
00875 } else if (order_id > moving_order && order_id <= target_order) {
00876 order_id--;
00877 } else if (order_id < moving_order && order_id >= target_order) {
00878 order_id++;
00879 }
00880 order->SetConditionSkipToOrder(order_id);
00881 }
00882 }
00883
00884
00885 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00886 }
00887
00888 return CommandCost();
00889 }
00890
00905 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00906 {
00907 VehicleOrderID sel_ord = GB(p1, 16, 16);
00908 VehicleID veh = GB(p1, 0, 16);
00909 ModifyOrderFlags mof = Extract<ModifyOrderFlags, 0, 4>(p2);
00910 uint16 data = GB(p2, 4, 11);
00911
00912 if (mof >= MOF_END) return CMD_ERROR;
00913
00914 Vehicle *v = Vehicle::GetIfValid(veh);
00915 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner)) return CMD_ERROR;
00916
00917
00918 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
00919
00920 Order *order = v->GetOrder(sel_ord);
00921 switch (order->GetType()) {
00922 case OT_GOTO_STATION:
00923 if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE) return CMD_ERROR;
00924 break;
00925
00926 case OT_GOTO_DEPOT:
00927 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
00928 break;
00929
00930 case OT_GOTO_WAYPOINT:
00931 if (mof != MOF_NON_STOP) return CMD_ERROR;
00932 break;
00933
00934 case OT_CONDITIONAL:
00935 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
00936 break;
00937
00938 default:
00939 return CMD_ERROR;
00940 }
00941
00942 switch (mof) {
00943 default: NOT_REACHED();
00944
00945 case MOF_NON_STOP:
00946 if (v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00947 if (data >= ONSF_END) return CMD_ERROR;
00948 if (data == order->GetNonStopType()) return CMD_ERROR;
00949 break;
00950
00951 case MOF_STOP_LOCATION:
00952 if (v->type != VEH_TRAIN) return CMD_ERROR;
00953 if (data >= OSL_END) return CMD_ERROR;
00954 break;
00955
00956 case MOF_UNLOAD:
00957 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
00958
00959 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
00960 if (data == order->GetUnloadType()) return CMD_ERROR;
00961 break;
00962
00963 case MOF_LOAD:
00964 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
00965 if (data == order->GetLoadType()) return CMD_ERROR;
00966 break;
00967
00968 case MOF_DEPOT_ACTION:
00969 if (data >= DA_END) return CMD_ERROR;
00970 break;
00971
00972 case MOF_COND_VARIABLE:
00973 if (data >= OCV_END) return CMD_ERROR;
00974 break;
00975
00976 case MOF_COND_COMPARATOR:
00977 if (data >= OCC_END) return CMD_ERROR;
00978 switch (order->GetConditionVariable()) {
00979 case OCV_UNCONDITIONALLY: return CMD_ERROR;
00980
00981 case OCV_REQUIRES_SERVICE:
00982 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
00983 break;
00984
00985 default:
00986 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
00987 break;
00988 }
00989 break;
00990
00991 case MOF_COND_VALUE:
00992 switch (order->GetConditionVariable()) {
00993 case OCV_UNCONDITIONALLY: return CMD_ERROR;
00994
00995 case OCV_LOAD_PERCENTAGE:
00996 case OCV_RELIABILITY:
00997 if (data > 100) return CMD_ERROR;
00998 break;
00999
01000 default:
01001 if (data > 2047) return CMD_ERROR;
01002 break;
01003 }
01004 break;
01005
01006 case MOF_COND_DESTINATION:
01007 if (data >= v->GetNumOrders()) return CMD_ERROR;
01008 break;
01009 }
01010
01011 if (flags & DC_EXEC) {
01012 switch (mof) {
01013 case MOF_NON_STOP:
01014 order->SetNonStopType((OrderNonStopFlags)data);
01015 break;
01016
01017 case MOF_STOP_LOCATION:
01018 order->SetStopLocation((OrderStopLocation)data);
01019 break;
01020
01021 case MOF_UNLOAD:
01022 order->SetUnloadType((OrderUnloadFlags)data);
01023 if ((data & OUFB_NO_UNLOAD) != 0 && (order->GetLoadType() & OLFB_NO_LOAD) != 0) {
01024 order->SetLoadType((OrderLoadFlags)(order->GetLoadType() & ~OLFB_NO_LOAD));
01025 }
01026 break;
01027
01028 case MOF_LOAD:
01029 order->SetLoadType((OrderLoadFlags)data);
01030 if ((data & OLFB_NO_LOAD) != 0 && (order->GetUnloadType() & OUFB_NO_UNLOAD) != 0) {
01031
01032 order->SetUnloadType((OrderUnloadFlags)(order->GetUnloadType() & ~OUFB_NO_UNLOAD));
01033 }
01034 break;
01035
01036 case MOF_DEPOT_ACTION: {
01037 switch (data) {
01038 case DA_ALWAYS_GO:
01039 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01040 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01041 break;
01042
01043 case DA_SERVICE:
01044 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
01045 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01046 break;
01047
01048 case DA_STOP:
01049 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01050 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
01051 break;
01052
01053 default:
01054 NOT_REACHED();
01055 }
01056 } break;
01057
01058 case MOF_COND_VARIABLE: {
01059 order->SetConditionVariable((OrderConditionVariable)data);
01060
01061 OrderConditionComparator occ = order->GetConditionComparator();
01062 switch (order->GetConditionVariable()) {
01063 case OCV_UNCONDITIONALLY:
01064 order->SetConditionComparator(OCC_EQUALS);
01065 order->SetConditionValue(0);
01066 break;
01067
01068 case OCV_REQUIRES_SERVICE:
01069 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
01070 break;
01071
01072 case OCV_LOAD_PERCENTAGE:
01073 case OCV_RELIABILITY:
01074 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
01075
01076 default:
01077 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
01078 break;
01079 }
01080 } break;
01081
01082 case MOF_COND_COMPARATOR:
01083 order->SetConditionComparator((OrderConditionComparator)data);
01084 break;
01085
01086 case MOF_COND_VALUE:
01087 order->SetConditionValue(data);
01088 break;
01089
01090 case MOF_COND_DESTINATION:
01091 order->SetConditionSkipToOrder(data);
01092 break;
01093
01094 default: NOT_REACHED();
01095 }
01096
01097
01098 Vehicle *u = v->FirstShared();
01099 DeleteOrderWarnings(u);
01100 for (; u != NULL; u = u->NextShared()) {
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110 if (sel_ord == u->cur_order_index &&
01111 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
01112 u->current_order.GetLoadType() != order->GetLoadType()) {
01113 u->current_order.SetLoadType(order->GetLoadType());
01114 }
01115 InvalidateVehicleOrder(u, -2);
01116 }
01117 }
01118
01119 return CommandCost();
01120 }
01121
01132 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01133 {
01134 VehicleID veh_src = GB(p1, 16, 16);
01135 VehicleID veh_dst = GB(p1, 0, 16);
01136
01137 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
01138 if (dst == NULL || !dst->IsPrimaryVehicle() || !CheckOwnership(dst->owner)) return CMD_ERROR;
01139
01140 switch (p2) {
01141 case CO_SHARE: {
01142 Vehicle *src = Vehicle::GetIfValid(veh_src);
01143
01144
01145 if (src == NULL || !src->IsPrimaryVehicle() || !CheckOwnership(src->owner) || dst->type != src->type || dst == src) return CMD_ERROR;
01146
01147
01148 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
01149 return CMD_ERROR;
01150 }
01151
01152
01153 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
01154
01155 const Order *order;
01156
01157 FOR_VEHICLE_ORDERS(src, order) {
01158 if (OrderGoesToStation(dst, order) &&
01159 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01160 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01161 }
01162 }
01163
01164 if (flags & DC_EXEC) {
01165
01166 DeleteVehicleOrders(dst);
01167
01168 dst->orders.list = src->orders.list;
01169
01170
01171 dst->AddToShared(src);
01172
01173 InvalidateVehicleOrder(dst, -1);
01174 InvalidateVehicleOrder(src, -2);
01175
01176 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01177 }
01178 } break;
01179
01180 case CO_COPY: {
01181 Vehicle *src = Vehicle::GetIfValid(veh_src);
01182
01183
01184 if (src == NULL || !src->IsPrimaryVehicle() || !CheckOwnership(src->owner) || dst->type != src->type || dst == src) return CMD_ERROR;
01185
01186
01187
01188 const Order *order;
01189 FOR_VEHICLE_ORDERS(src, order) {
01190 if (OrderGoesToStation(dst, order) &&
01191 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01192 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01193 }
01194 }
01195
01196
01197 int delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
01198 if (!Order::CanAllocateItem(delta) ||
01199 ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
01200 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01201 }
01202
01203 if (flags & DC_EXEC) {
01204 const Order *order;
01205 Order *first = NULL;
01206 Order **order_dst;
01207
01208
01209 DeleteVehicleOrders(dst, true);
01210
01211 order_dst = &first;
01212 FOR_VEHICLE_ORDERS(src, order) {
01213 *order_dst = new Order();
01214 (*order_dst)->AssignOrder(*order);
01215 order_dst = &(*order_dst)->next;
01216 }
01217 if (dst->orders.list == NULL) {
01218 dst->orders.list = new OrderList(first, dst);
01219 } else {
01220 assert(dst->orders.list->GetFirstOrder() == NULL);
01221 assert(!dst->orders.list->IsShared());
01222 delete dst->orders.list;
01223 dst->orders.list = new OrderList(first, dst);
01224 }
01225
01226 InvalidateVehicleOrder(dst, -1);
01227
01228 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01229 }
01230 } break;
01231
01232 case CO_UNSHARE: return DecloneOrder(dst, flags);
01233 default: return CMD_ERROR;
01234 }
01235
01236 return CommandCost();
01237 }
01238
01250 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01251 {
01252 VehicleID veh = GB(p1, 0, 16);
01253 VehicleOrderID order_number = GB(p2, 16, 8);
01254 CargoID cargo = GB(p2, 0, 8);
01255 byte subtype = GB(p2, 8, 8);
01256
01257 if (cargo >= NUM_CARGO) return CMD_ERROR;
01258
01259 const Vehicle *v = Vehicle::GetIfValid(veh);
01260 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner)) return CMD_ERROR;
01261
01262 Order *order = v->GetOrder(order_number);
01263 if (order == NULL) return CMD_ERROR;
01264
01265 if (flags & DC_EXEC) {
01266 order->SetRefit(cargo, subtype);
01267
01268 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
01269
01270 InvalidateVehicleOrder(u, -2);
01271
01272
01273 if (u->cur_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
01274 u->current_order.SetRefit(cargo, subtype);
01275 }
01276 }
01277 }
01278
01279 return CommandCost();
01280 }
01281
01288 void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
01289 {
01290
01291 free(bak->order);
01292 bak->order = NULL;
01293 free(bak->name);
01294 bak->name = NULL;
01295
01296
01297 bak->orderindex = v->cur_order_index;
01298 bak->group = v->group_id;
01299 bak->service_interval = v->service_interval;
01300 if (v->name != NULL) bak->name = strdup(v->name);
01301
01302
01303 if (v->IsOrderListShared()) {
01304 const Vehicle *u = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
01305
01306 bak->clone = u->index;
01307 } else {
01308
01309
01310
01311 bak->clone = INVALID_VEHICLE;
01312
01313
01314
01315 uint cnt = 0;
01316 const Order *order;
01317 FOR_VEHICLE_ORDERS(v, order) cnt++;
01318
01319
01320 bak->order = MallocT<Order>(cnt + 1);
01321
01322 Order *dest = bak->order;
01323
01324
01325 FOR_VEHICLE_ORDERS(v, order) {
01326 memcpy(dest, order, sizeof(Order));
01327 dest++;
01328 }
01329
01330 dest->Free();
01331 }
01332 }
01333
01339 void RestoreVehicleOrders(const Vehicle *v, const BackuppedOrders *bak)
01340 {
01341
01342 if (bak->name != NULL) DoCommandP(0, v->index, 0, CMD_RENAME_VEHICLE, NULL, bak->name);
01343
01344
01345 if (bak->clone != INVALID_VEHICLE) {
01346 DoCommandP(0, v->index | (bak->clone << 16), CO_SHARE, CMD_CLONE_ORDER);
01347 } else {
01348
01349
01350
01351
01352
01353 for (uint i = 0; !bak->order[i].IsType(OT_NOTHING); i++) {
01354 Order o = bak->order[i];
01355
01356 if (o.IsType(OT_CONDITIONAL)) o.SetConditionSkipToOrder(0);
01357
01358 if (!DoCommandP(0, v->index + (i << 16), o.Pack(),
01359 CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
01360 break;
01361 }
01362
01363
01364 if (_settings_game.order.timetabling && !DoCommandP(0, v->index | (i << 16) | (1 << 25),
01365 o.wait_time << 16 | o.travel_time,
01366 CMD_CHANGE_TIMETABLE | CMD_NO_TEST_IF_IN_NETWORK)) {
01367 break;
01368 }
01369 }
01370
01371
01372 for (uint i = 0; !bak->order[i].IsType(OT_NOTHING); i++) {
01373 if (!bak->order[i].IsType(OT_CONDITIONAL)) continue;
01374
01375 if (!DoCommandP(0, v->index + (i << 16), MOF_LOAD | (bak->order[i].GetConditionSkipToOrder() << 4),
01376 CMD_MODIFY_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
01377 break;
01378 }
01379 }
01380 }
01381
01382
01383 DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16), CMD_RESTORE_ORDER_INDEX);
01384
01385
01386 DoCommandP(0, bak->group, v->index, CMD_ADD_VEHICLE_GROUP);
01387 }
01388
01405 CommandCost CmdRestoreOrderIndex(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01406 {
01407 VehicleOrderID cur_ord = GB(p2, 0, 16);
01408 uint16 serv_int = GB(p2, 16, 16);
01409
01410 Vehicle *v = Vehicle::GetIfValid(p1);
01411
01412 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner)) return CMD_ERROR;
01413
01414 if (serv_int != GetServiceIntervalClamped(serv_int, v->owner) || cur_ord >= v->GetNumOrders()) return CMD_ERROR;
01415
01416 if (flags & DC_EXEC) {
01417 v->cur_order_index = cur_ord;
01418 v->service_interval = serv_int;
01419 }
01420
01421 return CommandCost();
01422 }
01423
01424
01430 void CheckOrders(const Vehicle *v)
01431 {
01432
01433 if (_settings_client.gui.order_review_system == 0) return;
01434
01435
01436 if (v->vehstatus & VS_CRASHED) return;
01437
01438
01439 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED))
01440 return;
01441
01442
01443 if (v->FirstShared() != v) return;
01444
01445
01446 if (v->owner == _local_company && v->day_counter % 20 == 0) {
01447 int n_st, problem_type = -1;
01448 const Order *order;
01449 int message = 0;
01450
01451
01452 n_st = 0;
01453
01454 FOR_VEHICLE_ORDERS(v, order) {
01455
01456 if (order->IsType(OT_DUMMY)) {
01457 problem_type = 1;
01458 break;
01459 }
01460
01461 if (order->IsType(OT_GOTO_STATION)) {
01462 const Station *st = Station::Get(order->GetDestination());
01463
01464 n_st++;
01465 if (!CanVehicleUseStation(v, st)) problem_type = 3;
01466 }
01467 }
01468
01469
01470 if (v->GetNumOrders() > 1) {
01471 const Order *last = v->GetLastOrder();
01472
01473 if (v->orders.list->GetFirstOrder()->Equals(*last)) {
01474 problem_type = 2;
01475 }
01476 }
01477
01478
01479 if (n_st < 2 && problem_type == -1) problem_type = 0;
01480
01481 #ifndef NDEBUG
01482 if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
01483 #endif
01484
01485
01486 if (problem_type < 0) return;
01487
01488 message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
01489
01490
01491 SetDParam(0, v->index);
01492 AddVehicleNewsItem(
01493 message,
01494 NS_ADVICE,
01495 v->index
01496 );
01497 }
01498 }
01499
01505 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01506 {
01507 Vehicle *v;
01508
01509
01510
01511
01512
01513
01514 FOR_ALL_VEHICLES(v) {
01515 Order *order;
01516
01517 order = &v->current_order;
01518 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01519 v->current_order.GetDestination() == destination) {
01520 order->MakeDummy();
01521 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01522 }
01523
01524
01525 int id = -1;
01526 FOR_VEHICLE_ORDERS(v, order) {
01527 id++;
01528 if (order->IsType(OT_GOTO_DEPOT) && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
01529 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01530 order->GetDestination() == destination) {
01531 order->MakeDummy();
01532 for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
01533
01534 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
01535 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
01536 }
01537 }
01538 }
01539 }
01540 }
01541
01549 bool VehicleHasDepotOrders(const Vehicle *v)
01550 {
01551 const Order *order;
01552
01553 FOR_VEHICLE_ORDERS(v, order) {
01554 if (order->IsType(OT_GOTO_DEPOT))
01555 return true;
01556 }
01557
01558 return false;
01559 }
01560
01566 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist)
01567 {
01568 DeleteOrderWarnings(v);
01569
01570 if (v->IsOrderListShared()) {
01571
01572 v->RemoveFromShared();
01573 v->orders.list = NULL;
01574 } else if (v->orders.list != NULL) {
01575
01576 v->orders.list->FreeChain(keep_orderlist);
01577 if (!keep_orderlist) v->orders.list = NULL;
01578 }
01579 }
01580
01581 uint16 GetServiceIntervalClamped(uint interval, CompanyID company_id)
01582 {
01583 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);
01584 }
01585
01594 static bool CheckForValidOrders(const Vehicle *v)
01595 {
01596 const Order *order;
01597
01598 FOR_VEHICLE_ORDERS(v, order) {
01599 switch (order->GetType()) {
01600 case OT_GOTO_STATION:
01601 case OT_GOTO_DEPOT:
01602 case OT_GOTO_WAYPOINT:
01603 return true;
01604
01605 default:
01606 break;
01607 }
01608 }
01609
01610 return false;
01611 }
01612
01616 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
01617 {
01618 switch (occ) {
01619 case OCC_EQUALS: return variable == value;
01620 case OCC_NOT_EQUALS: return variable != value;
01621 case OCC_LESS_THAN: return variable < value;
01622 case OCC_LESS_EQUALS: return variable <= value;
01623 case OCC_MORE_THAN: return variable > value;
01624 case OCC_MORE_EQUALS: return variable >= value;
01625 case OCC_IS_TRUE: return variable != 0;
01626 case OCC_IS_FALSE: return variable == 0;
01627 default: NOT_REACHED();
01628 }
01629 }
01630
01637 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
01638 {
01639 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
01640
01641 bool skip_order = false;
01642 OrderConditionComparator occ = order->GetConditionComparator();
01643 uint16 value = order->GetConditionValue();
01644
01645 switch (order->GetConditionVariable()) {
01646 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
01647 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
01648 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
01649 case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
01650 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
01651 case OCV_UNCONDITIONALLY: skip_order = true; break;
01652 default: NOT_REACHED();
01653 }
01654
01655 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
01656 }
01657
01664 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
01665 {
01666 if (conditional_depth > v->GetNumOrders()) return false;
01667
01668 switch (order->GetType()) {
01669 case OT_GOTO_STATION:
01670 v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
01671 return true;
01672
01673 case OT_GOTO_DEPOT:
01674 if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
01675
01676 TileIndex location;
01677 DestinationID destination;
01678 bool reverse;
01679
01680 if (v->FindClosestDepot(&location, &destination, &reverse)) {
01681 v->dest_tile = location;
01682 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());
01683
01684
01685 if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01686
01687 if (v->type == VEH_AIRCRAFT) {
01688 Aircraft *a = Aircraft::From(v);
01689 if (a->state == FLYING && a->targetairport != destination) {
01690
01691 extern void AircraftNextAirportPos_and_Order(Aircraft *a);
01692 AircraftNextAirportPos_and_Order(a);
01693 }
01694 }
01695 return true;
01696 }
01697
01698 UpdateVehicleTimetable(v, true);
01699 v->IncrementOrderIndex();
01700 } else if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
01701 UpdateVehicleTimetable(v, true);
01702 v->IncrementOrderIndex();
01703 } else {
01704 if (v->type != VEH_AIRCRAFT) {
01705 v->dest_tile = Depot::Get(order->GetDestination())->xy;
01706 }
01707 return true;
01708 }
01709 break;
01710
01711 case OT_GOTO_WAYPOINT:
01712 v->dest_tile = Waypoint::Get(order->GetDestination())->xy;
01713 return true;
01714
01715 case OT_CONDITIONAL: {
01716 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
01717 if (next_order != INVALID_VEH_ORDER_ID) {
01718 UpdateVehicleTimetable(v, false);
01719 v->cur_order_index = next_order;
01720 v->current_order_time += v->GetOrder(next_order)->travel_time;
01721 } else {
01722 UpdateVehicleTimetable(v, true);
01723 v->IncrementOrderIndex();
01724 }
01725 break;
01726 }
01727
01728 default:
01729 v->dest_tile = 0;
01730 return false;
01731 }
01732
01733 assert(v->cur_order_index < v->GetNumOrders());
01734
01735
01736 order = v->GetOrder(v->cur_order_index);
01737 v->current_order = *order;
01738 return UpdateOrderDest(v, order, conditional_depth + 1);
01739 }
01740
01748 bool ProcessOrders(Vehicle *v)
01749 {
01750 switch (v->current_order.GetType()) {
01751 case OT_GOTO_DEPOT:
01752
01753 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
01754 break;
01755
01756 case OT_LOADING:
01757 return false;
01758
01759 case OT_LEAVESTATION:
01760 if (v->type != VEH_AIRCRAFT) return false;
01761 break;
01762
01763 default: break;
01764 }
01765
01773 bool may_reverse = v->current_order.IsType(OT_NOTHING);
01774
01775
01776 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)) &&
01777 IsTileType(v->tile, MP_STATION) &&
01778 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
01779 if (v->current_order.IsType(OT_GOTO_STATION)) v->last_station_visited = v->current_order.GetDestination();
01780 UpdateVehicleTimetable(v, true);
01781 v->IncrementOrderIndex();
01782 }
01783
01784
01785 if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
01786
01787 const Order *order = v->GetOrder(v->cur_order_index);
01788
01789
01790 if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
01791 if (v->type == VEH_AIRCRAFT) {
01792
01793 extern void HandleMissingAircraftOrders(Aircraft *v);
01794 HandleMissingAircraftOrders(Aircraft::From(v));
01795 return false;
01796 }
01797
01798 v->current_order.Free();
01799 v->dest_tile = 0;
01800 return false;
01801 }
01802
01803
01804 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
01805 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
01806 return false;
01807 }
01808
01809
01810 v->current_order = *order;
01811
01812 InvalidateVehicleOrder(v, -2);
01813 switch (v->type) {
01814 default:
01815 NOT_REACHED();
01816
01817 case VEH_ROAD:
01818 case VEH_TRAIN:
01819 break;
01820
01821 case VEH_AIRCRAFT:
01822 case VEH_SHIP:
01823 SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
01824 break;
01825 }
01826
01827 return UpdateOrderDest(v, order) && may_reverse;
01828 }
01829
01837 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
01838 {
01839 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
01840 return
01841 (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
01842 v->last_station_visited != station &&
01843
01844 !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
01845 }
01846
01847 void InitializeOrders()
01848 {
01849 _order_pool.CleanPool();
01850
01851 _orderlist_pool.CleanPool();
01852
01853 _backup_orders_tile = 0;
01854 }