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