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 #include "infrastructure_func.h"
00031
00032 #include "table/strings.h"
00033
00034
00035
00036
00037 assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
00038 assert_compile(sizeof(DestinationID) >= sizeof(StationID));
00039
00040 TileIndex _backup_orders_tile;
00041 BackuppedOrders _backup_orders_data;
00042
00043 OrderPool _order_pool("Order");
00044 INSTANTIATE_POOL_METHODS(Order)
00045 OrderListPool _orderlist_pool("OrderList");
00046 INSTANTIATE_POOL_METHODS(OrderList)
00047
00048 void Order::Free()
00049 {
00050 this->type = OT_NOTHING;
00051 this->flags = 0;
00052 this->dest = 0;
00053 this->next = NULL;
00054 }
00055
00056 void Order::MakeGoToStation(StationID destination)
00057 {
00058 this->type = OT_GOTO_STATION;
00059 this->flags = 0;
00060 this->dest = destination;
00061 }
00062
00063 void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoID cargo, byte subtype)
00064 {
00065 this->type = OT_GOTO_DEPOT;
00066 this->SetDepotOrderType(order);
00067 this->SetDepotActionType(action);
00068 this->SetNonStopType(non_stop_type);
00069 this->dest = destination;
00070 this->SetRefit(cargo, subtype);
00071 }
00072
00073 void Order::MakeGoToWaypoint(StationID destination)
00074 {
00075 this->type = OT_GOTO_WAYPOINT;
00076 this->flags = 0;
00077 this->dest = destination;
00078 }
00079
00080 void Order::MakeLoading(bool ordered)
00081 {
00082 this->type = OT_LOADING;
00083 if (!ordered) this->flags = 0;
00084 }
00085
00086 void Order::MakeLeaveStation()
00087 {
00088 this->type = OT_LEAVESTATION;
00089 this->flags = 0;
00090 }
00091
00092 void Order::MakeDummy()
00093 {
00094 this->type = OT_DUMMY;
00095 this->flags = 0;
00096 }
00097
00098 void Order::MakeConditional(VehicleOrderID order)
00099 {
00100 this->type = OT_CONDITIONAL;
00101 this->flags = order;
00102 this->dest = 0;
00103 }
00104
00105 void Order::SetRefit(CargoID cargo, byte subtype)
00106 {
00107 this->refit_cargo = cargo;
00108 this->refit_subtype = subtype;
00109 }
00110
00111 bool Order::Equals(const Order &other) const
00112 {
00113
00114
00115
00116
00117
00118 if ((this->type == OT_GOTO_DEPOT && this->type == other.type) &&
00119 ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
00120 (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
00121 return
00122 this->GetDepotOrderType() == other.GetDepotOrderType() &&
00123 (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
00124 }
00125
00126 return
00127 this->type == other.type &&
00128 this->flags == other.flags &&
00129 this->dest == other.dest;
00130 }
00131
00132 uint32 Order::Pack() const
00133 {
00134 return this->dest << 16 | this->flags << 8 | this->type;
00135 }
00136
00137 uint16 Order::MapOldOrder() const
00138 {
00139 uint16 order = this->GetType();
00140 switch (this->type) {
00141 case OT_GOTO_STATION:
00142 if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5);
00143 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
00144 if (this->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) SetBit(order, 7);
00145 order |= GB(this->GetDestination(), 0, 8) << 8;
00146 break;
00147 case OT_GOTO_DEPOT:
00148 if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6);
00149 SetBit(order, 7);
00150 order |= GB(this->GetDestination(), 0, 8) << 8;
00151 break;
00152 case OT_LOADING:
00153 if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6);
00154 break;
00155 }
00156 return order;
00157 }
00158
00159 Order::Order(uint32 packed)
00160 {
00161 this->type = (OrderType)GB(packed, 0, 8);
00162 this->flags = GB(packed, 8, 8);
00163 this->dest = GB(packed, 16, 16);
00164 this->next = NULL;
00165 this->refit_cargo = CT_NO_REFIT;
00166 this->refit_subtype = 0;
00167 this->wait_time = 0;
00168 this->travel_time = 0;
00169 }
00170
00176 void InvalidateVehicleOrder(const Vehicle *v, int data)
00177 {
00178 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
00179
00180 if (data != 0) {
00181
00182 InvalidateWindowData(WC_VEHICLE_ORDERS, v->index, data);
00183 InvalidateWindowData(WC_VEHICLE_TIMETABLE, v->index, data);
00184 return;
00185 }
00186
00187 SetWindowDirty(WC_VEHICLE_ORDERS, v->index);
00188 SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
00189 }
00190
00197 void Order::AssignOrder(const Order &other)
00198 {
00199 this->type = other.type;
00200 this->flags = other.flags;
00201 this->dest = other.dest;
00202
00203 this->refit_cargo = other.refit_cargo;
00204 this->refit_subtype = other.refit_subtype;
00205
00206 this->wait_time = other.wait_time;
00207 this->travel_time = other.travel_time;
00208 }
00209
00210 void OrderList::Initialize(Order *chain, Vehicle *v)
00211 {
00212 this->first = chain;
00213 this->first_shared = v;
00214
00215 this->num_orders = 0;
00216 this->num_vehicles = 1;
00217 this->timetable_duration = 0;
00218
00219 for (Order *o = this->first; o != NULL; o = o->next) {
00220 ++this->num_orders;
00221 this->timetable_duration += o->wait_time + o->travel_time;
00222 }
00223
00224 for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) {
00225 ++this->num_vehicles;
00226 this->first_shared = u;
00227 }
00228
00229 for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles;
00230 }
00231
00232 void OrderList::FreeChain(bool keep_orderlist)
00233 {
00234 Order *next;
00235 for (Order *o = this->first; o != NULL; o = next) {
00236 next = o->next;
00237 delete o;
00238 }
00239
00240 if (keep_orderlist) {
00241 this->first = NULL;
00242 this->num_orders = 0;
00243 this->timetable_duration = 0;
00244 } else {
00245 delete this;
00246 }
00247 }
00248
00249 Order *OrderList::GetOrderAt(int index) const
00250 {
00251 if (index < 0) return NULL;
00252
00253 Order *order = this->first;
00254
00255 while (order != NULL && index-- > 0)
00256 order = order->next;
00257
00258 return order;
00259 }
00260
00261 void OrderList::InsertOrderAt(Order *new_order, int index)
00262 {
00263 if (this->first == NULL) {
00264 this->first = new_order;
00265 } else {
00266 if (index == 0) {
00267
00268 new_order->next = this->first;
00269 this->first = new_order;
00270 } else if (index >= this->num_orders) {
00271
00272 this->GetLastOrder()->next = new_order;
00273 } else {
00274
00275 Order *order = this->GetOrderAt(index - 1);
00276 new_order->next = order->next;
00277 order->next = new_order;
00278 }
00279 }
00280 ++this->num_orders;
00281 this->timetable_duration += new_order->wait_time + new_order->travel_time;
00282 }
00283
00284
00285 void OrderList::DeleteOrderAt(int index)
00286 {
00287 if (index >= this->num_orders) return;
00288
00289 Order *to_remove;
00290
00291 if (index == 0) {
00292 to_remove = this->first;
00293 this->first = to_remove->next;
00294 } else {
00295 Order *prev = GetOrderAt(index - 1);
00296 to_remove = prev->next;
00297 prev->next = to_remove->next;
00298 }
00299 --this->num_orders;
00300 this->timetable_duration -= (to_remove->wait_time + to_remove->travel_time);
00301 delete to_remove;
00302 }
00303
00304 void OrderList::MoveOrder(int from, int to)
00305 {
00306 if (from >= this->num_orders || to >= this->num_orders || from == to) return;
00307
00308 Order *moving_one;
00309
00310
00311 if (from == 0) {
00312 moving_one = this->first;
00313 this->first = moving_one->next;
00314 } else {
00315 Order *one_before = GetOrderAt(from - 1);
00316 moving_one = one_before->next;
00317 one_before->next = moving_one->next;
00318 }
00319
00320
00321 if (to == 0) {
00322 moving_one->next = this->first;
00323 this->first = moving_one;
00324 } else {
00325 Order *one_before = GetOrderAt(to - 1);
00326 moving_one->next = one_before->next;
00327 one_before->next = moving_one;
00328 }
00329 }
00330
00331 void OrderList::RemoveVehicle(Vehicle *v)
00332 {
00333 --this->num_vehicles;
00334 if (v == this->first_shared) this->first_shared = v->NextShared();
00335 }
00336
00337 bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const
00338 {
00339 for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) {
00340 if (v_shared == v) return true;
00341 }
00342
00343 return false;
00344 }
00345
00346 int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
00347 {
00348 int count = 0;
00349 for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++;
00350 return count;
00351 }
00352
00353 bool OrderList::IsCompleteTimetable() const
00354 {
00355 for (Order *o = this->first; o != NULL; o = o->next) {
00356 if (!o->IsCompletelyTimetabled()) return false;
00357 }
00358 return true;
00359 }
00360
00361 void OrderList::DebugCheckSanity() const
00362 {
00363 VehicleOrderID check_num_orders = 0;
00364 uint check_num_vehicles = 0;
00365 Ticks check_timetable_duration = 0;
00366
00367 DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
00368
00369 for (const Order *o = this->first; o != NULL; o = o->next) {
00370 ++check_num_orders;
00371 check_timetable_duration += o->wait_time + o->travel_time;
00372 }
00373 assert(this->num_orders == check_num_orders);
00374 assert(this->timetable_duration == check_timetable_duration);
00375
00376 for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
00377 ++check_num_vehicles;
00378 assert(v->orders.list == this);
00379 }
00380 assert(this->num_vehicles == check_num_vehicles);
00381 DEBUG(misc, 6, "... detected %u orders, %u vehicles, %i ticks", (uint)this->num_orders,
00382 this->num_vehicles, this->timetable_duration);
00383 }
00384
00392 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
00393 {
00394 return o->IsType(OT_GOTO_STATION) ||
00395 (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
00396 }
00397
00404 static void DeleteOrderWarnings(const Vehicle *v)
00405 {
00406 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
00407 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
00408 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
00409 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
00410 }
00411
00412
00413 static TileIndex GetOrderLocation(const Order& o)
00414 {
00415 switch (o.GetType()) {
00416 default: NOT_REACHED();
00417 case OT_GOTO_WAYPOINT: return Waypoint::Get(o.GetDestination())->xy;
00418 case OT_GOTO_STATION: return Station::Get(o.GetDestination())->xy;
00419 case OT_GOTO_DEPOT: return Depot::Get(o.GetDestination())->xy;
00420 }
00421 }
00422
00423 static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0)
00424 {
00425 assert(v->type == VEH_SHIP);
00426
00427 if (cur->IsType(OT_CONDITIONAL)) {
00428 if (conditional_depth > v->GetNumOrders()) return 0;
00429
00430 conditional_depth++;
00431
00432 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
00433 int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
00434 return max(dist1, dist2);
00435 }
00436
00437 return DistanceManhattan(GetOrderLocation(*prev), GetOrderLocation(*cur));
00438 }
00439
00452 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00453 {
00454 VehicleID veh = GB(p1, 0, 16);
00455 VehicleOrderID sel_ord = GB(p1, 16, 16);
00456 Order new_order(p2);
00457
00458 Vehicle *v = Vehicle::GetIfValid(veh);
00459 if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
00460
00461
00462
00463 switch (new_order.GetType()) {
00464 case OT_GOTO_STATION: {
00465 const Station *st = Station::GetIfValid(new_order.GetDestination());
00466 if (st == NULL) return CMD_ERROR;
00467
00468 if (!CheckInfraUsageAllowed(st->owner, v->type)) return CMD_ERROR;
00469
00470 if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00471 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
00472 if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
00473 }
00474
00475
00476 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00477
00478
00479 if ((new_order.GetLoadType() & OLFB_NO_LOAD) && (new_order.GetUnloadType() & OUFB_NO_UNLOAD)) return CMD_ERROR;
00480
00481
00482 switch (new_order.GetLoadType()) {
00483 case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
00484 default: return CMD_ERROR;
00485 }
00486 switch (new_order.GetUnloadType()) {
00487 case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
00488 default: return CMD_ERROR;
00489 }
00490
00491
00492 switch (new_order.GetStopLocation()) {
00493 case OSL_PLATFORM_NEAR_END:
00494 case OSL_PLATFORM_MIDDLE:
00495 if (v->type != VEH_TRAIN) return CMD_ERROR;
00496
00497 case OSL_PLATFORM_FAR_END:
00498 break;
00499
00500 default:
00501 return CMD_ERROR;
00502 }
00503
00504 break;
00505 }
00506
00507 case OT_GOTO_DEPOT: {
00508 if (new_order.GetDepotActionType() != ODATFB_NEAREST_DEPOT) {
00509 if (v->type == VEH_AIRCRAFT) {
00510 const Station *st = Station::GetIfValid(new_order.GetDestination());
00511
00512 if (st == NULL || !CheckInfraUsageAllowed(st->owner, v->type) ||
00513 !CanVehicleUseStation(v, st) ||
00514 st->Airport()->nof_depots == 0) {
00515 return CMD_ERROR;
00516 }
00517 } else {
00518 const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
00519
00520 if (dp == NULL || !CheckInfraUsageAllowed(GetTileOwner(dp->xy), v->type)) return CMD_ERROR;
00521
00522 switch (v->type) {
00523 case VEH_TRAIN:
00524 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
00525 break;
00526
00527 case VEH_ROAD:
00528 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
00529 break;
00530
00531 case VEH_SHIP:
00532 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
00533 break;
00534
00535 default: return CMD_ERROR;
00536 }
00537 }
00538 } else {
00539 if (!IsCompanyBuildableVehicleType(v)) return CMD_ERROR;
00540 }
00541
00542 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00543 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
00544 if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
00545 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
00546 break;
00547 }
00548
00549 case OT_GOTO_WAYPOINT: {
00550 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
00551 if (wp == NULL) return CMD_ERROR;
00552
00553 switch (v->type) {
00554 default: return CMD_ERROR;
00555
00556 case VEH_TRAIN:
00557 if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00558 break;
00559
00560 case VEH_SHIP:
00561 if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00562 break;
00563 }
00564 if (!CheckInfraUsageAllowed(wp->owner, v->type)) return CMD_ERROR;
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 }