diff --git a/simutrans/config/simuconf.tab b/simutrans/config/simuconf.tab
index efc351850..d74e41c61 100644
--- a/simutrans/config/simuconf.tab
+++ b/simutrans/config/simuconf.tab
@@ -111,6 +111,17 @@ way_count_maximum=2000
 # if defined, the default tool will try to calculate straight ways (like OpenTTD)
 straight_way_without_control = 0
 
+# Start with the way tool allowed to bridge gaps and dig tunnels by itself, so a
+# drag can cross a river or a hill instead of failing. Off by default, and it is
+# only the STARTING state: the toolbar toggle sets it during play.
+# Leave it off unless you want it: an automatic bridge or tunnel is built at the
+# ordinary price of that structure, so a single drag over water or through a hill
+# can cost far more than the plain way you asked for. The cost is shown in the
+# tooltip while you drag, before anything is built.
+# It does not look for the cheapest or the shortest crossing - it only tries a
+# structure where the straight step it was already taking is blocked.
+automatic_tunnel_and_bridges = 0
+
 # stop_halt_as_scheduled=1, trains stop at the scheduled tile (or advance until they fits)
 # stop_halt_as_scheduled=0 (default) trains will advance always to the end of a platform
 #stop_halt_as_scheduled=0
diff --git a/simutrans/text/en.tab b/simutrans/text/en.tab
index 0e8333d4b..320f009ce 100644
--- a/simutrans/text/en.tab
+++ b/simutrans/text/en.tab
@@ -467,6 +467,8 @@ Aufspanntransformator
 Transformer
 Autohalt muss auf\nStrasse liegen!\n
 Bus or car stops\nmust be\nplaced on the road.
+Automatic bridges and tunnels
+Automatic bridges and tunnels
 Bahndepot
 Train depot
 Bankrott:\n\nDu bist bankrott.\n
diff --git a/src/simutrans/dataobj/environment.cc b/src/simutrans/dataobj/environment.cc
index fcf4175eb..879f3d708 100644
--- a/src/simutrans/dataobj/environment.cc
+++ b/src/simutrans/dataobj/environment.cc
@@ -58,6 +58,7 @@ bool env_t::currency_left = false;
 plainstring env_t::default_theme;
 const char *env_t::savegame_version_str = SAVEGAME_VER_NR;
 bool env_t::straight_way_without_control = false;
+bool env_t::automatic_tunnel_and_bridges = false;
 bool env_t::networkmode = false;
 bool env_t::restore_UI = false;
 extern uint16 network_server_port;
diff --git a/src/simutrans/dataobj/environment.h b/src/simutrans/dataobj/environment.h
index 7701f1721..bf3b1d5bf 100644
--- a/src/simutrans/dataobj/environment.h
+++ b/src/simutrans/dataobj/environment.h
@@ -526,6 +526,12 @@ public:
 	/// cannot be used in network mode
 	static bool straight_way_without_control;
 
+	/// let the way tool span gaps with bridges and dig tunnels on its own.
+	/// This is the LOCAL preference only. It is copied into the tool when a drag
+	/// starts and then travels with the command, so a client never runs a foreign
+	/// order by its own setting. Do not read it while a route is calculated or built.
+	static bool automatic_tunnel_and_bridges;
+
 	/// initialize with default values
 	static void init();
 
