diff options
Diffstat (limited to 'src/order_cmd.cpp')
-rw-r--r-- | src/order_cmd.cpp | 196 |
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) { |