Add reverse at waypoint orders.

The train will reverse when its tail is within the waypoint tile.
This is useful for reversing on train en-route, without creating
dedicated reversing sidings or platforms.
pull/3/head
Jonathan G Rennison 9 years ago
parent 78f8627c34
commit 7bcd090a0f

@ -3771,6 +3771,9 @@ STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Select w
STR_ORDER_DROP_REFIT_AUTO :Fixed cargo
STR_ORDER_DROP_REFIT_AUTO_ANY :Available cargo
STR_ORDER_REVERSE :{BLACK}Reverse
STR_ORDER_REVERSE_TOOLTIP :{BLACK}Change the reversing behaviour of the highlighted order.
STR_ORDER_SERVICE :{BLACK}Service
STR_ORDER_DROP_GO_ALWAYS_DEPOT :Always go
STR_ORDER_DROP_SERVICE_DEPOT :Service if needed
@ -3822,6 +3825,8 @@ STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Show all
# String parts to build the order string
STR_ORDER_GO_TO_WAYPOINT :Go via {WAYPOINT}
STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Go non-stop via {WAYPOINT}
STR_ORDER_GO_TO_WAYPOINT_REVERSE :Go via and reverse at {WAYPOINT}
STR_ORDER_GO_NON_STOP_TO_WAYPOINT_REVERSE :Go non-stop via and reverse at {WAYPOINT}
STR_ORDER_SERVICE_AT :Service at
STR_ORDER_SERVICE_NON_STOP_AT :Service non-stop at

@ -1315,7 +1315,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
break;
case OT_GOTO_WAYPOINT:
if (mof != MOF_NON_STOP) return CMD_ERROR;
if (mof != MOF_NON_STOP && mof != MOF_WAYPOINT_FLAGS) return CMD_ERROR;
break;
case OT_CONDITIONAL:
@ -1397,6 +1397,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
case MOF_COND_DESTINATION:
if (data >= v->GetNumOrders()) return CMD_ERROR;
break;
case MOF_WAYPOINT_FLAGS:
if (data != (data & OWF_REVERSE)) return CMD_ERROR;
break;
}
if (flags & DC_EXEC) {
@ -1486,6 +1490,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
order->SetConditionSkipToOrder(data);
break;
case MOF_WAYPOINT_FLAGS:
order->SetWaypointFlags((OrderWaypointFlags)data);
break;
default: NOT_REACHED();
}

