00001
00002
00005 #include "stdafx.h"
00006 #include "debug.h"
00007 #include "command_func.h"
00008 #include "company_func.h"
00009 #include "news_func.h"
00010 #include "vehicle_gui.h"
00011 #include "cargotype.h"
00012 #include "station_map.h"
00013 #include "vehicle_base.h"
00014 #include "strings_func.h"
00015 #include "functions.h"
00016 #include "window_func.h"
00017 #include "newgrf_cargo.h"
00018 #include "timetable.h"
00019 #include "vehicle_func.h"
00020 #include "oldpool_func.h"
00021 #include "depot_base.h"
00022 #include "settings_type.h"
00023
00024 #include "table/strings.h"
00025
00026
00027
00028
00029 assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
00030 assert_compile(sizeof(DestinationID) >= sizeof(WaypointID));
00031 assert_compile(sizeof(DestinationID) >= sizeof(StationID));
00032
00033 TileIndex _backup_orders_tile;
00034 BackuppedOrders _backup_orders_data;
00035
00036 DEFINE_OLD_POOL_GENERIC(Order, Order);
00037 DEFINE_OLD_POOL_GENERIC(OrderList, OrderList);
00038
00039 void Order::Free()
00040 {
00041 this->type = OT_NOTHING;
00042 this->flags = 0;
00043 this->dest = 0;
00044 this->next = NULL;
00045 }
00046
00047 void Order::MakeGoToStation(StationID destination)
00048 {
00049 this->type = OT_GOTO_STATION;
00050 this->flags = 0;
00051 this->dest = destination;
00052 }
00053
00054 void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoID cargo, byte subtype)
00055 {
00056 this->type = OT_GOTO_DEPOT;
00057 this->SetDepotOrderType(order);
00058 this->SetDepotActionType(action);
00059 this->SetNonStopType(non_stop_type);
00060 this->dest = destination;
00061 this->SetRefit(cargo, subtype);
00062 }
00063
00064 void Order::MakeGoToWaypoint(WaypointID destination)
00065 {
00066 this->type = OT_GOTO_WAYPOINT;
00067 this->flags = 0;
00068 this->dest = destination;
00069 }
00070
00071 void Order::MakeLoading(bool ordered)
00072 {
00073 this->type = OT_LOADING;
00074 if (!ordered) this->flags = 0;
00075 }
00076
00077 void Order::MakeLeaveStation()
00078 {
00079 this->type = OT_LEAVESTATION;
00080 this->flags = 0;
00081 }
00082
00083 void Order::MakeDummy()
00084 {
00085 this->type = OT_DUMMY;
00086 this->flags = 0;
00087 }
00088
00089 void Order::MakeConditional(VehicleOrderID order)
00090 {
00091 this->type = OT_CONDITIONAL;
00092 this->flags = order;
00093 this->dest = 0;
00094 }
00095
00096 void Order::SetRefit(CargoID cargo, byte subtype)
00097 {
00098 this->refit_cargo = cargo;
00099 this->refit_subtype = subtype;
00100 }
00101
00102 bool Order::Equals(const Order &other) const
00103 {
00104
00105
00106
00107
00108
00109 if ((this->type == OT_GOTO_DEPOT && this->type == other.type) &&
00110 ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 ||
00111 (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) {
00112 return
00113 this->GetDepotOrderType() == other.GetDepotOrderType() &&
00114 (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT);
00115 }
00116
00117 return
00118 this->type == other.type &&
00119 this->flags == other.flags &&
00120 this->dest == other.dest;
00121 }
00122
00123 uint32 Order::Pack() const
00124 {
00125 return this->dest << 16 | this->flags << 8 | this->type;
00126 }
00127
00128 Order::Order(uint32 packed)
00129 {
00130 this->type = (OrderType)GB(packed, 0, 8);
00131 this->flags = GB(packed, 8, 8);
00132 this->dest = GB(packed, 16, 16);
00133 this->next = NULL;
00134 this->refit_cargo = CT_NO_REFIT;
00135 this->refit_subtype = 0;
00136 this->wait_time = 0;
00137 this->travel_time = 0;
00138 }
00139
00145 void InvalidateVehicleOrder(const Vehicle *v, int data)
00146 {
00147 InvalidateWindow(WC_VEHICLE_VIEW, v->index);
00148
00149 if (data != 0) {
00150
00151 InvalidateWindowData(WC_VEHICLE_ORDERS, v->index, data);
00152 InvalidateWindowData(WC_VEHICLE_TIMETABLE, v->index, data);
00153 return;
00154 }
00155
00156 InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
00157 InvalidateWindow(WC_VEHICLE_TIMETABLE, v->index);
00158 }
00159
00166 void Order::AssignOrder(const Order &other)
00167 {
00168 this->type = other.type;
00169 this->flags = other.flags;
00170 this->dest = other.dest;
00171
00172 this->refit_cargo = other.refit_cargo;
00173 this->refit_subtype = other.refit_subtype;
00174
00175 this->wait_time = other.wait_time;
00176 this->travel_time = other.travel_time;
00177 }
00178
00179
00180 OrderList::OrderList(Order *chain, Vehicle *v) :
00181 first(chain), num_orders(0), num_vehicles(1), first_shared(v),
00182 timetable_duration(0)
00183 {
00184 for (Order *o = this->first; o != NULL; o = o->next) {
00185 ++this->num_orders;
00186 this->timetable_duration += o->wait_time + o->travel_time;
00187 }
00188
00189 for (Vehicle *u = v->PreviousShared(); u != NULL; u = u->PreviousShared()) {
00190 ++this->num_vehicles;
00191 this->first_shared = u;
00192 }
00193
00194 for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles;
00195 }
00196
00197 void OrderList::FreeChain(bool keep_orderlist)
00198 {
00199 Order *next;
00200 for(Order *o = this->first; o != NULL; o = next) {
00201 next = o->next;
00202 delete o;
00203 }
00204
00205 if (keep_orderlist) {
00206 this->first = NULL;
00207 this->num_orders = 0;
00208 this->timetable_duration = 0;
00209 } else {
00210 delete this;
00211 }
00212 }
00213
00214 Order *OrderList::GetOrderAt(int index) const
00215 {
00216 if (index < 0) return NULL;
00217
00218 Order *order = this->first;
00219
00220 while (order != NULL && index-- > 0)
00221 order = order->next;
00222
00223 return order;
00224 }
00225
00226 void OrderList::InsertOrderAt(Order *new_order, int index)
00227 {
00228 if (this->first == NULL) {
00229 this->first = new_order;
00230 } else {
00231 if (index == 0) {
00232
00233 new_order->next = this->first;
00234 this->first = new_order;
00235 } else if (index >= this->num_orders) {
00236
00237 this->GetLastOrder()->next = new_order;
00238 } else {
00239
00240 Order *order = this->GetOrderAt(index - 1);
00241 new_order->next = order->next;
00242 order->next = new_order;
00243 }
00244 }
00245 ++this->num_orders;
00246 this->timetable_duration += new_order->wait_time + new_order->travel_time;
00247 }
00248
00249
00250 void OrderList::DeleteOrderAt(int index)
00251 {
00252 if (index >= this->num_orders) return;
00253
00254 Order *to_remove;
00255
00256 if (index == 0) {
00257 to_remove = this->first;
00258 this->first = to_remove->next;
00259 } else {
00260 Order *prev = GetOrderAt(index - 1);
00261 to_remove = prev->next;
00262 prev->next = to_remove->next;
00263 }
00264 --this->num_orders;
00265 this->timetable_duration -= (to_remove->wait_time + to_remove->travel_time);
00266 delete to_remove;
00267 }
00268
00269 void OrderList::MoveOrder(int from, int to)
00270 {
00271 if (from >= this->num_orders || to >= this->num_orders || from == to) return;
00272
00273 Order *moving_one;
00274
00275
00276 if (from == 0) {
00277 moving_one = this->first;
00278 this->first = moving_one->next;
00279 } else {
00280 Order *one_before = GetOrderAt(from - 1);
00281 moving_one = one_before->next;
00282 one_before->next = moving_one->next;
00283 }
00284
00285
00286 if (to == 0) {
00287 moving_one->next = this->first;
00288 this->first = moving_one;
00289 } else {
00290 Order *one_before = GetOrderAt(to - 1);
00291 moving_one->next = one_before->next;
00292 one_before->next = moving_one;
00293 }
00294 }
00295
00296 void OrderList::RemoveVehicle(Vehicle *v)
00297 {
00298 --this->num_vehicles;
00299 if (v == this->first_shared) this->first_shared = v->NextShared();
00300 }
00301
00302 bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const
00303 {
00304 for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) {
00305 if (v_shared == v) return true;
00306 }
00307
00308 return false;
00309 }
00310
00311 int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
00312 {
00313 int count = 0;
00314 for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++;
00315 return count;
00316 }
00317
00318 bool OrderList::IsCompleteTimetable() const
00319 {
00320 for (Order *o = this->first; o != NULL; o = o->next) {
00321 if (!o->IsCompletelyTimetabled()) return false;
00322 }
00323 return true;
00324 }
00325
00326 void OrderList::DebugCheckSanity() const
00327 {
00328 VehicleOrderID check_num_orders = 0;
00329 uint check_num_vehicles = 0;
00330 uint check_timetable_duration = 0;
00331
00332 DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
00333
00334 for (const Order *o = this->first; o != NULL; o = o->next) {
00335 ++check_num_orders;
00336 check_timetable_duration += o->wait_time + o->travel_time;
00337 }
00338 assert(this->num_orders == check_num_orders);
00339 assert(this->timetable_duration == check_timetable_duration);
00340
00341 for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
00342 ++check_num_vehicles;
00343 assert(v->orders.list == this);
00344 }
00345 assert(this->num_vehicles == check_num_vehicles);
00346 DEBUG(misc, 6, "... detected %u orders, %u vehicles, %u ticks", (uint)this->num_orders,
00347 this->num_vehicles, this->timetable_duration);
00348 }
00349
00357 static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
00358 {
00359 return o->IsType(OT_GOTO_STATION) ||
00360 (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
00361 }
00362
00369 static void DeleteOrderWarnings(const Vehicle *v)
00370 {
00371 DeleteVehicleNews(v->index, STR_VEHICLE_HAS_TOO_FEW_ORDERS);
00372 DeleteVehicleNews(v->index, STR_VEHICLE_HAS_VOID_ORDER);
00373 DeleteVehicleNews(v->index, STR_VEHICLE_HAS_DUPLICATE_ENTRY);
00374 DeleteVehicleNews(v->index, STR_VEHICLE_HAS_INVALID_ENTRY);
00375 }
00376
00377
00378 static TileIndex GetOrderLocation(const Order& o)
00379 {
00380 switch (o.GetType()) {
00381 default: NOT_REACHED();
00382 case OT_GOTO_STATION: return GetStation(o.GetDestination())->xy;
00383 case OT_GOTO_DEPOT: return GetDepot(o.GetDestination())->xy;
00384 }
00385 }
00386
00387 static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0)
00388 {
00389 if (cur->IsType(OT_CONDITIONAL)) {
00390 if (conditional_depth > v->GetNumOrders()) return 0;
00391
00392 conditional_depth++;
00393
00394 int dist1 = GetOrderDistance(prev, GetVehicleOrder(v, cur->GetConditionSkipToOrder()), v, conditional_depth);
00395 int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
00396 return max(dist1, dist2);
00397 }
00398
00399 return DistanceManhattan(GetOrderLocation(*prev), GetOrderLocation(*cur));
00400 }
00401
00412 CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00413 {
00414 Vehicle *v;
00415 VehicleID veh = GB(p1, 0, 16);
00416 VehicleOrderID sel_ord = GB(p1, 16, 16);
00417 Order new_order(p2);
00418
00419 if (!IsValidVehicleID(veh)) return CMD_ERROR;
00420
00421 v = GetVehicle(veh);
00422
00423 if (!CheckOwnership(v->owner)) return CMD_ERROR;
00424
00425
00426
00427 switch (new_order.GetType()) {
00428 case OT_GOTO_STATION: {
00429 if (!IsValidStationID(new_order.GetDestination())) return CMD_ERROR;
00430
00431 const Station *st = GetStation(new_order.GetDestination());
00432
00433 if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) return CMD_ERROR;
00434
00435 if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_CAN_T_ADD_ORDER);
00436 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
00437 if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_CAN_T_ADD_ORDER_SHARED);
00438 }
00439
00440
00441 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00442
00443
00444 if ((new_order.GetLoadType() & OLFB_NO_LOAD) && (new_order.GetUnloadType() & OUFB_NO_UNLOAD)) return CMD_ERROR;
00445
00446
00447 switch (new_order.GetLoadType()) {
00448 case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
00449 default: return CMD_ERROR;
00450 }
00451 switch (new_order.GetUnloadType()) {
00452 case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
00453 default: return CMD_ERROR;
00454 }
00455 break;
00456 }
00457
00458 case OT_GOTO_DEPOT: {
00459 if (new_order.GetDepotActionType() != ODATFB_NEAREST_DEPOT) {
00460 if (v->type == VEH_AIRCRAFT) {
00461 if (!IsValidStationID(new_order.GetDestination())) return CMD_ERROR;
00462
00463 const Station *st = GetStation(new_order.GetDestination());
00464
00465 if (!CheckOwnership(st->owner) ||
00466 !CanVehicleUseStation(v, st) ||
00467 st->Airport()->nof_depots == 0) {
00468 return CMD_ERROR;
00469 }
00470 } else {
00471 if (!IsValidDepotID(new_order.GetDestination())) return CMD_ERROR;
00472
00473 const Depot *dp = GetDepot(new_order.GetDestination());
00474
00475 if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
00476
00477 switch (v->type) {
00478 case VEH_TRAIN:
00479 if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
00480 break;
00481
00482 case VEH_ROAD:
00483 if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
00484 break;
00485
00486 case VEH_SHIP:
00487 if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
00488 break;
00489
00490 default: return CMD_ERROR;
00491 }
00492 }
00493 } else {
00494 if (!IsCompanyBuildableVehicleType(v)) return CMD_ERROR;
00495 }
00496
00497 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00498 if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR;
00499 if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR;
00500 if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR;
00501 break;
00502 }
00503
00504 case OT_GOTO_WAYPOINT: {
00505 if (v->type != VEH_TRAIN) return CMD_ERROR;
00506
00507 if (!IsValidWaypointID(new_order.GetDestination())) return CMD_ERROR;
00508 const Waypoint *wp = GetWaypoint(new_order.GetDestination());
00509
00510 if (!CheckOwnership(wp->owner)) return CMD_ERROR;
00511
00512
00513
00514
00515 if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
00516 break;
00517 }
00518
00519 case OT_CONDITIONAL: {
00520 VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
00521 if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR;
00522 if (new_order.GetConditionVariable() > OCV_END) return CMD_ERROR;
00523
00524 OrderConditionComparator occ = new_order.GetConditionComparator();
00525 if (occ > OCC_END) return CMD_ERROR;
00526 switch (new_order.GetConditionVariable()) {
00527 case OCV_REQUIRES_SERVICE:
00528 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR;
00529 break;
00530
00531 case OCV_UNCONDITIONALLY:
00532 if (occ != OCC_EQUALS) return CMD_ERROR;
00533 if (new_order.GetConditionValue() != 0) return CMD_ERROR;
00534 break;
00535
00536 case OCV_LOAD_PERCENTAGE:
00537 case OCV_RELIABILITY:
00538 if (new_order.GetConditionValue() > 100) return CMD_ERROR;
00539
00540 default:
00541 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
00542 break;
00543 }
00544 } break;
00545
00546 default: return CMD_ERROR;
00547 }
00548
00549 if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
00550
00551 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
00552 if (!Order::CanAllocateItem()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
00553 if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
00554
00555 if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) {
00556
00557 const Order *prev = NULL;
00558 uint n = 0;
00559
00560
00561
00562
00563 const Order *o;
00564 FOR_VEHICLE_ORDERS(v, o) {
00565 if (o->IsType(OT_GOTO_STATION) || o->IsType(OT_GOTO_DEPOT)) prev = o;
00566 if (++n == sel_ord && prev != NULL) break;
00567 }
00568 if (prev != NULL) {
00569 uint dist = GetOrderDistance(prev, &new_order, v);
00570 if (dist >= 130) {
00571 return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
00572 }
00573 }
00574 }
00575
00576 if (flags & DC_EXEC) {
00577 Order *new_o = new Order();
00578 new_o->AssignOrder(new_order);
00579
00580
00581 if (v->orders.list == NULL) {
00582 v->orders.list = new OrderList(new_o, v);
00583 } else {
00584 v->orders.list->InsertOrderAt(new_o, sel_ord);
00585 }
00586
00587 Vehicle *u = v->FirstShared();
00588 DeleteOrderWarnings(u);
00589 for (; u != NULL; u = u->NextShared()) {
00590 assert(v->orders.list == u->orders.list);
00591
00592
00593
00594 if (sel_ord <= u->cur_order_index) {
00595 uint cur = u->cur_order_index + 1;
00596
00597 if (cur < u->GetNumOrders())
00598 u->cur_order_index = cur;
00599 }
00600
00601 InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
00602 }
00603
00604
00605 VehicleOrderID cur_order_id = 0;
00606 Order *order;
00607 FOR_VEHICLE_ORDERS(v, order) {
00608 if (order->IsType(OT_CONDITIONAL)) {
00609 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00610 if (order_id >= sel_ord) {
00611 order->SetConditionSkipToOrder(order_id + 1);
00612 }
00613 if (order_id == cur_order_id) {
00614 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00615 }
00616 }
00617 cur_order_id++;
00618 }
00619
00620
00621 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00622 }
00623
00624 return CommandCost();
00625 }
00626
00631 static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags)
00632 {
00633 if (flags & DC_EXEC) {
00634 DeleteVehicleOrders(dst);
00635 InvalidateVehicleOrder(dst, -1);
00636 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
00637 }
00638 return CommandCost();
00639 }
00640
00647 CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00648 {
00649 Vehicle *v;
00650 VehicleID veh_id = p1;
00651 VehicleOrderID sel_ord = p2;
00652 Order *order;
00653
00654 if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
00655
00656 v = GetVehicle(veh_id);
00657
00658 if (!CheckOwnership(v->owner)) return CMD_ERROR;
00659
00660
00661 if (sel_ord >= v->GetNumOrders())
00662 return DecloneOrder(v, flags);
00663
00664 order = GetVehicleOrder(v, sel_ord);
00665 if (order == NULL) return CMD_ERROR;
00666
00667 if (flags & DC_EXEC) {
00668 v->orders.list->DeleteOrderAt(sel_ord);
00669
00670 Vehicle *u = v->FirstShared();
00671 DeleteOrderWarnings(u);
00672 for (; u != NULL; u = u->NextShared()) {
00673 if (sel_ord < u->cur_order_index)
00674 u->cur_order_index--;
00675
00676 assert(v->orders.list == u->orders.list);
00677
00678
00679
00680 if (sel_ord == u->cur_order_index && u->current_order.IsType(OT_LOADING)) {
00681 u->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
00682 }
00683
00684
00685 InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
00686 }
00687
00688
00689 VehicleOrderID cur_order_id = 0;
00690 FOR_VEHICLE_ORDERS(v, order) {
00691 if (order->IsType(OT_CONDITIONAL)) {
00692 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00693 if (order_id >= sel_ord) {
00694 order->SetConditionSkipToOrder(max(order_id - 1, 0));
00695 }
00696 if (order_id == cur_order_id) {
00697 order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders());
00698 }
00699 }
00700 cur_order_id++;
00701 }
00702
00703 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00704 }
00705
00706 return CommandCost();
00707 }
00708
00715 CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00716 {
00717 Vehicle *v;
00718 VehicleID veh_id = p1;
00719 VehicleOrderID sel_ord = p2;
00720
00721 if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
00722
00723 v = GetVehicle(veh_id);
00724
00725 if (!CheckOwnership(v->owner) || sel_ord == v->cur_order_index ||
00726 sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
00727
00728 if (flags & DC_EXEC) {
00729 v->cur_order_index = sel_ord;
00730
00731 if (v->type == VEH_ROAD) ClearSlot(v);
00732
00733 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
00734
00735 InvalidateVehicleOrder(v, 0);
00736 }
00737
00738
00739 if (v->type == VEH_AIRCRAFT) InvalidateWindowClasses(WC_AIRCRAFT_LIST);
00740 if (v->type == VEH_SHIP) InvalidateWindowClasses(WC_SHIPS_LIST);
00741
00742 return CommandCost();
00743 }
00744
00755 CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00756 {
00757 VehicleID veh = p1;
00758 VehicleOrderID moving_order = GB(p2, 0, 16);
00759 VehicleOrderID target_order = GB(p2, 16, 16);
00760
00761 if (!IsValidVehicleID(veh)) return CMD_ERROR;
00762
00763 Vehicle *v = GetVehicle(veh);
00764 if (!CheckOwnership(v->owner)) return CMD_ERROR;
00765
00766
00767 if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
00768 moving_order == target_order || v->GetNumOrders() <= 1)
00769 return CMD_ERROR;
00770
00771 Order *moving_one = GetVehicleOrder(v, moving_order);
00772
00773 if (moving_one == NULL) return CMD_ERROR;
00774
00775 if (flags & DC_EXEC) {
00776 v->orders.list->MoveOrder(moving_order, target_order);
00777
00778
00779 Vehicle *u = v->FirstShared();
00780
00781 DeleteOrderWarnings(u);
00782
00783 for (; u != NULL; u = u->NextShared()) {
00784
00785 if (u->cur_order_index == moving_order) {
00786 u->cur_order_index = target_order;
00787 } else if(u->cur_order_index > moving_order && u->cur_order_index <= target_order) {
00788 u->cur_order_index--;
00789 } else if(u->cur_order_index < moving_order && u->cur_order_index >= target_order) {
00790 u->cur_order_index++;
00791 }
00792
00793 assert(v->orders.list == u->orders.list);
00794
00795 InvalidateVehicleOrder(u, moving_order | (target_order << 8));
00796 }
00797
00798
00799 Order *order;
00800 FOR_VEHICLE_ORDERS(v, order) {
00801 if (order->IsType(OT_CONDITIONAL)) {
00802 VehicleOrderID order_id = order->GetConditionSkipToOrder();
00803 if (order_id == moving_order) {
00804 order_id = target_order;
00805 } else if(order_id > moving_order && order_id <= target_order) {
00806 order_id--;
00807 } else if(order_id < moving_order && order_id >= target_order) {
00808 order_id++;
00809 }
00810 order->SetConditionSkipToOrder(order_id);
00811 }
00812 }
00813
00814
00815 InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
00816 }
00817
00818 return CommandCost();
00819 }
00820
00833 CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00834 {
00835 VehicleOrderID sel_ord = GB(p1, 16, 16);
00836 VehicleID veh = GB(p1, 0, 16);
00837 ModifyOrderFlags mof = (ModifyOrderFlags)GB(p2, 0, 4);
00838 uint16 data = GB(p2, 4, 11);
00839
00840 if (mof >= MOF_END) return CMD_ERROR;
00841 if (!IsValidVehicleID(veh)) return CMD_ERROR;
00842
00843 Vehicle *v = GetVehicle(veh);
00844 if (!CheckOwnership(v->owner)) return CMD_ERROR;
00845
00846
00847 if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
00848
00849 Order *order = GetVehicleOrder(v, sel_ord);
00850 switch (order->GetType()) {
00851 case OT_GOTO_STATION:
00852 if (mof == MOF_COND_VARIABLE || mof == MOF_COND_COMPARATOR || mof == MOF_DEPOT_ACTION || mof == MOF_COND_VALUE || GetStation(order->GetDestination())->IsBuoy()) return CMD_ERROR;
00853 break;
00854
00855 case OT_GOTO_DEPOT:
00856 if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR;
00857 break;
00858
00859 case OT_GOTO_WAYPOINT:
00860 if (mof != MOF_NON_STOP) return CMD_ERROR;
00861 break;
00862
00863 case OT_CONDITIONAL:
00864 if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR;
00865 break;
00866
00867 default:
00868 return CMD_ERROR;
00869 }
00870
00871 switch (mof) {
00872 default: NOT_REACHED();
00873
00874 case MOF_NON_STOP:
00875 if (v->type != VEH_TRAIN && v->type != VEH_ROAD) return CMD_ERROR;
00876 if (data >= ONSF_END) return CMD_ERROR;
00877 if (data == order->GetNonStopType()) return CMD_ERROR;
00878 break;
00879
00880 case MOF_UNLOAD:
00881 if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
00882
00883 if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR;
00884 if (data == order->GetUnloadType()) return CMD_ERROR;
00885 break;
00886
00887 case MOF_LOAD:
00888 if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR;
00889 if (data == order->GetLoadType()) return CMD_ERROR;
00890 break;
00891
00892 case MOF_DEPOT_ACTION:
00893 if (data >= DA_END) return CMD_ERROR;
00894 break;
00895
00896 case MOF_COND_VARIABLE:
00897 if (data >= OCV_END) return CMD_ERROR;
00898 break;
00899
00900 case MOF_COND_COMPARATOR:
00901 if (data >= OCC_END) return CMD_ERROR;
00902 switch (order->GetConditionVariable()) {
00903 case OCV_UNCONDITIONALLY: return CMD_ERROR;
00904
00905 case OCV_REQUIRES_SERVICE:
00906 if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR;
00907 break;
00908
00909 default:
00910 if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR;
00911 break;
00912 }
00913 break;
00914
00915 case MOF_COND_VALUE:
00916 switch (order->GetConditionVariable()) {
00917 case OCV_UNCONDITIONALLY: return CMD_ERROR;
00918
00919 case OCV_LOAD_PERCENTAGE:
00920 case OCV_RELIABILITY:
00921 if (data > 100) return CMD_ERROR;
00922 break;
00923
00924 default:
00925 if (data > 2047) return CMD_ERROR;
00926 break;
00927 }
00928 break;
00929
00930 case MOF_COND_DESTINATION:
00931 if (data >= v->GetNumOrders()) return CMD_ERROR;
00932 break;
00933 }
00934
00935 if (flags & DC_EXEC) {
00936 switch (mof) {
00937 case MOF_NON_STOP:
00938 order->SetNonStopType((OrderNonStopFlags)data);
00939 break;
00940
00941 case MOF_UNLOAD:
00942 order->SetUnloadType((OrderUnloadFlags)data);
00943 if ((data & OUFB_NO_UNLOAD) != 0 && (order->GetLoadType() & OLFB_NO_LOAD) != 0) {
00944 order->SetLoadType((OrderLoadFlags)(order->GetLoadType() & ~OLFB_NO_LOAD));
00945 }
00946 break;
00947
00948 case MOF_LOAD:
00949 order->SetLoadType((OrderLoadFlags)data);
00950 if ((data & OLFB_NO_LOAD) != 0 && (order->GetUnloadType() & OUFB_NO_UNLOAD) != 0) {
00951
00952 order->SetUnloadType((OrderUnloadFlags)(order->GetUnloadType() & ~OUFB_NO_UNLOAD));
00953 }
00954 break;
00955
00956 case MOF_DEPOT_ACTION: {
00957 switch (data) {
00958 case DA_ALWAYS_GO:
00959 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
00960 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
00961 break;
00962
00963 case DA_SERVICE:
00964 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE));
00965 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT));
00966 break;
00967
00968 case DA_STOP:
00969 order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
00970 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT));
00971 break;
00972
00973 default:
00974 NOT_REACHED();
00975 }
00976 } break;
00977
00978 case MOF_COND_VARIABLE: {
00979 order->SetConditionVariable((OrderConditionVariable)data);
00980
00981 OrderConditionComparator occ = order->GetConditionComparator();
00982 switch (order->GetConditionVariable()) {
00983 case OCV_UNCONDITIONALLY:
00984 order->SetConditionComparator(OCC_EQUALS);
00985 order->SetConditionValue(0);
00986 break;
00987
00988 case OCV_REQUIRES_SERVICE:
00989 if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE);
00990 break;
00991
00992 case OCV_LOAD_PERCENTAGE:
00993 case OCV_RELIABILITY:
00994 if (order->GetConditionValue() > 100) order->SetConditionValue(100);
00995
00996 default:
00997 if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS);
00998 break;
00999 }
01000 } break;
01001
01002 case MOF_COND_COMPARATOR:
01003 order->SetConditionComparator((OrderConditionComparator)data);
01004 break;
01005
01006 case MOF_COND_VALUE:
01007 order->SetConditionValue(data);
01008 break;
01009
01010 case MOF_COND_DESTINATION:
01011 order->SetConditionSkipToOrder(data);
01012 break;
01013
01014 default: NOT_REACHED();
01015 }
01016
01017
01018 Vehicle *u = v->FirstShared();
01019 DeleteOrderWarnings(u);
01020 for (; u != NULL; u = u->NextShared()) {
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030 if (sel_ord == u->cur_order_index &&
01031 (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
01032 u->current_order.GetLoadType() != order->GetLoadType()) {
01033 u->current_order.SetLoadType(order->GetLoadType());
01034 }
01035 InvalidateVehicleOrder(u, 0);
01036 }
01037 }
01038
01039 return CommandCost();
01040 }
01041
01050 CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01051 {
01052 Vehicle *dst;
01053 VehicleID veh_src = GB(p1, 16, 16);
01054 VehicleID veh_dst = GB(p1, 0, 16);
01055
01056 if (!IsValidVehicleID(veh_dst)) return CMD_ERROR;
01057
01058 dst = GetVehicle(veh_dst);
01059
01060 if (!CheckOwnership(dst->owner)) return CMD_ERROR;
01061
01062 switch (p2) {
01063 case CO_SHARE: {
01064 Vehicle *src;
01065
01066 if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
01067
01068 src = GetVehicle(veh_src);
01069
01070
01071 if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
01072 return CMD_ERROR;
01073
01074
01075 if (src->type == VEH_ROAD) {
01076 if (src->cargo_type != dst->cargo_type && (IsCargoInClass(src->cargo_type, CC_PASSENGERS) || IsCargoInClass(dst->cargo_type, CC_PASSENGERS)))
01077 return CMD_ERROR;
01078 }
01079
01080
01081 if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR;
01082
01083 const Order *order;
01084
01085 FOR_VEHICLE_ORDERS(src, order) {
01086 if (OrderGoesToStation(dst, order) &&
01087 !CanVehicleUseStation(dst, GetStation(order->GetDestination()))) {
01088 return_cmd_error(STR_CAN_T_COPY_SHARE_ORDER);
01089 }
01090 }
01091
01092 if (flags & DC_EXEC) {
01093
01094 DeleteVehicleOrders(dst);
01095
01096 dst->orders.list = src->orders.list;
01097
01098
01099 dst->AddToShared(src);
01100
01101 InvalidateVehicleOrder(dst, -1);
01102 InvalidateVehicleOrder(src, 0);
01103
01104 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01105 }
01106 } break;
01107
01108 case CO_COPY: {
01109 Vehicle *src;
01110 int delta;
01111
01112 if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
01113
01114 src = GetVehicle(veh_src);
01115
01116
01117 if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
01118 return CMD_ERROR;
01119
01120
01121
01122 const Order *order;
01123 FOR_VEHICLE_ORDERS(src, order) {
01124 if (OrderGoesToStation(dst, order) &&
01125 !CanVehicleUseStation(dst, GetStation(order->GetDestination()))) {
01126 return_cmd_error(STR_CAN_T_COPY_SHARE_ORDER);
01127 }
01128 }
01129
01130
01131 delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
01132 if (!Order::CanAllocateItem(delta) ||
01133 ((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
01134 return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
01135 }
01136
01137 if (flags & DC_EXEC) {
01138 const Order *order;
01139 Order *first = NULL;
01140 Order **order_dst;
01141
01142
01143 DeleteVehicleOrders(dst, true);
01144
01145 order_dst = &first;
01146 FOR_VEHICLE_ORDERS(src, order) {
01147 *order_dst = new Order();
01148 (*order_dst)->AssignOrder(*order);
01149 order_dst = &(*order_dst)->next;
01150 }
01151 if (dst->orders.list == NULL) dst->orders.list = new OrderList(first, dst);
01152 else {
01153 assert(dst->orders.list->GetFirstOrder() == NULL);
01154 new (dst->orders.list) OrderList(first, dst);
01155 }
01156
01157 InvalidateVehicleOrder(dst, -1);
01158
01159 InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
01160 }
01161 } break;
01162
01163 case CO_UNSHARE: return DecloneOrder(dst, flags);
01164 default: return CMD_ERROR;
01165 }
01166
01167 return CommandCost();
01168 }
01169
01179 CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01180 {
01181 const Vehicle *v;
01182 Order *order;
01183 VehicleID veh = GB(p1, 0, 16);
01184 VehicleOrderID order_number = GB(p2, 16, 8);
01185 CargoID cargo = GB(p2, 0, 8);
01186 byte subtype = GB(p2, 8, 8);
01187
01188 if (!IsValidVehicleID(veh)) return CMD_ERROR;
01189
01190 v = GetVehicle(veh);
01191
01192 if (!CheckOwnership(v->owner)) return CMD_ERROR;
01193
01194 order = GetVehicleOrder(v, order_number);
01195 if (order == NULL) return CMD_ERROR;
01196
01197 if (flags & DC_EXEC) {
01198 order->SetRefit(cargo, subtype);
01199
01200 for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
01201
01202 InvalidateVehicleOrder(u, 0);
01203
01204
01205 if (u->cur_order_index == order_number && u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
01206 u->current_order.SetRefit(cargo, subtype);
01207 }
01208 }
01209 }
01210
01211 return CommandCost();
01212 }
01213
01220 void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
01221 {
01222
01223 free(bak->order);
01224 bak->order = NULL;
01225 free(bak->name);
01226 bak->name = NULL;
01227
01228
01229 bak->orderindex = v->cur_order_index;
01230 bak->group = v->group_id;
01231 bak->service_interval = v->service_interval;
01232 if (v->name != NULL) bak->name = strdup(v->name);
01233
01234
01235 if (v->IsOrderListShared()) {
01236 const Vehicle *u = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
01237
01238 bak->clone = u->index;
01239 } else {
01240
01241
01242
01243 bak->clone = INVALID_VEHICLE;
01244
01245
01246
01247 uint cnt = 0;
01248 const Order *order;
01249 FOR_VEHICLE_ORDERS(v, order) cnt++;
01250
01251
01252 bak->order = MallocT<Order>(cnt + 1);
01253
01254 Order *dest = bak->order;
01255
01256
01257 FOR_VEHICLE_ORDERS(v, order) {
01258 memcpy(dest, order, sizeof(Order));
01259 dest++;
01260 }
01261
01262 dest->Free();
01263 }
01264 }
01265
01271 void RestoreVehicleOrders(const Vehicle *v, const BackuppedOrders *bak)
01272 {
01273
01274 if (bak->name != NULL) DoCommandP(0, v->index, 0, CMD_RENAME_VEHICLE, NULL, bak->name);
01275
01276
01277 if (bak->clone != INVALID_VEHICLE) {
01278 DoCommandP(0, v->index | (bak->clone << 16), CO_SHARE, CMD_CLONE_ORDER);
01279 } else {
01280
01281
01282
01283
01284
01285 for (uint i = 0; bak->order[i].IsValid(); i++) {
01286 Order o = bak->order[i];
01287
01288 if (o.IsType(OT_CONDITIONAL)) o.SetConditionSkipToOrder(0);
01289
01290 if (!DoCommandP(0, v->index + (i << 16), o.Pack(),
01291 CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
01292 break;
01293 }
01294
01295
01296 if (_settings_game.order.timetabling && !DoCommandP(0, v->index | (i << 16) | (1 << 25),
01297 o.wait_time << 16 | o.travel_time,
01298 CMD_CHANGE_TIMETABLE | CMD_NO_TEST_IF_IN_NETWORK)) {
01299 break;
01300 }
01301 }
01302
01303
01304 for (uint i = 0; bak->order[i].IsValid(); i++) {
01305 if (!bak->order[i].IsType(OT_CONDITIONAL)) continue;
01306
01307 if (!DoCommandP(0, v->index + (i << 16), MOF_LOAD | (bak->order[i].GetConditionSkipToOrder() << 4),
01308 CMD_MODIFY_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
01309 break;
01310 }
01311 }
01312 }
01313
01314
01315 DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , CMD_RESTORE_ORDER_INDEX);
01316
01317
01318 DoCommandP(0, bak->group, v->index, CMD_ADD_VEHICLE_GROUP);
01319 }
01320
01335 CommandCost CmdRestoreOrderIndex(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01336 {
01337 Vehicle *v;
01338 VehicleOrderID cur_ord = GB(p2, 0, 16);
01339 uint16 serv_int = GB(p2, 16, 16);
01340
01341 if (!IsValidVehicleID(p1)) return CMD_ERROR;
01342
01343 v = GetVehicle(p1);
01344
01345
01346 if (!CheckOwnership(v->owner)) return CMD_ERROR;
01347 if (serv_int != GetServiceIntervalClamped(serv_int) || cur_ord >= v->GetNumOrders()) return CMD_ERROR;
01348
01349 if (flags & DC_EXEC) {
01350 v->cur_order_index = cur_ord;
01351 v->service_interval = serv_int;
01352 }
01353
01354 return CommandCost();
01355 }
01356
01357
01358 static TileIndex GetStationTileForVehicle(const Vehicle *v, const Station *st)
01359 {
01360 if (!CanVehicleUseStation(v, st)) return INVALID_TILE;
01361
01362 switch (v->type) {
01363 default: NOT_REACHED();
01364 case VEH_TRAIN: return st->train_tile;
01365 case VEH_AIRCRAFT: return st->airport_tile;
01366 case VEH_SHIP: return st->dock_tile;
01367 case VEH_ROAD: return st->GetPrimaryRoadStop(v)->xy;
01368 }
01369 }
01370
01371
01377 void CheckOrders(const Vehicle *v)
01378 {
01379
01380 if (_settings_client.gui.order_review_system == 0) return;
01381
01382
01383 if (v->vehstatus & VS_CRASHED) return;
01384
01385
01386 if (_settings_client.gui.order_review_system == 1 && v->vehstatus & VS_STOPPED)
01387 return;
01388
01389
01390 if (v->FirstShared() != v) return;
01391
01392
01393 if (v->owner == _local_company && v->day_counter % 20 == 0) {
01394 int n_st, problem_type = -1;
01395 const Order *order;
01396 int message = 0;
01397
01398
01399 n_st = 0;
01400
01401 FOR_VEHICLE_ORDERS(v, order) {
01402
01403 if (order->IsType(OT_DUMMY)) {
01404 problem_type = 1;
01405 break;
01406 }
01407
01408 if (order->IsType(OT_GOTO_STATION)) {
01409 const Station *st = GetStation(order->GetDestination());
01410 TileIndex required_tile = GetStationTileForVehicle(v, st);
01411
01412 n_st++;
01413 if (required_tile == INVALID_TILE) problem_type = 3;
01414 }
01415 }
01416
01417
01418 if (v->GetNumOrders() > 1) {
01419 const Order *last = GetLastVehicleOrder(v);
01420
01421 if (v->orders.list->GetFirstOrder()->Equals(*last)) {
01422 problem_type = 2;
01423 }
01424 }
01425
01426
01427 if (n_st < 2 && problem_type == -1) problem_type = 0;
01428
01429 #ifndef NDEBUG
01430 if (v->orders.list != NULL) v->orders.list->DebugCheckSanity();
01431 #endif
01432
01433
01434 if (problem_type < 0) return;
01435
01436 message = STR_VEHICLE_HAS_TOO_FEW_ORDERS + problem_type;
01437
01438
01439 SetDParam(0, v->index);
01440 AddNewsItem(
01441 message,
01442 NS_ADVICE,
01443 v->index,
01444 0
01445 );
01446 }
01447 }
01448
01454 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01455 {
01456 Vehicle *v;
01457
01458
01459
01460
01461
01462
01463 FOR_ALL_VEHICLES(v) {
01464 Order *order;
01465
01466
01467 if (v->last_station_visited == destination && type == OT_GOTO_STATION) {
01468 v->last_station_visited = INVALID_STATION;
01469 }
01470
01471 order = &v->current_order;
01472 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01473 v->current_order.GetDestination() == destination) {
01474 order->MakeDummy();
01475 InvalidateWindow(WC_VEHICLE_VIEW, v->index);
01476 }
01477
01478
01479 int id = -1;
01480 FOR_VEHICLE_ORDERS(v, order) {
01481 id++;
01482 if (order->IsType(OT_GOTO_DEPOT) && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
01483 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
01484 order->GetDestination() == destination) {
01485 order->MakeDummy();
01486 for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
01487
01488 InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
01489 InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id);
01490 }
01491 }
01492 }
01493 }
01494 }
01495
01503 bool VehicleHasDepotOrders(const Vehicle *v)
01504 {
01505 const Order *order;
01506
01507 FOR_VEHICLE_ORDERS(v, order) {
01508 if (order->IsType(OT_GOTO_DEPOT))
01509 return true;
01510 }
01511
01512 return false;
01513 }
01514
01520 void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist)
01521 {
01522 DeleteOrderWarnings(v);
01523
01524 if (v->IsOrderListShared()) {
01525
01526 v->RemoveFromShared();
01527 v->orders.list = NULL;
01528 } else if (v->orders.list != NULL) {
01529
01530 v->orders.list->FreeChain(keep_orderlist);
01531 if (!keep_orderlist) v->orders.list = NULL;
01532 }
01533 }
01534
01535 Date GetServiceIntervalClamped(uint index)
01536 {
01537 return (_settings_game.vehicle.servint_ispercent) ? Clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
01538 }
01539
01547 static bool CheckForValidOrders(const Vehicle *v)
01548 {
01549 const Order *order;
01550
01551 FOR_VEHICLE_ORDERS(v, order) if (!order->IsType(OT_DUMMY)) return true;
01552
01553 return false;
01554 }
01555
01559 static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
01560 {
01561 switch (occ) {
01562 case OCC_EQUALS: return variable == value;
01563 case OCC_NOT_EQUALS: return variable != value;
01564 case OCC_LESS_THAN: return variable < value;
01565 case OCC_LESS_EQUALS: return variable <= value;
01566 case OCC_MORE_THAN: return variable > value;
01567 case OCC_MORE_EQUALS: return variable >= value;
01568 case OCC_IS_TRUE: return variable != 0;
01569 case OCC_IS_FALSE: return variable == 0;
01570 default: NOT_REACHED();
01571 }
01572 }
01573
01580 VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
01581 {
01582 if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
01583
01584 bool skip_order = false;
01585 OrderConditionComparator occ = order->GetConditionComparator();
01586 uint16 value = order->GetConditionValue();
01587
01588 switch (order->GetConditionVariable()) {
01589 case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break;
01590 case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, v->reliability * 100 >> 16, value); break;
01591 case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
01592 case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break;
01593 case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break;
01594 case OCV_UNCONDITIONALLY: skip_order = true; break;
01595 default: NOT_REACHED();
01596 }
01597
01598 return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
01599 }
01600
01606 bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
01607 {
01608 switch (order->GetType()) {
01609 case OT_GOTO_STATION:
01610 v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
01611 break;
01612
01613 case OT_GOTO_DEPOT:
01614 if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
01615
01616 TileIndex location;
01617 DestinationID destination;
01618 bool reverse;
01619
01620 if (v->FindClosestDepot(&location, &destination, &reverse)) {
01621 v->dest_tile = location;
01622 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());
01623
01624
01625 if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01626
01627 if (v->type == VEH_AIRCRAFT && v->u.air.state == FLYING && v->u.air.targetairport != destination) {
01628
01629 extern void AircraftNextAirportPos_and_Order(Vehicle *v);
01630 AircraftNextAirportPos_and_Order(v);
01631 }
01632 } else {
01633 UpdateVehicleTimetable(v, true);
01634 v->cur_order_index++;
01635 }
01636 } else if (v->type != VEH_AIRCRAFT) {
01637 v->dest_tile = GetDepot(order->GetDestination())->xy;
01638 }
01639 break;
01640
01641 case OT_GOTO_WAYPOINT:
01642 v->dest_tile = GetWaypoint(order->GetDestination())->xy;
01643 break;
01644
01645 case OT_CONDITIONAL: {
01646 if (conditional_depth > v->GetNumOrders()) return false;
01647
01648 VehicleOrderID next_order = ProcessConditionalOrder(order, v);
01649 if (next_order != INVALID_VEH_ORDER_ID) {
01650 UpdateVehicleTimetable(v, false);
01651 v->cur_order_index = next_order;
01652 v->current_order_time += GetVehicleOrder(v, next_order)->travel_time;
01653 } else {
01654 UpdateVehicleTimetable(v, true);
01655 v->cur_order_index++;
01656 }
01657
01658
01659 if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
01660
01661 const Order *order = GetVehicleOrder(v, v->cur_order_index);
01662 v->current_order = *order;
01663 return UpdateOrderDest(v, order, conditional_depth + 1);
01664 }
01665
01666 default:
01667 v->dest_tile = 0;
01668 return false;
01669 }
01670 return true;
01671 }
01672
01680 bool ProcessOrders(Vehicle *v)
01681 {
01682 switch (v->current_order.GetType()) {
01683 case OT_GOTO_DEPOT:
01684
01685 if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
01686
01687 if ((v->current_order.GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
01688 UpdateVehicleTimetable(v, true);
01689 v->cur_order_index++;
01690 }
01691 break;
01692
01693 case OT_LOADING:
01694 return false;
01695
01696 case OT_LEAVESTATION:
01697 if (v->type != VEH_AIRCRAFT) return false;
01698 break;
01699
01700 default: break;
01701 }
01702
01710 bool may_reverse = v->current_order.IsType(OT_NOTHING);
01711
01712
01713 if (v->current_order.IsType(OT_GOTO_WAYPOINT) && v->tile == v->dest_tile) {
01714 UpdateVehicleTimetable(v, true);
01715 v->cur_order_index++;
01716 }
01717
01718
01719 if (v->current_order.IsType(OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) &&
01720 IsTileType(v->tile, MP_STATION) &&
01721 v->current_order.GetDestination() == GetStationIndex(v->tile)) {
01722 v->last_station_visited = v->current_order.GetDestination();
01723 UpdateVehicleTimetable(v, true);
01724 v->cur_order_index++;
01725 }
01726
01727
01728 if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
01729
01730 const Order *order = GetVehicleOrder(v, v->cur_order_index);
01731
01732
01733 if (order == NULL || (v->type == VEH_AIRCRAFT && order->IsType(OT_DUMMY) && !CheckForValidOrders(v))) {
01734 if (v->type == VEH_AIRCRAFT) {
01735
01736 extern void HandleMissingAircraftOrders(Vehicle *v);
01737 HandleMissingAircraftOrders(v);
01738 return false;
01739 }
01740
01741 v->current_order.Free();
01742 v->dest_tile = 0;
01743 if (v->type == VEH_ROAD) ClearSlot(v);
01744 return false;
01745 }
01746
01747
01748 if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) &&
01749 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || GetStation(order->GetDestination())->dock_tile != INVALID_TILE)) {
01750 return false;
01751 }
01752
01753
01754 v->current_order = *order;
01755
01756 InvalidateVehicleOrder(v, 0);
01757 switch (v->type) {
01758 default:
01759 NOT_REACHED();
01760
01761 case VEH_ROAD:
01762 case VEH_TRAIN:
01763 break;
01764
01765 case VEH_AIRCRAFT:
01766 case VEH_SHIP:
01767 InvalidateWindowClasses(GetWindowClassForVehicleType(v->type));
01768 break;
01769 }
01770
01771 return UpdateOrderDest(v, order) && may_reverse;
01772 }
01773
01781 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
01782 {
01783 bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station;
01784 return
01785 (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) &&
01786 v->last_station_visited != station &&
01787
01788 !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
01789 }
01790
01791 void InitializeOrders()
01792 {
01793 _Order_pool.CleanPool();
01794 _Order_pool.AddBlockToPool();
01795
01796 _OrderList_pool.CleanPool();
01797 _OrderList_pool.AddBlockToPool();
01798
01799 _backup_orders_tile = 0;
01800 }