summaryrefslogtreecommitdiff
path: root/src/order_cmd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/order_cmd.cpp')
-rw-r--r--src/order_cmd.cpp196
1 files changed, 195 insertions, 1 deletions
diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp
index e86e31900..145f27652 100644
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -26,6 +26,7 @@
#include "waypoint_base.h"
#include "company_base.h"
#include "order_backup.h"
+#include "cargodest_func.h"
#include "table/strings.h"
@@ -245,6 +246,21 @@ Order::Order(uint32 packed)
}
/**
+ * Invalidating some stuff after removing item from the pool.
+ * @param index index of deleted item.
+ */
+/* static */ void Order::PostDestructor(size_t index)
+{
+ Vehicle *v;
+ FOR_ALL_VEHICLES(v) {
+ if (v->current_order.index == index) v->current_order.index = INVALID_ORDER;
+ if (v->last_order_id == index) v->last_order_id = INVALID_ORDER;
+ }
+
+ InvalidateOrderRouteLinks((OrderID)index);
+}
+
+/**
*
* Updates the widgets of a vehicle which contains the order-data
*
@@ -529,6 +545,146 @@ void OrderList::DebugCheckSanity() const
this->num_vehicles, this->timetable_duration);
}
+/** Returns the number of running (i.e. not stopped) vehicles in the shared orders list. */
+int OrderList::GetNumRunningVehicles()
+{
+ int num_running_vehicles = 0;
+
+ for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
+ if (!(v->vehstatus & (VS_STOPPED | VS_CRASHED))) num_running_vehicles++;
+ }
+
+ return num_running_vehicles;
+}
+
+/** (Re-)Initializes Separation if necessary and possible. */
+void OrderList::InitializeSeparation()
+{
+ // Check whether separation can be used at all
+ if(!this->IsCompleteTimetable() || this->current_sep_mode == TTS_MODE_OFF) {
+ this->is_separation_valid = false;
+ return;
+ }
+
+ // Save current tick count as reference for future timetable start dates and reset the separation counter.
+ this->last_timetable_init = GetCurrentTickCount();
+ this->separation_counter = 0;
+
+ // Calculate separation amount depending on mode of operation.
+ switch (current_sep_mode) {
+ case TTS_MODE_AUTO: {
+ int num_running_vehicles = this->GetNumRunningVehicles();
+ assert(num_running_vehicles > 0);
+
+ this->current_separation = this->GetTimetableTotalDuration() / num_running_vehicles;
+ break;
+ }
+
+ case TTS_MODE_MAN_N:
+ this->current_separation = this->GetTimetableTotalDuration() / this->num_sep_vehicles;
+ break;
+
+ case TTS_MODE_MAN_T:
+ // separation is set manually -> nothing to do
+ break;
+
+ case TTS_MODE_BUFFERED_AUTO: {
+ int num_running_vehicles = this->GetNumRunningVehicles();
+ assert(num_running_vehicles > 0);
+
+ if(num_running_vehicles > 1)
+ num_running_vehicles--;
+
+ this->current_separation = this->GetTimetableTotalDuration() / num_running_vehicles;
+ break;
+ }
+
+ default:
+ NOT_REACHED();
+ break;
+ }
+
+ this->is_separation_valid = true;
+}
+
+/**
+ * Returns the delay setting required for correct separation and increases the separation counter by 1.
+ * @return the delay setting required for correct separation. */
+Ticks OrderList::SeparateVehicle()
+{
+ if (!this->is_separation_valid || this->current_sep_mode == TTS_MODE_OFF)
+ return INVALID_TICKS;
+
+ Ticks result = GetCurrentTickCount() - (this->separation_counter * this->current_separation + this->last_timetable_init);
+ this->separation_counter++;
+
+ return result;
+}
+
+/**
+ * Returns the current separation settings.
+ * @return the current separation settings.
+ */
+TTSepSettings OrderList::GetSepSettings()
+{
+ TTSepSettings result;
+
+ result.mode = this->current_sep_mode;
+ result.sep_ticks = GetSepTime();
+
+ // Depending on the operation mode return either the user setting or the true amount of vehicles running the timetable.
+ result.num_veh = (result.mode == TTS_MODE_MAN_N) ? this->num_sep_vehicles : GetNumVehicles();
+ return result;
+}
+
+/**
+ * Prepares command to set new separation settings.
+ * @param s Contains the new settings to be used for separation.
+ * @todo Clean this up (e.g. via union type)
+ */
+void OrderList::SetSepSettings(TTSepSettings s)
+{
+ uint32 p2 = GB<uint32>(s.mode,0,3);
+ AB<uint32, uint>(p2,3,29, (s.mode == TTS_MODE_MAN_N) ? s.num_veh : s.sep_ticks);
+ DoCommandP(0, this->first_shared->index, p2, CMD_REINIT_SEPARATION);
+}
+
+/**
+ * Sets new separation settings.
+ * @param mode Contains the operation mode that is to be used for separation.
+ * @param parameter Depending on the operation mode this contains either the number of vehicles (#TTS_MODE_MAN_N)
+ * or the time between vehicles in ticks (#TTS_MODE_MAN_T). For other modes, this is undefined.
+ */
+void OrderList::SetSepSettings(TTSepMode mode, uint32 parameter)
+{
+ this->current_sep_mode = mode;
+
+ switch (this->current_sep_mode)
+ {
+ case TTS_MODE_MAN_N:
+ this->current_separation = this->GetTimetableTotalDuration() / parameter;
+ this->num_sep_vehicles = parameter;
+ break;
+
+ case TTS_MODE_MAN_T:
+ this->current_separation = parameter;
+ this->num_sep_vehicles = this->GetTimetableTotalDuration() / this->current_separation;
+ break;
+
+ case TTS_MODE_AUTO:
+ case TTS_MODE_BUFFERED_AUTO:
+ case TTS_MODE_OFF:
+ /* nothing to do */
+ break;
+
+ default:
+ NOT_REACHED();
+ break;
+ }
+
+ this->is_separation_valid = false;
+}
+
/**
* Checks whether the order goes to a station or not, i.e. whether the
* destination is a station
@@ -902,6 +1058,8 @@ void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
cur_order_id++;
}
+ PrefillRouteLinks(v);
+
/* Make sure to rebuild the whole list */
InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
}
@@ -967,6 +1125,17 @@ static void CancelLoadingDueToDeletedOrder(Vehicle *v)
}
/**
+ * Invalidate the next unload station of all cargo packets of a vehicle chain.
+ * @param v The vehicle.
+ */
+static void InvalidateNextStation(Vehicle *v)
+{
+ for (; v != NULL; v = v->Next()) {
+ v->cargo.InvalidateNextStation();
+ }
+}
+
+/**
* Delete an order but skip the parameter validation.
* @param v The vehicle to delete the order from.
* @param sel_ord The id of the order to be deleted.
@@ -977,6 +1146,7 @@ void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
Vehicle *u = v->FirstShared();
DeleteOrderWarnings(u);
+ PrefillRouteLinks(u);
for (; u != NULL; u = u->NextShared()) {
assert(v->orders.list == u->orders.list);
@@ -1005,6 +1175,9 @@ void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
/* Update any possible open window of the vehicle */
InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
+
+ /* Clear the next unload station of all cargo packets, it might not be in the orders anymore. */
+ InvalidateNextStation(u);
}
/* As we delete an order, the order to skip to will be 'wrong'. */
@@ -1294,7 +1467,11 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
switch (mof) {
case MOF_NON_STOP:
order->SetNonStopType((OrderNonStopFlags)data);
- if (data & ONSF_NO_STOP_AT_DESTINATION_STATION) order->SetRefit(CT_NO_REFIT);
+ if (data & ONSF_NO_STOP_AT_DESTINATION_STATION) {
+ InvalidateOrderRouteLinks(order->index);
+ order->SetRefit(CT_NO_REFIT);
+ }
+ PrefillRouteLinks(v);
break;
case MOF_STOP_LOCATION:
@@ -1394,6 +1571,9 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
u->current_order.SetLoadType(order->GetLoadType());
}
InvalidateVehicleOrder(u, VIWD_MODIFY_ORDERS);
+
+ /* Invalidate the next unload station of all packets as we might not unload there anymore. */
+ InvalidateNextStation(u);
}
}
@@ -1502,6 +1682,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
/* Link this vehicle in the shared-list */
dst->AddToShared(src);
+ PrefillRouteLinks(dst);
InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
InvalidateVehicleOrder(src, VIWD_MODIFY_ORDERS);
@@ -1566,6 +1747,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
dst->orders.list = new OrderList(first, dst);
}
+ PrefillRouteLinks(dst);
InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS);
InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
@@ -1804,6 +1986,9 @@ void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indic
if (!keep_orderlist) v->orders.list = NULL;
}
+ /* Invalidate the next unload station of all cargo. */
+ InvalidateNextStation(v);
+
if (reset_order_indices) {
v->cur_implicit_order_index = v->cur_real_order_index = 0;
if (v->current_order.IsType(OT_LOADING)) {
@@ -2011,7 +2196,12 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool
}
v->current_order = *order;
+ /* Set the index of the current order to the index of the implicit order,
+ * this is needed as the index is used for route link generation. */
+ Order *implicit_order = v->GetOrder(v->cur_implicit_order_index);
+ v->current_order.index = implicit_order->index;
return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead);
+
}
/**
@@ -2094,6 +2284,10 @@ bool ProcessOrders(Vehicle *v)
/* Otherwise set it, and determine the destination tile. */
v->current_order = *order;
+ /* Set the index of the current order to the index of the implicit order,
+ * this is needed as the index is used for route link generation. */
+ Order *implicit_order = v->GetOrder(v->cur_implicit_order_index);
+ v->current_order.index = implicit_order->index;
InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
switch (v->type) {