@ -314,10 +314,13 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
}
break;
case OT_GOTO_WAYPOINT:
SetDParam(0, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_GO_NON_STOP_TO_WAYPOINT : STR_ORDER_GO_TO_WAYPOINT);
case OT_GOTO_WAYPOINT: {
StringID str = (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_GO_NON_STOP_TO_WAYPOINT : STR_ORDER_GO_TO_WAYPOINT;
if (order->GetWaypointFlags() & OWF_REVERSE) str += STR_ORDER_GO_TO_WAYPOINT_REVERSE - STR_ORDER_GO_TO_WAYPOINT;
SetDParam(0, str);
SetDParam(1, order->GetDestination());
break;
}
case OT_CONDITIONAL:
SetDParam(1, order->GetConditionSkipToOrder() + 1);
@ -489,6 +492,7 @@ private:
/* WID_O_SEL_TOP_LEFT */
DP_LEFT_LOAD = 0, ///< Display 'load' in the left button of the top row of the train/rv order window.
DP_LEFT_REFIT = 1, ///< Display 'refit' in the left button of the top row of the train/rv order window.
DP_LEFT_REVERSE = 2, ///< Display 'reverse' in the left button of the top row of the train/rv order window.
/* WID_O_SEL_TOP_MIDDLE */
DP_MIDDLE_UNLOAD = 0, ///< Display 'unload' in the middle button of the top row of the train/rv order window.
@ -999,13 +1003,14 @@ public:
row_sel->SetDisplayedPlane(DP_ROW_LOAD);
} else {
train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL);
left_sel->SetDisplayedPlane(DP_LEFT_LOAD);
left_sel->SetDisplayedPlane(DP_LEFT_REVERSE);
middle_sel->SetDisplayedPlane(DP_MIDDLE_UNLOAD);
right_sel->SetDisplayedPlane(DP_RIGHT_EMPTY);
this->EnableWidget(WID_O_NON_STOP);
this->SetWidgetLoweredState(WID_O_NON_STOP, order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
this->EnableWidget(WID_O_REVERSE);
this->SetWidgetLoweredState(WID_O_REVERSE, order->GetWaypointFlags() & OWF_REVERSE);
}
this->DisableWidget(WID_O_FULL_LOAD);
this->DisableWidget(WID_O_UNLOAD);
this->DisableWidget(WID_O_REFIT_DROPDOWN);
break;
@ -1287,6 +1292,17 @@ public:
}
break;
case WID_O_REVERSE: {
VehicleOrderID sel_ord = this->OrderGetSel();
const Order *order = this->vehicle->GetOrder(sel_ord);
if (order == NULL) break;
DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_WAYPOINT_FLAGS | (order->GetWaypointFlags() ^ OWF_REVERSE) << 4,
CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER));
break;
}
case WID_O_TIMETABLE_VIEW:
ShowTimetableWindow(this->vehicle);
break;
@ -1555,6 +1571,8 @@ static const NWidgetPart _nested_orders_train_widgets[] = {
SetDataTip(STR_ORDER_TOGGLE_FULL_LOAD, STR_ORDER_TOOLTIP_FULL_LOAD), SetResize(1, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_REFIT), SetMinimalSize(93, 12), SetFill(1, 0),
SetDataTip(STR_ORDER_REFIT, STR_ORDER_REFIT_TOOLTIP), SetResize(1, 0),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_O_REVERSE), SetMinimalSize(93, 12), SetFill(1, 0),
SetDataTip(STR_ORDER_REVERSE, STR_ORDER_REVERSE_TOOLTIP), SetResize(1, 0),
EndContainer(),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_TOP_MIDDLE),
NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_UNLOAD), SetMinimalSize(93, 12), SetFill(1, 0),

@ -117,6 +117,7 @@ DECLARE_ENUM_AS_BIT_SET(OrderDepotActionFlags)
*/
enum OrderWaypointFlags {
OWF_DEFAULT = 0, ///< Default waypoint behaviour
OWF_REVERSE = 1 << 0, ///< Reverse train at the waypoint
};
DECLARE_ENUM_AS_BIT_SET(OrderWaypointFlags)
@ -163,6 +164,7 @@ enum ModifyOrderFlags {
MOF_COND_COMPARATOR, ///< A comparator changes.
MOF_COND_VALUE, ///< The value to set the condition to.
MOF_COND_DESTINATION,///< Change the destination of a conditional order.
MOF_WAYPOINT_FLAGS, ///< Change the waypoint flags
MOF_END
};
template <> struct EnumPropsT<ModifyOrderFlags> : MakeEnumPropsT<ModifyOrderFlags, byte, MOF_NON_STOP, MOF_END, MOF_END, 4> {};

@ -2951,6 +2951,13 @@ bool AfterLoadGame()
}
}
if (SlXvIsFeatureMissing(XSLFI_REVERSE_AT_WAYPOINT)) {
Train *t;
FOR_ALL_TRAINS(t) {
t->reverse_distance = 0;
}
}
/*
* Only keep order-backups for network clients (and when replaying).
* If we are a network server or not networking, then we just loaded a previously

@ -45,6 +45,7 @@ std::vector<uint32> _sl_xv_discardable_chunk_ids; ///< list of chunks
static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version os SLXI chunk
const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_REVERSE_AT_WAYPOINT, XSCF_NULL, 1, 1, "reverse_at_waypoint", NULL, NULL, NULL },
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
};

@ -21,6 +21,7 @@
*/
enum SlXvFeatureIndex {
XSLFI_NULL = 0, ///< Unused value, to indicate that no extended feature test is in use
XSLFI_REVERSE_AT_WAYPOINT, ///< Reverse at waypoint orders
XSLFI_SIZE, ///< Total count of features, including null feature
};

