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 return BaseStation::Get(this->GetDestination())->xy;
00433
00434 case OT_GOTO_DEPOT:
00435 if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE;
00436 return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
00437
00438 default:
00439 return INVALID_TILE;
00440 }
00441 }
00442
00443 static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0)
00444 {
00445 assert(v->type == VEH_SHIP);
00446
00447 if (cur->IsType(OT_CONDITIONAL)) {
00448 if (conditional_depth > v->GetNumOrders()) return 0;
00449
00450 conditional_depth++;
00451
00452 int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
00453 int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
00454 return max(dist1, dist2);
00455 }
00456
00457 TileIndex prev_tile = prev->GetLocation(v);
00458 TileIndex cur_tile = cur->GetLocation(v);
00459 if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
00460 return DistanceManhattan(prev_tile, cur_tile);
00461 }
00462
00476 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00477 {
00478 VehicleID veh = GB(p1, 0, 20);
00479 VehicleOrderID sel_ord = GB(p1, 20, 8);
00480 Order new_order(p2);
00481
00482 Vehicle *v = Vehicle::GetIfValid(veh);
00483 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00484
00485 CommandCost ret = CheckOwnership(v->owner);
00486 if (ret.Failed()) return ret;
00487
00488
00489
00490 switch (new_order.GetType()) {
00491 case OT_GOTO_STATION: {
00492 const Station *st = Station::GetIfValid(new_order.GetDestination());
00493 if (st == NULL) return CMD_ERROR;
00494
00495 if (st->owner != OWNER_NONE) {
00496 CommandCost ret = CheckOwnership(st->owner);
00497 if (ret.Failed()) return ret;
00498 }
00499
00500 if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00501 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
00502 if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
00503 }
00504
00505
00506 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
00507
00508
00509 if ((new_order.GetLoadType() & OLFB_NO_LOAD) && (new_order.GetUnloadType() & OUFB_NO_UNLOAD)) return CMD_ERROR;
00510
00511
00512 switch (new_order.GetLoadType()) {
00513 case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
00514 default: return CMD_ERROR;
00515 }
00516 switch (new_order.GetUnloadType()) {
00517 case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
00518 default: return CMD_ERROR;
00519 }
00520
00521
00522 switch (new_order.GetStopLocation()) {
00523 case OSL_PLATFORM_NEAR_END:
00524 case OSL_PLATFORM_MIDDLE:
00525 if (v->type != VEH_TRAIN) return CMD_ERROR;
00526
00527 case OSL_PLATFORM_FAR_END:
00528 break;
00529
00530 default:
00531 return CMD_ERROR;
00532 }
00533
00534 break;
00535 }
00536
00537 case OT_GOTO_DEPOT: {
00538 if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
00539 if (v->type == VEH_AIRCRAFT) {
00540 const Station *st = Station::GetIfValid(new_order.GetDestination());
00541
00542 if (st == NULL) return CMD_ERROR;
00543
00544 CommandCost ret = CheckOwnership(st->owner);
00545 if (ret.Failed()) return ret;
00546
00547 if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
00548 return CMD_ERROR;
00549 }
00550 } else {
00551 const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
00552
00553 if (dp == NULL) return CMD_ERROR;
00554
00555 CommandCost ret = CheckOwnership(GetTileOwner(dp->xy));
00556 if (ret.Failed()) return ret;
00557
00558 switch (v->type) {
00559 case VEH_TRAIN:
00560 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
00561 break;
00562
00563 case VEH_ROAD:
00564 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
00565 break;
00566
00567 case VEH_SHIP:
00568 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
00569 break;
00570
00571 default: return CMD_ERROR;
00572 }
00573 }
00574 }
00575
00576 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
00577 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
00578 if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
00579 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
00580 break;
00581 }
00582
00583 case OT_GOTO_WAYPOINT: {
00584 const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
00585 if (wp == NULL) return CMD_ERROR;
00586
00587 switch (v->type) {
00588 default: return CMD_ERROR;
00589
00590 case VEH_TRAIN: {
00591 if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00592
00593 CommandCost ret = CheckOwnership(wp->owner);
00594 if (ret.Failed()) return ret;
00595 break;
00596 }
00597
00598 case VEH_SHIP:
00599 if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
00600 if (wp->owner != OWNER_NONE) {
00601 CommandCost ret = CheckOwnership(wp->owner);
00602 if (ret.Failed()) return ret;
00603 }
00604 break;
00605 }
00606
00607
00608
00609
00610 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
00611 break;
00612 }
00613
00614 case OT_CONDITIONAL: {
00615 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
00616 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR;
00617 if (new_order.GetConditionVariable() > OCV_END) return CMD_ERROR;
00618
00619 OrderConditionComparator occ = new_order.GetConditionComparator();
00620 if (occ > OCC_END) return CMD_ERROR;
00621 switch (new_order.GetConditionVariable()) {
00622 case OCV_REQUIRES_SERVICE:
00623 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
00624 break;
00625
00626 case OCV_UNCONDITIONALLY:
00627 if (occ != OCC_EQUALS) return CMD_ERROR;
00628 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
00629 break;
00630
00631 case OCV_LOAD_PERCENTAGE:
00632 case OCV_RELIABILITY:
00633 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
00634
00635 default:
00636 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
00637 break;
00638 }
00639 break;
00640 }
00641
00642 default: return CMD_ERROR;
00643 }
00644
00645 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
00646
00647 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS);
00648 if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00649 if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
00650
00651 if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) {
00652
00653 const Order *prev = NULL;
00654 uint n = 0;
00655
00656
00657
00658
00659 const Order *o;
00660 FOR_VEHICLE_ORDERS(v, o) {
00661 switch (o->GetType()) {
00662 case OT_GOTO_STATION:
00663 case OT_GOTO_DEPOT:
00664 case OT_GOTO_WAYPOINT:
00665 prev = o;
00666 break;
00667
00668 default: break;
00669 }
00670 if (++n == sel_ord && prev != NULL) break;
00671 }
00672 if (prev != NULL) {
00673 uint dist = GetOrderDistance(prev, &new_order, v);
00674 if (dist >= 130) {
00675 return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION);
00676 }
00677 }
00678 }
00679
00680 if (flags & DC_EXEC) {
00681 Order *new_o = new Order();
00682 new_o->AssignOrder(new_order);
00683 InsertOrder(v, new_o, sel_ord);
00684 }
00685
00686 return CommandCost();
00687 }
00688
00695 void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
00696 {
00697
00698 if (v->orders.list == NULL) {
00699 v->orders.list = new OrderList(new_o, v);
00700 } else {
00701 v->orders.list->InsertOrderAt(new_o, sel_ord);
00702 }
00703
00704 Vehicle *u = v->FirstShared();
00705 DeleteOrderWarnings(u);
00706 for (; u != NULL; u = u->NextShared()) {
00707 assert(v->orders.list == u->orders.list);
00708
00709
00710
00711 if (sel_ord <= u->cur_order_index) {
00712 uint cur = u->cur_order_index + 1;
00713
00714 if (cur < u->GetNumOrders()) {
00715 u->cur_order_index = cur;
00716 }
00717 }
00718
00719 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
00720 }
00721
00722
00723 VehicleOrderID cur_order_id = 0;
00724 Order *order;
00725 FOR_VEHICLE_ORDERS(v, order) {
00726 if (order->IsType(OT_CONDITIONAL)) {
00727 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00728 if (order_id >= sel_ord) {
00729 order->SetConditionSkipToOrder(order_id + 1);
00730 }
00731 if (order_id == cur_order_id) {
00732 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00733 }
00734 }
00735 cur_order_id++;
00736 }
00737
00738
00739 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00740 }
00741
00747 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
00748 {
00749 if (flags & DC_EXEC) {
00750 DeleteVehicleOrders(dst);
00751 InvalidateVehicleOrder(dst, -1);
00752 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
00753 }
00754 return CommandCost();
00755 }
00756
00766 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00767 {
00768 VehicleID veh_id = GB(p1, 0, 20);
00769 VehicleOrderID sel_ord = GB(p2, 0, 8);
00770
00771 Vehicle *v = Vehicle::GetIfValid(veh_id);
00772
00773 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00774
00775 CommandCost ret = CheckOwnership(v->owner);
00776 if (ret.Failed()) return ret;
00777
00778
00779 if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
00780
00781 if (v->GetOrder(sel_ord) == NULL) return CMD_ERROR;
00782
00783 if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
00784 return CommandCost();
00785 }
00786
00792 void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
00793 {
00794 v->orders.list->DeleteOrderAt(sel_ord);
00795
00796 Vehicle *u = v->FirstShared();
00797 DeleteOrderWarnings(u);
00798 for (; u != NULL; u = u->NextShared()) {
00799 if (sel_ord < u->cur_order_index) u->cur_order_index--;
00800
00801 assert(v->orders.list == u->orders.list);
00802
00803
00804
00805 if (sel_ord == u->cur_order_index && u->current_order.IsType(OT_LOADING)) {
00806 u->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
00807
00808
00809 if (u->current_order.GetLoadType() & OLFB_FULL_LOAD) u->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE);
00810 }
00811
00812
00813 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
00814 }
00815
00816
00817 VehicleOrderID cur_order_id = 0;
00818 Order *order = NULL;
00819 FOR_VEHICLE_ORDERS(v, order) {
00820 if (order->IsType(OT_CONDITIONAL)) {
00821 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00822 if (order_id >= sel_ord) {
00823 order->SetConditionSkipToOrder(max(order_id - 1, 0));
00824 }
00825 if (order_id == cur_order_id) {
00826 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00827 }
00828 }
00829 cur_order_id++;
00830 }
00831
00832 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00833 }
00834
00844 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00845 {
00846 VehicleID veh_id = GB(p1, 0, 20);
00847 VehicleOrderID sel_ord = GB(p2, 0, 8);
00848
00849 Vehicle *v = Vehicle::GetIfValid(veh_id);
00850
00851 if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
00852
00853 CommandCost ret = CheckOwnership(v->owner);
00854 if (ret.Failed()) return ret;
00855
00856 if (flags & DC_EXEC) {
00857 v->cur_order_index = sel_ord;
00858
00859 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
00860
00861 InvalidateVehicleOrder(v, -2);
00862 }
00863
00864
00865 if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
00866 if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
00867
00868 return CommandCost();
00869 }
00870
00884 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00885 {
00886 VehicleID veh = GB(p1, 0, 20);
00887 VehicleOrderID moving_order = GB(p2, 0, 16);
00888 VehicleOrderID target_order = GB(p2, 16, 16);
00889
00890 Vehicle *v = Vehicle::GetIfValid(veh);
00891 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00892
00893 CommandCost ret = CheckOwnership(v->owner);
00894 if (ret.Failed()) return ret;
00895
00896
00897 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
00898 moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
00899
00900 Order *moving_one = v->GetOrder(moving_order);
00901
00902 if (moving_one == NULL) return CMD_ERROR;
00903
00904 if (flags & DC_EXEC) {
00905 v->orders.list->MoveOrder(moving_order, target_order);
00906
00907
00908 Vehicle *u = v->FirstShared();
00909
00910 DeleteOrderWarnings(u);
00911
00912 for (; u != NULL; u = u->NextShared()) {
00913
00914 if (u->cur_order_index == moving_order) {
00915 u->cur_order_index = target_order;
00916 } else if (u->cur_order_index > moving_order && u->cur_order_index <= target_order) {
00917 u->cur_order_index--;
00918 } else if (u->cur_order_index < moving_order && u->cur_order_index >= target_order) {
00919 u->cur_order_index++;
00920 }
00921
00922 assert(v->orders.list == u->orders.list);
00923
00924 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
00925 }
00926
00927
00928 Order *order;
00929 FOR_VEHICLE_ORDERS(v, order) {
00930 if (order->IsType(OT_CONDITIONAL)) {
00931 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00932 if (order_id == moving_order) {
00933 order_id = target_order;
00934 } else if (order_id > moving_order && order_id <= target_order) {
00935 order_id--;
00936 } else if (order_id < moving_order && order_id >= target_order) {
00937 order_id++;
00938 }
00939 order->SetConditionSkipToOrder(order_id);
00940 }
00941 }
00942
00943
00944 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00945 }
00946
00947 return CommandCost();
00948 }
00949
00965 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00966 {
00967 VehicleOrderID sel_ord = GB(p1, 20, 8);
00968 VehicleID veh = GB(p1, 0, 20);
00969 ModifyOrderFlags mof = Extract<ModifyOrderFlags, 0, 4>(p2);
00970 uint16 data = GB(p2, 4, 11);
00971
00972 if (mof >= MOF_END) return CMD_ERROR;
00973
00974 Vehicle *v = Vehicle::GetIfValid(veh);
00975 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
00976
00977 CommandCost ret = CheckOwnership(v->owner);
00978 if (ret.Failed()) return ret;
00979
00980
00981 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
00982
00983 Order *order = v->GetOrder(sel_ord);
00984 switch (order->GetType()) {
00985 case OT_GOTO_STATION:
00986 if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE) return CMD_ERROR;
00987 break;
00988
00989 case OT_GOTO_DEPOT:
00990 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
00991 break;
00992
00993 case OT_GOTO_WAYPOINT:
00994 if (mof != MOF_NON_STOP) return CMD_ERROR;
00995 break;
00996
00997 case OT_CONDITIONAL:
00998 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
00999 break;
01000
01001 default:
01002 return CMD_ERROR;
01003 }
01004
01005 switch (mof) {
01006 default: NOT_REACHED();
01007
01008 case MOF_NON_STOP:
01009 if (!v->IsGroundVehicle()) return CMD_ERROR;
01010 if (data >= ONSF_END) return CMD_ERROR;
01011 if (data == order->GetNonStopType()) return CMD_ERROR;
01012 break;
01013
01014 case MOF_STOP_LOCATION:
01015 if (v->type != VEH_TRAIN) return CMD_ERROR;
01016 if (data >= OSL_END) return CMD_ERROR;
01017 break;
01018
01019 case MOF_UNLOAD:
01020 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
01021
01022 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
01023 if (data == order->GetUnloadType()) return CMD_ERROR;
01024 break;
01025
01026 case MOF_LOAD:
01027 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
01028 if (data == order->GetLoadType()) return CMD_ERROR;
01029 break;
01030
01031 case MOF_DEPOT_ACTION:
01032 if (data >= DA_END) return CMD_ERROR;
01033 break;
01034
01035 case MOF_COND_VARIABLE:
01036 if (data >= OCV_END) return CMD_ERROR;
01037 break;
01038
01039 case MOF_COND_COMPARATOR:
01040 if (data >= OCC_END) return CMD_ERROR;
01041 switch (order->GetConditionVariable()) {
01042 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01043
01044 case OCV_REQUIRES_SERVICE:
01045 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
01046 break;
01047
01048 default:
01049 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
01050 break;
01051 }
01052 break;
01053
01054 case MOF_COND_VALUE:
01055 switch (order->GetConditionVariable()) {
01056 case OCV_UNCONDITIONALLY: return CMD_ERROR;
01057
01058 case OCV_LOAD_PERCENTAGE:
01059 case OCV_RELIABILITY:
01060 if (data > 100) return CMD_ERROR;
01061 break;
01062
01063 default:
01064 if (data > 2047) return CMD_ERROR;
01065 break;
01066 }
01067 break;
01068
01069 case MOF_COND_DESTINATION:
01070 if (data >= v->GetNumOrders()) return CMD_ERROR;
01071 break;
01072 }
01073
01074 if (flags & DC_EXEC) {
01075 switch (mof) {
01076 case MOF_NON_STOP:
01077 order->SetNonStopType((OrderNonStopFlags)data);
01078 break;
01079
01080 case MOF_STOP_LOCATION:
01081 order->SetStopLocation((OrderStopLocation)data);
01082 break;
01083
01084 case MOF_UNLOAD:
01085 order->SetUnloadType((OrderUnloadFlags)data);
01086 if ((data & OUFB_NO_UNLOAD) != 0 && (order->GetLoadType() & OLFB_NO_LOAD) != 0) {
01087 order->SetLoadType((OrderLoadFlags)(order->GetLoadType() & ~OLFB_NO_LOAD));
01088 }
01089 break;
01090
01091 case MOF_LOAD:
01092 order->SetLoadType((OrderLoadFlags)data);
01093 if ((data & OLFB_NO_LOAD) != 0 && (order->GetUnloadType() & OUFB_NO_UNLOAD) != 0) {
01094
01095 order->SetUnloadType((OrderUnloadFlags)(order->GetUnloadType() & ~OUFB_NO_UNLOAD));
01096 }
01097 break;
01098
01099 case MOF_DEPOT_ACTION: {
01100 switch (data) {
01101 case DA_ALWAYS_GO:
01102 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01103 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01104 break;
01105
01106 case DA_SERVICE:
01107 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
01108 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
01109 break;
01110
01111 case DA_STOP:
01112 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
01113 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
01114 break;
01115
01116 default:
01117 NOT_REACHED();
01118 }
01119 break;
01120 }
01121
01122 case MOF_COND_VARIABLE: {
01123 order->SetConditionVariable((OrderConditionVariable)data);
01124
01125 OrderConditionComparator occ = order->GetConditionComparator();
01126 switch (order->GetConditionVariable()) {
01127 case OCV_UNCONDITIONALLY:
01128 order->SetConditionComparator(OCC_EQUALS);
01129 order->SetConditionValue(0);
01130 break;
01131
01132 case OCV_REQUIRES_SERVICE:
01133 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
01134 break;
01135
01136 case OCV_LOAD_PERCENTAGE:
01137 case OCV_RELIABILITY:
01138 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
01139
01140 default:
01141 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
01142 break;
01143 }
01144 break;
01145 }
01146
01147 case MOF_COND_COMPARATOR:
01148 order->SetConditionComparator((OrderConditionComparator)data);
01149 break;
01150
01151 case MOF_COND_VALUE:
01152 order->SetConditionValue(data);
01153 break;
01154
01155 case MOF_COND_DESTINATION:
01156 order->SetConditionSkipToOrder(data);
01157 break;
01158
01159 default: NOT_REACHED();
01160 }
01161
01162
01163 Vehicle *u = v->FirstShared();
01164 DeleteOrderWarnings(u);
01165 for (; u != NULL; u = u->NextShared()) {
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175 if (sel_ord == u->cur_order_index &&
01176 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
01177 u->current_order.GetLoadType() != order->GetLoadType()) {
01178 u->current_order.SetLoadType(order->GetLoadType());
01179 }
01180 InvalidateVehicleOrder(u, -2);
01181 }
01182 }
01183
01184 return CommandCost();
01185 }
01186
01198 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01199 {
01200 VehicleID veh_src = GB(p2, 0, 20);
01201 VehicleID veh_dst = GB(p1, 0, 20);
01202
01203 Vehicle *dst = Vehicle::GetIfValid(veh_dst);
01204 if (dst == NULL || !dst->IsPrimaryVehicle()) return CMD_ERROR;
01205
01206 CommandCost ret = CheckOwnership(dst->owner);
01207 if (ret.Failed()) return ret;
01208
01209 switch (GB(p1, 30, 2)) {
01210 case CO_SHARE: {
01211 Vehicle *src = Vehicle::GetIfValid(veh_src);
01212
01213
01214 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01215
01216 CommandCost ret = CheckOwnership(src->owner);
01217 if (ret.Failed()) return ret;
01218
01219
01220 if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) {
01221 return CMD_ERROR;
01222 }
01223
01224
01225 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
01226
01227 const Order *order;
01228
01229 FOR_VEHICLE_ORDERS(src, order) {
01230 if (OrderGoesToStation(dst, order) &&
01231 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01232 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01233 }
01234 }
01235
01236 if (flags & DC_EXEC) {
01237
01238 DeleteVehicleOrders(dst);
01239
01240 dst->orders.list = src->orders.list;
01241
01242
01243 dst->AddToShared(src);
01244
01245 InvalidateVehicleOrder(dst, -1);
01246 InvalidateVehicleOrder(src, -2);
01247
01248 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01249 }
01250 break;
01251 }
01252
01253 case CO_COPY: {
01254 Vehicle *src = Vehicle::GetIfValid(veh_src);
01255
01256
01257 if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR;
01258
01259 CommandCost ret = CheckOwnership(src->owner);
01260 if (ret.Failed()) return ret;
01261
01262
01263
01264 const Order *order;
01265 FOR_VEHICLE_ORDERS(src, order) {
01266 if (OrderGoesToStation(dst, order) &&
01267 !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) {
01268 return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER);
01269 }
01270 }
01271
01272
01273 int delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
01274 if (!Order::CanAllocateItem(delta) ||
01275 ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
01276 return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
01277 }
01278
01279 if (flags & DC_EXEC) {
01280 const Order *order;
01281 Order *first = NULL;
01282 Order **order_dst;
01283
01284
01285 DeleteVehicleOrders(dst, true);
01286
01287 order_dst = &first;
01288 FOR_VEHICLE_ORDERS(src, order) {
01289 *order_dst = new Order();
01290 (*order_dst)->AssignOrder(*order);
01291 order_dst = &(*order_dst)->next;
01292 }
01293 if (dst->orders.list == NULL) {
01294 dst->orders.list = new OrderList(first, dst);
01295 } else {
01296 assert(dst->orders.list->GetFirstOrder() == NULL);
01297 assert(!dst->orders.list->IsShared());
01298 delete dst->orders.list;
01299 dst->orders.list = new OrderList(first, dst);
01300 }
01301
01302 InvalidateVehicleOrder(dst, -1);
01303
01304 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01305 }
01306 break;
01307 }
01308
01309 case CO_UNSHARE: return DecloneOrder(dst, flags);
01310 default: return CMD_ERROR;
01311 }
01312
01313 return CommandCost();
01314 }
01315
01328 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01329 {
01330 VehicleID veh = GB(p1, 0, 20);
01331 VehicleOrderID order_number = GB(p2, 16, 8);
01332 CargoID cargo = GB(p2, 0, 8);
01333 byte subtype = GB(p2, 8, 8);
01334
01335 if (cargo >= NUM_CARGO) return CMD_ERROR;
01336
01337 const Vehicle *v = Vehicle::GetIfValid(veh);
01338 if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
01339
01340 CommandCost ret = CheckOwnership(v->owner);
01341 if (ret.Failed()) return ret;
01342
01343 Order *order = v->GetOrder(order_number);
01344 if (order == NULL) return CMD_ERROR;
01345
01346 if (flags & DC_EXEC) {
01347 order->SetRefit(cargo, subtype);
01348
01349 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
01350
01351 InvalidateVehicleOrder(u, -2);
01352
01353
01354 if (u->cur_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
01355 u->current_order.SetRefit(cargo, subtype);
01356 }
01357 }
01358 }
01359
01360 return CommandCost();
01361 }
01362
01363
01369 void CheckOrders(const Vehicle *v)
01370 {
01371
01372 if (_settings_client.gui.order_review_system == 0) return;
01373
01374
01375 if (v->vehstatus & VS_CRASHED) return;
01376
01377
01378 if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return;
01379
01380
01381 if (v->FirstShared() != v) return;
01382
01383
01384 if (v->owner == _local_company && v->day_counter % 20 == 0) {
01385 int n_st, problem_type = -1;
01386 const Order *order;
01387 int message = 0;
01388
01389
01390 n_st = 0;
01391
01392 FOR_VEHICLE_ORDERS(v, order) {
01393
01394 if (order->IsType(OT_DUMMY)) {
01395 problem_type = 1;
01396 break;
01397 }
01398
01399 if (order->IsType(OT_GOTO_STATION)) {
01400 const Station *st = Station::Get(order->GetDestination());
01401
01402 n_st++;
01403 if (!CanVehicleUseStation(v, st)) problem_type = 3;
01404 }
01405 }
01406
01407
01408 if (v->GetNumOrders() > 1) {
01409 const Order *last = v->GetLastOrder();
01410
01411 if (v->orders.list->GetFirstOrder()->Equals(*last)) {
01412 problem_type = 2;
01413 }
01414 }
01415
01416
01417 if (n_st < 2 && problem_type == -1) problem_type = 0;
01418
01419 #ifndef NDEBUG
01420 if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
01421 #endif
01422
01423
01424 if (problem_type < 0) return;
01425
01426 message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
01427
01428
01429 SetDParam(0, v->index);
01430 AddVehicleNewsItem(
01431 message,
01432 NS_ADVICE,
01433 v->index
01434 );
01435 }
01436 }
01437
01443 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01444 {
01445 Vehicle *v;
01446
01447
01448
01449
01450
01451
01452 FOR_ALL_VEHICLES(v) {
01453 Order *order;
01454
01455 order = &v->current_order;
01456 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01457 v->current_order.GetDestination() == destination) {
01458 order->MakeDummy();
01459 SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01460 }
01461
01462
01463 int id = -1;
01464 FOR_VEHICLE_ORDERS(v, order) {
01465 id++;
01466
01467 OrderType ot = order->GetType();
01468 if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
01469 if (ot == OT_AUTOMATIC || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
01470 if (ot == type && order->GetDestination() == destination) {
01471
01472
01473
01474 if (order->IsType(OT_AUTOMATIC)) {
01475 DeleteOrder(v, id);
01476 id--;
01477 continue;
01478 }
01479
01480 order->MakeDummy();
01481 for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
01482
01483 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
01484 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
01485 }
01486 }
01487 }
01488 }
01489 }
01490
01495 bool Vehicle::HasDepotOrder() const
01496 {
01497 const Order *order;
01498
01499 FOR_VEHICLE_ORDERS(this, order) {
01500 if (order->IsType(OT_GOTO_DEPOT)) return true;
01501 }
01502
01503 return false;
01504 }
01505
01511 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist)
01512 {
01513 DeleteOrderWarnings(v);
01514
01515 if (v->IsOrderListShared()) {
01516
01517 v->RemoveFromShared();
01518 v->orders.list = NULL;
01519 } else if (v->orders.list != NULL) {
01520
01521 v->orders.list->FreeChain(keep_orderlist);
01522 if (!keep_orderlist) v->orders.list = NULL;
01523 }
01524 }
01525
01526 uint16 GetServiceIntervalClamped(uint interval, CompanyID company_id)
01527 {
01528 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);
01529 }
01530
01539 static bool CheckForValidOrders(const Vehicle *v)
01540 {
01541 const Order *order;
01542
01543 FOR_VEHICLE_ORDERS(v, order) {
01544 switch (order->GetType()) {
01545 case OT_GOTO_STATION:
01546 case OT_GOTO_DEPOT:
01547 case OT_GOTO_WAYPOINT:
01548 return true;
01549
01550 default:
01551 break;
01552 }
01553 }
01554
01555 return false;
01556 }
01557
01561 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
01562 {
01563 switch (occ) {
01564 case OCC_EQUALS: return variable == value;
01565 case OCC_NOT_EQUALS: return variable != value;
01566 case OCC_LESS_THAN: return variable < value;
01567 case OCC_LESS_EQUALS: return variable <= value;
01568 case OCC_MORE_THAN: return variable > value;
01569 case OCC_MORE_EQUALS: return variable >= value;
01570 case OCC_IS_TRUE: return variable != 0;
01571 case OCC_IS_FALSE: return variable == 0;
01572 default: NOT_REACHED();
01573 }
01574 }
01575
01582 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
01583 {
01584 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
01585
01586 bool skip_order = false;
01587 OrderConditionComparator occ = order->GetConditionComparator();
01588 uint16 value = order->GetConditionValue();
01589
01590 switch (order->GetConditionVariable()) {
01591 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
01592 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break;
01593 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
01594 case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
01595 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
01596 case OCV_UNCONDITIONALLY: skip_order = true; break;
01597 default: NOT_REACHED();
01598 }
01599
01600 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
01601 }
01602
01609 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
01610 {
01611 if (conditional_depth > v->GetNumOrders()) return false;
01612
01613 switch (order->GetType()) {
01614 case OT_GOTO_STATION:
01615 v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
01616 return true;
01617
01618 case OT_GOTO_DEPOT:
01619 if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
01620 UpdateVehicleTimetable(v, true);
01621 v->IncrementOrderIndex();
01622 break;
01623 }
01624
01625 if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
01626
01627 TileIndex location;
01628 DestinationID destination;
01629 bool reverse;
01630
01631 if (v->FindClosestDepot(&location, &destination, &reverse)) {
01632 v->dest_tile = location;
01633 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());
01634
01635
01636 if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01637
01638 if (v->type == VEH_AIRCRAFT) {
01639 Aircraft *a = Aircraft::From(v);
01640 if (a->state == FLYING && a->targetairport != destination) {
01641
01642 extern void AircraftNextAirportPos_and_Order(Aircraft *a);
01643 AircraftNextAirportPos_and_Order(a);
01644 }
01645 }
01646 return true;
01647 }
01648
01649 UpdateVehicleTimetable(v, true);
01650 v->IncrementOrderIndex();
01651 } else {
01652 if (v->type != VEH_AIRCRAFT) {
01653 v->dest_tile = Depot::Get(order->GetDestination())->xy;
01654 }
01655 return true;
01656 }
01657 break;
01658
01659 case OT_GOTO_WAYPOINT:
01660 v->dest_tile = Waypoint::Get(order->GetDestination())->xy;
01661 return true;
01662
01663 case OT_CONDITIONAL: {
01664 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
01665 if (next_order != INVALID_VEH_ORDER_ID) {
01666 UpdateVehicleTimetable(v, false);
01667 v->cur_order_index = next_order;
01668 v->current_order_time += v->GetOrder(next_order)->travel_time;
01669 } else {
01670 UpdateVehicleTimetable(v, true);
01671 v->IncrementOrderIndex();
01672 }
01673 break;
01674 }
01675
01676 default:
01677 v->dest_tile = 0;
01678 return false;
01679 }
01680
01681 assert(v->cur_order_index < v->GetNumOrders());
01682
01683
01684 order = v->GetNextManualOrder(v->cur_order_index);
01685 if (order == NULL) {
01686 order = v->GetNextManualOrder(0);
01687 if (order == NULL) {
01688 v->current_order.Free();
01689 v->dest_tile = 0;
01690 return false;
01691 }
01692 }
01693 v->current_order = *order;
01694 return UpdateOrderDest(v, order, conditional_depth + 1);
01695 }
01696
01704 bool ProcessOrders(Vehicle *v)
01705 {
01706 switch (v->current_order.GetType()) {
01707 case OT_GOTO_DEPOT:
01708
01709 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
01710 break;
01711
01712 case OT_LOADING:
01713 return false;
01714
01715 case OT_LEAVESTATION:
01716 if (v->type != VEH_AIRCRAFT) return false;
01717 break;
01718
01719 default: break;
01720 }
01721
01729 bool may_reverse = v->current_order.IsType(OT_NOTHING);
01730
01731
01732 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)) &&
01733 IsTileType(v->tile, MP_STATION) &&
01734 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
01735
01736
01737
01738
01739 v->last_station_visited = v->current_order.GetDestination();
01740 UpdateVehicleTimetable(v, true);
01741 v->IncrementOrderIndex();
01742 }
01743
01744
01745 if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
01746
01747 const Order *order = v->GetNextManualOrder(v->cur_order_index);
01748
01749
01750 if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
01751 if (v->type == VEH_AIRCRAFT) {
01752
01753 extern void HandleMissingAircraftOrders(Aircraft *v);
01754 HandleMissingAircraftOrders(Aircraft::From(v));
01755 return false;
01756 }
01757
01758 v->current_order.Free();
01759 v->dest_tile = 0;
01760 return false;
01761 }
01762
01763
01764 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
01765 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) {
01766 return false;
01767 }
01768
01769
01770 v->current_order = *order;
01771
01772 InvalidateVehicleOrder(v, -2);
01773 switch (v->type) {
01774 default:
01775 NOT_REACHED();
01776
01777 case VEH_ROAD:
01778 case VEH_TRAIN:
01779 break;
01780
01781 case VEH_AIRCRAFT:
01782 case VEH_SHIP:
01783 SetWindowClassesDirty(GetWindowClassForVehicleType(v->type));
01784 break;
01785 }
01786
01787 return UpdateOrderDest(v, order) && may_reverse;
01788 }
01789
01797 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
01798 {
01799 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
01800
01801 return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
01802 v->last_station_visited != station &&
01803
01804 !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
01805 }
01806
01807 void InitializeOrders()
01808 {
01809 _order_pool.CleanPool();
01810 _orderlist_pool.CleanPool();
01811 }