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->IsType(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) == 0) {
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 if (u->current_order.GetLoadType() & OLFB_FULL_LOAD) u->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE);
00758 }
00759
00760
00761 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
00762 }
00763
00764
00765 VehicleOrderID cur_order_id = 0;
00766 FOR_VEHICLE_ORDERS(v, order) {
00767 if (order->IsType(OT_CONDITIONAL)) {
00768 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00769 if (order_id >= sel_ord) {
00770 order->SetConditionSkipToOrder(max(order_id - 1, 0));
00771 }
00772 if (order_id == cur_order_id) {
00773 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00774 }
00775 }
00776 cur_order_id++;
00777 }
00778
00779 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00780 }
00781
00782 return CommandCost();
00783 }
00784
00793 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00794 {
00795 VehicleID veh_id = p1;
00796 VehicleOrderID sel_ord = p2;
00797
00798 Vehicle *v = Vehicle::GetIfValid(veh_id);
00799
00800 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner) || sel_ord == v->cur_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
00801
00802 if (flags & DC_EXEC) {
00803 v->cur_order_index = sel_ord;
00804
00805 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
00806
00807 InvalidateVehicleOrder(v, -2);
00808 }
00809
00810
00811 if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
00812 if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
00813
00814 return CommandCost();
00815 }
00816
00830 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00831 {
00832 VehicleID veh = p1;
00833 VehicleOrderID moving_order = GB(p2, 0, 16);
00834 VehicleOrderID target_order = GB(p2, 16, 16);
00835
00836 Vehicle *v = Vehicle::GetIfValid(veh);
00837 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner)) return CMD_ERROR;
00838
00839
00840 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
00841 moving_order == target_order || v->GetNumOrders() <= 1)
00842 return CMD_ERROR;
00843
00844 Order *moving_one = v->GetOrder(moving_order);
00845
00846 if (moving_one == NULL) return CMD_ERROR;
00847
00848 if (flags & DC_EXEC) {
00849 v->orders.list->MoveOrder(moving_order, target_order);
00850
00851
00852 Vehicle *u = v->FirstShared();
00853
00854 DeleteOrderWarnings(u);
00855
00856 for (; u != NULL; u = u->NextShared()) {
00857
00858 if (u->cur_order_index == moving_order) {
00859 u->cur_order_index = target_order;
00860 } else if (u->cur_order_index > moving_order && u->cur_order_index <= target_order) {
00861 u->cur_order_index--;
00862 } else if (u->cur_order_index < moving_order && u->cur_order_index >= target_order) {
00863 u->cur_order_index++;
00864 }
00865
00866 assert(v->orders.list == u->orders.list);
00867
00868 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
00869 }
00870
00871
00872 Order *order;
00873 FOR_VEHICLE_ORDERS(v, order) {
00874 if (order->IsType(OT_CONDITIONAL)) {
00875 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00876 if (order_id == moving_order) {
00877 order_id = target_order;
00878 } else if (order_id > moving_order && order_id <= target_order) {
00879 order_id--;
00880 } else if (order_id < moving_order && order_id >= target_order) {
00881 order_id++;
00882 }
00883 order->SetConditionSkipToOrder(order_id);
00884 }
00885 }
00886
00887
00888 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00889 }
00890
00891 return CommandCost();
00892 }
00893
00908 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00909 {
00910 VehicleOrderID sel_ord = GB(p1, 16, 16);
00911 VehicleID veh = GB(p1, 0, 16);
00912 ModifyOrderFlags mof = Extract<ModifyOrderFlags, 0, 4>(p2);
00913 uint16 data = GB(p2, 4, 11);
00914
00915 if (mof >= MOF_END) return CMD_ERROR;
00916
00917 Vehicle *v = Vehicle::GetIfValid(veh);
00918 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner)) return CMD_ERROR;
00919
00920
00921 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
00922
00923 Order *order = v->GetOrder(sel_ord);
00924 switch (order->GetType()) {
00925 case OT_GOTO_STATION:
00926 if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE) return CMD_ERROR;
00927 break;
00928
00929 case OT_GOTO_DEPOT:
00930 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
00931 break;
00932
00933 case OT_GOTO_WAYPOINT:
00934 if (mof != MOF_NON_STOP) return CMD_ERROR;
00935 break;
00936
00937 case OT_CONDITIONAL:
00938 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
00939 break;
00940
00941 default:
00942 return CMD_ERROR;
00943 }
00944
00945 switch (mof) {
00946 default: NOT_REACHED();
00947
00948 case MOF_NON_STOP:
00949 if (v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00950 if (data >= ONSF_END) return CMD_ERROR;
00951 if (data == order->GetNonStopType()) return CMD_ERROR;
00952 break;
00953
00954 case MOF_STOP_LOCATION:
00955 if (v->type != VEH_TRAIN) return CMD_ERROR;
00956 if (data >= OSL_END) return CMD_ERROR;
00957 break;
00958
00959 case MOF_UNLOAD:
00960 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
00961
00962 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
00963 if (data == order->GetUnloadType()) return CMD_ERROR;
00964 break;
00965
00966 case MOF_LOAD:
00967 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
00968 if (data == order->GetLoadType()) return CMD_ERROR;
00969 break;
00970
00971 case MOF_DEPOT_ACTION:
00972 if (data >= DA_END) return CMD_ERROR;
00973 break;
00974
00975 case MOF_COND_VARIABLE:
00976 if (data >= OCV_END) return CMD_ERROR;
00977 break;
00978
00979 case MOF_COND_COMPARATOR:
00980 if (data >= OCC_END) return CMD_ERROR;
00981 switch (order->GetConditionVariable()) {
00982 case OCV_UNCONDITIONALLY: return CMD_ERROR;
00983
00984 case OCV_REQUIRES_SERVICE:
00985 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
00986 break;
00987
00988 default:
00989 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
00990 break;
00991 }
00992 break;
00993
00994 case MOF_COND_VALUE:
00995 switch (order->GetConditionVariable()) {
00996 case OCV_UNCONDITIONALLY: return CMD_ERROR;
00997
00998 case OCV_LOAD_PERCENTAGE:
00999 case OCV_RELIABILITY:
01000 if (data > 100) return CMD_ERROR;
01001 break;
01002
01003 default:
01004 if (data > 2047) return CMD_ERROR;
01005 break;
01006 }
01007 break;
01008
01009 case MOF_COND_DESTINATION:
01010 if (data >= v->GetNumOrders()) return CMD_ERROR;
01011 break;
01012 }
01013
01014 if (flags & DC_EXEC) {
01015 switch (mof) {
01016 case MOF_NON_STOP:
01017 order->SetNonStopType((OrderNonStopFlags)data);
01018 break;
01019
01020 case MOF_STOP_LOCATION:
01021 order->SetStopLocation((OrderStopLocation)data);
01022 break;
01023
01024 case MOF_UNLOAD:
01025 order->SetUnloadType((OrderUnloadFlags)data);
01026 if ((data & OUFB_NO_UNLOAD) != 0 && (order->GetLoadType() & OLFB_NO_LOAD) != 0) {
01027 order->SetLoadType((OrderLoadFlags)(order->GetLoadType() & ~OLFB_NO_LOAD));
01028 }
01029 break;
01030
01031 case MOF_LOAD:
01032 order->SetLoadType((OrderLoadFlags)data);
01033 if ((data & OLFB_NO_LOAD) != 0 && (order->GetUnloadType() & OUFB_NO_UNLOAD) != 0) {
01034
01035 order->SetUnloadType((OrderUnloadFlags)(order->GetUnloadType() & ~OUFB_NO_UNLOAD));
01036 }
01037 break;
01038
01039 case MOF_DEPOT_ACTION: {
01040 switch (data) {
01041 case DA_ALWAYS_GO:
01042 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01043 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01044 break;
01045
01046 case DA_SERVICE:
01047 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
01048 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01049 break;
01050
01051 case DA_STOP:
01052 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01053 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
01054 break;
01055
01056 default:
01057 NOT_REACHED();
01058 }
01059 } break;
01060
01061 case MOF_COND_VARIABLE: {
01062 order->SetConditionVariable((OrderConditionVariable)data);
01063
01064 OrderConditionComparator occ = order->GetConditionComparator();
01065 switch (order->GetConditionVariable()) {
01066 case OCV_UNCONDITIONALLY:
01067 order->SetConditionComparator(OCC_EQUALS);
01068 order->SetConditionValue(0);
01069 break;
01070
01071 case OCV_REQUIRES_SERVICE:
01072 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
01073 break;
01074
01075 case OCV_LOAD_PERCENTAGE:
01076 case OCV_RELIABILITY:
01077 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
01078
01079 default:
01080 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
01081 break;
01082 }
01083 } break;
01084
01085 case MOF_COND_COMPARATOR:
01086 order->SetConditionComparator((OrderConditionComparator)data);
01087 break;
01088
01089 case MOF_COND_VALUE:
01090 order->SetConditionValue(data);
01091 break;
01092
01093 case MOF_COND_DESTINATION:
01094 order->SetConditionSkipToOrder(data);
01095 break;
01096
01097 default: NOT_REACHED();
01098 }
01099
01100
01101 Vehicle *u = v->FirstShared();
01102 DeleteOrderWarnings(u);
01103 for (; u != NULL; u = u->NextShared()) {
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113 if (sel_ord == u->cur_order_index &&
01114 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
01115 u->current_order.GetLoadType() != order->GetLoadType()) {
01116 u->current_order.SetLoadType(order->GetLoadType());
01117 }
01118 InvalidateVehicleOrder(u, -2);
01119 }
01120 }
01121
01122 return CommandCost();
01123 }
01124
01135 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01136 {
01137 VehicleID veh_src = GB(p1, 16, 16);
01138 VehicleID veh_dst = GB(p1, 0, 16);
01139
01140 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
01141 if (dst == NULL || !dst->IsPrimaryVehicle() || !CheckOwnership(dst->owner)) return CMD_ERROR;
01142
01143 switch (p2) {
01144 case CO_SHARE: {
01145 Vehicle *src = Vehicle::GetIfValid(veh_src);
01146
01147
01148 if (src == NULL || !src->IsPrimaryVehicle() || !CheckOwnership(src->owner) || dst->type != src->type || dst == src) return CMD_ERROR;
01149
01150
01151 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
01152 return CMD_ERROR;
01153 }
01154
01155
01156 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
01157
01158 const Order *order;
01159
01160 FOR_VEHICLE_ORDERS(src, order) {
01161 if (OrderGoesToStation(dst, order) &&
01162 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01163 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01164 }
01165 }
01166
01167 if (flags & DC_EXEC) {
01168
01169 DeleteVehicleOrders(dst);
01170
01171 dst->orders.list = src->orders.list;
01172
01173
01174 dst->AddToShared(src);
01175
01176 InvalidateVehicleOrder(dst, -1);
01177 InvalidateVehicleOrder(src, -2);
01178
01179 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01180 }
01181 } break;
01182
01183 case CO_COPY: {
01184 Vehicle *src = Vehicle::GetIfValid(veh_src);
01185
01186
01187 if (src == NULL || !src->IsPrimaryVehicle() || !CheckOwnership(src->owner) || dst->type != src->type || dst == src) return CMD_ERROR;
01188
01189
01190
01191 const Order *order;
01192 FOR_VEHICLE_ORDERS(src, order) {
01193 if (OrderGoesToStation(dst, order) &&
01194 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01195 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01196 }
01197 }
01198
01199
01200 int delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
01201 if (!Order::CanAllocateItem(delta) ||
01202 ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
01203 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01204 }
01205
01206 if (flags & DC_EXEC) {
01207 const Order *order;
01208 Order *first = NULL;
01209 Order **order_dst;
01210
01211
01212 DeleteVehicleOrders(dst, true);
01213
01214 order_dst = &first;
01215 FOR_VEHICLE_ORDERS(src, order) {
01216 *order_dst = new Order();
01217 (*order_dst)->AssignOrder(*order);
01218 order_dst = &(*order_dst)->next;
01219 }
01220 if (dst->orders.list == NULL) {
01221 dst->orders.list = new OrderList(first, dst);
01222 } else {
01223 assert(dst->orders.list->GetFirstOrder() == NULL);
01224 assert(!dst->orders.list->IsShared());
01225 delete dst->orders.list;
01226 dst->orders.list = new OrderList(first, dst);
01227 }
01228
01229 InvalidateVehicleOrder(dst, -1);
01230
01231 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01232 }
01233 } break;
01234
01235 case CO_UNSHARE: return DecloneOrder(dst, flags);
01236 default: return CMD_ERROR;
01237 }
01238
01239 return CommandCost();
01240 }
01241
01253 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01254 {
01255 VehicleID veh = GB(p1, 0, 16);
01256 VehicleOrderID order_number = GB(p2, 16, 8);
01257 CargoID cargo = GB(p2, 0, 8);
01258 byte subtype = GB(p2, 8, 8);
01259
01260 if (cargo >= NUM_CARGO) return CMD_ERROR;
01261
01262 const Vehicle *v = Vehicle::GetIfValid(veh);
01263 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner)) return CMD_ERROR;
01264
01265 Order *order = v->GetOrder(order_number);
01266 if (order == NULL) return CMD_ERROR;
01267
01268 if (flags & DC_EXEC) {
01269 order->SetRefit(cargo, subtype);
01270
01271 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
01272
01273 InvalidateVehicleOrder(u, -2);
01274
01275
01276 if (u->cur_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
01277 u->current_order.SetRefit(cargo, subtype);
01278 }
01279 }
01280 }
01281
01282 return CommandCost();
01283 }
01284
01291 void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
01292 {
01293
01294 free(bak->order);
01295 bak->order = NULL;
01296 free(bak->name);
01297 bak->name = NULL;
01298
01299
01300 bak->orderindex = v->cur_order_index;
01301 bak->group = v->group_id;
01302 bak->service_interval = v->service_interval;
01303 if (v->name != NULL) bak->name = strdup(v->name);
01304
01305
01306 if (v->IsOrderListShared()) {
01307 const Vehicle *u = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
01308
01309 bak->clone = u->index;
01310 } else {
01311
01312
01313
01314 bak->clone = INVALID_VEHICLE;
01315
01316
01317
01318 uint cnt = 0;
01319 const Order *order;
01320 FOR_VEHICLE_ORDERS(v, order) cnt++;
01321
01322
01323 bak->order = MallocT<Order>(cnt + 1);
01324
01325 Order *dest = bak->order;
01326
01327
01328 FOR_VEHICLE_ORDERS(v, order) {
01329 memcpy(dest, order, sizeof(Order));
01330 dest++;
01331 }
01332
01333 dest->Free();
01334 }
01335 }
01336
01342 void RestoreVehicleOrders(const Vehicle *v, const BackuppedOrders *bak)
01343 {
01344
01345 if (bak->name != NULL) DoCommandP(0, v->index, 0, CMD_RENAME_VEHICLE, NULL, bak->name);
01346
01347
01348 if (bak->clone != INVALID_VEHICLE) {
01349 DoCommandP(0, v->index | (bak->clone << 16), CO_SHARE, CMD_CLONE_ORDER);
01350 } else {
01351
01352
01353
01354
01355
01356 for (uint i = 0; !bak->order[i].IsType(OT_NOTHING); i++) {
01357 Order o = bak->order[i];
01358
01359 if (o.IsType(OT_CONDITIONAL)) o.SetConditionSkipToOrder(0);
01360
01361 if (!DoCommandP(0, v->index + (i << 16), o.Pack(),
01362 CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
01363 break;
01364 }
01365
01366
01367 if (_settings_game.order.timetabling && !DoCommandP(0, v->index | (i << 16) | (1 << 25),
01368 o.wait_time << 16 | o.travel_time,
01369 CMD_CHANGE_TIMETABLE | CMD_NO_TEST_IF_IN_NETWORK)) {
01370 break;
01371 }
01372 }
01373
01374
01375 for (uint i = 0; !bak->order[i].IsType(OT_NOTHING); i++) {
01376 if (!bak->order[i].IsType(OT_CONDITIONAL)) continue;
01377
01378 if (!DoCommandP(0, v->index + (i << 16), MOF_LOAD | (bak->order[i].GetConditionSkipToOrder() << 4),
01379 CMD_MODIFY_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
01380 break;
01381 }
01382 }
01383 }
01384
01385
01386 DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16), CMD_RESTORE_ORDER_INDEX);
01387
01388
01389 DoCommandP(0, bak->group, v->index, CMD_ADD_VEHICLE_GROUP);
01390 }
01391
01408 CommandCost CmdRestoreOrderIndex(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01409 {
01410 VehicleOrderID cur_ord = GB(p2, 0, 16);
01411 uint16 serv_int = GB(p2, 16, 16);
01412
01413 Vehicle *v = Vehicle::GetIfValid(p1);
01414
01415 if (v == NULL || !v->IsPrimaryVehicle() || !CheckOwnership(v->owner)) return CMD_ERROR;
01416
01417 if (serv_int != GetServiceIntervalClamped(serv_int, v->owner) || cur_ord >= v->GetNumOrders()) return CMD_ERROR;
01418
01419 if (flags & DC_EXEC) {
01420 v->cur_order_index = cur_ord;
01421 v->service_interval = serv_int;
01422 }
01423
01424 return CommandCost();
01425 }
01426
01427
01433 void CheckOrders(const Vehicle *v)
01434 {
01435
01436 if (_settings_client.gui.order_review_system == 0) return;
01437
01438
01439 if (v->vehstatus & VS_CRASHED) return;
01440
01441
01442 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED))
01443 return;
01444
01445
01446 if (v->FirstShared() != v) return;
01447
01448
01449 if (v->owner == _local_company && v->day_counter % 20 == 0) {
01450 int n_st, problem_type = -1;
01451 const Order *order;
01452 int message = 0;
01453
01454
01455 n_st = 0;
01456
01457 FOR_VEHICLE_ORDERS(v, order) {
01458
01459 if (order->IsType(OT_DUMMY)) {
01460 problem_type = 1;
01461 break;
01462 }
01463
01464 if (order->IsType(OT_GOTO_STATION)) {
01465 const Station *st = Station::Get(order->GetDestination());
01466
01467 n_st++;
01468 if (!CanVehicleUseStation(v, st)) problem_type = 3;
01469 }
01470 }
01471
01472
01473 if (v->GetNumOrders() > 1) {
01474 const Order *last = v->GetLastOrder();
01475
01476 if (v->orders.list->GetFirstOrder()->Equals(*last)) {
01477 problem_type = 2;
01478 }
01479 }
01480
01481
01482 if (n_st < 2 && problem_type == -1) problem_type = 0;
01483
01484 #ifndef NDEBUG
01485 if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
01486 #endif
01487
01488
01489 if (problem_type < 0) return;
01490
01491 message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
01492
01493
01494 SetDParam(0, v->index);
01495 AddVehicleNewsItem(
01496 message,
01497 NS_ADVICE,
01498 v->index
01499 );
01500 }
01501 }
01502
01508 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01509 {
01510 Vehicle *v;
01511
01512
01513
01514
01515
01516
01517 FOR_ALL_VEHICLES(v) {
01518 Order *order;
01519
01520 order = &v->current_order;
01521 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01522 v->current_order.GetDestination() == destination) {
01523 order->MakeDummy();
01524 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01525 }
01526
01527
01528 int id = -1;
01529 FOR_VEHICLE_ORDERS(v, order) {
01530 id++;
01531 if (order->IsType(OT_GOTO_DEPOT) && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
01532 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01533 order->GetDestination() == destination) {
01534 order->MakeDummy();
01535 for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
01536
01537 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
01538 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
01539 }
01540 }
01541 }
01542 }
01543 }
01544
01552 bool VehicleHasDepotOrders(const Vehicle *v)
01553 {
01554 const Order *order;
01555
01556 FOR_VEHICLE_ORDERS(v, order) {
01557 if (order->IsType(OT_GOTO_DEPOT))
01558 return true;
01559 }
01560
01561 return false;
01562 }
01563
01569 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist)
01570 {
01571 DeleteOrderWarnings(v);
01572
01573 if (v->IsOrderListShared()) {
01574
01575 v->RemoveFromShared();
01576 v->orders.list = NULL;
01577 } else if (v->orders.list != NULL) {
01578
01579 v->orders.list->FreeChain(keep_orderlist);
01580 if (!keep_orderlist) v->orders.list = NULL;
01581 }
01582 }
01583
01584 uint16 GetServiceIntervalClamped(uint interval, CompanyID company_id)
01585 {
01586 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);
01587 }
01588
01597 static bool CheckForValidOrders(const Vehicle *v)
01598 {
01599 const Order *order;
01600
01601 FOR_VEHICLE_ORDERS(v, order) {
01602 switch (order->GetType()) {
01603 case OT_GOTO_STATION:
01604 case OT_GOTO_DEPOT:
01605 case OT_GOTO_WAYPOINT:
01606 return true;
01607
01608 default:
01609 break;
01610 }
01611 }
01612
01613 return false;
01614 }
01615
01619 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
01620 {
01621 switch (occ) {
01622 case OCC_EQUALS: return variable == value;
01623 case OCC_NOT_EQUALS: return variable != value;
01624 case OCC_LESS_THAN: return variable < value;
01625 case OCC_LESS_EQUALS: return variable <= value;
01626 case OCC_MORE_THAN: return variable > value;
01627 case OCC_MORE_EQUALS: return variable >= value;
01628 case OCC_IS_TRUE: return variable != 0;
01629 case OCC_IS_FALSE: return variable == 0;
01630 default: NOT_REACHED();
01631 }
01632 }
01633
01640 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
01641 {
01642 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
01643
01644 bool skip_order = false;
01645 OrderConditionComparator occ = order->GetConditionComparator();
01646 uint16 value = order->GetConditionValue();
01647
01648 switch (order->GetConditionVariable()) {
01649 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
01650 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
01651 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
01652 case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
01653 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
01654 case OCV_UNCONDITIONALLY: skip_order = true; break;
01655 default: NOT_REACHED();
01656 }
01657
01658 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
01659 }
01660
01667 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
01668 {
01669 if (conditional_depth > v->GetNumOrders()) return false;
01670
01671 switch (order->GetType()) {
01672 case OT_GOTO_STATION:
01673 v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
01674 return true;
01675
01676 case OT_GOTO_DEPOT:
01677 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
01678 UpdateVehicleTimetable(v, true);
01679 v->IncrementOrderIndex();
01680 break;
01681 }
01682
01683 if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
01684
01685 TileIndex location;
01686 DestinationID destination;
01687 bool reverse;
01688
01689 if (v->FindClosestDepot(&location, &destination, &reverse)) {
01690 v->dest_tile = location;
01691 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());
01692
01693
01694 if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01695
01696 if (v->type == VEH_AIRCRAFT) {
01697 Aircraft *a = Aircraft::From(v);
01698 if (a->state == FLYING && a->targetairport != destination) {
01699
01700 extern void AircraftNextAirportPos_and_Order(Aircraft *a);
01701 AircraftNextAirportPos_and_Order(a);
01702 }
01703 }
01704 return true;
01705 }
01706
01707 UpdateVehicleTimetable(v, true);
01708 v->IncrementOrderIndex();
01709 } else {
01710 if (v->type != VEH_AIRCRAFT) {
01711 v->dest_tile = Depot::Get(order->GetDestination())->xy;
01712 }
01713 return true;
01714 }
01715 break;
01716
01717 case OT_GOTO_WAYPOINT:
01718 v->dest_tile = Waypoint::Get(order->GetDestination())->xy;
01719 return true;
01720
01721 case OT_CONDITIONAL: {
01722 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
01723 if (next_order != INVALID_VEH_ORDER_ID) {
01724 UpdateVehicleTimetable(v, false);
01725 v->cur_order_index = next_order;
01726 v->current_order_time += v->GetOrder(next_order)->travel_time;
01727 } else {
01728 UpdateVehicleTimetable(v, true);
01729 v->IncrementOrderIndex();
01730 }
01731 break;
01732 }
01733
01734 default:
01735 v->dest_tile = 0;
01736 return false;
01737 }
01738
01739 assert(v->cur_order_index < v->GetNumOrders());
01740
01741
01742 order = v->GetOrder(v->cur_order_index);
01743 v->current_order = *order;
01744 return UpdateOrderDest(v, order, conditional_depth + 1);
01745 }
01746
01754 bool ProcessOrders(Vehicle *v)
01755 {
01756 switch (v->current_order.GetType()) {
01757 case OT_GOTO_DEPOT:
01758
01759 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
01760 break;
01761
01762 case OT_LOADING:
01763 return false;
01764
01765 case OT_LEAVESTATION:
01766 if (v->type != VEH_AIRCRAFT) return false;
01767 break;
01768
01769 default: break;
01770 }
01771
01779 bool may_reverse = v->current_order.IsType(OT_NOTHING);
01780
01781
01782 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)) &&
01783 IsTileType(v->tile, MP_STATION) &&
01784 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
01785
01786
01787
01788
01789 v->last_station_visited = v->current_order.GetDestination();
01790 UpdateVehicleTimetable(v, true);
01791 v->IncrementOrderIndex();
01792 }
01793
01794
01795 if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
01796
01797 const Order *order = v->GetOrder(v->cur_order_index);
01798
01799
01800 if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
01801 if (v->type == VEH_AIRCRAFT) {
01802
01803 extern void HandleMissingAircraftOrders(Aircraft *v);
01804 HandleMissingAircraftOrders(Aircraft::From(v));
01805 return false;
01806 }
01807
01808 v->current_order.Free();
01809 v->dest_tile = 0;
01810 return false;
01811 }
01812
01813
01814 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
01815 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
01816 return false;
01817 }
01818
01819
01820 v->current_order = *order;
01821
01822 InvalidateVehicleOrder(v, -2);
01823 switch (v->type) {
01824 default:
01825 NOT_REACHED();
01826
01827 case VEH_ROAD:
01828 case VEH_TRAIN:
01829 break;
01830
01831 case VEH_AIRCRAFT:
01832 case VEH_SHIP:
01833 SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
01834 break;
01835 }
01836
01837 return UpdateOrderDest(v, order) && may_reverse;
01838 }
01839
01847 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
01848 {
01849 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
01850 return
01851 (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
01852 v->last_station_visited != station &&
01853
01854 !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
01855 }
01856
01857 void InitializeOrders()
01858 {
01859 _order_pool.CleanPool();
01860
01861 _orderlist_pool.CleanPool();
01862
01863 _backup_orders_tile = 0;
01864 }