@ -724,6 +724,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
SLE_CONDNULL(2, 2, 19),
SLE_CONDVAR(Train, gv_flags, SLE_UINT16, 139, SL_MAX_VERSION),
SLE_CONDNULL(11, 2, 143), // old reserved space
SLE_CONDVAR_X(Train, reverse_distance, SLE_UINT16, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_REVERSE_AT_WAYPOINT)),
SLE_END()
};

@ -3129,6 +3129,11 @@ static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, i
{
if (v->type == VEH_TRAIN) {
StationID station_id = GetStationIndex(tile);
if (v->current_order.IsType(OT_GOTO_WAYPOINT) && v->current_order.GetDestination() == station_id && v->current_order.GetWaypointFlags() & OWF_REVERSE) {
Train *t = Train::From(v);
// reverse at waypoint
if (t->reverse_distance == 0) t->reverse_distance = t->gcache.cached_total_length;
}
if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
if (!IsRailStation(tile) || !v->IsFrontEngine()) return VETSB_CONTINUE;

@ -102,6 +102,8 @@ struct Train FINAL : public GroundVehicle<Train, VEH_TRAIN> {
/** Ticks waiting in front of a signal, ticks being stuck or a counter for forced proceeding through signals. */
uint16 wait_counter;
uint16 reverse_distance;
/** We don't want GCC to zero our struct! It already is zeroed and has an index! */
Train() : GroundVehicleBase() {}
/** We want to 'destruct' the right class. */

@ -624,6 +624,7 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const
v->owner = _current_company;
v->track = TRACK_BIT_DEPOT;
v->vehstatus = VS_HIDDEN | VS_DEFPAL;
v->reverse_distance = 0;
v->SetWagon();
@ -756,6 +757,7 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin
v->refit_cap = 0;
v->last_station_visited = INVALID_STATION;
v->last_loading_station = INVALID_STATION;
v->reverse_distance = 0;
v->engine_type = e->index;
v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
@ -1811,6 +1813,8 @@ void ReverseTrainDirection(Train *v)
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
}
v->reverse_distance = 0;
/* Clear path reservation in front if train is not stuck. */
if (!HasBit(v->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
@ -3104,6 +3108,22 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
Train *prev;
bool direction_changed = false; // has direction of any part changed?
if (reverse && v->reverse_distance == 1) {
goto reverse_train_direction;
}
if (v->reverse_distance > 1) {
v->vehstatus |= VS_TRAIN_SLOWING;
int target_speed;
if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC) {
target_speed = ((v->reverse_distance - 1) * 5) / 2;
} else {
target_speed = (v->reverse_distance - 1) * 10 - 5;
}
uint16 spd = max(0, target_speed);
if (spd < v->cur_speed) v->cur_speed = spd;
}
/* For every vehicle after and including the given vehicle */
for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) {
DiagDirection enterdir = DIAGDIR_BEGIN;
@ -3118,6 +3138,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
/* Inside depot */
gp.x = v->x_pos;
gp.y = v->y_pos;
v->reverse_distance = 0;
} else {
/* Not inside depot */
@ -3354,6 +3375,9 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
v->x_pos = gp.x;
v->y_pos = gp.y;
v->UpdatePosition();
if (v->reverse_distance > 1) {
v->reverse_distance--;
}
/* update the Z position of the vehicle */
int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false);

@ -1362,6 +1362,7 @@ void VehicleEnterDepot(Vehicle *v)
t->force_proceed = TFP_NONE;
ClrBit(t->flags, VRF_TOGGLE_REVERSE);
t->ConsistChanged(CCF_ARRANGE);
t->reverse_distance = 0;
break;
}

@ -29,6 +29,7 @@ enum OrderWidgets {
WID_O_SERVICE, ///< Select service (at depot).
WID_O_EMPTY, ///< Placeholder for refit dropdown when not owner.
WID_O_REFIT_DROPDOWN, ///< Open refit options.
WID_O_REVERSE, ///< Select waypoint reverse type
WID_O_COND_VARIABLE, ///< Choose condition variable.
WID_O_COND_COMPARATOR, ///< Choose condition type.
WID_O_COND_VALUE, ///< Choose condition value.

Loading…
Cancel
Save