diff --git a/client/gfx/dark/board_tile.rail.tunnel.svg b/client/gfx/dark/board_tile.rail.tunnel.svg
new file mode 100644
index 00000000..d60efe68
--- /dev/null
+++ b/client/gfx/dark/board_tile.rail.tunnel.svg
@@ -0,0 +1,86 @@
+
+
+
+
diff --git a/client/gfx/dark/dark.qrc b/client/gfx/dark/dark.qrc
index d4571bb0..6ef4c72b 100644
--- a/client/gfx/dark/dark.qrc
+++ b/client/gfx/dark/dark.qrc
@@ -70,5 +70,6 @@
board_tile.rail.bridge_45_left.svgboard_tile.rail.bridge_45_right.svgboard_tile.rail.sensor.svg
+ board_tile.rail.tunnel.svg
diff --git a/client/gfx/light/board_tile.rail.tunnel.svg b/client/gfx/light/board_tile.rail.tunnel.svg
new file mode 100644
index 00000000..548864b3
--- /dev/null
+++ b/client/gfx/light/board_tile.rail.tunnel.svg
@@ -0,0 +1,86 @@
+
+
+
+
diff --git a/client/gfx/light/light.qrc b/client/gfx/light/light.qrc
index 474d1b48..e1ec1de6 100644
--- a/client/gfx/light/light.qrc
+++ b/client/gfx/light/light.qrc
@@ -47,5 +47,6 @@
board_tile.rail.bridge_45_left.svgboard_tile.rail.bridge_45_right.svgboard_tile.rail.sensor.svg
+ board_tile.rail.tunnel.svg
\ No newline at end of file
diff --git a/client/src/board/boardareawidget.cpp b/client/src/board/boardareawidget.cpp
index 2d072064..9347410e 100644
--- a/client/src/board/boardareawidget.cpp
+++ b/client/src/board/boardareawidget.cpp
@@ -444,6 +444,7 @@ void BoardAreaWidget::paintEvent(QPaintEvent* event)
case TileId::RailBridge45Right:
case TileId::RailBridge90:
case TileId::RailBufferStop:
+ case TileId::RailTunnel:
tilePainter.draw(id, r, a);
break;
diff --git a/client/src/board/boardwidget.cpp b/client/src/board/boardwidget.cpp
index ebecfb29..c341097f 100644
--- a/client/src/board/boardwidget.cpp
+++ b/client/src/board/boardwidget.cpp
@@ -49,9 +49,10 @@ struct TileInfo
uint8_t rotates;
};
-const std::array tileInfo = {
+const std::array tileInfo = {
TileInfo{QStringLiteral("board_tile.rail.straight"), TileId::RailStraight, 0xFF},
TileInfo{QStringLiteral("board_tile.rail.buffer_stop"), TileId::RailBufferStop, 0xFF},
+ TileInfo{QStringLiteral("board_tile.rail.tunnel"), TileId::RailTunnel, 0xFF},
TileInfo{QStringLiteral(""), TileId::None, 0},
TileInfo{QStringLiteral("board_tile.rail.curve_45"), TileId::RailCurve45, 0xFF},
TileInfo{QStringLiteral("board_tile.rail.curve_90"), TileId::RailCurve90, 0xFF},
diff --git a/client/src/board/tilepainter.cpp b/client/src/board/tilepainter.cpp
index 61836b8b..e62bfb92 100644
--- a/client/src/board/tilepainter.cpp
+++ b/client/src/board/tilepainter.cpp
@@ -125,6 +125,23 @@ void TilePainter::draw(TileId id, const QRectF& r, TileRotate rotate)
drawBlock(id, r, rotate);
break;
+ case TileId::RailTunnel:
+ {
+ setTrackPen();
+ drawStraight(r, rotate);
+
+ // tunnel arc:
+ const int angle = -toDeg(rotate) * 16 - 45 * 8; // - 22.5 deg
+ const int angleLength = 225 * 16; // 225 deg
+ const qreal m = r.width() / 5;
+ const QRectF rArc = r.adjusted(m, m, -m, -m);
+
+ m_painter.setPen(QPen(backgroundColor, m_trackWidth, Qt::SolidLine, Qt::FlatCap));
+ m_painter.drawArc(rArc, angle, angleLength);
+ m_painter.setPen(QPen(trackColor, m_trackWidth / 2., Qt::SolidLine, Qt::FlatCap));
+ m_painter.drawArc(rArc, angle, angleLength);
+ break;
+ }
case TileId::None:
case TileId::ReservedForFutureExpension:
break;
diff --git a/manual/traintasticmanual/en-us/board/tiles.md b/manual/traintasticmanual/en-us/board/tiles.md
index c6d1c428..252c8732 100644
--- a/manual/traintasticmanual/en-us/board/tiles.md
+++ b/manual/traintasticmanual/en-us/board/tiles.md
@@ -3,6 +3,7 @@
## Rail tiles {#tiles-rail}
-  Straight
-  Buffer stop
+-  Tunnel
-  Curve 45°
-  Curve 90°
-  Crossover 45°
diff --git a/manual/traintasticmanual/gfx/board/tiles/board_tile.rail.tunnel.png b/manual/traintasticmanual/gfx/board/tiles/board_tile.rail.tunnel.png
new file mode 100644
index 00000000..6bfc2b04
Binary files /dev/null and b/manual/traintasticmanual/gfx/board/tiles/board_tile.rail.tunnel.png differ
diff --git a/server/src/board/tile/rail/tunnelrailtile.cpp b/server/src/board/tile/rail/tunnelrailtile.cpp
new file mode 100644
index 00000000..72137371
--- /dev/null
+++ b/server/src/board/tile/rail/tunnelrailtile.cpp
@@ -0,0 +1,28 @@
+/**
+ * server/src/board/tile/rail/tunnelrailtile.cpp
+ *
+ * This file is part of the traintastic source code.
+ *
+ * Copyright (C) 2021 Reinder Feenstra
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "tunnelrailtile.hpp"
+
+TunnelRailTile::TunnelRailTile(const std::weak_ptr& world, std::string_view _id)
+ : StraightRailTile(world, _id, TileId::RailTunnel)
+{
+}
diff --git a/server/src/board/tile/rail/tunnelrailtile.hpp b/server/src/board/tile/rail/tunnelrailtile.hpp
new file mode 100644
index 00000000..bd0e784f
--- /dev/null
+++ b/server/src/board/tile/rail/tunnelrailtile.hpp
@@ -0,0 +1,37 @@
+/**
+ * server/src/board/tile/rail/tunnelrailtile.hpp
+ *
+ * This file is part of the traintastic source code.
+ *
+ * Copyright (C) 2021 Reinder Feenstra
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TRAINTASTIC_SERVER_BOARD_TILE_RAIL_TUNNELRAILTILE_HPP
+#define TRAINTASTIC_SERVER_BOARD_TILE_RAIL_TUNNELRAILTILE_HPP
+
+#include "straightrailtile.hpp"
+
+class TunnelRailTile : public StraightRailTile
+{
+ CLASS_ID("board_tile.rail.tunnel")
+ CREATE(TunnelRailTile)
+
+ public:
+ TunnelRailTile(const std::weak_ptr& world, std::string_view _id);
+};
+
+#endif
diff --git a/server/src/board/tile/tiles.cpp b/server/src/board/tile/tiles.cpp
index f8f0ead0..9a18eaec 100644
--- a/server/src/board/tile/tiles.cpp
+++ b/server/src/board/tile/tiles.cpp
@@ -49,5 +49,6 @@ std::shared_ptr Tiles::create(const std::shared_ptr& world, std::st
IF_CLASSID_CREATE(BufferStopRailTile)
IF_CLASSID_CREATE(SensorRailTile)
IF_CLASSID_CREATE(BlockRailTile)
+ IF_CLASSID_CREATE(TunnelRailTile)
return std::shared_ptr();
}
diff --git a/server/src/board/tile/tiles.hpp b/server/src/board/tile/tiles.hpp
index 06add224..f158f4ee 100644
--- a/server/src/board/tile/tiles.hpp
+++ b/server/src/board/tile/tiles.hpp
@@ -48,6 +48,7 @@
#include "rail/bufferstoprailtile.hpp"
#include "rail/sensorrailtile.hpp"
#include "rail/blockrailtile.hpp"
+#include "rail/tunnelrailtile.hpp"
struct Tiles
{
@@ -76,7 +77,8 @@ struct Tiles
Signal3AspectRailTile::classId,
BufferStopRailTile::classId,
SensorRailTile::classId,
- BlockRailTile::classId
+ BlockRailTile::classId,
+ TunnelRailTile::classId
);
static std::shared_ptr create(const std::shared_ptr& world, std::string_view classId, std::string_view id = {});
diff --git a/server/test/board/addtile.cpp b/server/test/board/addtile.cpp
index e67383ba..a308df0c 100644
--- a/server/test/board/addtile.cpp
+++ b/server/test/board/addtile.cpp
@@ -47,6 +47,7 @@
#include "../src/board/tile/rail/bufferstoprailtile.hpp"
#include "../src/board/tile/rail/sensorrailtile.hpp"
#include "../src/board/tile/rail/blockrailtile.hpp"
+#include "../src/board/tile/rail/tunnelrailtile.hpp"
TEST_CASE("Board: Add non existing tile", "[board][board-add]")
{
@@ -80,6 +81,7 @@ TEMPLATE_TEST_CASE("Board: Add tile", "[board][board-add]"
, BufferStopRailTile
, SensorRailTile
, BlockRailTile
+ , TunnelRailTile
)
{
auto world = World::create();
diff --git a/shared/src/traintastic/board/tileid.hpp b/shared/src/traintastic/board/tileid.hpp
index 7a6fefdc..e652b0cf 100644
--- a/shared/src/traintastic/board/tileid.hpp
+++ b/shared/src/traintastic/board/tileid.hpp
@@ -51,6 +51,7 @@ enum class TileId : uint16_t // 10 bit
RailBridge45Left = 21,
RailBridge45Right = 22,
RailBridge90 = 23,
+ RailTunnel = 24,
ReservedForFutureExpension = 1023
};
diff --git a/shared/translations/en-us.txt b/shared/translations/en-us.txt
index 60113814..3c231bf3 100644
--- a/shared/translations/en-us.txt
+++ b/shared/translations/en-us.txt
@@ -46,6 +46,7 @@ class_id:board_tile.rail.signal_2aspect=Signal 2 aspect
class_id:board_tile.rail.signal_3_aspect=Signal (3 aspects)
class_id:board_tile.rail.signal_3aspect=Signal 3 aspect
class_id:board_tile.rail.straight=Straight track
+class_id:board_tile.rail.tunnel=Tunnel
class_id:board_tile.rail.turnout_3way=Turnout 3-way
class_id:board_tile.rail.turnout_doubleslip=Double slip
class_id:board_tile.rail.turnout_left_45=Turnout left 45°