00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "order.h"
00008 #include "airport.h"
00009 #include "depot.h"
00010 #include "waypoint.h"
00011 #include "command_func.h"
00012 #include "station.h"
00013 #include "player_func.h"
00014 #include "news.h"
00015 #include "saveload.h"
00016 #include "vehicle_gui.h"
00017 #include "cargotype.h"
00018 #include "aircraft.h"
00019 #include "strings_func.h"
00020 #include "core/alloc_func.hpp"
00021 #include "functions.h"
00022 #include "window_func.h"
00023 #include "settings_type.h"
00024 #include "string_func.h"
00025
00026 #include "table/strings.h"
00027
00028 TileIndex _backup_orders_tile;
00029 BackuppedOrders _backup_orders_data;
00030
00031 DEFINE_OLD_POOL_GENERIC(Order, Order)
00032
00033
00038 Order UnpackOldOrder(uint16 packed)
00039 {
00040 Order order;
00041 order.type = (OrderType)GB(packed, 0, 4);
00042 order.flags = GB(packed, 4, 4);
00043 order.dest = GB(packed, 8, 8);
00044 order.next = NULL;
00045
00046 order.refit_cargo = CT_NO_REFIT;
00047 order.refit_subtype = 0;
00048 order.wait_time = 0;
00049 order.travel_time = 0;
00050 order.index = 0;
00051
00052
00053
00054 if (!order.IsValid() && (order.flags != 0 || order.dest != 0)) {
00055 order.type = OT_DUMMY;
00056 order.flags = 0;
00057 }
00058
00059 return order;
00060 }
00061
00067 static Order UnpackVersion4Order(uint16 packed)
00068 {
00069 Order order;
00070 order.type = (OrderType)GB(packed, 0, 4);
00071 order.flags = GB(packed, 4, 4);
00072 order.dest = GB(packed, 8, 8);
00073 order.next = NULL;
00074 order.index = 0;
00075 order.refit_cargo = CT_NO_REFIT;
00076 order.refit_subtype = 0;
00077 order.wait_time = 0;
00078 order.travel_time = 0;
00079 return order;
00080 }
00081
00087 void InvalidateVehicleOrder(const Vehicle *v)
00088 {
00089 InvalidateWindow(WC_VEHICLE_VIEW, v->index);
00090 InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
00091 InvalidateWindow(WC_VEHICLE_TIMETABLE, v->index);
00092 }
00093
00099 static void SwapOrders(Order *order1, Order *order2)
00100 {
00101 Order temp_order;
00102
00103 temp_order = *order1;
00104 AssignOrder(order1, *order2);
00105 order1->next = order2->next;
00106 AssignOrder(order2, temp_order);
00107 order2->next = temp_order.next;
00108 }
00109
00116 void AssignOrder(Order *order, Order data)
00117 {
00118 order->type = data.type;
00119 order->flags = data.flags;
00120 order->dest = data.dest;
00121
00122 order->refit_cargo = data.refit_cargo;
00123 order->refit_subtype = data.refit_subtype;
00124
00125 order->wait_time = data.wait_time;
00126 order->travel_time = data.travel_time;
00127 }
00128
00129
00136 static void DeleteOrderWarnings(const Vehicle* v)
00137 {
00138 DeleteVehicleNews(v->index, STR_TRAIN_HAS_TOO_FEW_ORDERS + v->type * 4);
00139 DeleteVehicleNews(v->index, STR_TRAIN_HAS_VOID_ORDER + v->type * 4);
00140 DeleteVehicleNews(v->index, STR_TRAIN_HAS_DUPLICATE_ENTRY + v->type * 4);
00141 DeleteVehicleNews(v->index, STR_TRAIN_HAS_INVALID_ENTRY + v->type * 4);
00142 }
00143
00144
00145 static TileIndex GetOrderLocation(const Order& o)
00146 {
00147 switch (o.type) {
00148 default: NOT_REACHED();
00149 case OT_GOTO_STATION: return GetStation(o.dest)->xy;
00150 case OT_GOTO_DEPOT: return GetDepot(o.dest)->xy;
00151 }
00152 }
00153
00154
00165 CommandCost CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00166 {
00167 Vehicle *v;
00168 VehicleID veh = GB(p1, 0, 16);
00169 VehicleOrderID sel_ord = GB(p1, 16, 16);
00170 Order new_order = UnpackOrder(p2);
00171
00172 if (!IsValidVehicleID(veh)) return CMD_ERROR;
00173
00174 v = GetVehicle(veh);
00175
00176 if (!CheckOwnership(v->owner)) return CMD_ERROR;
00177
00178
00179
00180 switch (new_order.type) {
00181 case OT_GOTO_STATION: {
00182 const Station *st;
00183
00184 if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
00185 st = GetStation(new_order.dest);
00186
00187 if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) {
00188 return CMD_ERROR;
00189 }
00190
00191 switch (v->type) {
00192 case VEH_TRAIN:
00193 if (!(st->facilities & FACIL_TRAIN)) return CMD_ERROR;
00194 break;
00195
00196 case VEH_ROAD:
00197 if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
00198 if (!(st->facilities & FACIL_BUS_STOP)) return CMD_ERROR;
00199 } else {
00200 if (!(st->facilities & FACIL_TRUCK_STOP)) return CMD_ERROR;
00201 }
00202 break;
00203
00204 case VEH_SHIP:
00205 if (!(st->facilities & FACIL_DOCK)) return CMD_ERROR;
00206 break;
00207
00208 case VEH_AIRCRAFT:
00209 if (!(st->facilities & FACIL_AIRPORT) || !CanAircraftUseStation(v->engine_type, st)) {
00210 return CMD_ERROR;
00211 }
00212 break;
00213
00214 default: return CMD_ERROR;
00215 }
00216
00217
00218
00219
00220 switch (new_order.flags) {
00221 case 0:
00222 case OFB_FULL_LOAD:
00223 case OFB_FULL_LOAD | OFB_TRANSFER:
00224 case OFB_UNLOAD:
00225 case OFB_UNLOAD | OFB_TRANSFER:
00226 case OFB_TRANSFER:
00227 break;
00228
00229 case OFB_NON_STOP:
00230 case OFB_NON_STOP | OFB_FULL_LOAD:
00231 case OFB_NON_STOP | OFB_FULL_LOAD | OFB_TRANSFER:
00232 case OFB_NON_STOP | OFB_UNLOAD:
00233 case OFB_NON_STOP | OFB_UNLOAD | OFB_TRANSFER:
00234 case OFB_NON_STOP | OFB_TRANSFER:
00235 if (v->type != VEH_TRAIN) return CMD_ERROR;
00236 break;
00237
00238 default: return CMD_ERROR;
00239 }
00240 break;
00241 }
00242
00243 case OT_GOTO_DEPOT: {
00244 if (v->type == VEH_AIRCRAFT) {
00245 const Station* st;
00246
00247 if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
00248 st = GetStation(new_order.dest);
00249
00250 if (!CheckOwnership(st->owner) ||
00251 !(st->facilities & FACIL_AIRPORT) ||
00252 st->Airport()->nof_depots == 0 ||
00253 !CanAircraftUseStation(v->engine_type, st)) {
00254 return CMD_ERROR;
00255 }
00256 } else {
00257 const Depot* dp;
00258
00259 if (!IsValidDepotID(new_order.dest)) return CMD_ERROR;
00260 dp = GetDepot(new_order.dest);
00261
00262 if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
00263
00264 switch (v->type) {
00265 case VEH_TRAIN:
00266 if (!IsTileDepotType(dp->xy, TRANSPORT_RAIL)) return CMD_ERROR;
00267 break;
00268
00269 case VEH_ROAD:
00270 if (!IsTileDepotType(dp->xy, TRANSPORT_ROAD)) return CMD_ERROR;
00271 break;
00272
00273 case VEH_SHIP:
00274 if (!IsTileDepotType(dp->xy, TRANSPORT_WATER)) return CMD_ERROR;
00275 break;
00276
00277 default: return CMD_ERROR;
00278 }
00279 }
00280
00281
00282
00283
00284 switch (new_order.flags) {
00285 case OFB_PART_OF_ORDERS:
00286 case OFB_PART_OF_ORDERS | OFB_HALT_IN_DEPOT:
00287 break;
00288
00289 case OFB_NON_STOP | OFB_PART_OF_ORDERS:
00290 case OFB_NON_STOP | OFB_PART_OF_ORDERS | OFB_HALT_IN_DEPOT:
00291 if (v->type != VEH_TRAIN) return CMD_ERROR;
00292 break;
00293
00294 default: return CMD_ERROR;
00295 }
00296 break;
00297 }
00298
00299 case OT_GOTO_WAYPOINT: {
00300 const Waypoint* wp;
00301
00302 if (v->type != VEH_TRAIN) return CMD_ERROR;
00303
00304 if (!IsValidWaypointID(new_order.dest)) return CMD_ERROR;
00305 wp = GetWaypoint(new_order.dest);
00306
00307 if (!CheckOwnership(GetTileOwner(wp->xy))) return CMD_ERROR;
00308
00309
00310
00311
00312 switch (new_order.flags) {
00313 case 0: break;
00314
00315 case OFB_NON_STOP:
00316 if (v->type != VEH_TRAIN) return CMD_ERROR;
00317 break;
00318
00319 default: return CMD_ERROR;
00320 }
00321 break;
00322 }
00323
00324 default: return CMD_ERROR;
00325 }
00326
00327 if (sel_ord > v->num_orders) return CMD_ERROR;
00328
00329 if (!HasOrderPoolFree(1)) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
00330
00331 if (v->type == VEH_SHIP && IsHumanPlayer(v->owner) && _patches.pathfinder_for_ships != VPF_NPF) {
00332
00333 const Order *prev = NULL;
00334 uint n = 0;
00335
00336
00337
00338
00339 for (const Order *o = v->orders; o != NULL; o = o->next) {
00340 if (o->type == OT_GOTO_STATION || o->type == OT_GOTO_DEPOT) prev = o;
00341 if (++n == sel_ord && prev != NULL) break;
00342 }
00343 if (prev != NULL) {
00344 uint dist = DistanceManhattan(
00345 GetOrderLocation(*prev),
00346 GetOrderLocation(new_order)
00347 );
00348 if (dist >= 130) {
00349 return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO);
00350 }
00351 }
00352 }
00353
00354 if (flags & DC_EXEC) {
00355 Vehicle *u;
00356 Order *new_o = new Order();
00357 AssignOrder(new_o, new_order);
00358
00359
00360 if (v->orders == NULL) {
00361 v->orders = new_o;
00362 } else {
00363
00364
00365 Order *order = GetVehicleOrder(v, sel_ord - 1);
00366
00367 if (order == NULL && GetVehicleOrder(v, sel_ord) != NULL) {
00368
00369
00370
00371
00372 SwapOrders(v->orders, new_o);
00373
00374 v->orders->next = new_o;
00375 } else if (order == NULL) {
00376
00377 order = GetLastVehicleOrder(v);
00378 order->next = new_o;
00379 } else {
00380
00381 new_o->next = order->next;
00382 order->next = new_o;
00383 }
00384 }
00385
00386 u = GetFirstVehicleFromSharedList(v);
00387 DeleteOrderWarnings(u);
00388 for (; u != NULL; u = u->next_shared) {
00389
00390 u->num_orders++;
00391
00392
00393 if (u->orders == NULL) u->orders = v->orders;
00394
00395 assert(v->orders == u->orders);
00396
00397
00398
00399 if (sel_ord <= u->cur_order_index) {
00400 uint cur = u->cur_order_index + 1;
00401
00402 if (cur < u->num_orders)
00403 u->cur_order_index = cur;
00404 }
00405
00406 InvalidateVehicleOrder(u);
00407 }
00408
00409
00410 RebuildVehicleLists();
00411 }
00412
00413 return CommandCost();
00414 }
00415
00420 static CommandCost DecloneOrder(Vehicle *dst, uint32 flags)
00421 {
00422 if (flags & DC_EXEC) {
00423 DeleteVehicleOrders(dst);
00424 InvalidateVehicleOrder(dst);
00425 RebuildVehicleLists();
00426 }
00427 return CommandCost();
00428 }
00429
00434 static void RemoveSharedOrderVehicleList(Vehicle *v)
00435 {
00436 assert(v->orders != NULL);
00437 WindowClass window_class = WC_NONE;
00438
00439 switch (v->type) {
00440 default: NOT_REACHED();
00441 case VEH_TRAIN: window_class = WC_TRAINS_LIST; break;
00442 case VEH_ROAD: window_class = WC_ROADVEH_LIST; break;
00443 case VEH_SHIP: window_class = WC_SHIPS_LIST; break;
00444 case VEH_AIRCRAFT: window_class = WC_AIRCRAFT_LIST; break;
00445 }
00446 DeleteWindowById(window_class, (v->orders->index << 16) | (v->type << 11) | VLW_SHARED_ORDERS | v->owner);
00447 }
00448
00455 CommandCost CmdDeleteOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00456 {
00457 Vehicle *v, *u;
00458 VehicleID veh_id = p1;
00459 VehicleOrderID sel_ord = p2;
00460 Order *order;
00461
00462 if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
00463
00464 v = GetVehicle(veh_id);
00465
00466 if (!CheckOwnership(v->owner)) return CMD_ERROR;
00467
00468
00469 if (sel_ord >= v->num_orders)
00470 return DecloneOrder(v, flags);
00471
00472 order = GetVehicleOrder(v, sel_ord);
00473 if (order == NULL) return CMD_ERROR;
00474
00475 if (flags & DC_EXEC) {
00476 if (GetVehicleOrder(v, sel_ord - 1) == NULL) {
00477 if (GetVehicleOrder(v, sel_ord + 1) != NULL) {
00478
00479
00480
00481 order = GetVehicleOrder(v, sel_ord + 1);
00482 SwapOrders(v->orders, order);
00483 } else {
00484
00485
00486
00487 RemoveSharedOrderVehicleList(v);
00488
00489 v->orders = NULL;
00490 }
00491 } else {
00492 GetVehicleOrder(v, sel_ord - 1)->next = order->next;
00493 }
00494
00495
00496 delete order;
00497
00498 u = GetFirstVehicleFromSharedList(v);
00499 DeleteOrderWarnings(u);
00500 for (; u != NULL; u = u->next_shared) {
00501 u->num_orders--;
00502
00503 if (sel_ord < u->cur_order_index)
00504 u->cur_order_index--;
00505
00506
00507
00508 if (v->orders == NULL) u->orders = NULL;
00509
00510 assert(v->orders == u->orders);
00511
00512
00513
00514 if (sel_ord == u->cur_order_index && u->current_order.type == OT_LOADING &&
00515 HasBit(u->current_order.flags, OF_NON_STOP)) {
00516 u->current_order.flags = 0;
00517 }
00518
00519
00520 InvalidateVehicleOrder(u);
00521 }
00522
00523 RebuildVehicleLists();
00524 }
00525
00526 return CommandCost();
00527 }
00528
00535 CommandCost CmdSkipToOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00536 {
00537 Vehicle *v;
00538 VehicleID veh_id = p1;
00539 VehicleOrderID sel_ord = p2;
00540
00541 if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
00542
00543 v = GetVehicle(veh_id);
00544
00545 if (!CheckOwnership(v->owner) || sel_ord == v->cur_order_index ||
00546 sel_ord >= v->num_orders || v->num_orders < 2) return CMD_ERROR;
00547
00548 if (flags & DC_EXEC) {
00549 v->cur_order_index = sel_ord;
00550
00551 if (v->type == VEH_ROAD) ClearSlot(v);
00552
00553 if (v->current_order.type == OT_LOADING) {
00554 v->LeaveStation();
00555
00556
00557 if (HasBit(v->current_order.flags, OF_NON_STOP)) v->current_order.flags = 0;
00558 }
00559
00560 InvalidateVehicleOrder(v);
00561 }
00562
00563
00564 if (v->type == VEH_AIRCRAFT) InvalidateWindowClasses(WC_AIRCRAFT_LIST);
00565 if (v->type == VEH_SHIP) InvalidateWindowClasses(WC_SHIPS_LIST);
00566
00567 return CommandCost();
00568 }
00569
00580 CommandCost CmdMoveOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00581 {
00582 VehicleID veh = p1;
00583 VehicleOrderID moving_order = GB(p2, 0, 16);
00584 VehicleOrderID target_order = GB(p2, 16, 16);
00585
00586 if (!IsValidVehicleID(veh)) return CMD_ERROR;
00587
00588 Vehicle *v = GetVehicle(veh);
00589 if (!CheckOwnership(v->owner)) return CMD_ERROR;
00590
00591
00592 if (moving_order >= v->num_orders || target_order >= v->num_orders ||
00593 moving_order == target_order || v->num_orders <= 1)
00594 return CMD_ERROR;
00595
00596 Order *moving_one = GetVehicleOrder(v, moving_order);
00597
00598 if (moving_one == NULL) return CMD_ERROR;
00599
00600 if (flags & DC_EXEC) {
00601
00602 Order *one_before = GetVehicleOrder(v, moving_order - 1);
00603 Order *one_past = GetVehicleOrder(v, moving_order + 1);
00604
00605 if (one_before == NULL) {
00606
00607 v->orders = moving_one->next;
00608 } else {
00609 one_before->next = moving_one->next;
00610 }
00611
00612
00613 one_before = GetVehicleOrder(v, target_order - 1);
00614 one_past = GetVehicleOrder(v, target_order);
00615
00616 moving_one->next = one_past;
00617
00618 if (one_before == NULL) {
00619
00620 SwapOrders(v->orders, moving_one);
00621 v->orders->next = moving_one;
00622 } else {
00623 one_before->next = moving_one;
00624 }
00625
00626
00627 Vehicle *u = GetFirstVehicleFromSharedList(v);
00628
00629 DeleteOrderWarnings(u);
00630
00631 for (; u != NULL; u = u->next_shared) {
00632
00633 if (u->orders != v->orders) u->orders = v->orders;
00634
00635
00636 if (u->cur_order_index == moving_order) {
00637 u->cur_order_index = target_order;
00638 } else if(u->cur_order_index > moving_order && u->cur_order_index <= target_order) {
00639 u->cur_order_index--;
00640 } else if(u->cur_order_index < moving_order && u->cur_order_index >= target_order) {
00641 u->cur_order_index++;
00642 }
00643
00644 assert(v->orders == u->orders);
00645
00646 InvalidateVehicleOrder(u);
00647 }
00648
00649
00650 RebuildVehicleLists();
00651 }
00652
00653 return CommandCost();
00654 }
00655
00666 CommandCost CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00667 {
00668 Vehicle *v;
00669 Order *order;
00670 VehicleOrderID sel_ord = GB(p1, 16, 16);
00671 VehicleID veh = GB(p1, 0, 16);
00672
00673 if (!IsValidVehicleID(veh)) return CMD_ERROR;
00674 if (p2 != OF_FULL_LOAD && p2 != OF_UNLOAD && p2 != OF_NON_STOP && p2 != OF_TRANSFER) return CMD_ERROR;
00675
00676 v = GetVehicle(veh);
00677
00678 if (!CheckOwnership(v->owner)) return CMD_ERROR;
00679
00680
00681 if (sel_ord >= v->num_orders) return CMD_ERROR;
00682
00683 order = GetVehicleOrder(v, sel_ord);
00684 if ((order->type != OT_GOTO_STATION || GetStation(order->dest)->IsBuoy()) &&
00685 (order->type != OT_GOTO_DEPOT || p2 == OF_UNLOAD) &&
00686 (order->type != OT_GOTO_WAYPOINT || p2 != OF_NON_STOP)) {
00687 return CMD_ERROR;
00688 }
00689
00690 if (flags & DC_EXEC) {
00691 switch (p2) {
00692 case OF_FULL_LOAD:
00693 ToggleBit(order->flags, OF_FULL_LOAD);
00694 if (order->type != OT_GOTO_DEPOT) ClrBit(order->flags, OF_UNLOAD);
00695 break;
00696 case OF_UNLOAD:
00697 ToggleBit(order->flags, OF_UNLOAD);
00698 ClrBit(order->flags, OF_FULL_LOAD);
00699 break;
00700 case OF_NON_STOP:
00701 ToggleBit(order->flags, OF_NON_STOP);
00702 break;
00703 case OF_TRANSFER:
00704 ToggleBit(order->flags, OF_TRANSFER);
00705 break;
00706 default: NOT_REACHED();
00707 }
00708
00709
00710 {
00711 Vehicle* u;
00712
00713 u = GetFirstVehicleFromSharedList(v);
00714 DeleteOrderWarnings(u);
00715 for (; u != NULL; u = u->next_shared) {
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725 if (sel_ord == u->cur_order_index &&
00726 u->current_order.type != OT_GOTO_DEPOT &&
00727 HasBit(u->current_order.flags, OF_FULL_LOAD) != HasBit(order->flags, OF_FULL_LOAD)) {
00728 ToggleBit(u->current_order.flags, OF_FULL_LOAD);
00729 }
00730 InvalidateVehicleOrder(u);
00731 }
00732 }
00733 }
00734
00735 return CommandCost();
00736 }
00737
00746 CommandCost CmdCloneOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00747 {
00748 Vehicle *dst;
00749 VehicleID veh_src = GB(p1, 16, 16);
00750 VehicleID veh_dst = GB(p1, 0, 16);
00751
00752 if (!IsValidVehicleID(veh_dst)) return CMD_ERROR;
00753
00754 dst = GetVehicle(veh_dst);
00755
00756 if (!CheckOwnership(dst->owner)) return CMD_ERROR;
00757
00758 switch (p2) {
00759 case CO_SHARE: {
00760 Vehicle *src;
00761
00762 if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
00763
00764 src = GetVehicle(veh_src);
00765
00766
00767 if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
00768 return CMD_ERROR;
00769
00770
00771 if (src->type == VEH_ROAD) {
00772 if (src->cargo_type != dst->cargo_type && (IsCargoInClass(src->cargo_type, CC_PASSENGERS) || IsCargoInClass(dst->cargo_type, CC_PASSENGERS)))
00773 return CMD_ERROR;
00774 }
00775
00776
00777 {
00778 const Vehicle* u;
00779
00780 for (u = GetFirstVehicleFromSharedList(src); u != NULL; u = u->next_shared) {
00781 if (u == dst) return CMD_ERROR;
00782 }
00783 }
00784
00785 if (flags & DC_EXEC) {
00786
00787 DeleteVehicleOrders(dst);
00788
00789 dst->orders = src->orders;
00790 dst->num_orders = src->num_orders;
00791
00792
00793 dst->next_shared = src->next_shared;
00794 dst->prev_shared = src;
00795 if (src->next_shared != NULL) src->next_shared->prev_shared = dst;
00796 src->next_shared = dst;
00797
00798 InvalidateVehicleOrder(dst);
00799 InvalidateVehicleOrder(src);
00800
00801 RebuildVehicleLists();
00802 }
00803 } break;
00804
00805 case CO_COPY: {
00806 Vehicle *src;
00807 int delta;
00808
00809 if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
00810
00811 src = GetVehicle(veh_src);
00812
00813
00814 if (!CheckOwnership(src->owner) || dst->type != src->type || dst == src)
00815 return CMD_ERROR;
00816
00817
00818 if (src->type == VEH_ROAD) {
00819 const Order *order;
00820 TileIndex required_dst = INVALID_TILE;
00821
00822 FOR_VEHICLE_ORDERS(src, order) {
00823 if (order->type == OT_GOTO_STATION) {
00824 const Station *st = GetStation(order->dest);
00825 if (IsCargoInClass(dst->cargo_type, CC_PASSENGERS)) {
00826 if (st->bus_stops != NULL) required_dst = st->bus_stops->xy;
00827 } else {
00828 if (st->truck_stops != NULL) required_dst = st->truck_stops->xy;
00829 }
00830
00831 if (required_dst == INVALID_TILE)
00832 return CMD_ERROR;
00833 }
00834 }
00835 }
00836
00837
00838 delta = dst->IsOrderListShared() ? src->num_orders + 1 : src->num_orders - dst->num_orders;
00839 if (!HasOrderPoolFree(delta))
00840 return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
00841
00842 if (flags & DC_EXEC) {
00843 const Order *order;
00844 Order **order_dst;
00845
00846
00847 DeleteVehicleOrders(dst);
00848
00849 order_dst = &dst->orders;
00850 FOR_VEHICLE_ORDERS(src, order) {
00851 *order_dst = new Order();
00852 AssignOrder(*order_dst, *order);
00853 order_dst = &(*order_dst)->next;
00854 }
00855
00856 dst->num_orders = src->num_orders;
00857
00858 InvalidateVehicleOrder(dst);
00859
00860 RebuildVehicleLists();
00861 }
00862 } break;
00863
00864 case CO_UNSHARE: return DecloneOrder(dst, flags);
00865 default: return CMD_ERROR;
00866 }
00867
00868 return CommandCost();
00869 }
00870
00880 CommandCost CmdOrderRefit(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00881 {
00882 const Vehicle *v;
00883 Order *order;
00884 VehicleID veh = GB(p1, 0, 16);
00885 VehicleOrderID order_number = GB(p2, 16, 8);
00886 CargoID cargo = GB(p2, 0, 8);
00887 byte subtype = GB(p2, 8, 8);
00888
00889 if (!IsValidVehicleID(veh)) return CMD_ERROR;
00890
00891 v = GetVehicle(veh);
00892
00893 if (!CheckOwnership(v->owner)) return CMD_ERROR;
00894
00895 order = GetVehicleOrder(v, order_number);
00896 if (order == NULL) return CMD_ERROR;
00897
00898 if (flags & DC_EXEC) {
00899 Vehicle *u;
00900
00901 order->refit_cargo = cargo;
00902 order->refit_subtype = subtype;
00903
00904 u = GetFirstVehicleFromSharedList(v);
00905 for (; u != NULL; u = u->next_shared) {
00906
00907 InvalidateVehicleOrder(u);
00908
00909
00910 if (u->cur_order_index == order_number && HasBit(u->current_order.flags, OF_PART_OF_ORDERS)) {
00911 u->current_order.refit_cargo = cargo;
00912 u->current_order.refit_subtype = subtype;
00913 }
00914 }
00915 }
00916
00917 return CommandCost();
00918 }
00919
00926 void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
00927 {
00928
00929 free(bak->order);
00930 bak->order = NULL;
00931 free(bak->name);
00932 bak->name = NULL;
00933
00934
00935 bak->orderindex = v->cur_order_index;
00936 bak->group = v->group_id;
00937 bak->service_interval = v->service_interval;
00938 if (v->name != NULL) bak->name = strdup(v->name);
00939
00940
00941 if (v->IsOrderListShared()) {
00942 const Vehicle *u = (v->next_shared) ? v->next_shared : v->prev_shared;
00943
00944 bak->clone = u->index;
00945 } else {
00946
00947
00948
00949 bak->clone = INVALID_VEHICLE;
00950
00951
00952
00953 uint cnt = 0;
00954 const Order *order;
00955 FOR_VEHICLE_ORDERS(v, order) cnt++;
00956
00957
00958 bak->order = MallocT<Order>(cnt + 1);
00959
00960 Order *dest = bak->order;
00961
00962
00963 FOR_VEHICLE_ORDERS(v, order) {
00964 *dest = *order;
00965 dest++;
00966 }
00967
00968 dest->Free();
00969 }
00970 }
00971
00977 void RestoreVehicleOrders(const Vehicle *v, const BackuppedOrders *bak)
00978 {
00979
00980 if (bak->name != NULL) {
00981 _cmd_text = bak->name;
00982 DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
00983 }
00984
00985
00986 if (bak->clone != INVALID_VEHICLE) {
00987 DoCommandP(0, v->index | (bak->clone << 16), CO_SHARE, NULL, CMD_CLONE_ORDER);
00988 } else {
00989
00990
00991
00992
00993
00994 for (uint i = 0; bak->order[i].IsValid(); i++) {
00995 if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL,
00996 CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
00997 break;
00998 }
00999
01000
01001 if (_patches.timetabling && !DoCommandP(0, v->index | (i << 16) | (1 << 25),
01002 bak->order[i].wait_time << 16 | bak->order[i].travel_time, NULL,
01003 CMD_CHANGE_TIMETABLE | CMD_NO_TEST_IF_IN_NETWORK)) {
01004 break;
01005 }
01006 }
01007 }
01008
01009
01010 DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , NULL, CMD_RESTORE_ORDER_INDEX);
01011
01012
01013 DoCommandP(0, bak->group, v->index, NULL, CMD_ADD_VEHICLE_GROUP);
01014 }
01015
01030 CommandCost CmdRestoreOrderIndex(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
01031 {
01032 Vehicle *v;
01033 VehicleOrderID cur_ord = GB(p2, 0, 16);
01034 uint16 serv_int = GB(p2, 16, 16);
01035
01036 if (!IsValidVehicleID(p1)) return CMD_ERROR;
01037
01038 v = GetVehicle(p1);
01039
01040
01041 if (!CheckOwnership(v->owner)) return CMD_ERROR;
01042 if (serv_int != GetServiceIntervalClamped(serv_int) || cur_ord >= v->num_orders) return CMD_ERROR;
01043
01044 if (flags & DC_EXEC) {
01045 v->cur_order_index = cur_ord;
01046 v->service_interval = serv_int;
01047 }
01048
01049 return CommandCost();
01050 }
01051
01052
01053 static TileIndex GetStationTileForVehicle(const Vehicle* v, const Station* st)
01054 {
01055 switch (v->type) {
01056 default: NOT_REACHED();
01057 case VEH_TRAIN: return st->train_tile;
01058 case VEH_AIRCRAFT: return CanAircraftUseStation(v->engine_type, st) ? st->airport_tile : 0;
01059 case VEH_SHIP: return st->dock_tile;
01060 case VEH_ROAD:
01061 if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
01062 return (st->bus_stops != NULL) ? st->bus_stops->xy : 0;
01063 } else {
01064 return (st->truck_stops != NULL) ? st->truck_stops->xy : 0;
01065 }
01066 }
01067 }
01068
01069
01075 void CheckOrders(const Vehicle* v)
01076 {
01077
01078 if (_patches.order_review_system == 0) return;
01079
01080
01081 if (v->vehstatus & VS_CRASHED) return;
01082
01083
01084 if (_patches.order_review_system == 1 && v->vehstatus & VS_STOPPED)
01085 return;
01086
01087
01088 if (v->next_shared != NULL) return;
01089
01090
01091 if (v->owner == _local_player && v->day_counter % 20 == 0) {
01092 int n_st, problem_type = -1;
01093 const Order *order;
01094 int message = 0;
01095
01096
01097 n_st = 0;
01098
01099 FOR_VEHICLE_ORDERS(v, order) {
01100
01101 if (order->type == OT_DUMMY) {
01102 problem_type = 1;
01103 break;
01104 }
01105
01106 if (order->type == OT_GOTO_STATION) {
01107 const Station* st = GetStation(order->dest);
01108 TileIndex required_tile = GetStationTileForVehicle(v, st);
01109
01110 n_st++;
01111 if (required_tile == 0) problem_type = 3;
01112 }
01113 }
01114
01115
01116 if (v->num_orders > 1) {
01117 const Order* last = GetLastVehicleOrder(v);
01118
01119 if (v->orders->type == last->type &&
01120 v->orders->flags == last->flags &&
01121 v->orders->dest == last->dest) {
01122 problem_type = 2;
01123 }
01124 }
01125
01126
01127 if (n_st < 2 && problem_type == -1) problem_type = 0;
01128
01129
01130 if (problem_type < 0) return;
01131
01132 message = STR_TRAIN_HAS_TOO_FEW_ORDERS + (v->type << 2) + problem_type;
01133
01134
01135 SetDParam(0, v->unitnumber);
01136 AddNewsItem(
01137 message,
01138 NEWS_FLAGS(NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, 0),
01139 v->index,
01140 0
01141 );
01142 }
01143 }
01144
01150 void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
01151 {
01152 Vehicle *v;
01153
01154
01155
01156
01157
01158
01159 FOR_ALL_VEHICLES(v) {
01160 Order *order;
01161 bool invalidate;
01162
01163
01164 if (v->last_station_visited == destination && type == OT_GOTO_STATION) {
01165 v->last_station_visited = INVALID_STATION;
01166 }
01167
01168 order = &v->current_order;
01169 if ((v->type == VEH_AIRCRAFT && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
01170 v->current_order.dest == destination) {
01171 order->type = OT_DUMMY;
01172 order->flags = 0;
01173 InvalidateWindow(WC_VEHICLE_VIEW, v->index);
01174 }
01175
01176
01177 invalidate = false;
01178 FOR_VEHICLE_ORDERS(v, order) {
01179 if ((v->type == VEH_AIRCRAFT && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
01180 order->dest == destination) {
01181 order->type = OT_DUMMY;
01182 order->flags = 0;
01183 invalidate = true;
01184 }
01185 }
01186
01187
01188 if (invalidate) {
01189 for (const Vehicle *w = GetFirstVehicleFromSharedList(v); w != NULL; w = w->next_shared) {
01190 InvalidateVehicleOrder(w);
01191 }
01192 }
01193 }
01194 }
01195
01203 bool VehicleHasDepotOrders(const Vehicle *v)
01204 {
01205 const Order *order;
01206
01207 FOR_VEHICLE_ORDERS(v, order) {
01208 if (order->type == OT_GOTO_DEPOT)
01209 return true;
01210 }
01211
01212 return false;
01213 }
01214
01220 void DeleteVehicleOrders(Vehicle *v)
01221 {
01222 DeleteOrderWarnings(v);
01223
01224
01225
01226 if (v->IsOrderListShared()) {
01227 Vehicle *u = v;
01228
01229 v->orders = NULL;
01230 v->num_orders = 0;
01231
01232
01233 if (v->prev_shared != NULL) {
01234 v->prev_shared->next_shared = v->next_shared;
01235 u = v->prev_shared;
01236 }
01237 if (v->next_shared != NULL) {
01238 v->next_shared->prev_shared = v->prev_shared;
01239 u = v->next_shared;
01240 }
01241 v->prev_shared = NULL;
01242 v->next_shared = NULL;
01243
01244
01245
01246 if (u->prev_shared == NULL && u->next_shared == NULL && u->orders != NULL) RemoveSharedOrderVehicleList(u);
01247
01248
01249
01250
01251
01252
01253 InvalidateVehicleOrder(u);
01254 return;
01255 }
01256
01257
01258 Order *cur = v->orders;
01259
01260 if (cur != NULL) RemoveSharedOrderVehicleList(v);
01261 v->orders = NULL;
01262 v->num_orders = 0;
01263
01264 if (cur != NULL) {
01265 cur->FreeChain();
01266 }
01267 }
01268
01269 Date GetServiceIntervalClamped(uint index)
01270 {
01271 return (_patches.servint_ispercent) ? Clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
01272 }
01273
01274
01282 bool CheckForValidOrders(const Vehicle* v)
01283 {
01284 const Order *order;
01285
01286 FOR_VEHICLE_ORDERS(v, order) if (order->type != OT_DUMMY) return true;
01287
01288 return false;
01289 }
01290
01291 void InitializeOrders()
01292 {
01293 _Order_pool.CleanPool();
01294 _Order_pool.AddBlockToPool();
01295
01296 _backup_orders_tile = 0;
01297 }
01298
01299 static const SaveLoad _order_desc[] = {
01300 SLE_VAR(Order, type, SLE_UINT8),
01301 SLE_VAR(Order, flags, SLE_UINT8),
01302 SLE_VAR(Order, dest, SLE_UINT16),
01303 SLE_REF(Order, next, REF_ORDER),
01304 SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, 36, SL_MAX_VERSION),
01305 SLE_CONDVAR(Order, refit_subtype, SLE_UINT8, 36, SL_MAX_VERSION),
01306 SLE_CONDVAR(Order, wait_time, SLE_UINT16, 67, SL_MAX_VERSION),
01307 SLE_CONDVAR(Order, travel_time, SLE_UINT16, 67, SL_MAX_VERSION),
01308
01309
01310
01311 SLE_CONDNULL(10, 5, 35),
01312 SLE_END()
01313 };
01314
01315 static void Save_ORDR()
01316 {
01317 Order *order;
01318
01319 FOR_ALL_ORDERS(order) {
01320 SlSetArrayIndex(order->index);
01321 SlObject(order, _order_desc);
01322 }
01323 }
01324
01325 static void Load_ORDR()
01326 {
01327 if (CheckSavegameVersionOldStyle(5, 2)) {
01328
01329
01330 uint len = SlGetFieldLength();
01331 uint i;
01332
01333 if (CheckSavegameVersion(5)) {
01334
01335
01336 len /= sizeof(uint16);
01337 uint16 *orders = MallocT<uint16>(len + 1);
01338
01339 SlArray(orders, len, SLE_UINT16);
01340
01341 for (i = 0; i < len; ++i) {
01342 Order *order = new (i) Order();
01343 AssignOrder(order, UnpackVersion4Order(orders[i]));
01344 }
01345
01346 free(orders);
01347 } else if (CheckSavegameVersionOldStyle(5, 2)) {
01348 len /= sizeof(uint16);
01349 uint16 *orders = MallocT<uint16>(len + 1);
01350
01351 SlArray(orders, len, SLE_UINT32);
01352
01353 for (i = 0; i < len; ++i) {
01354 Order *order = new (i) Order();
01355 AssignOrder(order, UnpackOrder(orders[i]));
01356 }
01357
01358 free(orders);
01359 }
01360
01361
01362 for (i = 1; i < len; ++i) {
01363
01364
01365
01366 if (GetOrder(i)->IsValid())
01367 GetOrder(i - 1)->next = GetOrder(i);
01368 }
01369 } else {
01370 int index;
01371
01372 while ((index = SlIterateArray()) != -1) {
01373 Order *order = new (index) Order();
01374 SlObject(order, _order_desc);
01375 }
01376 }
01377 }
01378
01379 extern const ChunkHandler _order_chunk_handlers[] = {
01380 { 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY | CH_LAST},
01381 };