diff --git a/src/simutrans/dataobj/settings.cc b/src/simutrans/dataobj/settings.cc
index a966ea4f6..1230c3b1e 100644
--- a/src/simutrans/dataobj/settings.cc
+++ b/src/simutrans/dataobj/settings.cc
@@ -805,6 +805,9 @@ void settings_t::parse_simuconf( tabfile_t& simuconf, sint16& disp_width, sint16
 
 	env_t::straight_way_without_control = contents.get_int( "straight_way_without_control", env_t::straight_way_without_control ) != 0;
 
+	// only the initial state of the local mode; the toggle tool changes it afterwards
+	env_t::automatic_tunnel_and_bridges = contents.get_int( "automatic_tunnel_and_bridges", env_t::automatic_tunnel_and_bridges ) != 0;
+
 	env_t::road_user_info = contents.get_int( "pedes_and_car_info", env_t::road_user_info ) != 0;
 	env_t::tree_info      = contents.get_int( "tree_info",          env_t::tree_info      ) != 0;
 	env_t::ground_info    = contents.get_int( "ground_info",        env_t::ground_info    ) != 0;
diff --git a/src/simutrans/tool/simmenu.cc b/src/simutrans/tool/simmenu.cc
index 8f219db4f..c3ba9c304 100644
--- a/src/simutrans/tool/simmenu.cc
+++ b/src/simutrans/tool/simmenu.cc
@@ -344,6 +344,7 @@ tool_t* create_simple_tool(int toolnr)
 	case TOOL_SINGLE_WAY_TOOGLE:    tool = new tool_show_single_ways_t();     break;
 	case TOOL_WORK_WORLD:           tool = new tool_work_world_t();           break;
 	case TOOL_HALT_PERMISSION:      tool = new tool_change_permission_t();    break;
+	case TOOL_TOGGLE_AUTO_TUNNEL_BRIDGE: tool = new tool_toggle_auto_tunnel_bridge_t(); break;
 	case UNUSED_TOOL_ADD_MESSAGE: // fall-through - intended!!!111elf
 	case UNUSED_WKZ_PWDHASH_TOOL:
 		dbg->warning("create_simple_tool()", "Deprecated tool [%i] requested", toolnr);
diff --git a/src/simutrans/tool/simmenu.h b/src/simutrans/tool/simmenu.h
index 756b41cf1..fd971f2bd 100644
--- a/src/simutrans/tool/simmenu.h
+++ b/src/simutrans/tool/simmenu.h
@@ -134,6 +134,7 @@ enum {
 	TOOL_SINGLE_WAY_TOOGLE,
 	TOOL_WORK_WORLD,
 	TOOL_HALT_PERMISSION,
+	TOOL_TOGGLE_AUTO_TUNNEL_BRIDGE,
 	SIMPLE_TOOL_COUNT,
 	SIMPLE_TOOL = 0x2000
 };
@@ -317,6 +318,14 @@ public:
 	virtual bool is_work_keeps_game_state() const { return false; }
 	virtual bool is_work_here_keeps_game_state(player_t *, koord3d) { return false; }
 
+	/**
+	 * A tool that copies a local preference (env_t) at init() time keeps working with that
+	 * copy for as long as it stays selected. When a toggle flips such a preference the
+	 * selected tool is not initialised again, so it is told here instead and can refresh
+	 * its copy. Local state only - nothing about the world changes, and nothing is sent.
+	 */
+	virtual void local_preference_changed() {}
+
 	// will draw a dark frame, if selected
 	virtual void draw_after(scr_coord pos, bool dirty) const;
 
diff --git a/src/simutrans/tool/simtool.cc b/src/simutrans/tool/simtool.cc
index d57c242bf..c28d036f6 100644
--- a/src/simutrans/tool/simtool.cc
+++ b/src/simutrans/tool/simtool.cc
@@ -2585,10 +2585,15 @@ const way_desc_t *tool_build_way_t::get_desc() const
 	const way_desc_t* desc;
 	const char* n;
 	if (default_param && (n = strchr(default_param, ','))) {
+		// The option suffix was always understood by init(), but the descriptor was
+		// looked up with the WHOLE parameter, so any "<way>,<options>" failed to
+		// resolve and the tool refused to start. Cut at the comma, as was intended:
+		// the caller keeps the full string, only the name is used to find the way.
 		char name[256];
 		long len = (long)(n-default_param);
-		tstrncpy( name, default_param, min(255,len));
-		desc = way_builder_t::get_desc(default_param, 0);
+		// tstrncpy terminates at dest[n-1], so ask for one more than the name length
+		tstrncpy( name, default_param, min(255l,len)+1 );
+		desc = way_builder_t::get_desc(name, 0);
 	}
 	else {
 		desc = default_param ? way_builder_t::get_desc(default_param, 0) : NULL;
@@ -2696,6 +2701,15 @@ bool tool_build_way_t::init( player_t *player )
 		cursor = desc->get_cursor()->get_image_id(0);
 	}
 
+	// Take the local mode for the commands this tool is about to issue. On a client that
+	// is replaying someone else's order this is harmless: nwc_tool_t reads the custom data
+	// again after init(), so the value that arrived on the wire is the one that survives.
+	automatic_tunnel_and_bridges = env_t::automatic_tunnel_and_bridges;
+
+	// Legacy: "<way>,<auto>,<maxlen>" was the only way in before the mode became a real
+	// setting. Kept so an outside caller that already builds such a string keeps working,
+	// and it overrides the local preference for that call. Nothing in the game writes it
+	// any more and the toolbar toggle does not use it.
 	const char* n;
 	if (default_param && (n = strchr(default_param, ','))!=NULL) {
 		automatic_tunnel_and_bridges = n[1] == '1';
@@ -2732,6 +2746,41 @@ void tool_build_way_t::start_at( koord3d &new_start )
 	two_click_tool_t::start_at( new_start );
 }
 
+
+void tool_build_way_t::rdwr_custom_data(memory_rw_t *packet)
+{
+	two_click_tool_t::rdwr_custom_data(packet);
+	packet->rdwr_bool(automatic_tunnel_and_bridges);
+}
+
+
+void tool_build_way_t::local_preference_changed()
+{
+	// The toggle moved while this tool was still selected, so init() will not run again.
+	// Pick the new value up, but never for an invocation that named the mode explicitly:
+	// the legacy suffix outranks the preference, exactly as it does in init().
+	if(  default_param  &&  strchr(default_param, ',')  ) {
+		return;
+	}
+	automatic_tunnel_and_bridges = env_t::automatic_tunnel_and_bridges;
+}
+
+
+bool tool_toggle_auto_tunnel_bridge_t::init(player_t *player)
+{
+	env_t::automatic_tunnel_and_bridges = !env_t::automatic_tunnel_and_bridges;
+
+	// This tool returns false, so the tool selected before us stays selected and is not
+	// initialised again. Hand it the new value directly, or the button would do nothing
+	// visible until the player reselected the way tool.
+	if(  player  ) {
+		if(  tool_t *selected = welt->get_tool(player->get_player_nr())  ) {
+			selected->local_preference_changed();
+		}
+	}
+	return false;
+}
+
 uint8 tool_build_way_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d & )
 {
 	error = NULL;
diff --git a/src/simutrans/tool/simtool.h b/src/simutrans/tool/simtool.h
index 08e3dc40c..f4d4bb4fd 100644
--- a/src/simutrans/tool/simtool.h
+++ b/src/simutrans/tool/simtool.h
@@ -298,6 +298,11 @@ private:
 
 protected:
 	const way_desc_t *desc;
+	/// The mode THIS command runs in - not a user setting. It is taken from
+	/// env_t::automatic_tunnel_and_bridges in init(), refreshed by
+	/// local_preference_changed() while the tool stays selected, and then travels in the
+	/// custom data, so a receiving client runs the order it was sent and not whatever
+	/// its own toggle happens to say by then.
 	bool   automatic_tunnel_and_bridges;
 	uint32 max_length;
 
@@ -316,6 +321,8 @@ public:
 	char const* get_default_param(player_t*) const OVERRIDE;
 	bool is_selected() const OVERRIDE;
 	bool init(player_t*) OVERRIDE;
+	void rdwr_custom_data(memory_rw_t*) OVERRIDE;
+	void local_preference_changed() OVERRIDE;
 	bool is_init_keeps_game_state() const OVERRIDE { return true; }
 	waytype_t get_waytype() const OVERRIDE;
 	// remove preview necessary while building elevated ways
@@ -1015,6 +1022,29 @@ public:
 	bool is_work_keeps_game_state() const OVERRIDE { return true; }
 };
 
