summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lang/english.txt7
-rw-r--r--src/order_base.h6
-rw-r--r--src/order_cmd.cpp23
-rw-r--r--src/order_gui.cpp12
-rw-r--r--src/order_type.h13
-rw-r--r--src/saveload/afterload.cpp8
-rw-r--r--src/saveload/order_sl.cpp2
-rw-r--r--src/saveload/saveload.cpp2
-rw-r--r--src/settings_gui.cpp1
-rw-r--r--src/settings_type.h1
-rw-r--r--src/station_cmd.cpp48
-rw-r--r--src/table/settings.h1
-rw-r--r--src/train.h2
-rw-r--r--src/train_cmd.cpp70
14 files changed, 168 insertions, 28 deletions
diff --git a/src/lang/english.txt b/src/lang/english.txt
index 9ae0cd068..674f32b67 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -938,6 +938,10 @@ STR_CONFIG_SETTING_LONGDATE :{LTBLUE}Always
STR_CONFIG_SETTING_SIGNALSIDE :{LTBLUE}Show signals on the drive side: {ORANGE}{STRING1}
STR_CONFIG_SETTING_SHOWFINANCES :{LTBLUE}Show finances window at the end of the year: {ORANGE}{STRING1}
STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :{LTBLUE}New orders are 'non-stop' by default: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_STOP_LOCATION :{LTBLUE}New train orders stop by default at the {ORANGE}{STRING1}{LTBLUE} of the platform
+STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :near end
+STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :middle
+STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :far end
STR_CONFIG_SETTING_ROADVEH_QUEUE :{LTBLUE}Road vehicle queueing (with quantum effects): {ORANGE}{STRING1}
STR_CONFIG_SETTING_AUTOSCROLL :{LTBLUE}Pan window when mouse is at the edge: {ORANGE}{STRING1}
STR_CONFIG_SETTING_BRIBE :{LTBLUE}Allow bribing of the local authority: {ORANGE}{STRING1}
@@ -2615,6 +2619,9 @@ STR_ORDER_GO_TO :Go to
STR_ORDER_GO_NON_STOP_TO :Go non-stop to
STR_ORDER_GO_VIA :Go via
STR_ORDER_GO_NON_STOP_VIA :Go non-stop via
+STR_ORDER_STOP_LOCATION_NEAR_END :[near end]
+STR_ORDER_STOP_LOCATION_MIDDLE :[middle]
+STR_ORDER_STOP_LOCATION_FAR_END :[far end]
STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}Full load any cargo
STR_ORDER_DROP_LOAD_IF_POSSIBLE :Load if available
STR_ORDER_DROP_FULL_LOAD_ALL :Full load all cargo
diff --git a/src/order_base.h b/src/order_base.h
index 44e8d9c15..7b0f0ab13 100644
--- a/src/order_base.h
+++ b/src/order_base.h
@@ -166,8 +166,10 @@ public:
inline OrderLoadFlags GetLoadType() const { return (OrderLoadFlags)GB(this->flags, 4, 4); }
/** How must the consist be unloaded? */
inline OrderUnloadFlags GetUnloadType() const { return (OrderUnloadFlags)GB(this->flags, 0, 4); }
- /** Where must we stop? */
+ /** At which stations must we stop? */
inline OrderNonStopFlags GetNonStopType() const { return (OrderNonStopFlags)GB(this->type, 6, 2); }
+ /** Where must we stop at the platform? */
+ inline OrderStopLocation GetStopLocation() const { return (OrderStopLocation)GB(this->type, 4, 2); }
/** What caused us going to the depot? */
inline OrderDepotTypeFlags GetDepotOrderType() const { return (OrderDepotTypeFlags)GB(this->flags, 0, 4); }
/** What are we going to do when in the depot. */
@@ -187,6 +189,8 @@ public:
inline void SetUnloadType(OrderUnloadFlags unload_type) { SB(this->flags, 0, 4, unload_type); }
/** Set whether we must stop at stations or not. */
inline void SetNonStopType(OrderNonStopFlags non_stop_type) { SB(this->type, 6, 2, non_stop_type); }
+ /** Set where we must stop at the platform. */
+ inline void SetStopLocation(OrderStopLocation stop_location) { SB(this->type, 4, 2, stop_location); }
/** Set the cause to go to the depot. */
inline void SetDepotOrderType(OrderDepotTypeFlags depot_order_type) { SB(this->flags, 0, 4, depot_order_type); }
/** Set what we are going to do in the depot. */
diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp
index b980d1711..b9f1a0e4f 100644
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -454,6 +454,20 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
default: return CMD_ERROR;
}
+
+ /* Filter invalid stop locations */
+ switch (new_order.GetStopLocation()) {
+ case OSL_PLATFORM_NEAR_END:
+ case OSL_PLATFORM_MIDDLE:
+ if (v->type != VEH_TRAIN) return CMD_ERROR;
+ /* FALL THROUGH */
+ case OSL_PLATFORM_FAR_END:
+ break;
+
+ default:
+ return CMD_ERROR;
+ }
+
break;
}
@@ -878,6 +892,11 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
if (data == order->GetNonStopType()) return CMD_ERROR;
break;
+ case MOF_STOP_LOCATION:
+ if (v->type != VEH_TRAIN) return CMD_ERROR;
+ if (data >= OSL_END) return CMD_ERROR;
+ break;
+
case MOF_UNLOAD:
if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR;
/* Unload and no-unload are mutual exclusive and so are transfer and no unload. */
@@ -939,6 +958,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
order->SetNonStopType((OrderNonStopFlags)data);
break;
+ case MOF_STOP_LOCATION:
+ order->SetStopLocation((OrderStopLocation)data);
+ break;
+
case MOF_UNLOAD:
order->SetUnloadType((OrderUnloadFlags)data);
if ((data & OUFB_NO_UNLOAD) != 0 && (order->GetLoadType() & OLFB_NO_LOAD) != 0) {
diff --git a/src/order_gui.cpp b/src/order_gui.cpp
index be09ff6b2..b0dfb8f52 100644
--- a/src/order_gui.cpp
+++ b/src/order_gui.cpp
@@ -202,6 +202,9 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
}
} else {
SetDParam(4, (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) ? STR_EMPTY : _station_load_types[unload][load]);
+ if (v->type == VEH_TRAIN) {
+ SetDParam(6, order->GetStopLocation() + STR_ORDER_STOP_LOCATION_NEAR_END);
+ }
}
} break;
@@ -361,6 +364,7 @@ static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
order.MakeGoToStation(st_index);
if (_ctrl_pressed) order.SetLoadType(OLF_FULL_LOAD_ANY);
if (_settings_client.gui.new_nonstop && (v->type == VEH_TRAIN || v->type == VEH_ROAD)) order.SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
+ order.SetStopLocation(v->type == VEH_TRAIN ? (OrderStopLocation)(_settings_client.gui.stop_location) : OSL_PLATFORM_FAR_END);
return order;
}
}
@@ -868,9 +872,15 @@ public:
this->DeleteChildWindows();
HideDropDownMenu(this);
- if (sel == INVALID_ORDER || sel == this->selected_order) {
+ if (sel == INVALID_ORDER) {
/* Deselect clicked order */
this->selected_order = -1;
+ } else if (sel == this->selected_order) {
+ if (this->vehicle->type == VEH_TRAIN) {
+ DoCommandP(this->vehicle->tile, this->vehicle->index + (sel << 16),
+ MOF_STOP_LOCATION | ((GetVehicleOrder(this->vehicle, sel)->GetStopLocation() + 1) % OSL_END) << 4,
+ CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ }
} else {
/* Select clicked order */
this->selected_order = sel;
diff --git a/src/order_type.h b/src/order_type.h
index 0a43dc8f7..8823e8a41 100644
--- a/src/order_type.h
+++ b/src/order_type.h
@@ -72,6 +72,16 @@ enum OrderNonStopFlags {
};
/**
+ * Where to stop the trains.
+ */
+enum OrderStopLocation {
+ OSL_PLATFORM_NEAR_END = 0, ///< Stop at the near end of the platform
+ OSL_PLATFORM_MIDDLE = 1, ///< Stop at the middle of the platform
+ OSL_PLATFORM_FAR_END = 2, ///< Stop at the far end of the platform
+ OSL_END
+};
+
+/**
* Reasons that could cause us to go to the depot.
*/
enum OrderDepotTypeFlags {
@@ -122,7 +132,8 @@ enum OrderConditionComparator {
* Enumeration for the data to set in CmdModifyOrder.
*/
enum ModifyOrderFlags {
- MOF_NON_STOP, ///< Passes a OrderNonStopFlags.
+ MOF_NON_STOP, ///< Passes an OrderNonStopFlags.
+ MOF_STOP_LOCATION, ///< Passes an OrderStopLocation.
MOF_UNLOAD, ///< Passes an OrderUnloadType.
MOF_LOAD, ///< Passes an OrderLoadType
MOF_DEPOT_ACTION, ///< Selects the OrderDepotAction
diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp
index 5f7cc1848..7dca7a53a 100644
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -1797,6 +1797,14 @@ bool AfterLoadGame()
}
}
+ /* Trains could now stop in a specific location. */
+ if (CheckSavegameVersion(117)) {
+ Order *o;
+ FOR_ALL_ORDERS(o) {
+ if (o->IsType(OT_GOTO_STATION)) o->SetStopLocation(OSL_PLATFORM_FAR_END);
+ }
+ }
+
AfterLoadLabelMaps();
GamelogPrintDebug(1);
diff --git a/src/saveload/order_sl.cpp b/src/saveload/order_sl.cpp
index 0ec506f1d..8579746ce 100644
--- a/src/saveload/order_sl.cpp
+++ b/src/saveload/order_sl.cpp
@@ -39,6 +39,8 @@ void Order::ConvertFromOldSavegame()
this->SetLoadType(_settings_client.gui.sg_full_load_any || CheckSavegameVersion(22) ? OLF_FULL_LOAD_ANY : OLFB_FULL_LOAD);
}
+ if (this->IsType(OT_GOTO_STATION)) this->SetStopLocation(OSL_PLATFORM_FAR_END);
+
/* Finally fix the unload flags */
if ((old_flags & 1) != 0) { // OFB_TRANSFER
this->SetUnloadType(OUFB_TRANSFER);
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index 13c437746..a8368ba4d 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -40,7 +40,7 @@
#include "saveload_internal.h"
-extern const uint16 SAVEGAME_VERSION = 116;
+extern const uint16 SAVEGAME_VERSION = 117;
SavegameType _savegame_type; ///< type of savegame we are loading
diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp
index 184ed6f5a..13913d60a 100644
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -1280,6 +1280,7 @@ static SettingEntry _settings_vehicles_trains[] = {
SettingEntry("vehicle.wagon_speed_limits"),
SettingEntry("vehicle.disable_elrails"),
SettingEntry("vehicle.freight_trains"),
+ SettingEntry("gui.stop_location"),
};
/** Trains sub-page */
static SettingsPage _settings_vehicles_trains_page = {_settings_vehicles_trains, lengthof(_settings_vehicles_trains)};
diff --git a/src/settings_type.h b/src/settings_type.h
index f52c77008..35a531ef5 100644
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -43,6 +43,7 @@ struct GUISettings {
bool show_finances; ///< show finances at end of year
bool sg_new_nonstop; ///< ttdpatch compatible nonstop handling read from pre v93 savegames
bool new_nonstop; ///< ttdpatch compatible nonstop handling
+ uint8 stop_location; ///< what is the default stop location of trains?
bool autoscroll; ///< scroll when moving mouse to the edge
byte errmsg_duration; ///< duration of error message
bool link_terraform_toolbar; ///< display terraform toolbar when displaying rail, road, water and airport toolbars
diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp
index e601e57e9..563c440a9 100644
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -2671,25 +2671,35 @@ static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, i
if (v->type == VEH_TRAIN) {
if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
- if (IsRailwayStation(tile) && IsFrontEngine(v) &&
- !IsCompatibleTrainStationTile(tile + TileOffsByDiagDir(DirToDiagDir(v->direction)), tile)) {
- DiagDirection dir = DirToDiagDir(v->direction);
-
- x &= 0xF;
- y &= 0xF;
-
- if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
- if (y == TILE_SIZE / 2) {
- if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
- int stop = TILE_SIZE - (v->u.rail.cached_veh_length + 1) / 2;
- if (x == stop) return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
- if (x < stop) {
- uint16 spd;
-
- v->vehstatus |= VS_TRAIN_SLOWING;
- spd = max(0, (stop - x) * 20 - 15);
- if (spd < v->cur_speed) v->cur_speed = spd;
- }
+ if (!IsRailwayStation(tile) || !IsFrontEngine(v)) return VETSB_CONTINUE;
+
+ int station_ahead;
+ int station_length;
+ int stop = GetTrainStopLocation(station_id, tile, v, &station_ahead, &station_length);
+
+ /* Stop whenever that amount of station ahead + the distance from the
+ * begin of the platform to the stop location is longer than the length
+ * of the platform. Station ahead 'includes' the current tile where the
+ * vehicle is on, so we need to substract that. */
+ if (station_length <= stop + station_ahead - TILE_SIZE) return VETSB_CONTINUE;
+
+ DiagDirection dir = DirToDiagDir(v->direction);
+
+ x &= 0xF;
+ y &= 0xF;
+
+ if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
+ if (y == TILE_SIZE / 2) {
+ if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
+ stop &= TILE_SIZE - 1;
+
+ if (x == stop) return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
+ if (x < stop) {
+ uint16 spd;
+
+ v->vehstatus |= VS_TRAIN_SLOWING;
+ spd = max(0, (stop - x) * 20 - 15);
+ if (spd < v->cur_speed) v->cur_speed = spd;
}
}
} else if (v->type == VEH_ROAD) {
diff --git a/src/table/settings.h b/src/table/settings.h
index 0163f1626..2097c8e8a 100644
--- a/src/table/settings.h
+++ b/src/table/settings.h
@@ -550,6 +550,7 @@ const SettingDesc _settings[] = {
SDTC_VAR(gui.autorenew_money, SLE_UINT, S, CR,100000, 0, 2000000, 0, STR_CONFIG_SETTING_AUTORENEW_MONEY, EngineRenewMoneyUpdate),
SDTC_BOOL(gui.always_build_infrastructure, S, 0, false, STR_CONFIG_SETTING_ALWAYS_BUILD_INFRASTRUCTURE, RedrawScreen),
SDTC_BOOL(gui.new_nonstop, S, 0, false, STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT, NULL),
+ SDTC_VAR(gui.stop_location, SLE_UINT8, S, MS, 2, 0, 2, 1, STR_CONFIG_SETTING_STOP_LOCATION, NULL),
SDTC_BOOL(gui.keep_all_autosave, S, 0, false, STR_NULL, NULL),
SDTC_BOOL(gui.autosave_on_exit, S, 0, false, STR_NULL, NULL),
SDTC_VAR(gui.max_num_autosaves, SLE_UINT8, S, 0, 16, 0, 255, 0, STR_NULL, NULL),
diff --git a/src/train.h b/src/train.h
index 02125efc9..750dbe3f1 100644
--- a/src/train.h
+++ b/src/train.h
@@ -300,6 +300,8 @@ void CheckTrainsLengths();
void FreeTrainTrackReservation(const Vehicle *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR);
bool TryPathReserve(Vehicle *v, bool mark_as_stuck = false, bool first_tile_okay = false);
+int GetTrainStopLocation(StationID station_id, TileIndex tile, const Vehicle *v, int *station_ahead, int *station_length);
+
/**
* This class 'wraps' Vehicle; you do not actually instantiate this class.
* You create a Vehicle using AllocateVehicle, so it is added to the pool
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index 579291f7b..484d0c5c1 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -354,6 +354,55 @@ enum AccelType {
AM_BRAKE
};
+/**
+ * Get the stop location of (the center) of the front vehicle of a train at
+ * a platform of a station.
+ * @param station_id the ID of the station where we're stopping
+ * @param tile the tile where the vehicle currently is
+ * @param v the vehicle to get the stop location of
+ * @param station_ahead 'return' the amount of 1/16th tiles in front of the train
+ * @param station_length 'return' the station length in 1/16th tiles
+ * @return the location, calculated from the begin of the station to stop at.
+ */
+int GetTrainStopLocation(StationID station_id, TileIndex tile, const Vehicle *v, int *station_ahead, int *station_length)
+{
+ const Station *st = GetStation(station_id);
+ *station_ahead = st->GetPlatformLength(tile, DirToDiagDir(v->direction)) * TILE_SIZE;
+ *station_length = st->GetPlatformLength(tile) * TILE_SIZE;
+
+ /* Default to the middle of the station for stations stops that are not in
+ * the order list like intermediate stations when non-stop is disabled */
+ OrderStopLocation osl = OSL_PLATFORM_MIDDLE;
+ if (v->u.rail.cached_total_length >= *station_length) {
+ /* The train is longer than the station, make it stop at the far end of the platform */
+ osl = OSL_PLATFORM_FAR_END;
+ } else if (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == station_id) {
+ osl = v->current_order.GetStopLocation();
+ }
+
+ /* The stop location of the FRONT! of the train */
+ int stop;
+ switch (osl) {
+ default: NOT_REACHED();
+
+ case OSL_PLATFORM_NEAR_END:
+ stop = v->u.rail.cached_total_length;
+ break;
+
+ case OSL_PLATFORM_MIDDLE:
+ stop = *station_length - (*station_length - v->u.rail.cached_total_length) / 2;
+ break;
+
+ case OSL_PLATFORM_FAR_END:
+ stop = *station_length;
+ break;
+ }
+
+ /* Substract half the front vehicle length of the train so we get the real
+ * stop location of the train. */
+ return stop - (v->u.rail.cached_veh_length + 1) / 2;
+}
+
/** new acceleration*/
static int GetTrainAcceleration(Vehicle *v, bool mode)
{
@@ -416,17 +465,23 @@ static int GetTrainAcceleration(Vehicle *v, bool mode)
}
if (IsTileType(v->tile, MP_STATION) && IsFrontEngine(v)) {
- if (v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile))) {
- int station_length = GetStationByTile(v->tile)->GetPlatformLength(v->tile, DirToDiagDir(v->direction));
-
+ StationID sid = GetStationIndex(v->tile);
+ if (v->current_order.ShouldStopAtStation(v, sid)) {
+ int station_ahead;
+ int station_length;
+ int stop_at = GetTrainStopLocation(sid, v->tile, v, &station_ahead, &station_length);
+
+ /* The distance to go is whatever is still ahead of the train minus the
+ * distance from the train's stop location to the end of the platform */
+ int distance_to_go = station_ahead / TILE_SIZE - (station_length - stop_at) / TILE_SIZE;
int st_max_speed = 120;
- int delta_v = v->cur_speed / (station_length + 1);
+ int delta_v = v->cur_speed / (distance_to_go + 1);
if (v->max_speed > (v->cur_speed - delta_v)) {
st_max_speed = v->cur_speed - (delta_v / 10);
}
- st_max_speed = max(st_max_speed, 25 * station_length);
+ st_max_speed = max(st_max_speed, 25 * distance_to_go);
max_speed = min(max_speed, st_max_speed);
}
}
@@ -3781,6 +3836,11 @@ static void TrainController(Vehicle *v, Vehicle *nomove)
/* Always try to extend the reservation when entering a tile. */
CheckNextTrainTile(v);
}
+
+ if (HasBit(r, VETS_ENTERED_STATION)) {
+ /* The new position is the location where we want to stop */
+ TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET);
+ }
}
} else {
/* In a tunnel or on a bridge