summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2010-12-26 09:03:19 +0000
committerrubidium <rubidium@openttd.org>2010-12-26 09:03:19 +0000
commit64f04c3a74be3769a3e0bbf2e1c68bd27d6579eb (patch)
tree8608582c367f18f6c6669751ca8f0374e9f6a54d
parent8a278f771163b11074d23a573840af7b945abb8c (diff)
downloadopenttd-64f04c3a74be3769a3e0bbf2e1c68bd27d6579eb.tar.xz
(svn r21642) -Feature: concept of automatic station orders; add stub orders for intermediate stations and remove them when not visiting them anymore. This allows you to see what trains visit a station without actually having to order a vehicle to stop at all stations. Based on patch by fonsinchen
-rw-r--r--src/lang/english.txt3
-rw-r--r--src/order_base.h6
-rw-r--r--src/order_cmd.cpp37
-rw-r--r--src/order_gui.cpp18
-rw-r--r--src/order_type.h1
-rw-r--r--src/timetable_cmd.cpp12
-rw-r--r--src/timetable_gui.cpp32
-rw-r--r--src/vehicle.cpp37
-rw-r--r--src/vehicle_base.h2
-rw-r--r--src/vehiclelist.cpp2
10 files changed, 123 insertions, 27 deletions
diff --git a/src/lang/english.txt b/src/lang/english.txt
index f2848f0f0..aa2e449df 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -3252,6 +3252,8 @@ STR_ORDER_STOP_ORDER :(Stop)
STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING}
+STR_ORDER_AUTOMATIC :(Automatic)
+
STR_ORDER_FULL_LOAD :(Full load)
STR_ORDER_FULL_LOAD_ANY :(Full load any cargo)
STR_ORDER_NO_LOAD :(No loading)
@@ -3285,6 +3287,7 @@ STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}Switch t
STR_TIMETABLE_TOOLTIP :{BLACK}Timetable - click on an order to highlight it
STR_TIMETABLE_NO_TRAVEL :No travel
+STR_TIMETABLE_NOT_TIMETABLEABLE :Travel (automatic; timetabled by next manual order)
STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Travel (not timetabled)
STR_TIMETABLE_TRAVEL_FOR :Travel for {STRING1}
STR_TIMETABLE_STAY_FOR :and stay for {STRING1}
diff --git a/src/order_base.h b/src/order_base.h
index 2b605925b..6503c2999 100644
--- a/src/order_base.h
+++ b/src/order_base.h
@@ -124,6 +124,12 @@ public:
void MakeConditional(VehicleOrderID order);
/**
+ * Makes this order an automatic order.
+ * @param destination the station to go to.
+ */
+ void MakeAutomatic(StationID destination);
+
+ /**
* Gets the destination of this order.
* @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION).
* @return the destination of the order.
diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp
index 684ff62c9..57df98a8b 100644
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -99,6 +99,12 @@ void Order::MakeConditional(VehicleOrderID order)
this->dest = 0;
}
+void Order::MakeAutomatic(StationID destination)
+{
+ this->type = OT_AUTOMATIC;
+ this->dest = destination;
+}
+
void Order::SetRefit(CargoID cargo, byte subtype)
{
this->refit_cargo = cargo;
@@ -346,6 +352,8 @@ int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
bool OrderList::IsCompleteTimetable() const
{
for (Order *o = this->first; o != NULL; o = o->next) {
+ /* Automatic orders are, by definition, not timetabled. */
+ if (o->IsType(OT_AUTOMATIC)) continue;
if (!o->IsCompletelyTimetabled()) return false;
}
return true;
@@ -1446,9 +1454,20 @@ void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
int id = -1;
FOR_VEHICLE_ORDERS(v, order) {
id++;
- if (order->IsType(OT_GOTO_DEPOT) && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
- if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type &&
- order->GetDestination() == destination) {
+
+ OrderType ot = order->GetType();
+ if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
+ if (ot == OT_AUTOMATIC || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION;
+ if (ot == type && order->GetDestination() == destination) {
+ /* We want to clear automatic orders, but we don't want to make them
+ * dummy orders. They should just vanish. Also check the actual order
+ * type as ot is currently OT_GOTO_STATION. */
+ if (order->IsType(OT_AUTOMATIC)) {
+ DeleteOrder(v, id);
+ id--;
+ continue;
+ }
+
order->MakeDummy();
for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) {
/* In GUI, simulate by removing the order and adding it back */
@@ -1653,7 +1672,15 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth)
assert(v->cur_order_index < v->GetNumOrders());
/* Get the current order */
- order = v->GetOrder(v->cur_order_index);
+ order = v->GetNextManualOrder(v->cur_order_index);
+ if (order == NULL) {
+ order = v->GetNextManualOrder(0);
+ if (order == NULL) {
+ v->current_order.Free();
+ v->dest_tile = 0;
+ return false;
+ }
+ }
v->current_order = *order;
return UpdateOrderDest(v, order, conditional_depth + 1);
}
@@ -1708,7 +1735,7 @@ bool ProcessOrders(Vehicle *v)
/* Get the current order */
if (v->cur_order_index >= v->GetNumOrders()) v->cur_order_index = 0;
- const Order *order = v->GetOrder(v->cur_order_index);
+ const Order *order = v->GetNextManualOrder(v->cur_order_index);
/* If no order, do nothing. */
if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) {
diff --git a/src/order_gui.cpp b/src/order_gui.cpp
index cc0701f4a..a63df3fc4 100644
--- a/src/order_gui.cpp
+++ b/src/order_gui.cpp
@@ -200,8 +200,15 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
DrawSprite(sprite, PAL_NONE, rtl ? right - sprite_size.width : left, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2);
}
+ TextColour colour = TC_BLACK;
+ if (order->IsType(OT_AUTOMATIC)) {
+ colour = (selected ? TC_SILVER : TC_GREY) | TC_NO_SHADE;
+ } else if (selected) {
+ colour = TC_WHITE;
+ }
+
SetDParam(0, order_index + 1);
- DrawString(left, rtl ? right - sprite_size.width - 3 : middle, y, STR_ORDER_INDEX, selected ? TC_WHITE : TC_BLACK, SA_RIGHT | SA_FORCE);
+ DrawString(left, rtl ? right - sprite_size.width - 3 : middle, y, STR_ORDER_INDEX, colour, SA_RIGHT | SA_FORCE);
SetDParam(5, STR_EMPTY);
@@ -211,6 +218,13 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
SetDParam(1, order->GetDestination());
break;
+ case OT_AUTOMATIC:
+ SetDParam(0, STR_ORDER_GO_TO_STATION);
+ SetDParam(1, STR_ORDER_GO_TO);
+ SetDParam(2, order->GetDestination());
+ SetDParam(3, timetable ? STR_EMPTY : STR_ORDER_AUTOMATIC);
+ break;
+
case OT_GOTO_STATION: {
OrderLoadFlags load = order->GetLoadType();
OrderUnloadFlags unload = order->GetUnloadType();
@@ -298,7 +312,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
default: NOT_REACHED();
}
- DrawString(rtl ? left : middle, rtl ? middle : right, y, STR_ORDER_TEXT, selected ? TC_WHITE : TC_BLACK);
+ DrawString(rtl ? left : middle, rtl ? middle : right, y, STR_ORDER_TEXT, colour);
}
diff --git a/src/order_type.h b/src/order_type.h
index 7b252add0..6d9b0f0b3 100644
--- a/src/order_type.h
+++ b/src/order_type.h
@@ -38,6 +38,7 @@ enum OrderType {
OT_DUMMY = 5,
OT_GOTO_WAYPOINT = 6,
OT_CONDITIONAL = 7,
+ OT_AUTOMATIC = 8,
OT_END
};
diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp
index 0f8fc39e9..40064f4a9 100644
--- a/src/timetable_cmd.cpp
+++ b/src/timetable_cmd.cpp
@@ -72,7 +72,7 @@ CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, u
VehicleOrderID order_number = GB(p1, 20, 8);
Order *order = v->GetOrder(order_number);
- if (order == NULL) return CMD_ERROR;
+ if (order == NULL || order->IsType(OT_AUTOMATIC)) return CMD_ERROR;
bool is_journey = HasBit(p1, 28);
@@ -238,11 +238,17 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
v->current_order_time = 0;
if (!_settings_game.order.timetabling) return;
+ if (v->current_order.IsType(OT_AUTOMATIC)) return; // no timetabling of auto orders
+
+ VehicleOrderID first_manual_order = 0;
+ for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_AUTOMATIC); o = o->next) {
+ ++first_manual_order;
+ }
bool just_started = false;
/* This vehicle is arriving at the first destination in the timetable. */
- if (v->cur_order_index == 0 && travelling) {
+ if (v->cur_order_index == first_manual_order && travelling) {
/* If the start date hasn't been set, or it was set automatically when
* the vehicle last arrived at the first destination, update it to the
* current time. Otherwise set the late counter appropriately to when
@@ -279,7 +285,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
ChangeTimetable(v, v->cur_order_index, time_taken, travelling);
}
- if (v->cur_order_index == 0 && travelling) {
+ if (v->cur_order_index == first_manual_order && travelling) {
/* If we just started we would have returned earlier and have not reached
* this code. So obviously, we have completed our round: So turn autofill
* off again. */
diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp
index 026d20a10..fdd308bed 100644
--- a/src/timetable_gui.cpp
+++ b/src/timetable_gui.cpp
@@ -90,7 +90,7 @@ static void SetArrivalDepartParams(int param1, int param2, Ticks ticks)
static bool CanDetermineTimeTaken(const Order *order, bool travelling)
{
/* Current order is conditional */
- if (order->IsType(OT_CONDITIONAL)) return false;
+ if (order->IsType(OT_CONDITIONAL) || order->IsType(OT_AUTOMATIC)) return false;
/* No travel time and we have not already finished travelling */
if (travelling && order->travel_time == 0) return false;
/* No wait time but we are loading at this timetabled station */
@@ -126,15 +126,20 @@ static void FillTimetableArrivalDepartureTable(const Vehicle *v, VehicleOrderID
/* Cyclically loop over all orders until we reach the current one again.
* As we may start at the current order, do a post-checking loop */
do {
- if (travelling || i != start) {
- if (!CanDetermineTimeTaken(order, true)) return;
- sum += order->travel_time;
- table[i].arrival = sum;
- }
+ /* Automatic orders don't influence the overall timetable;
+ * they just add some untimetabled entries, but the time till
+ * the next non-automatic order can still be known. */
+ if (!order->IsType(OT_AUTOMATIC)) {
+ if (travelling || i != start) {
+ if (!CanDetermineTimeTaken(order, true)) return;
+ sum += order->travel_time;
+ table[i].arrival = sum;
+ }
- if (!CanDetermineTimeTaken(order, false)) return;
- sum += order->wait_time;
- table[i].departure = sum;
+ if (!CanDetermineTimeTaken(order, false)) return;
+ sum += order->wait_time;
+ table[i].departure = sum;
+ }
++i;
order = order->next;
@@ -317,7 +322,7 @@ struct TimetableWindow : Window {
if (selected != -1) {
const Order *order = v->GetOrder(((selected + 1) / 2) % v->GetNumOrders());
if (selected % 2 == 1) {
- disable = order != NULL && order->IsType(OT_CONDITIONAL);
+ disable = order != NULL && (order->IsType(OT_CONDITIONAL) || order->IsType(OT_AUTOMATIC));
} else {
disable = order == NULL || ((!order->IsType(OT_GOTO_STATION) || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) && !order->IsType(OT_CONDITIONAL));
}
@@ -387,9 +392,12 @@ struct TimetableWindow : Window {
}
} else {
StringID string;
-
+ TextColour colour = (i == selected) ? TC_WHITE : TC_BLACK;
if (order->IsType(OT_CONDITIONAL)) {
string = STR_TIMETABLE_NO_TRAVEL;
+ } else if(order->IsType(OT_AUTOMATIC)) {
+ string = STR_TIMETABLE_NOT_TIMETABLEABLE;
+ colour = ((i == selected) ? TC_SILVER : TC_GREY) | TC_NO_SHADE;
} else if (order->travel_time == 0) {
string = STR_TIMETABLE_TRAVEL_NOT_TIMETABLED;
} else {
@@ -397,7 +405,7 @@ struct TimetableWindow : Window {
string = STR_TIMETABLE_TRAVEL_FOR;
}
- DrawString(rtl ? r.left + WD_FRAMERECT_LEFT : middle, rtl ? middle : r.right - WD_FRAMERECT_LEFT, y, string, (i == selected) ? TC_WHITE : TC_BLACK);
+ DrawString(rtl ? r.left + WD_FRAMERECT_LEFT : middle, rtl ? middle : r.right - WD_FRAMERECT_LEFT, y, string, colour);
if (final_order) break;
}
diff --git a/src/vehicle.cpp b/src/vehicle.cpp
index bc5469062..9dc25a2dd 100644
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -1231,7 +1231,7 @@ void VehicleEnterDepot(Vehicle *v)
if (v->current_order.IsType(OT_GOTO_DEPOT)) {
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
- const Order *real_order = v->GetOrder(v->cur_order_index);
+ const Order *real_order = v->GetNextManualOrder(v->cur_order_index);
Order t = v->current_order;
v->current_order.MakeDummy();
@@ -1747,6 +1747,12 @@ void Vehicle::BeginLoading()
current_order.MakeLoading(true);
UpdateVehicleTimetable(this, true);
+ for (Order *order = this->GetOrder(this->cur_order_index);
+ order != NULL && order->IsType(OT_AUTOMATIC);
+ order = order->next) {
+ DeleteOrder(this, this->cur_order_index);
+ }
+
/* Furthermore add the Non Stop flag to mark that this station
* is the actual destination of the vehicle, which is (for example)
* necessary to be known for HandleTrainLoading to determine
@@ -1755,6 +1761,18 @@ void Vehicle::BeginLoading()
this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
} else {
+ /* We weren't scheduled to stop here. Insert an automatic order
+ * to show that we are stopping here. */
+ Order *in_list = this->GetOrder(this->cur_order_index);
+ if (this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID &&
+ ((in_list == NULL && this->cur_order_index == 0) ||
+ (in_list != NULL && (!in_list->IsType(OT_AUTOMATIC) ||
+ in_list->GetDestination() != this->last_station_visited)))) {
+ Order *auto_order = new Order();
+ auto_order->MakeAutomatic(this->last_station_visited);
+ InsertOrder(this, auto_order, this->cur_order_index);
+ if (this->cur_order_index > 0) --this->cur_order_index;
+ }
current_order.MakeLoading(false);
}
@@ -1808,11 +1826,8 @@ void Vehicle::HandleLoading(bool mode)
this->PlayLeaveStationSound();
- bool at_destination_station = this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE;
this->LeaveStation();
- /* If this was not the final order, don't remove it from the list. */
- if (!at_destination_station) return;
break;
}
@@ -2143,6 +2158,20 @@ void Vehicle::RemoveFromShared()
this->previous_shared = NULL;
}
+/**
+ * Get the next manual (not OT_AUTOMATIC) order after the one at the given index.
+ * @param index The index to start searching at.
+ * @return The next manual order at or after index or NULL if there is none.
+ */
+Order *Vehicle::GetNextManualOrder(int index) const
+{
+ Order *order = this->GetOrder(index);
+ while(order != NULL && order->IsType(OT_AUTOMATIC)) {
+ order = order->next;
+ }
+ return order;
+}
+
void StopAllVehicles()
{
Vehicle *v;
diff --git a/src/vehicle_base.h b/src/vehicle_base.h
index 381a5e3f6..2d59c3795 100644
--- a/src/vehicle_base.h
+++ b/src/vehicle_base.h
@@ -662,6 +662,8 @@ public:
return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
}
+ Order *GetNextManualOrder(int index) const;
+
/**
* Returns the last order of a vehicle, or NULL if it doesn't exists
* @return last order of a vehicle, if available
diff --git a/src/vehiclelist.cpp b/src/vehiclelist.cpp
index 5303e1904..1d0f09634 100644
--- a/src/vehiclelist.cpp
+++ b/src/vehiclelist.cpp
@@ -119,7 +119,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli
const Order *order;
FOR_VEHICLE_ORDERS(v, order) {
- if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT))
+ if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_AUTOMATIC))
&& order->GetDestination() == vli.index) {
*list->Append() = v;
break;