(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

pull/155/head
rubidium 14 years ago
parent 19685ead47
commit 4d6841b553

@ -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}

@ -123,6 +123,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).

@ -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))) {

@ -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);
}

@ -38,6 +38,7 @@ enum OrderType {
OT_DUMMY = 5,
OT_GOTO_WAYPOINT = 6,
OT_CONDITIONAL = 7,
OT_AUTOMATIC = 8,
OT_END
};

@ -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. */

@ -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;
}

@ -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;

@ -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

@ -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;

Loading…
Cancel
Save