+/**
+ * Flips the local "let the way tool build bridges and tunnels for me" preference.
+ * It changes nothing in the world, so it never travels: the way tool copies the
+ * preference into the command in tool_build_way_t::init(), and from there it is
+ * serialised with the order.
+ *
+ * Because this tool returns false from init(), the tool that was selected before stays
+ * selected and is NOT initialised again (karte_t::local_set_tool only re-selects when
+ * init() returns true). The already-selected tool would therefore keep the old value
+ * until the player picked it again, and the button would look broken. So init() tells
+ * the selected tool that a local preference moved under it - see
+ * tool_t::local_preference_changed().
+ */
+class tool_toggle_auto_tunnel_bridge_t : public tool_t {
+public:
+	tool_toggle_auto_tunnel_bridge_t() : tool_t(TOOL_TOGGLE_AUTO_TUNNEL_BRIDGE | SIMPLE_TOOL) {}
+	char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Automatic bridges and tunnels"); }
+	bool is_selected() const OVERRIDE { return env_t::automatic_tunnel_and_bridges; }
+	bool init(player_t*) OVERRIDE;
+	bool is_init_keeps_game_state() const OVERRIDE { return true; }
+	bool is_work_keeps_game_state() const OVERRIDE { return true; }
+};
+
 class tool_load_scenario_t : public tool_t {
 	// internal tool to start a scenario
 	// command i.filename
