--- a/src/order_cmd.cpp Mon Apr 14 20:32:36 2008 +0000
+++ b/src/order_cmd.cpp Tue Apr 15 00:47:19 2008 +0000
@@ -4,14 +4,14 @@
#include "stdafx.h"
#include "openttd.h"
-#include "order.h"
+#include "order_base.h"
+#include "order_func.h"
#include "airport.h"
#include "depot.h"
#include "waypoint.h"
#include "command_func.h"
-#include "station.h"
#include "player_func.h"
-#include "news.h"
+#include "news_func.h"
#include "saveload.h"
#include "vehicle_gui.h"
#include "cargotype.h"
@@ -22,41 +22,139 @@
#include "window_func.h"
#include "settings_type.h"
#include "string_func.h"
+#include "newgrf_cargo.h"
+#include "timetable.h"
+#include "vehicle_func.h"
+#include "oldpool_func.h"
#include "table/strings.h"
+/* DestinationID must be at least as large as every these below, because it can
+ * be any of them
+ */
+assert_compile(sizeof(DestinationID) >= sizeof(DepotID));
+assert_compile(sizeof(DestinationID) >= sizeof(WaypointID));
+assert_compile(sizeof(DestinationID) >= sizeof(StationID));
+
TileIndex _backup_orders_tile;
BackuppedOrders _backup_orders_data;
-DEFINE_OLD_POOL_GENERIC(Order, Order)
+DEFINE_OLD_POOL_GENERIC(Order, Order);
-/**
- *
- * Unpacks a order from savegames made with TTD(Patch)
- *
- */
-Order UnpackOldOrder(uint16 packed)
+OrderLoadFlags Order::GetLoadType() const
{
- Order order;
- order.type = (OrderType)GB(packed, 0, 4);
- order.flags = GB(packed, 4, 4);
- order.dest = GB(packed, 8, 8);
- order.next = NULL;
+ if ((this->flags & OLFB_FULL_LOAD) == 0) return OLF_LOAD_IF_POSSIBLE;
+ return _patches.full_load_any ? OLF_FULL_LOAD_ANY : OLFB_FULL_LOAD;
+}
- order.refit_cargo = CT_NO_REFIT;
- order.refit_subtype = 0;
- order.wait_time = 0;
- order.travel_time = 0;
- order.index = 0; // avoid compiler warning
-
- // Sanity check
- // TTD stores invalid orders as OT_NOTHING with non-zero flags/station
- if (!order.IsValid() && (order.flags != 0 || order.dest != 0)) {
- order.type = OT_DUMMY;
- order.flags = 0;
+OrderNonStopFlags Order::GetNonStopType() const
+{
+ if (_patches.new_nonstop) {
+ return (this->flags & 0x08) ? ONSF_NO_STOP_AT_ANY_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS;
}
- return order;
+ return (this->flags & 0x08) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE;
+}
+
+void Order::Free()
+{
+ this->type = OT_NOTHING;
+ this->flags = 0;
+ this->dest = 0;
+ this->next = NULL;
+}
+
+void Order::MakeGoToStation(StationID destination)
+{
+ this->type = OT_GOTO_STATION;
+ this->flags = 0;
+ this->dest = destination;
+}
+
+void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, CargoID cargo, byte subtype)
+{
+ this->type = OT_GOTO_DEPOT;
+ this->flags = 0;
+ this->SetDepotOrderType(order);
+ if (!(order & ODTFB_PART_OF_ORDERS)) {
+ this->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
+ }
+ this->dest = destination;
+ this->SetRefit(cargo, subtype);
+}
+
+void Order::MakeGoToWaypoint(WaypointID destination)
+{
+ this->type = OT_GOTO_WAYPOINT;
+ this->flags = 0;
+ this->dest = destination;
+}
+
+void Order::MakeLoading(bool ordered)
+{
+ this->type = OT_LOADING;
+ if (!ordered) this->flags = 0;
+}
+
+void Order::MakeLeaveStation()
+{
+ this->type = OT_LEAVESTATION;
+ this->flags = 0;
+}
+
+void Order::MakeDummy()
+{
+ this->type = OT_DUMMY;
+ this->flags = 0;
+}
+
+void Order::SetRefit(CargoID cargo, byte subtype)
+{
+ this->refit_cargo = cargo;
+ this->refit_subtype = subtype;
+}
+
+void Order::FreeChain()
+{
+ if (next != NULL) next->FreeChain();
+ delete this;
+}
+
+bool Order::Equals(const Order &other) const
+{
+ return
+ this->type == other.type &&
+ this->flags == other.flags &&
+ this->dest == other.dest;
+}
+
+static bool HasOrderPoolFree(uint amount)
+{
+ const Order *order;
+
+ /* There is always room if not all blocks in the pool are reserved */
+ if (_Order_pool.CanAllocateMoreBlocks()) return true;
+
+ FOR_ALL_ORDERS(order) if (!order->IsValid() && --amount == 0) return true;
+
+ return false;
+}
+
+uint32 Order::Pack() const
+{
+ return this->dest << 16 | this->flags << 8 | this->type;
+}
+
+Order::Order(uint32 packed)
+{
+ this->type = (OrderType)GB(packed, 0, 8);
+ this->flags = GB(packed, 8, 8);
+ this->dest = GB(packed, 16, 16);
+ this->next = NULL;
+ this->refit_cargo = CT_NO_REFIT;
+ this->refit_subtype = 0;
+ this->wait_time = 0;
+ this->travel_time = 0;
}
/**
@@ -66,16 +164,26 @@
*/
static Order UnpackVersion4Order(uint16 packed)
{
- Order order;
- order.type = (OrderType)GB(packed, 0, 4);
- order.flags = GB(packed, 4, 4);
- order.dest = GB(packed, 8, 8);
- order.next = NULL;
- order.index = 0; // avoid compiler warning
- order.refit_cargo = CT_NO_REFIT;
- order.refit_subtype = 0;
- order.wait_time = 0;
- order.travel_time = 0;
+ return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4));
+}
+
+/**
+ *
+ * Unpacks a order from savegames made with TTD(Patch)
+ *
+ */
+Order UnpackOldOrder(uint16 packed)
+{
+ Order order = UnpackVersion4Order(packed);
+
+ /*
+ * Sanity check
+ * TTD stores invalid orders as OT_NOTHING with non-zero flags/station
+ */
+ if (!order.IsValid() && (order.GetLoadType() != 0 || order.GetUnloadType() != 0 || order.GetDestination() != 0)) {
+ order.MakeDummy();
+ }
+
return order;
}
@@ -101,9 +209,9 @@
Order temp_order;
temp_order = *order1;
- AssignOrder(order1, *order2);
+ order1->AssignOrder(*order2);
order1->next = order2->next;
- AssignOrder(order2, temp_order);
+ order2->AssignOrder(temp_order);
order2->next = temp_order.next;
}
@@ -113,17 +221,17 @@
* This function makes sure that the index is maintained correctly
*
*/
-void AssignOrder(Order *order, Order data)
+void Order::AssignOrder(const Order &other)
{
- order->type = data.type;
- order->flags = data.flags;
- order->dest = data.dest;
+ this->type = other.type;
+ this->flags = other.flags;
+ this->dest = other.dest;
- order->refit_cargo = data.refit_cargo;
- order->refit_subtype = data.refit_subtype;
+ this->refit_cargo = other.refit_cargo;
+ this->refit_subtype = other.refit_subtype;
- order->wait_time = data.wait_time;
- order->travel_time = data.travel_time;
+ this->wait_time = other.wait_time;
+ this->travel_time = other.travel_time;
}
@@ -144,10 +252,10 @@
static TileIndex GetOrderLocation(const Order& o)
{
- switch (o.type) {
+ switch (o.GetType()) {
default: NOT_REACHED();
- case OT_GOTO_STATION: return GetStation(o.dest)->xy;
- case OT_GOTO_DEPOT: return GetDepot(o.dest)->xy;
+ case OT_GOTO_STATION: return GetStation(o.GetDestination())->xy;
+ case OT_GOTO_DEPOT: return GetDepot(o.GetDestination())->xy;
}
}
@@ -167,7 +275,7 @@
Vehicle *v;
VehicleID veh = GB(p1, 0, 16);
VehicleOrderID sel_ord = GB(p1, 16, 16);
- Order new_order = UnpackOrder(p2);
+ Order new_order(p2);
if (!IsValidVehicleID(veh)) return CMD_ERROR;
@@ -177,12 +285,11 @@
/* Check if the inserted order is to the correct destination (owner, type),
* and has the correct flags if any */
- switch (new_order.type) {
+ switch (new_order.GetType()) {
case OT_GOTO_STATION: {
- const Station *st;
+ if (!IsValidStationID(new_order.GetDestination())) return CMD_ERROR;
- if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
- st = GetStation(new_order.dest);
+ const Station *st = GetStation(new_order.GetDestination());
if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) {
return CMD_ERROR;
@@ -214,38 +321,26 @@
default: return CMD_ERROR;
}
- /* Order flags can be any of the following for stations:
- * [full-load | unload] [+ transfer] [+ non-stop]
- * non-stop orders (if any) are only valid for trains */
- switch (new_order.flags) {
- case 0:
- case OFB_FULL_LOAD:
- case OFB_FULL_LOAD | OFB_TRANSFER:
- case OFB_UNLOAD:
- case OFB_UNLOAD | OFB_TRANSFER:
- case OFB_TRANSFER:
- break;
+ /* Non stop not allowed for non-trains. */
+ // TODO: implement properly once savegame bump is done. if ((new_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) != 0 && v->type != VEH_TRAIN) return CMD_ERROR;
- case OFB_NON_STOP:
- case OFB_NON_STOP | OFB_FULL_LOAD:
- case OFB_NON_STOP | OFB_FULL_LOAD | OFB_TRANSFER:
- case OFB_NON_STOP | OFB_UNLOAD:
- case OFB_NON_STOP | OFB_UNLOAD | OFB_TRANSFER:
- case OFB_NON_STOP | OFB_TRANSFER:
- if (v->type != VEH_TRAIN) return CMD_ERROR;
- break;
+ /* Full load and unload are mutual exclusive. */
+ if ((new_order.GetLoadType() & OLFB_FULL_LOAD) && (new_order.GetUnloadType() & OUFB_UNLOAD)) return CMD_ERROR;
+ /* Filter invalid load/unload types. */
+ switch (new_order.GetLoadType()) {
+ case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: break;
default: return CMD_ERROR;
}
+ if (new_order.GetUnloadType() & ~(OUFB_UNLOAD | OUFB_TRANSFER)) return CMD_ERROR;
break;
}
case OT_GOTO_DEPOT: {
if (v->type == VEH_AIRCRAFT) {
- const Station* st;
+ if (!IsValidStationID(new_order.GetDestination())) return CMD_ERROR;
- if (!IsValidStationID(new_order.dest)) return CMD_ERROR;
- st = GetStation(new_order.dest);
+ const Station *st = GetStation(new_order.GetDestination());
if (!CheckOwnership(st->owner) ||
!(st->facilities & FACIL_AIRPORT) ||
@@ -254,10 +349,9 @@
return CMD_ERROR;
}
} else {
- const Depot* dp;
+ if (!IsValidDepotID(new_order.GetDestination())) return CMD_ERROR;
- if (!IsValidDepotID(new_order.dest)) return CMD_ERROR;
- dp = GetDepot(new_order.dest);
+ const Depot *dp = GetDepot(new_order.GetDestination());
if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
@@ -278,46 +372,26 @@
}
}
- /* Order flags can be any of the following for depots:
- * order [+ halt] [+ non-stop]
- * non-stop orders (if any) are only valid for trains */
- switch (new_order.flags) {
- case OFB_PART_OF_ORDERS:
- case OFB_PART_OF_ORDERS | OFB_HALT_IN_DEPOT:
- break;
-
- case OFB_NON_STOP | OFB_PART_OF_ORDERS:
- case OFB_NON_STOP | OFB_PART_OF_ORDERS | OFB_HALT_IN_DEPOT:
- if (v->type != VEH_TRAIN) return CMD_ERROR;
- break;
-
- default: return CMD_ERROR;
- }
+ // TODO: implement properly once savegame bump is done. if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
+ if (new_order.GetDepotOrderType() & ~ODTFB_PART_OF_ORDERS) return CMD_ERROR;
+ if (new_order.GetDepotActionType() & ~ODATFB_HALT) return CMD_ERROR;
break;
}
case OT_GOTO_WAYPOINT: {
- const Waypoint* wp;
if (v->type != VEH_TRAIN) return CMD_ERROR;
- if (!IsValidWaypointID(new_order.dest)) return CMD_ERROR;
- wp = GetWaypoint(new_order.dest);
+ if (!IsValidWaypointID(new_order.GetDestination())) return CMD_ERROR;
+ const Waypoint *wp = GetWaypoint(new_order.GetDestination());
if (!CheckOwnership(GetTileOwner(wp->xy))) return CMD_ERROR;
/* Order flags can be any of the following for waypoints:
* [non-stop]
* non-stop orders (if any) are only valid for trains */
- switch (new_order.flags) {
- case 0: break;
+ // TODO: implement properly once savegame bump is done. if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
- case OFB_NON_STOP:
- if (v->type != VEH_TRAIN) return CMD_ERROR;
- break;
-
- default: return CMD_ERROR;
- }
break;
}
@@ -337,7 +411,7 @@
* If the order is to be inserted at the beginning of the order list this
* finds the last order in the list. */
for (const Order *o = v->orders; o != NULL; o = o->next) {
- if (o->type == OT_GOTO_STATION || o->type == OT_GOTO_DEPOT) prev = o;
+ if (o->IsType(OT_GOTO_STATION) || o->IsType(OT_GOTO_DEPOT)) prev = o;
if (++n == sel_ord && prev != NULL) break;
}
if (prev != NULL) {
@@ -354,7 +428,7 @@
if (flags & DC_EXEC) {
Vehicle *u;
Order *new_o = new Order();
- AssignOrder(new_o, new_order);
+ new_o->AssignOrder(new_order);
/* Create new order and link in list */
if (v->orders == NULL) {
@@ -511,9 +585,8 @@
/* NON-stop flag is misused to see if a train is in a station that is
* on his order list or not */
- if (sel_ord == u->cur_order_index && u->current_order.type == OT_LOADING &&
- HasBit(u->current_order.flags, OF_NON_STOP)) {
- u->current_order.flags = 0;
+ if (sel_ord == u->cur_order_index && u->current_order.IsType(OT_LOADING)) {
+ u->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
}
/* Update any possible open window of the vehicle */
@@ -550,12 +623,7 @@
if (v->type == VEH_ROAD) ClearSlot(v);
- if (v->current_order.type == OT_LOADING) {
- v->LeaveStation();
- /* NON-stop flag is misused to see if a train is in a station that is
- * on his order list or not */
- if (HasBit(v->current_order.flags, OF_NON_STOP)) v->current_order.flags = 0;
- }
+ if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
InvalidateVehicleOrder(v);
}
@@ -661,74 +729,112 @@
* - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given,
* the order will be inserted before that one
* only the first 8 bits used currently (bit 16 - 23) (max 255)
- * @param p2 mode to change the order to (always set)
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit 0 - 1) - what data to modify (@see ModifyOrderFlags)
+ * - p2 = (bit 2 - 5) - the data to modify
*/
CommandCost CmdModifyOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
- Vehicle *v;
- Order *order;
VehicleOrderID sel_ord = GB(p1, 16, 16); // XXX - automatically truncated to 8 bits.
- VehicleID veh = GB(p1, 0, 16);
+ VehicleID veh = GB(p1, 0, 16);
+ ModifyOrderFlags mof = (ModifyOrderFlags)GB(p2, 0, 2);
+ uint8 data = GB(p2, 2, 4);
if (!IsValidVehicleID(veh)) return CMD_ERROR;
- if (p2 != OF_FULL_LOAD && p2 != OF_UNLOAD && p2 != OF_NON_STOP && p2 != OF_TRANSFER) return CMD_ERROR;
- v = GetVehicle(veh);
-
+ Vehicle *v = GetVehicle(veh);
if (!CheckOwnership(v->owner)) return CMD_ERROR;
/* Is it a valid order? */
if (sel_ord >= v->num_orders) return CMD_ERROR;
- order = GetVehicleOrder(v, sel_ord);
- if ((order->type != OT_GOTO_STATION || GetStation(order->dest)->IsBuoy()) &&
- (order->type != OT_GOTO_DEPOT || p2 == OF_UNLOAD) &&
- (order->type != OT_GOTO_WAYPOINT || p2 != OF_NON_STOP)) {
- return CMD_ERROR;
+ Order *order = GetVehicleOrder(v, sel_ord);
+ switch (order->GetType()) {
+ case OT_GOTO_STATION:
+ if (mof == MOF_DEPOT_ACTION || GetStation(order->GetDestination())->IsBuoy()) return CMD_ERROR;
+ break;
+
+ case OT_GOTO_DEPOT:
+ if (mof == MOF_UNLOAD || mof == MOF_LOAD) return CMD_ERROR;
+ break;
+
+ case OT_GOTO_WAYPOINT:
+ if (mof != MOF_NON_STOP) return CMD_ERROR;
+ break;
+
+ default:
+ return CMD_ERROR;
+ }
+
+ switch (mof) {
+ case MOF_NON_STOP:
+ if (data >= ONSF_END) return CMD_ERROR;
+ if (data == order->GetNonStopType()) return CMD_ERROR;
+ break;
+
+ case MOF_UNLOAD:
+ if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER)) != 0) return CMD_ERROR;
+ if (data == order->GetUnloadType()) return CMD_ERROR;
+ break;
+
+ case MOF_LOAD:
+ if ((data & ~OLFB_FULL_LOAD) != 0) return CMD_ERROR;
+ if (data == order->GetLoadType()) return CMD_ERROR;
+ break;
+
+ case MOF_DEPOT_ACTION:
+ if (data != 0) return CMD_ERROR;
+ break;
}
if (flags & DC_EXEC) {
- switch (p2) {
- case OF_FULL_LOAD:
- ToggleBit(order->flags, OF_FULL_LOAD);
- if (order->type != OT_GOTO_DEPOT) ClrBit(order->flags, OF_UNLOAD);
- break;
- case OF_UNLOAD:
- ToggleBit(order->flags, OF_UNLOAD);
- ClrBit(order->flags, OF_FULL_LOAD);
- break;
- case OF_NON_STOP:
- ToggleBit(order->flags, OF_NON_STOP);
- break;
- case OF_TRANSFER:
- ToggleBit(order->flags, OF_TRANSFER);
- break;
- default: NOT_REACHED();
+ switch (mof) {
+ case MOF_NON_STOP:
+ order->SetNonStopType((OrderNonStopFlags)data);
+ break;
+
+ case MOF_UNLOAD:
+ order->SetUnloadType((OrderUnloadFlags)data);
+ /* Full loading gets disabled when un loading! */
+ if ((data & OUFB_UNLOAD) != 0) {
+ order->SetLoadType((OrderLoadFlags)(order->GetLoadType() & ~(OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)));
+ }
+ break;
+
+ case MOF_LOAD:
+ order->SetLoadType((OrderLoadFlags)data);
+ /* Unloading gets disabled when full loading! */
+ if ((data & OLFB_FULL_LOAD) != 0) {
+ order->SetUnloadType((OrderUnloadFlags)(order->GetUnloadType() & ~OUFB_UNLOAD));
+ }
+ break;
+
+ case MOF_DEPOT_ACTION:
+ order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() ^ ODTFB_SERVICE));
+ break;
+
+ default: NOT_REACHED();
}
/* Update the windows and full load flags, also for vehicles that share the same order list */
- {
- Vehicle* u;
-
- u = GetFirstVehicleFromSharedList(v);
- DeleteOrderWarnings(u);
- for (; u != NULL; u = u->next_shared) {
- /* Toggle u->current_order "Full load" flag if it changed.
- * However, as the same flag is used for depot orders, check
- * whether we are not going to a depot as there are three
- * cases where the full load flag can be active and only
- * one case where the flag is used for depot orders. In the
- * other cases for the OrderTypeByte the flags are not used,
- * so do not care and those orders should not be active
- * when this function is called.
- */
- if (sel_ord == u->cur_order_index &&
- u->current_order.type != OT_GOTO_DEPOT &&
- HasBit(u->current_order.flags, OF_FULL_LOAD) != HasBit(order->flags, OF_FULL_LOAD)) {
- ToggleBit(u->current_order.flags, OF_FULL_LOAD);
- }
- InvalidateVehicleOrder(u);
+ Vehicle *u = GetFirstVehicleFromSharedList(v);
+ DeleteOrderWarnings(u);
+ for (; u != NULL; u = u->next_shared) {
+ /* Toggle u->current_order "Full load" flag if it changed.
+ * However, as the same flag is used for depot orders, check
+ * whether we are not going to a depot as there are three
+ * cases where the full load flag can be active and only
+ * one case where the flag is used for depot orders. In the
+ * other cases for the OrderTypeByte the flags are not used,
+ * so do not care and those orders should not be active
+ * when this function is called.
+ */
+ if (sel_ord == u->cur_order_index &&
+ (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) &&
+ u->current_order.GetLoadType() != order->GetLoadType()) {
+ u->current_order.SetLoadType(order->GetLoadType());
}
+ InvalidateVehicleOrder(u);
}
}
@@ -820,8 +926,8 @@
TileIndex required_dst = INVALID_TILE;
FOR_VEHICLE_ORDERS(src, order) {
- if (order->type == OT_GOTO_STATION) {
- const Station *st = GetStation(order->dest);
+ if (order->IsType(OT_GOTO_STATION)) {
+ const Station *st = GetStation(order->GetDestination());
if (IsCargoInClass(dst->cargo_type, CC_PASSENGERS)) {
if (st->bus_stops != NULL) required_dst = st->bus_stops->xy;
} else {
@@ -849,7 +955,7 @@
order_dst = &dst->orders;
FOR_VEHICLE_ORDERS(src, order) {
*order_dst = new Order();
- AssignOrder(*order_dst, *order);
+ (*order_dst)->AssignOrder(*order);
order_dst = &(*order_dst)->next;
}
@@ -898,8 +1004,7 @@
if (flags & DC_EXEC) {
Vehicle *u;
- order->refit_cargo = cargo;
- order->refit_subtype = subtype;
+ order->SetRefit(cargo, subtype);
u = GetFirstVehicleFromSharedList(v);
for (; u != NULL; u = u->next_shared) {
@@ -907,9 +1012,8 @@
InvalidateVehicleOrder(u);
/* If the vehicle already got the current depot set as current order, then update current order as well */
- if (u->cur_order_index == order_number && HasBit(u->current_order.flags, OF_PART_OF_ORDERS)) {
- u->current_order.refit_cargo = cargo;
- u->current_order.refit_subtype = subtype;
+ if (u->cur_order_index == order_number && u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
+ u->current_order.SetRefit(cargo, subtype);
}
}
}
@@ -992,7 +1096,7 @@
* in network the commands are queued before send, the second insert always
* fails in test mode. By bypassing the test-mode, that no longer is a problem. */
for (uint i = 0; bak->order[i].IsValid(); i++) {
- if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL,
+ if (!DoCommandP(0, v->index + (i << 16), bak->order[i].Pack(), NULL,
CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) {
break;
}
@@ -1098,13 +1202,13 @@
FOR_VEHICLE_ORDERS(v, order) {
/* Dummy order? */
- if (order->type == OT_DUMMY) {
+ if (order->IsType(OT_DUMMY)) {
problem_type = 1;
break;
}
/* Does station have a load-bay for this vehicle? */
- if (order->type == OT_GOTO_STATION) {
- const Station* st = GetStation(order->dest);
+ if (order->IsType(OT_GOTO_STATION)) {
+ const Station* st = GetStation(order->GetDestination());
TileIndex required_tile = GetStationTileForVehicle(v, st);
n_st++;
@@ -1116,9 +1220,7 @@
if (v->num_orders > 1) {
const Order* last = GetLastVehicleOrder(v);
- if (v->orders->type == last->type &&
- v->orders->flags == last->flags &&
- v->orders->dest == last->dest) {
+ if (v->orders->Equals(*last)) {
problem_type = 2;
}
}
@@ -1135,7 +1237,7 @@
SetDParam(0, v->unitnumber);
AddNewsItem(
message,
- NEWS_FLAGS(NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, 0),
+ NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE,
v->index,
0
);
@@ -1166,20 +1268,18 @@
}
order = &v->current_order;
- if ((v->type == VEH_AIRCRAFT && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
- v->current_order.dest == destination) {
- order->type = OT_DUMMY;
- order->flags = 0;
+ if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
+ v->current_order.GetDestination() == destination) {
+ order->MakeDummy();
InvalidateWindow(WC_VEHICLE_VIEW, v->index);
}
/* Clear the order from the order-list */
invalidate = false;
FOR_VEHICLE_ORDERS(v, order) {
- if ((v->type == VEH_AIRCRAFT && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type &&
- order->dest == destination) {
- order->type = OT_DUMMY;
- order->flags = 0;
+ if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
+ order->GetDestination() == destination) {
+ order->MakeDummy();
invalidate = true;
}
}
@@ -1201,7 +1301,7 @@
const Order *order;
FOR_VEHICLE_ORDERS(v, order) {
- if (order->type == OT_GOTO_DEPOT)
+ if (order->IsType(OT_GOTO_DEPOT))
return true;
}
@@ -1267,7 +1367,6 @@
return (_patches.servint_ispercent) ? Clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
}
-
/**
*
* Check if a vehicle has any valid orders
@@ -1275,15 +1374,149 @@
* @return false if there are no valid orders
*
*/
-bool CheckForValidOrders(const Vehicle* v)
+static bool CheckForValidOrders(const Vehicle *v)
{
const Order *order;
- FOR_VEHICLE_ORDERS(v, order) if (order->type != OT_DUMMY) return true;
+ FOR_VEHICLE_ORDERS(v, order) if (!order->IsType(OT_DUMMY)) return true;
return false;
}
+/**
+ * Handle the orders of a vehicle and determine the next place
+ * to go to if needed.
+ * @param v the vehicle to do this for.
+ * @return true *if* the vehicle is eligible for reversing
+ * (basically only when leaving a station).
+ */
+bool ProcessOrders(Vehicle *v)
+{
+ switch (v->current_order.GetType()) {
+ case OT_GOTO_DEPOT:
+ /* Let a depot order in the orderlist interrupt. */
+ if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false;
+
+ if ((v->current_order.GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
+ UpdateVehicleTimetable(v, true);
+ v->cur_order_index++;
+ }
+ break;
+
+ case OT_LOADING:
+ return false;
+
+ case OT_LEAVESTATION:
+ if (v->type != VEH_AIRCRAFT) return false;
+ break;
+
+ default: break;
+ }
+
+ /**
+ * Reversing because of order change is allowed only just after leaving a
+ * station (and the difficulty setting to allowed, of course)
+ * this can be detected because only after OT_LEAVESTATION, current_order
+ * will be reset to nothing. (That also happens if no order, but in that case
+ * it won't hit the point in code where may_reverse is checked)
+ */
+ bool may_reverse = v->current_order.IsType(OT_NOTHING);
+
+ /* Check if we've reached the waypoint? */
+ if (v->current_order.IsType(OT_GOTO_WAYPOINT) && v->tile == v->dest_tile) {
+ UpdateVehicleTimetable(v, true);
+ v->cur_order_index++;
+ }
+
+ /* Check if we've reached a non-stop station.. */
+ if ((v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) &&
+ IsTileType(v->tile, MP_STATION) &&
+ v->current_order.GetDestination() == GetStationIndex(v->tile)) {
+ v->last_station_visited = v->current_order.GetDestination();
+ UpdateVehicleTimetable(v, true);
+ v->cur_order_index++;
+ }
+
+ /* Get the current order */
+ if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
+
+ const Order *order = GetVehicleOrder(v, v->cur_order_index);
+
+ /* If no order, do nothing. */
+ if (order == NULL || (v->type == VEH_AIRCRAFT && order->IsType(OT_DUMMY) && !CheckForValidOrders(v))) {
+ if (v->type == VEH_AIRCRAFT) {
+ /* Aircraft do something vastly different here, so handle separately */
+ extern void HandleMissingAircraftOrders(Vehicle *v);
+ HandleMissingAircraftOrders(v);
+ return false;
+ }
+
+ v->current_order.Free();
+ v->dest_tile = 0;
+ if (v->type == VEH_ROAD) ClearSlot(v);
+ return false;
+ }
+
+ /* If it is unchanged, keep it. */
+ if (order->Equals(v->current_order) &&
+ (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || GetStation(order->GetDestination())->dock_tile != 0)) {
+ return false;
+ }
+
+ /* Otherwise set it, and determine the destination tile. */
+ v->current_order = *order;
+
+ InvalidateVehicleOrder(v);
+ switch (v->type) {
+ default:
+ NOT_REACHED();
+
+ case VEH_ROAD:
+ case VEH_TRAIN:
+ break;
+
+ case VEH_AIRCRAFT:
+ case VEH_SHIP:
+ InvalidateWindowClasses(v->GetVehicleListWindowClass());
+ break;
+ }
+
+ switch (order->GetType()) {
+ case OT_GOTO_STATION:
+ v->dest_tile = v->GetOrderStationLocation(order->GetDestination());
+ break;
+
+ case OT_GOTO_DEPOT:
+ if (v->type != VEH_AIRCRAFT) v->dest_tile = GetDepot(order->GetDestination())->xy;
+ break;
+
+ case OT_GOTO_WAYPOINT:
+ v->dest_tile = GetWaypoint(order->GetDestination())->xy;
+ break;
+
+ default:
+ v->dest_tile = 0;
+ return false;
+ }
+
+ return may_reverse;
+}
+
+/**
+ * Check whether the given vehicle should stop at the given station
+ * based on this order and the non-stop settings.
+ * @param v the vehicle that might be stopping.
+ * @param station the station to stop at.
+ * @return true if the vehicle should stop.
+ */
+bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const
+{
+ return
+ v->last_station_visited != station && // Do stop only when we've not just been there
+ /* Finally do stop when there is no non-stop flag set for this type of station. */
+ !(this->GetNonStopType() & ((this->dest == station) ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS));
+}
+
void InitializeOrders()
{
_Order_pool.CleanPool();
@@ -1292,6 +1525,7 @@
_backup_orders_tile = 0;
}
+const SaveLoad *GetOrderDescription() {
static const SaveLoad _order_desc[] = {
SLE_VAR(Order, type, SLE_UINT8),
SLE_VAR(Order, flags, SLE_UINT8),
@@ -1307,6 +1541,8 @@
SLE_CONDNULL(10, 5, 35),
SLE_END()
};
+ return _order_desc;
+}
static void Save_ORDR()
{
@@ -1314,7 +1550,7 @@
FOR_ALL_ORDERS(order) {
SlSetArrayIndex(order->index);
- SlObject(order, _order_desc);
+ SlObject(order, GetOrderDescription());
}
}
@@ -1336,7 +1572,7 @@
for (i = 0; i < len; ++i) {
Order *order = new (i) Order();
- AssignOrder(order, UnpackVersion4Order(orders[i]));
+ order->AssignOrder(UnpackVersion4Order(orders[i]));
}
free(orders);
@@ -1347,8 +1583,7 @@
SlArray(orders, len, SLE_UINT32);
for (i = 0; i < len; ++i) {
- Order *order = new (i) Order();
- AssignOrder(order, UnpackOrder(orders[i]));
+ new (i) Order(orders[i]);
}
free(orders);
@@ -1367,7 +1602,7 @@
while ((index = SlIterateArray()) != -1) {
Order *order = new (index) Order();
- SlObject(order, _order_desc);
+ SlObject(order, GetOrderDescription());
}
}
}