summaryrefslogtreecommitdiff
path: root/src/timetable_cmd.cpp
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2013-06-09 13:55:33 +0000
committerrubidium <rubidium@openttd.org>2013-06-09 13:55:33 +0000
commita2af1f69afd1971f062ca2ce4047496ed0dbf320 (patch)
tree4c4e01f32aa3d4aaa3f4a69dbda83309917fc397 /src/timetable_cmd.cpp
parenta724a9924bb4b489370befce7dcf3c3a39c310bb (diff)
downloadopenttd-a2af1f69afd1971f062ca2ce4047496ed0dbf320.tar.xz
(svn r25377) -Feature: timetable spreading of vehicles by Ctrl+Click when setting a start date
Diffstat (limited to 'src/timetable_cmd.cpp')
-rw-r--r--src/timetable_cmd.cpp81
1 files changed, 76 insertions, 5 deletions
diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp
index 166b817eb..a25f0b09a 100644
--- a/src/timetable_cmd.cpp
+++ b/src/timetable_cmd.cpp
@@ -16,6 +16,7 @@
#include "window_func.h"
#include "vehicle_base.h"
#include "cmd_helper.h"
+#include "core/sort_func.hpp"
#include "table/strings.h"
@@ -179,16 +180,60 @@ CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32 p1,
}
/**
+ * Order vehicles based on their timetable. The vehicles will be sorted in order
+ * they would reach the first station.
+ *
+ * @param ap First Vehicle pointer.
+ * @param bp Second Vehicle pointer.
+ * @return Comparison value.
+ */
+static int CDECL VehicleTimetableSorter(Vehicle * const *ap, Vehicle * const *bp)
+{
+ const Vehicle *a = *ap;
+ const Vehicle *b = *bp;
+
+ VehicleOrderID a_order = a->cur_real_order_index;
+ VehicleOrderID b_order = b->cur_real_order_index;
+ int j = (int)b_order - (int)a_order;
+
+ /* Are we currently at an ordered station (un)loading? */
+ bool a_load = a->current_order.IsType(OT_LOADING) && a->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE;
+ bool b_load = b->current_order.IsType(OT_LOADING) && b->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE;
+
+ /* If the current order is not loading at the ordered station, decrease the order index by one since we have
+ * not yet arrived at the station (and thus the timetable entry; still in the travelling of the previous one).
+ * Since the ?_order variables are unsigned the -1 will flow under and place the vehicles going to order #0 at
+ * the begin of the list with vehicles arriving at #0. */
+ if (!a_load) a_order--;
+ if (!b_load) b_order--;
+
+ /* First check the order index that accounted for loading, then just the raw one. */
+ int i = (int)b_order - (int)a_order;
+ if (i != 0) return i;
+ if (j != 0) return j;
+
+ /* Look at the time we spent in this order; the higher, the closer to its destination. */
+ i = b->current_order_time - a->current_order_time;
+ if (i != 0) return i;
+
+ /* If all else is equal, use some unique index to sort it the same way. */
+ return b->unitnumber - a->unitnumber;
+}
+
+/**
* Set the start date of the timetable.
* @param tile Not used.
* @param flags Operation to perform.
- * @param p1 Vehicle id.
+ * @param p2 Various bitstuffed elements
+ * - p2 = (bit 0-19) - Vehicle ID.
+ * - p2 = (bit 20) - Set to 1 to set timetable start for all vehicles sharing this order
* @param p2 The timetable start date.
* @param text Not used.
* @return The error or cost of the operation.
*/
CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
+ bool timetable_all = HasBit(p1, 20);
Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20));
if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
@@ -200,13 +245,39 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (start_date < 0 || start_date > MAX_DAY) return CMD_ERROR;
if (start_date - _date > 15 * DAYS_IN_LEAP_YEAR) return CMD_ERROR;
if (_date - start_date > DAYS_IN_LEAP_YEAR) return CMD_ERROR;
+ if (timetable_all && !v->orders.list->IsCompleteTimetable()) return CMD_ERROR;
if (flags & DC_EXEC) {
- v->lateness_counter = 0;
- ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
- v->timetable_start = start_date;
+ SmallVector<Vehicle *, 8> vehs;
+
+ if (timetable_all) {
+ for (Vehicle *w = v->orders.list->GetFirstSharedVehicle(); w != NULL; w = w->NextShared()) {
+ *vehs.Append() = w;
+ }
+ } else {
+ *vehs.Append() = v;
+ }
+
+ int total_duration = v->orders.list->GetTimetableTotalDuration();
+ int num_vehs = vehs.Length();
+
+ if (num_vehs >= 2) {
+ QSortT(vehs.Begin(), vehs.Length(), &VehicleTimetableSorter);
+ }
+
+ int base = vehs.FindIndex(v);
+
+ for (Vehicle **viter = vehs.Begin(); viter != vehs.End(); viter++) {
+ int idx = (viter - vehs.Begin()) - base;
+ Vehicle *w = *viter;
+
+ w->lateness_counter = 0;
+ ClrBit(w->vehicle_flags, VF_TIMETABLE_STARTED);
+ /* Do multiplication, then division to reduce rounding errors. */
+ w->timetable_start = start_date + idx * total_duration / num_vehs / DAY_TICKS;
+ SetWindowDirty(WC_VEHICLE_TIMETABLE, w->index);
+ }
- SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index);
}
return CommandCost();