00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "debug.h"
00014 #include "cmd_helper.h"
00015 #include "command_func.h"
00016 #include "company_func.h"
00017 #include "news_func.h"
00018 #include "vehicle_gui.h"
00019 #include "strings_func.h"
00020 #include "functions.h"
00021 #include "window_func.h"
00022 #include "timetable.h"
00023 #include "vehicle_func.h"
00024 #include "depot_base.h"
00025 #include "core/pool_func.hpp"
00026 #include "aircraft.h"
00027 #include "roadveh.h"
00028 #include "station_base.h"
00029 #include "waypoint_base.h"
00030 #include "company_base.h"
00031
00032 #include "table/strings.h"
00033
00034
00035
00036
00037 assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
00038 assert_compile(sizeof(DestinationID) >= sizeof(StationID));
00039
00040 OrderPool _order_pool("Order");
00041 INSTANTIATE_POOL_METHODS(Order)
00042 OrderListPool _orderlist_pool("OrderList");
00043 INSTANTIATE_POOL_METHODS(OrderList)
00044
00045 void Order::Free()
00046 {
00047 this->type = OT_NOTHING;
00048 this->flags = 0;
00049 this->dest = 0;
00050 this->next = NULL;
00051 }
00052
00053 void Order::MakeGoToStation(StationID destination)
00054 {
00055 this->type = OT_GOTO_STATION;
00056 this->flags = 0;
00057 this->dest = destination;
00058 }
00059
00060 void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoID cargo, byte subtype)
00061 {
00062 this->type = OT_GOTO_DEPOT;
00063 this->SetDepotOrderType(order);
00064 this->SetDepotActionType(action);
00065 this->SetNonStopType(non_stop_type);
00066 this->dest = destination;
00067 this->SetRefit(cargo, subtype);
00068 }
00069
00070 void Order::MakeGoToWaypoint(StationID destination)
00071 {
00072 this->type = OT_GOTO_WAYPOINT;
00073 this->flags = 0;
00074 this->dest = destination;
00075 }
00076
00077 void Order::MakeLoading(bool ordered)
00078 {
00079 this->type = OT_LOADING;
00080 if (!ordered) this->flags = 0;
00081 }
00082
00083 void Order::MakeLeaveStation()
00084 {
00085 this->type = OT_LEAVESTATION;
00086 this->flags = 0;
00087 }
00088
00089 void Order::MakeDummy()
00090 {
00091 this->type = OT_DUMMY;
00092 this->flags = 0;
00093 }
00094
00095 void Order::MakeConditional(VehicleOrderID order)
00096 {
00097 this->type = OT_CONDITIONAL;
00098 this->flags = order;
00099 this->dest = 0;
00100 }
00101
00102 void Order::MakeAutomatic(StationID destination)
00103 {
00104 this->type = OT_AUTOMATIC;
00105 this->dest = destination;
00106 }
00107
00108 void Order::SetRefit(CargoID cargo, byte subtype)
00109 {
00110 this->refit_cargo = cargo;
00111 this->refit_subtype = subtype;
00112 }
00113
00114 bool Order::Equals(const Order &other) const
00115 {
00116
00117
00118
00119
00120
00121 if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) &&
00122 ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
00123 (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
00124 return this->GetDepotOrderType() == other.GetDepotOrderType() &&
00125 (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
00126 }
00127
00128 return this->type == other.type && this->flags == other.flags && 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_manual_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 if (!o->IsType(OT_AUTOMATIC)) ++this->num_manual_orders;
00222 this->timetable_duration += o->wait_time + o->travel_time;
00223 }
00224
00225 for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) {
00226 ++this->num_vehicles;
00227 this->first_shared = u;
00228 }
00229
00230 for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles;
00231 }
00232
00233 void OrderList::FreeChain(bool keep_orderlist)
00234 {
00235 Order *next;
00236 for (Order *o = this->first; o != NULL; o = next) {
00237 next = o->next;
00238 delete o;
00239 }
00240
00241 if (keep_orderlist) {
00242 this->first = NULL;
00243 this->num_orders = 0;
00244 this->num_manual_orders = 0;
00245 this->timetable_duration = 0;
00246 } else {
00247 delete this;
00248 }
00249 }
00250
00251 Order *OrderList::GetOrderAt(int index) const
00252 {
00253 if (index < 0) return NULL;
00254
00255 Order *order = this->first;
00256
00257 while (order != NULL && index-- > 0) {
00258 order = order->next;
00259 }
00260 return order;
00261 }
00262
00263 void OrderList::InsertOrderAt(Order *new_order, int index)
00264 {
00265 if (this->first == NULL) {
00266 this->first = new_order;
00267 } else {
00268 if (index == 0) {
00269
00270 new_order->next = this->first;
00271 this->first = new_order;
00272 } else if (index >= this->num_orders) {
00273
00274 this->GetLastOrder()->next = new_order;
00275 } else {
00276
00277 Order *order = this->GetOrderAt(index - 1);
00278 new_order->next = order->next;
00279 order->next = new_order;
00280 }
00281 }
00282 ++this->num_orders;
00283 if (!new_order->IsType(OT_AUTOMATIC)) ++this->num_manual_orders;
00284 this->timetable_duration += new_order->wait_time + new_order->travel_time;
00285 }
00286
00287
00288 void OrderList::DeleteOrderAt(int index)
00289 {
00290 if (index >= this->num_orders) return;
00291
00292 Order *to_remove;
00293
00294 if (index == 0) {
00295 to_remove = this->first;
00296 this->first = to_remove->next;
00297 } else {
00298 Order *prev = GetOrderAt(index - 1);
00299 to_remove = prev->next;
00300 prev->next = to_remove->next;
00301 }
00302 --this->num_orders;
00303 if (!to_remove->IsType(OT_AUTOMATIC)) --this->num_manual_orders;
00304 this->timetable_duration -= (to_remove->wait_time + to_remove->travel_time);
00305 delete to_remove;
00306 }
00307
00308 void OrderList::MoveOrder(int from, int to)
00309 {
00310 if (from >= this->num_orders || to >= this->num_orders || from == to) return;
00311
00312 Order *moving_one;
00313
00314
00315 if (from == 0) {
00316 moving_one = this->first;
00317 this->first = moving_one->next;
00318 } else {
00319 Order *one_before = GetOrderAt(from - 1);
00320 moving_one = one_before->next;
00321 one_before->next = moving_one->next;
00322 }
00323
00324
00325 if (to == 0) {
00326 moving_one->next = this->first;
00327 this->first = moving_one;
00328 } else {
00329 Order *one_before = GetOrderAt(to - 1);
00330 moving_one->next = one_before->next;
00331 one_before->next = moving_one;
00332 }
00333 }
00334
00335 void OrderList::RemoveVehicle(Vehicle *v)
00336 {
00337 --this->num_vehicles;
00338 if (v == this->first_shared) this->first_shared = v->NextShared();
00339 }
00340
00341 bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const
00342 {
00343 for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) {
00344 if (v_shared == v) return true;
00345 }
00346
00347 return false;
00348 }
00349
00350 int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
00351 {
00352 int count = 0;
00353 for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++;
00354 return count;
00355 }
00356
00357 bool OrderList::IsCompleteTimetable() const
00358 {
00359 for (Order *o = this->first; o != NULL; o = o->next) {
00360
00361 if (o->IsType(OT_AUTOMATIC)) continue;
00362 if (!o->IsCompletelyTimetabled()) return false;
00363 }
00364 return true;
00365 }
00366
00367 void OrderList::DebugCheckSanity() const
00368 {
00369 VehicleOrderID check_num_orders = 0;
00370 VehicleOrderID check_num_manual_orders = 0;
00371 uint check_num_vehicles = 0;
00372 Ticks check_timetable_duration = 0;
00373
00374 DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
00375
00376 for (const Order *o = this->first; o != NULL; o = o->next) {
00377 ++check_num_orders;
00378 if (!o->IsType(OT_AUTOMATIC)) ++check_num_manual_orders;
00379 check_timetable_duration += o->wait_time + o->travel_time;
00380 }
00381 assert(this->num_orders == check_num_orders);
00382 assert(this->num_manual_orders == check_num_manual_orders);
00383 assert(this->timetable_duration == check_timetable_duration);
00384
00385 for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
00386 ++check_num_vehicles;
00387 assert(v->orders.list == this);
00388 }
00389 assert(this->num_vehicles == check_num_vehicles);
00390 DEBUG(misc, 6, "... detected %u orders (%u manual), %u vehicles, %i ticks",
00391 (uint)this->num_orders, (uint)this->num_manual_orders,
00392 this->num_vehicles, this->timetable_duration);
00393 }
00394
00402 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
00403 {
00404 return o->IsType(OT_GOTO_STATION) ||
00405 (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
00406 }
00407
00414 static void DeleteOrderWarnings(const Vehicle *v)
00415 {
00416 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
00417 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
00418 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
00419 DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
00420 }
00421
00427 TileIndex Order::GetLocation(const Vehicle *v) const
00428 {
00429 switch (this->GetType()) {
00430 case OT_GOTO_WAYPOINT:
00431 case OT_GOTO_STATION:
00432 case OT_AUTOMATIC:
00433 return BaseStation::Get(this->GetDestination())->xy;
00434
00435 case OT_GOTO_DEPOT:
00436 if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE;
00437 return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
00438
00439 default:
00440 return INVALID_TILE;
00441 }
00442 }
00443
00444 static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0)
00445 {
00446 assert(v->type == VEH_SHIP);
00447
00448 if (cur->IsType(OT_CONDITIONAL)) {
00449 if (conditional_depth > v->GetNumOrders()) return 0;
00450
00451 conditional_depth++;
00452
00453 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
00454 int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
00455 return max(dist1, dist2);
00456 }
00457
00458 TileIndex prev_tile = prev->GetLocation(v);
00459 TileIndex cur_tile = cur->GetLocation(v);
00460 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
00461 return DistanceManhattan(prev_tile, cur_tile);
00462 }
00463
00477 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00478 {
00479 VehicleID veh = GB(p1, 0, 20);
00480 VehicleOrderID sel_ord = GB(p1, 20, 8);
00481 Order new_order(p2);
00482
00483 Vehicle *v = Vehicle::GetIfValid(veh);
00484 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00485
00486 CommandCost ret = CheckOwnership(v->owner);
00487 if (ret.Failed()) return ret;
00488
00489
00490
00491 switch (new_order.GetType()) {
00492 case OT_GOTO_STATION: {
00493 const Station *st = Station::GetIfValid(new_order.GetDestination());
00494 if (st == NULL) return CMD_ERROR;
00495
00496 if (st->owner != OWNER_NONE) {
00497 CommandCost ret = CheckOwnership(st->owner);
00498 if (ret.Failed()) return ret;
00499 }
00500
00501 if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00502 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
00503 if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
00504 }
00505
00506
00507 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
00508
00509
00510 if ((new_order.GetLoadType() & OLFB_NO_LOAD) && (new_order.GetUnloadType() & OUFB_NO_UNLOAD)) return CMD_ERROR;
00511
00512
00513 switch (new_order.GetLoadType()) {
00514 case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
00515 default: return CMD_ERROR;
00516 }
00517 switch (new_order.GetUnloadType()) {
00518 case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
00519 default: return CMD_ERROR;
00520 }
00521
00522
00523 switch (new_order.GetStopLocation()) {
00524 case OSL_PLATFORM_NEAR_END:
00525 case OSL_PLATFORM_MIDDLE:
00526 if (v->type != VEH_TRAIN) return CMD_ERROR;
00527
00528 case OSL_PLATFORM_FAR_END:
00529 break;
00530
00531 default:
00532 return CMD_ERROR;
00533 }
00534
00535 break;
00536 }
00537
00538 case OT_GOTO_DEPOT: {
00539 if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
00540 if (v->type == VEH_AIRCRAFT) {
00541 const Station *st = Station::GetIfValid(new_order.GetDestination());
00542
00543 if (st == NULL) return CMD_ERROR;
00544
00545 CommandCost ret = CheckOwnership(st->owner);
00546 if (ret.Failed()) return ret;
00547
00548 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
00549 return CMD_ERROR;
00550 }
00551 } else {
00552 const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
00553
00554 if (dp == NULL) return CMD_ERROR;
00555
00556 CommandCost ret = CheckOwnership(GetTileOwner(dp->xy));
00557 if (ret.Failed()) return ret;
00558
00559 switch (v->type) {
00560 case VEH_TRAIN:
00561 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
00562 break;
00563
00564 case VEH_ROAD:
00565 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
00566 break;
00567
00568 case VEH_SHIP:
00569 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
00570 break;
00571
00572 default: return CMD_ERROR;
00573 }
00574 }
00575 }
00576
00577 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
00578 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
00579 if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
00580 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
00581 break;
00582 }
00583
00584 case OT_GOTO_WAYPOINT: {
00585 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
00586 if (wp == NULL) return CMD_ERROR;
00587
00588 switch (v->type) {
00589 default: return CMD_ERROR;
00590
00591 case VEH_TRAIN: {
00592 if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00593
00594 CommandCost ret = CheckOwnership(wp->owner);
00595 if (ret.Failed()) return ret;
00596 break;
00597 }
00598
00599 case VEH_SHIP:
00600 if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00601 if (wp->owner != OWNER_NONE) {
00602 CommandCost ret = CheckOwnership(wp->owner);
00603 if (ret.Failed()) return ret;
00604 }
00605 break;
00606 }
00607
00608
00609
00610
00611 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
00612 break;
00613 }
00614
00615 case OT_CONDITIONAL: {
00616 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
00617 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR;
00618 if (new_order.GetConditionVariable() > OCV_END) return CMD_ERROR;
00619
00620 OrderConditionComparator occ = new_order.GetConditionComparator();
00621 if (occ > OCC_END) return CMD_ERROR;
00622 switch (new_order.GetConditionVariable()) {
00623 case OCV_REQUIRES_SERVICE:
00624 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
00625 break;
00626
00627 case OCV_UNCONDITIONALLY:
00628 if (occ != OCC_EQUALS) return CMD_ERROR;
00629 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
00630 break;
00631
00632 case OCV_LOAD_PERCENTAGE:
00633 case OCV_RELIABILITY:
00634 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
00635
00636 default:
00637 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
00638 break;
00639 }
00640 break;
00641 }
00642
00643 default: return CMD_ERROR;
00644 }
00645
00646 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
00647
00648 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS);
00649 if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00650 if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00651
00652 if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) {
00653
00654 const Order *prev = NULL;
00655 uint n = 0;
00656
00657
00658
00659
00660 const Order *o;
00661 FOR_VEHICLE_ORDERS(v, o) {
00662 switch (o->GetType()) {
00663 case OT_GOTO_STATION:
00664 case OT_GOTO_DEPOT:
00665 case OT_GOTO_WAYPOINT:
00666 prev = o;
00667 break;
00668
00669 default: break;
00670 }
00671 if (++n == sel_ord && prev != NULL) break;
00672 }
00673 if (prev != NULL) {
00674 uint dist = GetOrderDistance(prev, &new_order, v);
00675 if (dist >= 130) {
00676 return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION);
00677 }
00678 }
00679 }
00680
00681 if (flags & DC_EXEC) {
00682 Order *new_o = new Order();
00683 new_o->AssignOrder(new_order);
00684 InsertOrder(v, new_o, sel_ord);
00685 }
00686
00687 return CommandCost();
00688 }
00689
00696 void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
00697 {
00698
00699 if (v->orders.list == NULL) {
00700 v->orders.list = new OrderList(new_o, v);
00701 } else {
00702 v->orders.list->InsertOrderAt(new_o, sel_ord);
00703 }
00704
00705 Vehicle *u = v->FirstShared();
00706 DeleteOrderWarnings(u);
00707 for (; u != NULL; u = u->NextShared()) {
00708 assert(v->orders.list == u->orders.list);
00709
00710
00711
00712 if (sel_ord <= u->cur_order_index) {
00713 uint cur = u->cur_order_index + 1;
00714
00715 if (cur < u->GetNumOrders()) {
00716 u->cur_order_index = cur;
00717 }
00718 }
00719
00720 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
00721 }
00722
00723
00724 VehicleOrderID cur_order_id = 0;
00725 Order *order;
00726 FOR_VEHICLE_ORDERS(v, order) {
00727 if (order->IsType(OT_CONDITIONAL)) {
00728 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00729 if (order_id >= sel_ord) {
00730 order->SetConditionSkipToOrder(order_id + 1);
00731 }
00732 if (order_id == cur_order_id) {
00733 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00734 }
00735 }
00736 cur_order_id++;
00737 }
00738
00739
00740 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00741 }
00742
00748 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
00749 {
00750 if (flags & DC_EXEC) {
00751 DeleteVehicleOrders(dst);
00752 InvalidateVehicleOrder(dst, -1);
00753 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
00754 }
00755 return CommandCost();
00756 }
00757
00767 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00768 {
00769 VehicleID veh_id = GB(p1, 0, 20);
00770 VehicleOrderID sel_ord = GB(p2, 0, 8);
00771
00772 Vehicle *v = Vehicle::GetIfValid(veh_id);
00773
00774 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00775
00776 CommandCost ret = CheckOwnership(v->owner);
00777 if (ret.Failed()) return ret;
00778
00779
00780 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
00781
00782 if (v->GetOrder(sel_ord) == NULL) return CMD_ERROR;
00783
00784 if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
00785 return CommandCost();
00786 }
00787
00793 void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
00794 {
00795 v->orders.list->DeleteOrderAt(sel_ord);
00796
00797 Vehicle *u = v->FirstShared();
00798 DeleteOrderWarnings(u);
00799 for (; u != NULL; u = u->NextShared()) {
00800 assert(v->orders.list == u->orders.list);
00801
00802
00803
00804 if (sel_ord == u->cur_order_index && u->current_order.IsType(OT_LOADING)) {
00805 u->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
00806
00807
00808 if (u->current_order.GetLoadType() & OLFB_FULL_LOAD) u->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE);
00809 }
00810
00811 if (sel_ord < u->cur_order_index) u->cur_order_index--;
00812
00813
00814 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
00815 }
00816
00817
00818 VehicleOrderID cur_order_id = 0;
00819 Order *order = NULL;
00820 FOR_VEHICLE_ORDERS(v, order) {
00821 if (order->IsType(OT_CONDITIONAL)) {
00822 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00823 if (order_id >= sel_ord) {
00824 order->SetConditionSkipToOrder(max(order_id - 1, 0));
00825 }
00826 if (order_id == cur_order_id) {
00827 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00828 }
00829 }
00830 cur_order_id++;
00831 }
00832
00833 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00834 }
00835
00845 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00846 {
00847 VehicleID veh_id = GB(p1, 0, 20);
00848 VehicleOrderID sel_ord = GB(p2, 0, 8);
00849
00850 Vehicle *v = Vehicle::GetIfValid(veh_id);
00851
00852 if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
00853
00854 CommandCost ret = CheckOwnership(v->owner);
00855 if (ret.Failed()) return ret;
00856
00857 if (flags & DC_EXEC) {
00858 v->cur_order_index = sel_ord;
00859
00860 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
00861
00862 InvalidateVehicleOrder(v, -2);
00863 }
00864
00865
00866 if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
00867 if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
00868
00869 return CommandCost();
00870 }
00871
00885 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00886 {
00887 VehicleID veh = GB(p1, 0, 20);
00888 VehicleOrderID moving_order = GB(p2, 0, 16);
00889 VehicleOrderID target_order = GB(p2, 16, 16);
00890
00891 Vehicle *v = Vehicle::GetIfValid(veh);
00892 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00893
00894 CommandCost ret = CheckOwnership(v->owner);
00895 if (ret.Failed()) return ret;
00896
00897
00898 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
00899 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
00900
00901 Order *moving_one = v->GetOrder(moving_order);
00902
00903 if (moving_one == NULL) return CMD_ERROR;
00904
00905 if (flags & DC_EXEC) {
00906 v->orders.list->MoveOrder(moving_order, target_order);
00907
00908
00909 Vehicle *u = v->FirstShared();
00910
00911 DeleteOrderWarnings(u);
00912
00913 for (; u != NULL; u = u->NextShared()) {
00914
00915 if (u->cur_order_index == moving_order) {
00916 u->cur_order_index = target_order;
00917 } else if (u->cur_order_index > moving_order && u->cur_order_index <= target_order) {
00918 u->cur_order_index--;
00919 } else if (u->cur_order_index < moving_order && u->cur_order_index >= target_order) {
00920 u->cur_order_index++;
00921 }
00922
00923 assert(v->orders.list == u->orders.list);
00924
00925 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
00926 }
00927
00928
00929 Order *order;
00930 FOR_VEHICLE_ORDERS(v, order) {
00931 if (order->IsType(OT_CONDITIONAL)) {
00932 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00933 if (order_id == moving_order) {
00934 order_id = target_order;
00935 } else if (order_id > moving_order && order_id <= target_order) {
00936 order_id--;
00937 } else if (order_id < moving_order && order_id >= target_order) {
00938 order_id++;
00939 }
00940 order->SetConditionSkipToOrder(order_id);
00941 }
00942 }
00943
00944
00945 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00946 }
00947
00948 return CommandCost();
00949 }
00950
00966 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00967 {
00968 VehicleOrderID sel_ord = GB(p1, 20, 8);
00969 VehicleID veh = GB(p1, 0, 20);
00970 ModifyOrderFlags mof = Extract<ModifyOrderFlags, 0, 4>(p2);
00971 uint16 data = GB(p2, 4, 11);
00972
00973 if (mof >= MOF_END) return CMD_ERROR;
00974
00975 Vehicle *v = Vehicle::GetIfValid(veh);
00976 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00977
00978 CommandCost ret = CheckOwnership(v->owner);
00979 if (ret.Failed()) return ret;
00980
00981
00982 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
00983
00984 Order *order = v->GetOrder(sel_ord);
00985 switch (order->GetType()) {
00986 case OT_GOTO_STATION:
00987 if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE) return CMD_ERROR;
00988 break;
00989
00990 case OT_GOTO_DEPOT:
00991 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
00992 break;
00993
00994 case OT_GOTO_WAYPOINT:
00995 if (mof != MOF_NON_STOP) return CMD_ERROR;
00996 break;
00997
00998 case OT_CONDITIONAL:
00999 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
01000 break;
01001
01002 default:
01003 return CMD_ERROR;
01004 }
01005
01006 switch (mof) {
01007 default: NOT_REACHED();
01008
01009 case MOF_NON_STOP:
01010 if (!v->IsGroundVehicle()) return CMD_ERROR;
01011 if (data >= ONSF_END) return CMD_ERROR;
01012 if (data == order->GetNonStopType()) return CMD_ERROR;
01013 break;
01014
01015 case MOF_STOP_LOCATION:
01016 if (v->type != VEH_TRAIN) return CMD_ERROR;
01017 if (data >= OSL_END) return CMD_ERROR;
01018 break;
01019
01020 case MOF_UNLOAD:
01021 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
01022
01023 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
01024 if (data == order->GetUnloadType()) return CMD_ERROR;
01025 break;
01026
01027 case MOF_LOAD:
01028 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
01029 if (data == order->GetLoadType()) return CMD_ERROR;
01030 break;
01031
01032 case MOF_DEPOT_ACTION:
01033 if (data >= DA_END) return CMD_ERROR;
01034 break;
01035
01036 case MOF_COND_VARIABLE:
01037 if (data >= OCV_END) return CMD_ERROR;
01038 break;
01039
01040 case MOF_COND_COMPARATOR:
01041 if (data >= OCC_END) return CMD_ERROR;
01042 switch (order->GetConditionVariable()) {
01043 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01044
01045 case OCV_REQUIRES_SERVICE:
01046 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
01047 break;
01048
01049 default:
01050 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
01051 break;
01052 }
01053 break;
01054
01055 case MOF_COND_VALUE:
01056 switch (order->GetConditionVariable()) {
01057 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01058
01059 case OCV_LOAD_PERCENTAGE:
01060 case OCV_RELIABILITY:
01061 if (data > 100) return CMD_ERROR;
01062 break;
01063
01064 default:
01065 if (data > 2047) return CMD_ERROR;
01066 break;
01067 }
01068 break;
01069
01070 case MOF_COND_DESTINATION:
01071 if (data >= v->GetNumOrders()) return CMD_ERROR;
01072 break;
01073 }
01074
01075 if (flags & DC_EXEC) {
01076 switch (mof) {
01077 case MOF_NON_STOP:
01078 order->SetNonStopType((OrderNonStopFlags)data);
01079 break;
01080
01081 case MOF_STOP_LOCATION:
01082 order->SetStopLocation((OrderStopLocation)data);
01083 break;
01084
01085 case MOF_UNLOAD:
01086 order->SetUnloadType((OrderUnloadFlags)data);
01087 if ((data & OUFB_NO_UNLOAD) != 0 && (order->GetLoadType() & OLFB_NO_LOAD) != 0) {
01088 order->SetLoadType((OrderLoadFlags)(order->GetLoadType() & ~OLFB_NO_LOAD));
01089 }
01090 break;
01091
01092 case MOF_LOAD:
01093 order->SetLoadType((OrderLoadFlags)data);
01094 if ((data & OLFB_NO_LOAD) != 0 && (order->GetUnloadType() & OUFB_NO_UNLOAD) != 0) {
01095
01096 order->SetUnloadType((OrderUnloadFlags)(order->GetUnloadType() & ~OUFB_NO_UNLOAD));
01097 }
01098 break;
01099
01100 case MOF_DEPOT_ACTION: {
01101 switch (data) {
01102 case DA_ALWAYS_GO:
01103 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01104 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01105 break;
01106
01107 case DA_SERVICE:
01108 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
01109 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01110 break;
01111
01112 case DA_STOP:
01113 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01114 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
01115 break;
01116
01117 default:
01118 NOT_REACHED();
01119 }
01120 break;
01121 }
01122
01123 case MOF_COND_VARIABLE: {
01124 order->SetConditionVariable((OrderConditionVariable)data);
01125
01126 OrderConditionComparator occ = order->GetConditionComparator();
01127 switch (order->GetConditionVariable()) {
01128 case OCV_UNCONDITIONALLY:
01129 order->SetConditionComparator(OCC_EQUALS);
01130 order->SetConditionValue(0);
01131 break;
01132
01133 case OCV_REQUIRES_SERVICE:
01134 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
01135 break;
01136
01137 case OCV_LOAD_PERCENTAGE:
01138 case OCV_RELIABILITY:
01139 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
01140
01141 default:
01142 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
01143 break;
01144 }
01145 break;
01146 }
01147
01148 case MOF_COND_COMPARATOR:
01149 order->SetConditionComparator((OrderConditionComparator)data);
01150 break;
01151
01152 case MOF_COND_VALUE:
01153 order->SetConditionValue(data);
01154 break;
01155
01156 case MOF_COND_DESTINATION:
01157 order->SetConditionSkipToOrder(data);
01158 break;
01159
01160 default: NOT_REACHED();
01161 }
01162
01163
01164 Vehicle *u = v->FirstShared();
01165 DeleteOrderWarnings(u);
01166 for (; u != NULL; u = u->NextShared()) {
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176 if (sel_ord == u->cur_order_index &&
01177 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
01178 u->current_order.GetLoadType() != order->GetLoadType()) {
01179 u->current_order.SetLoadType(order->GetLoadType());
01180 }
01181 InvalidateVehicleOrder(u, -2);
01182 }
01183 }
01184
01185 return CommandCost();
01186 }
01187
01199 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01200 {
01201 VehicleID veh_src = GB(p2, 0, 20);
01202 VehicleID veh_dst = GB(p1, 0, 20);
01203
01204 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
01205 if (dst == NULL || !dst->IsPrimaryVehicle()) return CMD_ERROR;
01206
01207 CommandCost ret = CheckOwnership(dst->owner);
01208 if (ret.Failed()) return ret;
01209
01210 switch (GB(p1, 30, 2)) {
01211 case CO_SHARE: {
01212 Vehicle *src = Vehicle::GetIfValid(veh_src);
01213
01214
01215 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01216
01217 CommandCost ret = CheckOwnership(src->owner);
01218 if (ret.Failed()) return ret;
01219
01220
01221 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
01222 return CMD_ERROR;
01223 }
01224
01225
01226 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
01227
01228 const Order *order;
01229
01230 FOR_VEHICLE_ORDERS(src, order) {
01231 if (OrderGoesToStation(dst, order) &&
01232 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01233 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01234 }
01235 }
01236
01237 if (flags & DC_EXEC) {
01238
01239 DeleteVehicleOrders(dst);
01240
01241 dst->orders.list = src->orders.list;
01242
01243
01244 dst->AddToShared(src);
01245
01246 InvalidateVehicleOrder(dst, -1);
01247 InvalidateVehicleOrder(src, -2);
01248
01249 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01250 }
01251 break;
01252 }
01253
01254 case CO_COPY: {
01255 Vehicle *src = Vehicle::GetIfValid(veh_src);
01256
01257
01258 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01259
01260 CommandCost ret = CheckOwnership(src->owner);
01261 if (ret.Failed()) return ret;
01262
01263
01264
01265 const Order *order;
01266 FOR_VEHICLE_ORDERS(src, order) {
01267 if (OrderGoesToStation(dst, order) &&
01268 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01269 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01270 }
01271 }
01272
01273
01274 int delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
01275 if (!Order::CanAllocateItem(delta) ||
01276 ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
01277 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01278 }
01279
01280 if (flags & DC_EXEC) {
01281 const Order *order;
01282 Order *first = NULL;
01283 Order **order_dst;
01284
01285
01286 DeleteVehicleOrders(dst, true);
01287
01288 order_dst = &first;
01289 FOR_VEHICLE_ORDERS(src, order) {
01290 *order_dst = new Order();
01291 (*order_dst)->AssignOrder(*order);
01292 order_dst = &(*order_dst)->next;
01293 }
01294 if (dst->orders.list == NULL) {
01295 dst->orders.list = new OrderList(first, dst);
01296 } else {
01297 assert(dst->orders.list->GetFirstOrder() == NULL);
01298 assert(!dst->orders.list->IsShared());
01299 delete dst->orders.list;
01300 dst->orders.list = new OrderList(first, dst);
01301 }
01302
01303 InvalidateVehicleOrder(dst, -1);
01304
01305 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01306 }
01307 break;
01308 }
01309
01310 case CO_UNSHARE: return DecloneOrder(dst, flags);
01311 default: return CMD_ERROR;
01312 }
01313
01314 return CommandCost();
01315 }
01316
01329 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01330 {
01331 VehicleID veh = GB(p1, 0, 20);
01332 VehicleOrderID order_number = GB(p2, 16, 8);
01333 CargoID cargo = GB(p2, 0, 8);
01334 byte subtype = GB(p2, 8, 8);
01335
01336 if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT) return CMD_ERROR;
01337
01338 const Vehicle *v = Vehicle::GetIfValid(veh);
01339 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01340
01341 CommandCost ret = CheckOwnership(v->owner);
01342 if (ret.Failed()) return ret;
01343
01344 Order *order = v->GetOrder(order_number);
01345 if (order == NULL) return CMD_ERROR;
01346
01347 if (flags & DC_EXEC) {
01348 order->SetRefit(cargo, subtype);
01349
01350 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
01351
01352 InvalidateVehicleOrder(u, -2);
01353
01354
01355 if (u->cur_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
01356 u->current_order.SetRefit(cargo, subtype);
01357 }
01358 }
01359 }
01360
01361 return CommandCost();
01362 }
01363
01364
01370 void CheckOrders(const Vehicle *v)
01371 {
01372
01373 if (_settings_client.gui.order_review_system == 0) return;
01374
01375
01376 if (v->vehstatus & VS_CRASHED) return;
01377
01378
01379 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
01380
01381
01382 if (v->FirstShared() != v) return;
01383
01384
01385 if (v->owner == _local_company && v->day_counter % 20 == 0) {
01386 int n_st, problem_type = -1;
01387 const Order *order;
01388 int message = 0;
01389
01390
01391 n_st = 0;
01392
01393 FOR_VEHICLE_ORDERS(v, order) {
01394
01395 if (order->IsType(OT_DUMMY)) {
01396 problem_type = 1;
01397 break;
01398 }
01399
01400 if (order->IsType(OT_GOTO_STATION)) {
01401 const Station *st = Station::Get(order->GetDestination());
01402
01403 n_st++;
01404 if (!CanVehicleUseStation(v, st)) problem_type = 3;
01405 }
01406 }
01407
01408
01409 if (v->GetNumOrders() > 1) {
01410 const Order *last = v->GetLastOrder();
01411
01412 if (v->orders.list->GetFirstOrder()->Equals(*last)) {
01413 problem_type = 2;
01414 }
01415 }
01416
01417
01418 if (n_st < 2 && problem_type == -1) problem_type = 0;
01419
01420 #ifndef NDEBUG
01421 if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
01422 #endif
01423
01424
01425 if (problem_type < 0) return;
01426
01427 message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
01428
01429
01430 SetDParam(0, v->index);
01431 AddVehicleNewsItem(
01432 message,
01433 NS_ADVICE,
01434 v->index
01435 );
01436 }
01437 }
01438
01444 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01445 {
01446 Vehicle *v;
01447
01448
01449
01450
01451
01452
01453 FOR_ALL_VEHICLES(v) {
01454 Order *order;
01455
01456 order = &v->current_order;
01457 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01458 v->current_order.GetDestination() == destination) {
01459 order->MakeDummy();
01460 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01461 }
01462
01463
01464 int id = -1;
01465 FOR_VEHICLE_ORDERS(v, order) {
01466 id++;
01467
01468 OrderType ot = order->GetType();
01469 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
01470 if (ot == OT_AUTOMATIC || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
01471 if (ot == type && order->GetDestination() == destination) {
01472
01473
01474
01475 if (order->IsType(OT_AUTOMATIC)) {
01476 DeleteOrder(v, id);
01477 id--;
01478 continue;
01479 }
01480
01481 order->MakeDummy();
01482 for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
01483
01484 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
01485 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
01486 }
01487 }
01488 }
01489 }
01490 }
01491
01496 bool Vehicle::HasDepotOrder() const
01497 {
01498 const Order *order;
01499
01500 FOR_VEHICLE_ORDERS(this, order) {
01501 if (order->IsType(OT_GOTO_DEPOT)) return true;
01502 }
01503
01504 return false;
01505 }
01506
01512 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist)
01513 {
01514 DeleteOrderWarnings(v);
01515
01516 if (v->IsOrderListShared()) {
01517
01518 v->RemoveFromShared();
01519 v->orders.list = NULL;
01520 } else if (v->orders.list != NULL) {
01521
01522 v->orders.list->FreeChain(keep_orderlist);
01523 if (!keep_orderlist) v->orders.list = NULL;
01524 }
01525 }
01526
01527 uint16 GetServiceIntervalClamped(uint interval, CompanyID company_id)
01528 {
01529 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);
01530 }
01531
01540 static bool CheckForValidOrders(const Vehicle *v)
01541 {
01542 const Order *order;
01543
01544 FOR_VEHICLE_ORDERS(v, order) {
01545 switch (order->GetType()) {
01546 case OT_GOTO_STATION:
01547 case OT_GOTO_DEPOT:
01548 case OT_GOTO_WAYPOINT:
01549 return true;
01550
01551 default:
01552 break;
01553 }
01554 }
01555
01556 return false;
01557 }
01558
01562 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
01563 {
01564 switch (occ) {
01565 case OCC_EQUALS: return variable == value;
01566 case OCC_NOT_EQUALS: return variable != value;
01567 case OCC_LESS_THAN: return variable < value;
01568 case OCC_LESS_EQUALS: return variable <= value;
01569 case OCC_MORE_THAN: return variable > value;
01570 case OCC_MORE_EQUALS: return variable >= value;
01571 case OCC_IS_TRUE: return variable != 0;
01572 case OCC_IS_FALSE: return variable == 0;
01573 default: NOT_REACHED();
01574 }
01575 }
01576
01583 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
01584 {
01585 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
01586
01587 bool skip_order = false;
01588 OrderConditionComparator occ = order->GetConditionComparator();
01589 uint16 value = order->GetConditionValue();
01590
01591 switch (order->GetConditionVariable()) {
01592 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
01593 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
01594 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
01595 case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
01596 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
01597 case OCV_UNCONDITIONALLY: skip_order = true; break;
01598 default: NOT_REACHED();
01599 }
01600
01601 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
01602 }
01603
01610 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
01611 {
01612 if (conditional_depth > v->GetNumOrders()) return false;
01613
01614 switch (order->GetType()) {
01615 case OT_GOTO_STATION:
01616 v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
01617 return true;
01618
01619 case OT_GOTO_DEPOT:
01620 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
01621 UpdateVehicleTimetable(v, true);
01622 v->IncrementOrderIndex();
01623 break;
01624 }
01625
01626 if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
01627
01628 TileIndex location;
01629 DestinationID destination;
01630 bool reverse;
01631
01632 if (v->FindClosestDepot(&location, &destination, &reverse)) {
01633 v->dest_tile = location;
01634 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());
01635
01636
01637 if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01638
01639 if (v->type == VEH_AIRCRAFT) {
01640 Aircraft *a = Aircraft::From(v);
01641 if (a->state == FLYING && a->targetairport != destination) {
01642
01643 extern void AircraftNextAirportPos_and_Order(Aircraft *a);
01644 AircraftNextAirportPos_and_Order(a);
01645 }
01646 }
01647 return true;
01648 }
01649
01650 UpdateVehicleTimetable(v, true);
01651 v->IncrementOrderIndex();
01652 } else {
01653 if (v->type != VEH_AIRCRAFT) {
01654 v->dest_tile = Depot::Get(order->GetDestination())->xy;
01655 }
01656 return true;
01657 }
01658 break;
01659
01660 case OT_GOTO_WAYPOINT:
01661 v->dest_tile = Waypoint::Get(order->GetDestination())->xy;
01662 return true;
01663
01664 case OT_CONDITIONAL: {
01665 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
01666 if (next_order != INVALID_VEH_ORDER_ID) {
01667 UpdateVehicleTimetable(v, false);
01668 v->cur_order_index = next_order;
01669 v->current_order_time += v->GetOrder(next_order)->travel_time;
01670 } else {
01671 UpdateVehicleTimetable(v, true);
01672 v->IncrementOrderIndex();
01673 }
01674 break;
01675 }
01676
01677 default:
01678 v->dest_tile = 0;
01679 return false;
01680 }
01681
01682 assert(v->cur_order_index < v->GetNumOrders());
01683
01684
01685 order = v->GetNextManualOrder(v->cur_order_index);
01686 if (order == NULL) {
01687 order = v->GetNextManualOrder(0);
01688 if (order == NULL) {
01689 v->current_order.Free();
01690 v->dest_tile = 0;
01691 return false;
01692 }
01693 }
01694 v->current_order = *order;
01695 return UpdateOrderDest(v, order, conditional_depth + 1);
01696 }
01697
01705 bool ProcessOrders(Vehicle *v)
01706 {
01707 switch (v->current_order.GetType()) {
01708 case OT_GOTO_DEPOT:
01709
01710 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
01711 break;
01712
01713 case OT_LOADING:
01714 return false;
01715
01716 case OT_LEAVESTATION:
01717 if (v->type != VEH_AIRCRAFT) return false;
01718 break;
01719
01720 default: break;
01721 }
01722
01730 bool may_reverse = v->current_order.IsType(OT_NOTHING);
01731
01732
01733 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)) &&
01734 IsTileType(v->tile, MP_STATION) &&
01735 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
01736
01737
01738
01739
01740 v->last_station_visited = v->current_order.GetDestination();
01741 UpdateVehicleTimetable(v, true);
01742 v->IncrementOrderIndex();
01743 }
01744
01745
01746 if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
01747
01748 const Order *order = v->GetNextManualOrder(v->cur_order_index);
01749
01750
01751 if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
01752 if (v->type == VEH_AIRCRAFT) {
01753
01754 extern void HandleMissingAircraftOrders(Aircraft *v);
01755 HandleMissingAircraftOrders(Aircraft::From(v));
01756 return false;
01757 }
01758
01759 v->current_order.Free();
01760 v->dest_tile = 0;
01761 return false;
01762 }
01763
01764
01765 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
01766 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
01767 return false;
01768 }
01769
01770
01771 v->current_order = *order;
01772
01773 InvalidateVehicleOrder(v, -2);
01774 switch (v->type) {
01775 default:
01776 NOT_REACHED();
01777
01778 case VEH_ROAD:
01779 case VEH_TRAIN:
01780 break;
01781
01782 case VEH_AIRCRAFT:
01783 case VEH_SHIP:
01784 SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
01785 break;
01786 }
01787
01788 return UpdateOrderDest(v, order) && may_reverse;
01789 }
01790
01798 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
01799 {
01800 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
01801
01802 return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
01803 v->last_station_visited != station &&
01804
01805 !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
01806 }
01807
01808 void InitializeOrders()
01809 {
01810 _order_pool.CleanPool();
01811 _orderlist_pool.CleanPool();
01812 }