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