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 "roadstop_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
00411
00412 static TileIndex GetOrderLocation(const Order& o)
00413 {
00414 switch (o.GetType()) {
00415 default: NOT_REACHED();
00416 case OT_GOTO_WAYPOINT: return Waypoint::Get(o.GetDestination())->xy;
00417 case OT_GOTO_STATION: return Station::Get(o.GetDestination())->xy;
00418 case OT_GOTO_DEPOT: return Depot::Get(o.GetDestination())->xy;
00419 }
00420 }
00421
00422 static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0)
00423 {
00424 assert(v->type == VEH_SHIP);
00425
00426 if (cur->IsType(OT_CONDITIONAL)) {
00427 if (conditional_depth > v->GetNumOrders()) return 0;
00428
00429 conditional_depth++;
00430
00431 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
00432 int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
00433 return max(dist1, dist2);
00434 }
00435
00436 return DistanceManhattan(GetOrderLocation(*prev), GetOrderLocation(*cur));
00437 }
00438
00451 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00452 {
00453 VehicleID veh = GB(p1, 0, 16);
00454 VehicleOrderID sel_ord = GB(p1, 16, 16);
00455 Order new_order(p2);
00456
00457 Vehicle *v = Vehicle::GetIfValid(veh);
00458 if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
00459
00460
00461
00462 switch (new_order.GetType()) {
00463 case OT_GOTO_STATION: {
00464 const Station *st = Station::GetIfValid(new_order.GetDestination());
00465 if (st == NULL) return CMD_ERROR;
00466
00467 if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) return CMD_ERROR;
00468
00469 if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00470 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
00471 if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
00472 }
00473
00474
00475 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00476
00477
00478 if ((new_order.GetLoadType() & OLFB_NO_LOAD) && (new_order.GetUnloadType() & OUFB_NO_UNLOAD)) return CMD_ERROR;
00479
00480
00481 switch (new_order.GetLoadType()) {
00482 case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
00483 default: return CMD_ERROR;
00484 }
00485 switch (new_order.GetUnloadType()) {
00486 case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
00487 default: return CMD_ERROR;
00488 }
00489
00490
00491 switch (new_order.GetStopLocation()) {
00492 case OSL_PLATFORM_NEAR_END:
00493 case OSL_PLATFORM_MIDDLE:
00494 if (v->type != VEH_TRAIN) return CMD_ERROR;
00495
00496 case OSL_PLATFORM_FAR_END:
00497 break;
00498
00499 default:
00500 return CMD_ERROR;
00501 }
00502
00503 break;
00504 }
00505
00506 case OT_GOTO_DEPOT: {
00507 if (new_order.GetDepotActionType() != ODATFB_NEAREST_DEPOT) {
00508 if (v->type == VEH_AIRCRAFT) {
00509 const Station *st = Station::GetIfValid(new_order.GetDestination());
00510
00511 if (st == NULL || !CheckOwnership(st->owner) ||
00512 !CanVehicleUseStation(v, st) ||
00513 st->Airport()->nof_depots == 0) {
00514 return CMD_ERROR;
00515 }
00516 } else {
00517 const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
00518
00519 if (dp == NULL || !CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
00520
00521 switch (v->type) {
00522 case VEH_TRAIN:
00523 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
00524 break;
00525
00526 case VEH_ROAD:
00527 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
00528 break;
00529
00530 case VEH_SHIP:
00531 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
00532 break;
00533
00534 default: return CMD_ERROR;
00535 }
00536 }
00537 } else {
00538 if (!IsCompanyBuildableVehicleType(v)) return CMD_ERROR;
00539 }
00540
00541 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00542 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
00543 if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
00544 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
00545 break;
00546 }
00547
00548 case OT_GOTO_WAYPOINT: {
00549 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
00550 if (wp == NULL) return CMD_ERROR;
00551
00552 switch (v->type) {
00553 default: return CMD_ERROR;
00554
00555 case VEH_TRAIN:
00556 if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00557 if (!CheckOwnership(wp->owner)) return CMD_ERROR;
00558 break;
00559
00560 case VEH_SHIP:
00561 if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00562 if (!CheckOwnership(wp->owner) && wp->owner != OWNER_NONE) return CMD_ERROR;
00563 break;
00564 }
00565
00566
00567
00568
00569 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
00570 break;
00571 }
00572
00573 case OT_CONDITIONAL: {
00574 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
00575 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR;
00576 if (new_order.GetConditionVariable() > OCV_END) return CMD_ERROR;
00577
00578 OrderConditionComparator occ = new_order.GetConditionComparator();
00579 if (occ > OCC_END) return CMD_ERROR;
00580 switch (new_order.GetConditionVariable()) {
00581 case OCV_REQUIRES_SERVICE:
00582 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
00583 break;
00584
00585 case OCV_UNCONDITIONALLY:
00586 if (occ != OCC_EQUALS) return CMD_ERROR;
00587 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
00588 break;
00589
00590 case OCV_LOAD_PERCENTAGE:
00591 case OCV_RELIABILITY:
00592 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
00593
00594 default:
00595 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
00596 break;
00597 }
00598 } break;
00599
00600 default: return CMD_ERROR;
00601 }
00602
00603 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
00604
00605 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS);
00606 if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00607 if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00608
00609 if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) {
00610
00611 const Order *prev = NULL;
00612 uint n = 0;
00613
00614
00615
00616
00617 const Order *o;
00618 FOR_VEHICLE_ORDERS(v, o) {
00619 switch (o->GetType()) {
00620 case OT_GOTO_STATION:
00621 case OT_GOTO_DEPOT:
00622 case OT_GOTO_WAYPOINT:
00623 prev = o;
00624 break;
00625
00626 default: break;
00627 }
00628 if (++n == sel_ord && prev != NULL) break;
00629 }
00630 if (prev != NULL) {
00631 uint dist = GetOrderDistance(prev, &new_order, v);
00632 if (dist >= 130) {
00633 return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION);
00634 }
00635 }
00636 }
00637
00638 if (flags & DC_EXEC) {
00639 Order *new_o = new Order();
00640 new_o->AssignOrder(new_order);
00641
00642
00643 if (v->orders.list == NULL) {
00644 v->orders.list = new OrderList(new_o, v);
00645 } else {
00646 v->orders.list->InsertOrderAt(new_o, sel_ord);
00647 }
00648
00649 Vehicle *u = v->FirstShared();
00650 DeleteOrderWarnings(u);
00651 for (; u != NULL; u = u->NextShared()) {
00652 assert(v->orders.list == u->orders.list);
00653
00654
00655
00656 if (sel_ord <= u->cur_order_index) {
00657 uint cur = u->cur_order_index + 1;
00658
00659 if (cur < u->GetNumOrders())
00660 u->cur_order_index = cur;
00661 }
00662
00663 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
00664 }
00665
00666
00667 VehicleOrderID cur_order_id = 0;
00668 Order *order;
00669 FOR_VEHICLE_ORDERS(v, order) {
00670 if (order->IsType(OT_CONDITIONAL)) {
00671 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00672 if (order_id >= sel_ord) {
00673 order->SetConditionSkipToOrder(order_id + 1);
00674 }
00675 if (order_id == cur_order_id) {
00676 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00677 }
00678 }
00679 cur_order_id++;
00680 }
00681
00682
00683 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00684 }
00685
00686 return CommandCost();
00687 }
00688
00693 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
00694 {
00695 if (flags & DC_EXEC) {
00696 DeleteVehicleOrders(dst);
00697 InvalidateVehicleOrder(dst, -1);
00698 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
00699 }
00700 return CommandCost();
00701 }
00702
00711 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00712 {
00713 VehicleID veh_id = p1;
00714 VehicleOrderID sel_ord = p2;
00715 Order *order;
00716
00717 Vehicle *v = Vehicle::GetIfValid(veh_id);
00718
00719 if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
00720
00721
00722 if (sel_ord >= v->GetNumOrders())
00723 return DecloneOrder(v, flags);
00724
00725 order = v->GetOrder(sel_ord);
00726 if (order == NULL) return CMD_ERROR;
00727
00728 if (flags & DC_EXEC) {
00729 v->orders.list->DeleteOrderAt(sel_ord);
00730
00731 Vehicle *u = v->FirstShared();
00732 DeleteOrderWarnings(u);
00733 for (; u != NULL; u = u->NextShared()) {
00734 if (sel_ord < u->cur_order_index)
00735 u->cur_order_index--;
00736
00737 assert(v->orders.list == u->orders.list);
00738
00739
00740
00741 if (sel_ord == u->cur_order_index && u->current_order.IsType(OT_LOADING)) {
00742 u->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
00743 }
00744
00745
00746 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
00747 }
00748
00749
00750 VehicleOrderID cur_order_id = 0;
00751 FOR_VEHICLE_ORDERS(v, order) {
00752 if (order->IsType(OT_CONDITIONAL)) {
00753 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00754 if (order_id >= sel_ord) {
00755 order->SetConditionSkipToOrder(max(order_id - 1, 0));
00756 }
00757 if (order_id == cur_order_id) {
00758 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00759 }
00760 }
00761 cur_order_id++;
00762 }
00763
00764 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00765 }
00766
00767 return CommandCost();
00768 }
00769
00778 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00779 {
00780 VehicleID veh_id = p1;
00781 VehicleOrderID sel_ord = p2;
00782
00783 Vehicle *v = Vehicle::GetIfValid(veh_id);
00784
00785 if (v == NULL || !CheckOwnership(v->owner) || sel_ord == v->cur_order_index ||
00786 sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) {
00787 return CMD_ERROR;
00788 }
00789
00790 if (flags & DC_EXEC) {
00791 v->cur_order_index = sel_ord;
00792
00793 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
00794
00795 InvalidateVehicleOrder(v, -2);
00796 }
00797
00798
00799 if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
00800 if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
00801
00802 return CommandCost();
00803 }
00804
00818 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00819 {
00820 VehicleID veh = p1;
00821 VehicleOrderID moving_order = GB(p2, 0, 16);
00822 VehicleOrderID target_order = GB(p2, 16, 16);
00823
00824 Vehicle *v = Vehicle::GetIfValid(veh);
00825 if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
00826
00827
00828 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
00829 moving_order == target_order || v->GetNumOrders() <= 1)
00830 return CMD_ERROR;
00831
00832 Order *moving_one = v->GetOrder(moving_order);
00833
00834 if (moving_one == NULL) return CMD_ERROR;
00835
00836 if (flags & DC_EXEC) {
00837 v->orders.list->MoveOrder(moving_order, target_order);
00838
00839
00840 Vehicle *u = v->FirstShared();
00841
00842 DeleteOrderWarnings(u);
00843
00844 for (; u != NULL; u = u->NextShared()) {
00845
00846 if (u->cur_order_index == moving_order) {
00847 u->cur_order_index = target_order;
00848 } else if (u->cur_order_index > moving_order && u->cur_order_index <= target_order) {
00849 u->cur_order_index--;
00850 } else if (u->cur_order_index < moving_order && u->cur_order_index >= target_order) {
00851 u->cur_order_index++;
00852 }
00853
00854 assert(v->orders.list == u->orders.list);
00855
00856 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
00857 }
00858
00859
00860 Order *order;
00861 FOR_VEHICLE_ORDERS(v, order) {
00862 if (order->IsType(OT_CONDITIONAL)) {
00863 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00864 if (order_id == moving_order) {
00865 order_id = target_order;
00866 } else if (order_id > moving_order && order_id <= target_order) {
00867 order_id--;
00868 } else if (order_id < moving_order && order_id >= target_order) {
00869 order_id++;
00870 }
00871 order->SetConditionSkipToOrder(order_id);
00872 }
00873 }
00874
00875
00876 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00877 }
00878
00879 return CommandCost();
00880 }
00881
00896 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00897 {
00898 VehicleOrderID sel_ord = GB(p1, 16, 16);
00899 VehicleID veh = GB(p1, 0, 16);
00900 ModifyOrderFlags mof = (ModifyOrderFlags)GB(p2, 0, 4);
00901 uint16 data = GB(p2, 4, 11);
00902
00903 if (mof >= MOF_END) return CMD_ERROR;
00904
00905 Vehicle *v = Vehicle::GetIfValid(veh);
00906 if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
00907
00908
00909 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
00910
00911 Order *order = v->GetOrder(sel_ord);
00912 switch (order->GetType()) {
00913 case OT_GOTO_STATION:
00914 if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE) return CMD_ERROR;
00915 break;
00916
00917 case OT_GOTO_DEPOT:
00918 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
00919 break;
00920
00921 case OT_GOTO_WAYPOINT:
00922 if (mof != MOF_NON_STOP) return CMD_ERROR;
00923 break;
00924
00925 case OT_CONDITIONAL:
00926 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
00927 break;
00928
00929 default:
00930 return CMD_ERROR;
00931 }
00932
00933 switch (mof) {
00934 default: NOT_REACHED();
00935
00936 case MOF_NON_STOP:
00937 if (v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00938 if (data >= ONSF_END) return CMD_ERROR;
00939 if (data == order->GetNonStopType()) return CMD_ERROR;
00940 break;
00941
00942 case MOF_STOP_LOCATION:
00943 if (v->type != VEH_TRAIN) return CMD_ERROR;
00944 if (data >= OSL_END) return CMD_ERROR;
00945 break;
00946
00947 case MOF_UNLOAD:
00948 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
00949
00950 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
00951 if (data == order->GetUnloadType()) return CMD_ERROR;
00952 break;
00953
00954 case MOF_LOAD:
00955 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
00956 if (data == order->GetLoadType()) return CMD_ERROR;
00957 break;
00958
00959 case MOF_DEPOT_ACTION:
00960 if (data >= DA_END) return CMD_ERROR;
00961 break;
00962
00963 case MOF_COND_VARIABLE:
00964 if (data >= OCV_END) return CMD_ERROR;
00965 break;
00966
00967 case MOF_COND_COMPARATOR:
00968 if (data >= OCC_END) return CMD_ERROR;
00969 switch (order->GetConditionVariable()) {
00970 case OCV_UNCONDITIONALLY: return CMD_ERROR;
00971
00972 case OCV_REQUIRES_SERVICE:
00973 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
00974 break;
00975
00976 default:
00977 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
00978 break;
00979 }
00980 break;
00981
00982 case MOF_COND_VALUE:
00983 switch (order->GetConditionVariable()) {
00984 case OCV_UNCONDITIONALLY: return CMD_ERROR;
00985
00986 case OCV_LOAD_PERCENTAGE:
00987 case OCV_RELIABILITY:
00988 if (data > 100) return CMD_ERROR;
00989 break;
00990
00991 default:
00992 if (data > 2047) return CMD_ERROR;
00993 break;
00994 }
00995 break;
00996
00997 case MOF_COND_DESTINATION:
00998 if (data >= v->GetNumOrders()) return CMD_ERROR;
00999 break;
01000 }
01001
01002 if (flags & DC_EXEC) {
01003 switch (mof) {
01004 case MOF_NON_STOP:
01005 order->SetNonStopType((OrderNonStopFlags)data);
01006 break;
01007
01008 case MOF_STOP_LOCATION:
01009 order->SetStopLocation((OrderStopLocation)data);
01010 break;
01011
01012 case MOF_UNLOAD:
01013 order->SetUnloadType((OrderUnloadFlags)data);
01014 if ((data & OUFB_NO_UNLOAD) != 0 && (order->GetLoadType() & OLFB_NO_LOAD) != 0) {
01015 order->SetLoadType((OrderLoadFlags)(order->GetLoadType() & ~OLFB_NO_LOAD));
01016 }
01017 break;
01018
01019 case MOF_LOAD:
01020 order->SetLoadType((OrderLoadFlags)data);
01021 if ((data & OLFB_NO_LOAD) != 0 && (order->GetUnloadType() & OUFB_NO_UNLOAD) != 0) {
01022
01023 order->SetUnloadType((OrderUnloadFlags)(order->GetUnloadType() & ~OUFB_NO_UNLOAD));
01024 }
01025 break;
01026
01027 case MOF_DEPOT_ACTION: {
01028 switch (data) {
01029 case DA_ALWAYS_GO:
01030 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01031 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01032 break;
01033
01034 case DA_SERVICE:
01035 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
01036 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01037 break;
01038
01039 case DA_STOP:
01040 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01041 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
01042 break;
01043
01044 default:
01045 NOT_REACHED();
01046 }
01047 } break;
01048
01049 case MOF_COND_VARIABLE: {
01050 order->SetConditionVariable((OrderConditionVariable)data);
01051
01052 OrderConditionComparator occ = order->GetConditionComparator();
01053 switch (order->GetConditionVariable()) {
01054 case OCV_UNCONDITIONALLY:
01055 order->SetConditionComparator(OCC_EQUALS);
01056 order->SetConditionValue(0);
01057 break;
01058
01059 case OCV_REQUIRES_SERVICE:
01060 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
01061 break;
01062
01063 case OCV_LOAD_PERCENTAGE:
01064 case OCV_RELIABILITY:
01065 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
01066
01067 default:
01068 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
01069 break;
01070 }
01071 } break;
01072
01073 case MOF_COND_COMPARATOR:
01074 order->SetConditionComparator((OrderConditionComparator)data);
01075 break;
01076
01077 case MOF_COND_VALUE:
01078 order->SetConditionValue(data);
01079 break;
01080
01081 case MOF_COND_DESTINATION:
01082 order->SetConditionSkipToOrder(data);
01083 break;
01084
01085 default: NOT_REACHED();
01086 }
01087
01088
01089 Vehicle *u = v->FirstShared();
01090 DeleteOrderWarnings(u);
01091 for (; u != NULL; u = u->NextShared()) {
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101 if (sel_ord == u->cur_order_index &&
01102 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
01103 u->current_order.GetLoadType() != order->GetLoadType()) {
01104 u->current_order.SetLoadType(order->GetLoadType());
01105 }
01106 InvalidateVehicleOrder(u, -2);
01107 }
01108 }
01109
01110 return CommandCost();
01111 }
01112
01123 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01124 {
01125 VehicleID veh_src = GB(p1, 16, 16);
01126 VehicleID veh_dst = GB(p1, 0, 16);
01127
01128 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
01129
01130 if (dst == NULL || !CheckOwnership(dst->owner)) return CMD_ERROR;
01131
01132 switch (p2) {
01133 case CO_SHARE: {
01134 Vehicle *src = Vehicle::GetIfValid(veh_src);
01135
01136
01137 if (src == NULL || !CheckOwnership(src->owner) || dst->type != src->type || dst == src) {
01138 return CMD_ERROR;
01139 }
01140
01141
01142 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
01143 return CMD_ERROR;
01144 }
01145
01146
01147 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
01148
01149 const Order *order;
01150
01151 FOR_VEHICLE_ORDERS(src, order) {
01152 if (OrderGoesToStation(dst, order) &&
01153 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01154 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01155 }
01156 }
01157
01158 if (flags & DC_EXEC) {
01159
01160 DeleteVehicleOrders(dst);
01161
01162 dst->orders.list = src->orders.list;
01163
01164
01165 dst->AddToShared(src);
01166
01167 InvalidateVehicleOrder(dst, -1);
01168 InvalidateVehicleOrder(src, -2);
01169
01170 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01171 }
01172 } break;
01173
01174 case CO_COPY: {
01175 Vehicle *src = Vehicle::GetIfValid(veh_src);
01176
01177
01178 if (src == NULL || !CheckOwnership(src->owner) || dst->type != src->type || dst == src) {
01179 return CMD_ERROR;
01180 }
01181
01182
01183
01184 const Order *order;
01185 FOR_VEHICLE_ORDERS(src, order) {
01186 if (OrderGoesToStation(dst, order) &&
01187 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01188 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01189 }
01190 }
01191
01192
01193 int delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
01194 if (!Order::CanAllocateItem(delta) ||
01195 ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
01196 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01197 }
01198
01199 if (flags & DC_EXEC) {
01200 const Order *order;
01201 Order *first = NULL;
01202 Order **order_dst;
01203
01204
01205 DeleteVehicleOrders(dst, true);
01206
01207 order_dst = &first;
01208 FOR_VEHICLE_ORDERS(src, order) {
01209 *order_dst = new Order();
01210 (*order_dst)->AssignOrder(*order);
01211 order_dst = &(*order_dst)->next;
01212 }
01213 if (dst->orders.list == NULL) {
01214 dst->orders.list = new OrderList(first, dst);
01215 } else {
01216 assert(dst->orders.list->GetFirstOrder() == NULL);
01217 assert(!dst->orders.list->IsShared());
01218 delete dst->orders.list;
01219 dst->orders.list = new OrderList(first, dst);
01220 }
01221
01222 InvalidateVehicleOrder(dst, -1);
01223
01224 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01225 }
01226 } break;
01227
01228 case CO_UNSHARE: return DecloneOrder(dst, flags);
01229 default: return CMD_ERROR;
01230 }
01231
01232 return CommandCost();
01233 }
01234
01246 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01247 {
01248 VehicleID veh = GB(p1, 0, 16);
01249 VehicleOrderID order_number = GB(p2, 16, 8);
01250 CargoID cargo = GB(p2, 0, 8);
01251 byte subtype = GB(p2, 8, 8);
01252
01253 const Vehicle *v = Vehicle::GetIfValid(veh);
01254 if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
01255
01256 Order *order = v->GetOrder(order_number);
01257 if (order == NULL) return CMD_ERROR;
01258
01259 if (flags & DC_EXEC) {
01260 order->SetRefit(cargo, subtype);
01261
01262 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
01263
01264 InvalidateVehicleOrder(u, -2);
01265
01266
01267 if (u->cur_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
01268 u->current_order.SetRefit(cargo, subtype);
01269 }
01270 }
01271 }
01272
01273 return CommandCost();
01274 }
01275
01282 void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
01283 {
01284
01285 free(bak->order);
01286 bak->order = NULL;
01287 free(bak->name);
01288 bak->name = NULL;
01289
01290
01291 bak->orderindex = v->cur_order_index;
01292 bak->group = v->group_id;
01293 bak->service_interval = v->service_interval;
01294 if (v->name != NULL) bak->name = strdup(v->name);
01295
01296
01297 if (v->IsOrderListShared()) {
01298 const Vehicle *u = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
01299
01300 bak->clone = u->index;
01301 } else {
01302
01303
01304
01305 bak->clone = INVALID_VEHICLE;
01306
01307
01308
01309 uint cnt = 0;
01310 const Order *order;
01311 FOR_VEHICLE_ORDERS(v, order) cnt++;
01312
01313
01314 bak->order = MallocT<Order>(cnt + 1);
01315
01316 Order *dest = bak->order;
01317
01318
01319 FOR_VEHICLE_ORDERS(v, order) {
01320 memcpy(dest, order, sizeof(Order));
01321 dest++;
01322 }
01323
01324 dest->Free();
01325 }
01326 }
01327
01333 void RestoreVehicleOrders(const Vehicle *v, const BackuppedOrders *bak)
01334 {
01335
01336 if (bak->name != NULL) DoCommandP(0, v->index, 0, CMD_RENAME_VEHICLE, NULL, bak->name);
01337
01338
01339 if (bak->clone != INVALID_VEHICLE) {
01340 DoCommandP(0, v->index | (bak->clone << 16), CO_SHARE, CMD_CLONE_ORDER);
01341 } else {
01342
01343
01344
01345
01346
01347 for (uint i = 0; !bak->order[i].IsType(OT_NOTHING); i++) {
01348 Order o = bak->order[i];
01349
01350 if (o.IsType(OT_CONDITIONAL)) o.SetConditionSkipToOrder(0);
01351
01352 if (!DoCommandP(0, v->index + (i << 16), o.Pack(),
01353 CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
01354 break;
01355 }
01356
01357
01358 if (_settings_game.order.timetabling && !DoCommandP(0, v->index | (i << 16) | (1 << 25),
01359 o.wait_time << 16 | o.travel_time,
01360 CMD_CHANGE_TIMETABLE | CMD_NO_TEST_IF_IN_NETWORK)) {
01361 break;
01362 }
01363 }
01364
01365
01366 for (uint i = 0; !bak->order[i].IsType(OT_NOTHING); i++) {
01367 if (!bak->order[i].IsType(OT_CONDITIONAL)) continue;
01368
01369 if (!DoCommandP(0, v->index + (i << 16), MOF_LOAD | (bak->order[i].GetConditionSkipToOrder() << 4),
01370 CMD_MODIFY_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
01371 break;
01372 }
01373 }
01374 }
01375
01376
01377 DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16), CMD_RESTORE_ORDER_INDEX);
01378
01379
01380 DoCommandP(0, bak->group, v->index, CMD_ADD_VEHICLE_GROUP);
01381 }
01382
01399 CommandCost CmdRestoreOrderIndex(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01400 {
01401 VehicleOrderID cur_ord = GB(p2, 0, 16);
01402 uint16 serv_int = GB(p2, 16, 16);
01403
01404 Vehicle *v = Vehicle::GetIfValid(p1);
01405
01406 if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
01407 if (serv_int != GetServiceIntervalClamped(serv_int, v->owner) || cur_ord >= v->GetNumOrders()) return CMD_ERROR;
01408
01409 if (flags & DC_EXEC) {
01410 v->cur_order_index = cur_ord;
01411 v->service_interval = serv_int;
01412 }
01413
01414 return CommandCost();
01415 }
01416
01417
01418 static TileIndex GetStationTileForVehicle(const Vehicle *v, const Station *st)
01419 {
01420 if (!CanVehicleUseStation(v, st)) return INVALID_TILE;
01421
01422 switch (v->type) {
01423 default: NOT_REACHED();
01424 case VEH_TRAIN: return st->train_station.tile;
01425 case VEH_AIRCRAFT: return st->airport_tile;
01426 case VEH_SHIP: return st->dock_tile;
01427 case VEH_ROAD: return st->GetPrimaryRoadStop(RoadVehicle::From(v))->xy;
01428 }
01429 }
01430
01431
01437 void CheckOrders(const Vehicle *v)
01438 {
01439
01440 if (_settings_client.gui.order_review_system == 0) return;
01441
01442
01443 if (v->vehstatus & VS_CRASHED) return;
01444
01445
01446 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED))
01447 return;
01448
01449
01450 if (v->FirstShared() != v) return;
01451
01452
01453 if (v->owner == _local_company && v->day_counter % 20 == 0) {
01454 int n_st, problem_type = -1;
01455 const Order *order;
01456 int message = 0;
01457
01458
01459 n_st = 0;
01460
01461 FOR_VEHICLE_ORDERS(v, order) {
01462
01463 if (order->IsType(OT_DUMMY)) {
01464 problem_type = 1;
01465 break;
01466 }
01467
01468 if (order->IsType(OT_GOTO_STATION)) {
01469 const Station *st = Station::Get(order->GetDestination());
01470 TileIndex required_tile = GetStationTileForVehicle(v, st);
01471
01472 n_st++;
01473 if (required_tile == INVALID_TILE) problem_type = 3;
01474 }
01475 }
01476
01477
01478 if (v->GetNumOrders() > 1) {
01479 const Order *last = v->GetLastOrder();
01480
01481 if (v->orders.list->GetFirstOrder()->Equals(*last)) {
01482 problem_type = 2;
01483 }
01484 }
01485
01486
01487 if (n_st < 2 && problem_type == -1) problem_type = 0;
01488
01489 #ifndef NDEBUG
01490 if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
01491 #endif
01492
01493
01494 if (problem_type < 0) return;
01495
01496 message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
01497
01498
01499 SetDParam(0, v->index);
01500 AddVehicleNewsItem(
01501 message,
01502 NS_ADVICE,
01503 v->index
01504 );
01505 }
01506 }
01507
01513 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01514 {
01515 Vehicle *v;
01516
01517
01518
01519
01520
01521
01522 FOR_ALL_VEHICLES(v) {
01523 Order *order;
01524
01525 order = &v->current_order;
01526 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01527 v->current_order.GetDestination() == destination) {
01528 order->MakeDummy();
01529 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01530 }
01531
01532
01533 int id = -1;
01534 FOR_VEHICLE_ORDERS(v, order) {
01535 id++;
01536 if (order->IsType(OT_GOTO_DEPOT) && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
01537 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01538 order->GetDestination() == destination) {
01539 order->MakeDummy();
01540 for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
01541
01542 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
01543 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
01544 }
01545 }
01546 }
01547 }
01548 }
01549
01557 bool VehicleHasDepotOrders(const Vehicle *v)
01558 {
01559 const Order *order;
01560
01561 FOR_VEHICLE_ORDERS(v, order) {
01562 if (order->IsType(OT_GOTO_DEPOT))
01563 return true;
01564 }
01565
01566 return false;
01567 }
01568
01574 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist)
01575 {
01576 DeleteOrderWarnings(v);
01577
01578 if (v->IsOrderListShared()) {
01579
01580 v->RemoveFromShared();
01581 v->orders.list = NULL;
01582 } else if (v->orders.list != NULL) {
01583
01584 v->orders.list->FreeChain(keep_orderlist);
01585 if (!keep_orderlist) v->orders.list = NULL;
01586 }
01587 }
01588
01589 uint16 GetServiceIntervalClamped(uint interval, CompanyID company_id)
01590 {
01591 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);
01592 }
01593
01602 static bool CheckForValidOrders(const Vehicle *v)
01603 {
01604 const Order *order;
01605
01606 FOR_VEHICLE_ORDERS(v, order) {
01607 switch (order->GetType()) {
01608 case OT_GOTO_STATION:
01609 case OT_GOTO_DEPOT:
01610 case OT_GOTO_WAYPOINT:
01611 return true;
01612
01613 default:
01614 break;
01615 }
01616 }
01617
01618 return false;
01619 }
01620
01624 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
01625 {
01626 switch (occ) {
01627 case OCC_EQUALS: return variable == value;
01628 case OCC_NOT_EQUALS: return variable != value;
01629 case OCC_LESS_THAN: return variable < value;
01630 case OCC_LESS_EQUALS: return variable <= value;
01631 case OCC_MORE_THAN: return variable > value;
01632 case OCC_MORE_EQUALS: return variable >= value;
01633 case OCC_IS_TRUE: return variable != 0;
01634 case OCC_IS_FALSE: return variable == 0;
01635 default: NOT_REACHED();
01636 }
01637 }
01638
01645 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
01646 {
01647 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
01648
01649 bool skip_order = false;
01650 OrderConditionComparator occ = order->GetConditionComparator();
01651 uint16 value = order->GetConditionValue();
01652
01653 switch (order->GetConditionVariable()) {
01654 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
01655 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
01656 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
01657 case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
01658 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
01659 case OCV_UNCONDITIONALLY: skip_order = true; break;
01660 default: NOT_REACHED();
01661 }
01662
01663 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
01664 }
01665
01672 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
01673 {
01674 if (conditional_depth > v->GetNumOrders()) return false;
01675
01676 switch (order->GetType()) {
01677 case OT_GOTO_STATION:
01678 v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
01679 return true;
01680
01681 case OT_GOTO_DEPOT:
01682 if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
01683
01684 TileIndex location;
01685 DestinationID destination;
01686 bool reverse;
01687
01688 if (v->FindClosestDepot(&location, &destination, &reverse)) {
01689 v->dest_tile = location;
01690 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());
01691
01692
01693 if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01694
01695 if (v->type == VEH_AIRCRAFT) {
01696 Aircraft *a = Aircraft::From(v);
01697 if (a->state == FLYING && a->targetairport != destination) {
01698
01699 extern void AircraftNextAirportPos_and_Order(Aircraft *a);
01700 AircraftNextAirportPos_and_Order(a);
01701 }
01702 }
01703 return true;
01704 }
01705
01706 UpdateVehicleTimetable(v, true);
01707 v->IncrementOrderIndex();
01708 } else if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
01709 UpdateVehicleTimetable(v, true);
01710 v->IncrementOrderIndex();
01711 } else {
01712 if (v->type != VEH_AIRCRAFT) {
01713 v->dest_tile = Depot::Get(order->GetDestination())->xy;
01714 }
01715 return true;
01716 }
01717 break;
01718
01719 case OT_GOTO_WAYPOINT:
01720 v->dest_tile = Waypoint::Get(order->GetDestination())->xy;
01721 return true;
01722
01723 case OT_CONDITIONAL: {
01724 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
01725 if (next_order != INVALID_VEH_ORDER_ID) {
01726 UpdateVehicleTimetable(v, false);
01727 v->cur_order_index = next_order;
01728 v->current_order_time += v->GetOrder(next_order)->travel_time;
01729 } else {
01730 UpdateVehicleTimetable(v, true);
01731 v->IncrementOrderIndex();
01732 }
01733 break;
01734 }
01735
01736 default:
01737 v->dest_tile = 0;
01738 return false;
01739 }
01740
01741 assert(v->cur_order_index < v->GetNumOrders());
01742
01743
01744 order = v->GetOrder(v->cur_order_index);
01745 v->current_order = *order;
01746 return UpdateOrderDest(v, order, conditional_depth + 1);
01747 }
01748
01756 bool ProcessOrders(Vehicle *v)
01757 {
01758 switch (v->current_order.GetType()) {
01759 case OT_GOTO_DEPOT:
01760
01761 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
01762 break;
01763
01764 case OT_LOADING:
01765 return false;
01766
01767 case OT_LEAVESTATION:
01768 if (v->type != VEH_AIRCRAFT) return false;
01769 break;
01770
01771 default: break;
01772 }
01773
01781 bool may_reverse = v->current_order.IsType(OT_NOTHING);
01782
01783
01784 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)) &&
01785 IsTileType(v->tile, MP_STATION) &&
01786 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
01787 if (v->current_order.IsType(OT_GOTO_STATION)) v->last_station_visited = v->current_order.GetDestination();
01788 UpdateVehicleTimetable(v, true);
01789 v->IncrementOrderIndex();
01790 }
01791
01792
01793 if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
01794
01795 const Order *order = v->GetOrder(v->cur_order_index);
01796
01797
01798 if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
01799 if (v->type == VEH_AIRCRAFT) {
01800
01801 extern void HandleMissingAircraftOrders(Aircraft *v);
01802 HandleMissingAircraftOrders(Aircraft::From(v));
01803 return false;
01804 }
01805
01806 v->current_order.Free();
01807 v->dest_tile = 0;
01808 return false;
01809 }
01810
01811
01812 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
01813 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
01814 return false;
01815 }
01816
01817
01818 v->current_order = *order;
01819
01820 InvalidateVehicleOrder(v, -2);
01821 switch (v->type) {
01822 default:
01823 NOT_REACHED();
01824
01825 case VEH_ROAD:
01826 case VEH_TRAIN:
01827 break;
01828
01829 case VEH_AIRCRAFT:
01830 case VEH_SHIP:
01831 SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
01832 break;
01833 }
01834
01835 return UpdateOrderDest(v, order) && may_reverse;
01836 }
01837
01845 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
01846 {
01847 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
01848 return
01849 (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
01850 v->last_station_visited != station &&
01851
01852 !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
01853 }
01854
01855 void InitializeOrders()
01856 {
01857 _order_pool.CleanPool();
01858
01859 _orderlist_pool.CleanPool();
01860
01861 _backup_orders_tile = 0;
01862 }