summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/data/tramtrkw.grfbin0 -> 42018 bytes
-rw-r--r--readme.txt1
-rw-r--r--src/gfxinit.cpp3
-rw-r--r--src/lang/english.txt26
-rw-r--r--src/main_gui.cpp2
-rw-r--r--src/misc_gui.cpp1
-rw-r--r--src/newgrf.cpp10
-rw-r--r--src/road.h6
-rw-r--r--src/road_cmd.cpp68
-rw-r--r--src/road_gui.cpp65
-rw-r--r--src/roadveh_cmd.cpp31
-rw-r--r--src/roadveh_gui.cpp2
-rw-r--r--src/station_cmd.cpp32
-rw-r--r--src/table/files.h1
-rw-r--r--src/table/road_land.h35
-rw-r--r--src/table/roadveh.h385
-rw-r--r--src/table/sprites.h22
-rw-r--r--src/tunnelbridge_cmd.cpp76
18 files changed, 730 insertions, 36 deletions
diff --git a/bin/data/tramtrkw.grf b/bin/data/tramtrkw.grf
new file mode 100644
index 000000000..d4a38d1f8
--- /dev/null
+++ b/bin/data/tramtrkw.grf
Binary files differ
diff --git a/readme.txt b/readme.txt
index 41bb82da1..7b32a912a 100644
--- a/readme.txt
+++ b/readme.txt
@@ -317,6 +317,7 @@ Thanks to:
Richard Kempton (RichK67) - Additional airports, initial TGP implementation
Michael Blunck - For revolutionizing TTD with awesome graphics
George - Canal graphics
+ David Dallaston (Pikka) - Tram tracks
All Translators - For their support to make OpenTTD a truly international game
Bug Reporters - Thanks for all bug reports
Chris Sawyer - For an amazing game!
diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp
index 6ff742f0c..5faad52d4 100644
--- a/src/gfxinit.cpp
+++ b/src/gfxinit.cpp
@@ -396,6 +396,9 @@ static void LoadSpriteTables()
assert(load_index == SPR_GROUP_BASE);
load_index += LoadGrfFile("group.grf", load_index, i++);
+ assert(load_index == SPR_TRAMWAY_BASE);
+ load_index += LoadGrfFile("tramtrkw.grf", load_index, i++);
+
/* Initialize the unicode to sprite mapping table */
InitializeUnicodeGlyphMap();
diff --git a/src/lang/english.txt b/src/lang/english.txt
index 49b46ba28..e01f17c9e 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -1597,22 +1597,38 @@ STR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Must rem
STR_1801_MUST_REMOVE_ROAD_FIRST :{WHITE}Must remove road first
STR_ROAD_WORKS_IN_PROGRESS :{WHITE}Road works in progress
STR_1802_ROAD_CONSTRUCTION :{WHITE}Road Construction
+STR_1802_TRAMWAY_CONSTRUCTION :{WHITE}Tramway Construction
STR_1803_SELECT_ROAD_BRIDGE :{WHITE}Select Road Bridge
STR_1804_CAN_T_BUILD_ROAD_HERE :{WHITE}Can't build road here...
+STR_1804_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Can't build tramway here...
STR_1805_CAN_T_REMOVE_ROAD_FROM :{WHITE}Can't remove road from here...
+STR_1805_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Can't remove tramway from here...
STR_1806_ROAD_DEPOT_ORIENTATION :{WHITE}Road Depot Orientation
+STR_1806_TRAM_DEPOT_ORIENTATION :{WHITE}Tram Depot Orientation
STR_1807_CAN_T_BUILD_ROAD_VEHICLE :{WHITE}Can't build road vehicle depot here...
+STR_1807_CAN_T_BUILD_TRAM_VEHICLE :{WHITE}Can't build tram vehicle depot here...
STR_1808_CAN_T_BUILD_BUS_STATION :{WHITE}Can't build bus station...
STR_1809_CAN_T_BUILD_TRUCK_STATION :{WHITE}Can't build lorry station...
+STR_1808_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Can't build passenger tram station...
+STR_1809_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Can't build cargo tram station...
STR_180A_ROAD_CONSTRUCTION :Road construction
+STR_180A_TRAMWAY_CONSTRUCTION :Tramway construction
STR_180B_BUILD_ROAD_SECTION :{BLACK}Build road section
+STR_180B_BUILD_TRAMWAY_SECTION :{BLACK}Build tramway section
STR_180C_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Build road vehicle depot (for building and servicing vehicles)
+STR_180C_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Build tram vehicle depot (for building and servicing vehicles)
STR_180D_BUILD_BUS_STATION :{BLACK}Build bus station
STR_180E_BUILD_TRUCK_LOADING_BAY :{BLACK}Build lorry loading bay
+STR_180D_BUILD_PASSENGER_TRAM_STATION :{BLACK}Build passenger tram station
+STR_180E_BUILD_CARGO_TRAM_STATION :{BLACK}Build cargo tram station
STR_180F_BUILD_ROAD_BRIDGE :{BLACK}Build road bridge
+STR_180F_BUILD_TRAMWAY_BRIDGE :{BLACK}Build tramway bridge
STR_1810_BUILD_ROAD_TUNNEL :{BLACK}Build road tunnel
+STR_1810_BUILD_TRAMWAY_TUNNEL :{BLACK}Build tramway tunnel
STR_1811_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Toggle build/remove for road construction
+STR_1811_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Toggle build/remove for tramway construction
STR_1813_SELECT_ROAD_VEHICLE_DEPOT :{BLACK}Select road vehicle depot orientation
+STR_1813_SELECT_TRAM_VEHICLE_DEPOT :{BLACK}Select tram vehicle depot orientation
STR_1814_ROAD :Road
STR_1815_ROAD_WITH_STREETLIGHTS :Road with streetlights
STR_1816_TREE_LINED_ROAD :Tree-lined road
@@ -1620,6 +1636,8 @@ STR_1817_ROAD_VEHICLE_DEPOT :Road vehicle de
STR_1818_ROAD_RAIL_LEVEL_CROSSING :Road/rail level crossing
STR_CAN_T_REMOVE_BUS_STATION :{WHITE}Can't remove bus station...
STR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Can't remove lorry station...
+STR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}Can't remove passenger tram station...
+STR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}Can't remove cargo tram station...
##id 0x2000
STR_2000_TOWNS :{WHITE}Towns
@@ -1783,9 +1801,13 @@ STR_303F_NO_LONGER_ACCEPTS_OR :{WHITE}{STATION
STR_3040_NOW_ACCEPTS :{WHITE}{STATION} now accepts {STRING}
STR_3041_NOW_ACCEPTS_AND :{WHITE}{STATION} now accepts {STRING} and {STRING}
STR_3042_BUS_STATION_ORIENTATION :{WHITE}Bus Station Orientation
-STR_3043_TRUCK_STATION_ORIENT :{WHITE}Lorry Station Orient.
+STR_3043_TRUCK_STATION_ORIENT :{WHITE}Lorry Station Orientation
+STR_3042_PASSENGER_TRAM_STATION_ORIENTATION :{WHITE}Passenger Tram Orientation
+STR_3043_CARGO_TRAM_STATION_ORIENT :{WHITE}Cargo Tram Orientation
STR_3046_MUST_DEMOLISH_BUS_STATION :{WHITE}Must demolish bus station first
STR_3047_MUST_DEMOLISH_TRUCK_STATION :{WHITE}Must demolish lorry station first
+STR_3046_MUST_DEMOLISH_PASSENGER_TRAM_STATION :{WHITE}Must demolish passenger tram station first
+STR_3047_MUST_DEMOLISH_CARGO_TRAM_STATION :{WHITE}Must demolish cargo tram station first
STR_3048_STATIONS :{WHITE}{COMPANY} - {COMMA} Station{P "" s}
STR_3049_0 :{YELLOW}{STATION} {STATIONFEATURES}
STR_304A_NONE :{YELLOW}- None -
@@ -2720,6 +2742,8 @@ STR_902D_CAN_T_NAME_ROAD_VEHICLE :{WHITE}Can't na
STR_902E_NAME_ROAD_VEHICLE :{BLACK}Name road vehicle
STR_902F_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Citizens celebrate . . .{}First bus arrives at {STATION}!
STR_9030_CITIZENS_CELEBRATE_FIRST :{BLACK}{BIGFONT}Citizens celebrate . . .{}First truck arrives at {STATION}!
+STR_902F_CITIZENS_CELEBRATE_FIRST_TRAM :{BLACK}{BIGFONT}Citizens celebrate . . .{}First passenger tram arrives at {STATION}!
+STR_9030_CITIZENS_CELEBRATE_FIRST_TRAM :{BLACK}{BIGFONT}Citizens celebrate . . .{}First cargo tram arrives at {STATION}!
STR_9031_ROAD_VEHICLE_CRASH_DRIVER :{BLACK}{BIGFONT}Road Vehicle Crash!{}Driver dies in fireball after collision with train
STR_9032_ROAD_VEHICLE_CRASH_DIE :{BLACK}{BIGFONT}Road Vehicle Crash!{}{COMMA} die in fireball after collision with train
STR_9033_CAN_T_MAKE_VEHICLE_TURN :{WHITE}Can't make vehicle turn around...
diff --git a/src/main_gui.cpp b/src/main_gui.cpp
index 97d146cad..d48cd82fb 100644
--- a/src/main_gui.cpp
+++ b/src/main_gui.cpp
@@ -938,7 +938,7 @@ static void ToolbarBuildRoadClick(Window *w)
{
const Player *p = GetPlayer(_local_player);
/* The standard road button is *always* available */
- Window *w2 = PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 1, ~(p->avail_roadtypes | 1));
+ Window *w2 = PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 2, ~(p->avail_roadtypes | 1));
WP(w2, menu_d).sel_index = _last_built_roadtype;
}
diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp
index 34c1564d5..92c7ac9ce 100644
--- a/src/misc_gui.cpp
+++ b/src/misc_gui.cpp
@@ -239,6 +239,7 @@ static const char *credits[] = {
"",
" Michael Blunck - Pre-Signals and Semaphores © 2003",
" George - Canal/Lock graphics © 2003-2004",
+ " David Dallaston - Tram tracks",
" Marcin Grzegorczyk - Foundations for Tracks on Slopes",
" All Translators - Who made OpenTTD a truly international game",
" Bug Reporters - Without whom OpenTTD would still be full of bugs!",
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index 6095832ed..9c04ec9d1 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -2905,6 +2905,14 @@ static void GraphicsNew(byte *buf, int len)
replace = SPR_2CCMAP_BASE;
break;
+ case 0x0B: // tramways
+ if (num != 113) {
+ grfmsg(1, "GraphicsNews: Tramway graphics sprite count must be 113, skipping");
+ return;
+ }
+ replace = SPR_TRAMWAY_BASE;
+ break;
+
case 0x0D: // Coast graphics
if (num != 16) {
grfmsg(1, "GraphicsNew: Coast graphics sprite count must be 16, skipping");
@@ -4237,7 +4245,7 @@ static void InitializeGRFSpecial()
| (1 << 0x11) // autoreplace
| (1 << 0x12) // autoslope
| (0 << 0x13) // followvehicle
- | (0 << 0x14) // trams
+ | (1 << 0x14) // trams
| (0 << 0x15) // enhancetunnels
| (0 << 0x16) // shortrvs
| (0 << 0x17) // articulatedrvs
diff --git a/src/road.h b/src/road.h
index 4c875dce0..acb958246 100644
--- a/src/road.h
+++ b/src/road.h
@@ -43,7 +43,7 @@ DECLARE_ENUM_AS_BIT_SET(RoadTypes);
*/
static inline bool IsValidRoadType(RoadType rt)
{
- return rt == ROADTYPE_ROAD;
+ return rt == ROADTYPE_ROAD || rt == ROADTYPE_TRAM;
}
/**
@@ -53,7 +53,7 @@ static inline bool IsValidRoadType(RoadType rt)
*/
static inline bool AreValidRoadTypes(RoadTypes rts)
{
- return rts == ROADTYPES_ROAD;
+ return HASBIT(rts, ROADTYPE_ROAD) || HASBIT(rts, ROADTYPE_TRAM);
}
/**
@@ -115,4 +115,6 @@ static inline bool IsStraightRoadTrackdir(Trackdir dir)
*/
bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road, RoadType rt);
+void DrawTramCatenary(TileInfo *ti, RoadBits tram);
+
#endif /* ROAD_H */
diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp
index 394dcc370..b85017d2e 100644
--- a/src/road_cmd.cpp
+++ b/src/road_cmd.cpp
@@ -815,19 +815,57 @@ static bool AlwaysDrawUnpavedRoads(TileIndex tile, Roadside roadside)
}
/**
+ * Draws the catenary for the given tile
+ * @param ti information about the tile (slopes, height etc)
+ * @param tram the roadbits for the tram
+ */
+void DrawTramCatenary(TileInfo *ti, RoadBits tram)
+{
+ /* Don't draw the catenary under a low bridge */
+ if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile) && !HASBIT(_transparent_opt, TO_BUILDINGS)) {
+ uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile));
+
+ if (height <= TilePixelHeight(ti->tile) + TILE_HEIGHT) return;
+ }
+
+ SpriteID front;
+ SpriteID back;
+
+ if (ti->tileh != SLOPE_FLAT) {
+ back = SPR_TRAMWAY_BACK_WIRES_SLOPED + _road_sloped_sprites[ti->tileh - 1];
+ front = SPR_TRAMWAY_FRONT_WIRES_SLOPED + _road_sloped_sprites[ti->tileh - 1];
+ } else {
+ back = SPR_TRAMWAY_BASE + _road_backpole_sprites_1[tram];
+ front = SPR_TRAMWAY_BASE + _road_frontwire_sprites_1[tram];
+ }
+
+ SpriteID pal = PAL_NONE;
+ if (HASBIT(_transparent_opt, TO_BUILDINGS)) {
+ SETBIT(front, PALETTE_MODIFIER_TRANSPARENT);
+ SETBIT(back, PALETTE_MODIFIER_TRANSPARENT);
+ pal = PALETTE_TO_TRANSPARENT;
+ }
+
+ AddSortableSpriteToDraw(back, pal, ti->x, ti->y, 16, 16, 0x20, ti->z);
+ AddSortableSpriteToDraw(front, pal, ti->x, ti->y, 16, 16, 0, ti->z);
+}
+
+/**
* Draw ground sprite and road pieces
* @param ti TileInfo
*/
static void DrawRoadBits(TileInfo* ti)
{
RoadBits road = GetRoadBits(ti->tile, ROADTYPE_ROAD);
+ RoadBits tram = GetRoadBits(ti->tile, ROADTYPE_TRAM);
+
const DrawRoadTileStruct *drts;
SpriteID image = 0;
SpriteID pal = PAL_NONE;
Roadside roadside;
if (ti->tileh != SLOPE_FLAT) {
- int foundation = GetRoadFoundation(ti->tileh, road);
+ int foundation = GetRoadFoundation(ti->tileh, road | tram);
if (foundation != 0) DrawFoundation(ti, foundation);
@@ -836,7 +874,7 @@ static void DrawRoadBits(TileInfo* ti)
if (ti->tileh != SLOPE_FLAT) image = _road_sloped_sprites[ti->tileh - 1] + 0x53F;
}
- if (image == 0) image = _road_tile_sprites_1[road];
+ if (image == 0) image = _road_tile_sprites_1[road != ROAD_NONE ? road : tram];
roadside = GetRoadside(ti->tile);
@@ -853,12 +891,27 @@ static void DrawRoadBits(TileInfo* ti)
DrawGroundSprite(image, pal);
+ /* For tram we overlay the road graphics with either tram tracks only
+ * (when there is actual road beneath the trams) or with tram tracks
+ * and some dirts which hides the road graphics */
+ if (tram != ROAD_NONE) {
+ if (ti->tileh != SLOPE_FLAT) {
+ image = _road_sloped_sprites[ti->tileh - 1] + SPR_TRAMWAY_SLOPED_OFFSET;
+ } else {
+ image = _road_tile_sprites_1[tram] - SPR_ROAD_Y;
+ }
+ image += (road == ROAD_NONE) ? SPR_TRAMWAY_TRAM : SPR_TRAMWAY_OVERLAY;
+ DrawGroundSprite(image, pal);
+ }
+
if (HasRoadWorks(ti->tile)) {
/* Road works */
- DrawGroundSprite(road & ROAD_X ? SPR_EXCAVATION_X : SPR_EXCAVATION_Y, PAL_NONE);
+ DrawGroundSprite((road | tram) & ROAD_X ? SPR_EXCAVATION_X : SPR_EXCAVATION_Y, PAL_NONE);
return;
}
+ if (tram != ROAD_NONE) DrawTramCatenary(ti, tram);
+
/* Return if full detail is disabled, or we are zoomed fully out. */
if (!HASBIT(_display_opt, DO_FULL_DETAIL) || _cur_dpi->zoom > ZOOM_LVL_DETAIL) return;
@@ -916,7 +969,12 @@ static void DrawTile_Road(TileInfo *ti)
palette = PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile));
- dts = &_road_depot[GetRoadDepotDirection(ti->tile)];
+ if (HASBIT(GetRoadTypes(ti->tile), ROADTYPE_TRAM)) {
+ dts = &_tram_depot[GetRoadDepotDirection(ti->tile)];
+ } else {
+ dts = &_road_depot[GetRoadDepotDirection(ti->tile)];
+ }
+
DrawGroundSprite(dts->ground_sprite, PAL_NONE);
for (dtss = dts->seq; dtss->image != 0; dtss++) {
@@ -948,7 +1006,7 @@ static void DrawTile_Road(TileInfo *ti)
void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt)
{
SpriteID palette = PLAYER_SPRITE_COLOR(_local_player);
- const DrawTileSprites* dts = &_road_depot[dir];
+ const DrawTileSprites* dts = (rt == ROADTYPE_TRAM) ? &_tram_depot[dir] : &_road_depot[dir];
const DrawTileSeqStruct* dtss;
x += 33;
diff --git a/src/road_gui.cpp b/src/road_gui.cpp
index 3723f675f..c5dbc9c2a 100644
--- a/src/road_gui.cpp
+++ b/src/road_gui.cpp
@@ -94,6 +94,16 @@ static const RoadTypeInfo _road_type_infos[] = {
SPR_CURSOR_ROAD_NESW,
SPR_CURSOR_ROAD_NWSE,
},
+ {
+ STR_1804_CAN_T_BUILD_TRAMWAY_HERE,
+ STR_1805_CAN_T_REMOVE_TRAMWAY_FROM,
+ STR_1807_CAN_T_BUILD_TRAM_VEHICLE,
+ { STR_1808_CAN_T_BUILD_PASSENGER_TRAM_STATION, STR_1809_CAN_T_BUILD_CARGO_TRAM_STATION },
+ { STR_CAN_T_REMOVE_PASSENGER_TRAM_STATION, STR_CAN_T_REMOVE_CARGO_TRAM_STATION },
+
+ SPR_CURSOR_TRAMWAY_NESW,
+ SPR_CURSOR_TRAMWAY_NWSE,
+ },
};
static void PlaceRoad_Tunnel(TileIndex tile)
@@ -375,13 +385,39 @@ static const WindowDesc _build_road_desc = {
BuildRoadToolbWndProc
};
+static const Widget _build_tramway_widgets[] = {
+{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
+{ WWT_CAPTION, RESIZE_NONE, 7, 11, 205, 0, 13, STR_1802_TRAMWAY_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_STICKYBOX, RESIZE_NONE, 7, 206, 217, 0, 13, 0x0, STR_STICKY_BUTTON},
+
+{ WWT_IMGBTN, RESIZE_NONE, 7, 0, 21, 14, 35, SPR_IMG_TRAMWAY_NW, STR_180B_BUILD_TRAMWAY_SECTION},
+{ WWT_IMGBTN, RESIZE_NONE, 7, 22, 43, 14, 35, SPR_IMG_TRAMWAY_NE, STR_180B_BUILD_TRAMWAY_SECTION},
+{ WWT_IMGBTN, RESIZE_NONE, 7, 44, 65, 14, 35, SPR_IMG_DYNAMITE, STR_018D_DEMOLISH_BUILDINGS_ETC},
+{ WWT_IMGBTN, RESIZE_NONE, 7, 66, 87, 14, 35, SPR_IMG_ROAD_DEPOT, STR_180C_BUILD_TRAM_VEHICLE_DEPOT},
+{ WWT_IMGBTN, RESIZE_NONE, 7, 88, 109, 14, 35, SPR_IMG_BUS_STATION, STR_180D_BUILD_PASSENGER_TRAM_STATION},
+{ WWT_IMGBTN, RESIZE_NONE, 7, 110, 131, 14, 35, SPR_IMG_TRUCK_BAY, STR_180E_BUILD_CARGO_TRAM_STATION},
+
+{ WWT_IMGBTN, RESIZE_NONE, 7, 132, 173, 14, 35, SPR_IMG_BRIDGE, STR_180F_BUILD_TRAMWAY_BRIDGE},
+{ WWT_IMGBTN, RESIZE_NONE, 7, 174, 195, 14, 35, SPR_IMG_ROAD_TUNNEL, STR_1810_BUILD_TRAMWAY_TUNNEL},
+{ WWT_IMGBTN, RESIZE_NONE, 7, 196, 217, 14, 35, SPR_IMG_REMOVE, STR_1811_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS},
+{ WIDGETS_END},
+};
+
+static const WindowDesc _build_tramway_desc = {
+ WDP_ALIGN_TBR, 22, 218, 36,
+ WC_BUILD_TOOLBAR, WC_NONE,
+ WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
+ _build_tramway_widgets,
+ BuildRoadToolbWndProc
+};
+
void ShowBuildRoadToolbar(RoadType roadtype)
{
if (!IsValidPlayer(_current_player)) return;
_cur_roadtype = roadtype;
DeleteWindowById(WC_BUILD_TOOLBAR, 0);
- Window *w = AllocateWindowDesc(&_build_road_desc);
+ Window *w = AllocateWindowDesc(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc);
if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
}
@@ -462,6 +498,17 @@ static const Widget _build_road_depot_widgets[] = {
{ WIDGETS_END},
};
+static const Widget _build_tram_depot_widgets[] = {
+{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
+{ WWT_CAPTION, RESIZE_NONE, 7, 11, 139, 0, 13, STR_1806_TRAM_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PANEL, RESIZE_NONE, 7, 0, 139, 14, 121, 0x0, STR_NULL},
+{ WWT_PANEL, RESIZE_NONE, 14, 71, 136, 17, 66, 0x0, STR_1813_SELECT_TRAM_VEHICLE_DEPOT},
+{ WWT_PANEL, RESIZE_NONE, 14, 71, 136, 69, 118, 0x0, STR_1813_SELECT_TRAM_VEHICLE_DEPOT},
+{ WWT_PANEL, RESIZE_NONE, 14, 3, 68, 69, 118, 0x0, STR_1813_SELECT_TRAM_VEHICLE_DEPOT},
+{ WWT_PANEL, RESIZE_NONE, 14, 3, 68, 17, 66, 0x0, STR_1813_SELECT_TRAM_VEHICLE_DEPOT},
+{ WIDGETS_END},
+};
+
static const WindowDesc _build_road_depot_desc = {
WDP_AUTO, WDP_AUTO, 140, 122,
WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
@@ -470,9 +517,17 @@ static const WindowDesc _build_road_depot_desc = {
BuildRoadDepotWndProc
};
+static const WindowDesc _build_tram_depot_desc = {
+ WDP_AUTO, WDP_AUTO, 140, 122,
+ WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
+ WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+ _build_tram_depot_widgets,
+ BuildRoadDepotWndProc
+};
+
static void ShowRoadDepotPicker()
{
- AllocateWindowDesc(&_build_road_depot_desc);
+ AllocateWindowDesc(_cur_roadtype == ROADTYPE_ROAD ? &_build_road_depot_desc : &_build_tram_depot_desc);
}
static void RoadStationPickerWndProc(Window *w, WindowEvent *e)
@@ -581,7 +636,8 @@ static const WindowDesc _bus_station_picker_desc = {
static void ShowBusStationPicker()
{
- AllocateWindowDesc(&_bus_station_picker_desc);
+ Window *w = AllocateWindowDesc(&_bus_station_picker_desc);
+ if (w != NULL) w->widget[1].data = (_cur_roadtype == ROADTYPE_ROAD) ? STR_3042_BUS_STATION_ORIENTATION : STR_3042_PASSENGER_TRAM_STATION_ORIENTATION;
}
static const Widget _truck_station_picker_widgets[] = {
@@ -610,7 +666,8 @@ static const WindowDesc _truck_station_picker_desc = {
static void ShowTruckStationPicker()
{
- AllocateWindowDesc(&_truck_station_picker_desc);
+ Window *w = AllocateWindowDesc(&_truck_station_picker_desc);
+ if (w != NULL) w->widget[1].data = (_cur_roadtype == ROADTYPE_ROAD) ? STR_3043_TRUCK_STATION_ORIENT : STR_3043_CARGO_TRAM_STATION_ORIENT;
}
void InitializeRoadGui()
diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp
index 9a00a6af4..4381572ec 100644
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -472,6 +472,7 @@ int32 CmdTurnRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR;
if (v->vehstatus & VS_STOPPED ||
+ v->u.road.roadtype == ROADTYPE_TRAM ||
v->u.road.crashed_ctr != 0 ||
v->breakdown_ctr != 0 ||
v->u.road.overtaking != 0 ||
@@ -836,7 +837,7 @@ static void RoadVehArrivesAt(const Vehicle* v, Station* st)
SetDParam(0, st->index);
flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
AddNewsItem(
- STR_902F_CITIZENS_CELEBRATE_FIRST,
+ v->u.road.roadtype == ROADTYPE_ROAD ? STR_902F_CITIZENS_CELEBRATE_FIRST : STR_902F_CITIZENS_CELEBRATE_FIRST_TRAM,
flags,
v->index,
0);
@@ -850,7 +851,7 @@ static void RoadVehArrivesAt(const Vehicle* v, Station* st)
SetDParam(0, st->index);
flags = (v->owner == _local_player) ? NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) : NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ARRIVAL_OTHER, 0);
AddNewsItem(
- STR_9030_CITIZENS_CELEBRATE_FIRST,
+ v->u.road.roadtype == ROADTYPE_ROAD ? STR_9030_CITIZENS_CELEBRATE_FIRST : STR_9030_CITIZENS_CELEBRATE_FIRST_TRAM,
flags,
v->index,
0
@@ -1303,7 +1304,7 @@ static void RoadVehController(Vehicle *v)
v->direction = DiagDirToDir(dir);
tdir = _roadveh_depot_exit_trackdir[dir];
- rdp = _road_drive_data[(_opt.road_side << RVS_DRIVE_SIDE) + tdir];
+ rdp = _road_drive_data[v->u.road.roadtype][(_opt.road_side << RVS_DRIVE_SIDE) + tdir];
x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
@@ -1372,7 +1373,7 @@ static void RoadVehController(Vehicle *v)
/* Get move position data for next frame.
* For a drive-through road stop use 'straight road' move data.
* In this case v->u.road.state is masked to give the road stop entry direction. */
- rd = _road_drive_data[(
+ rd = _road_drive_data[v->u.road.roadtype][(
(HASBIT(v->u.road.state, RVS_IN_DT_ROAD_STOP) ? v->u.road.state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->u.road.state) +
(_opt.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking][v->u.road.frame + 1];
@@ -1391,11 +1392,27 @@ static void RoadVehController(Vehicle *v)
again:
if (IsReversingRoadTrackdir(dir)) {
/* Turning around */
- tile = v->tile;
+ if (v->u.road.roadtype == ROADTYPE_TRAM) {
+ RoadBits needed; // The road bits the tram needs to be able to turn around
+ switch (dir) {
+ default: NOT_REACHED();
+ case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
+ case TRACKDIR_RVREV_SE: needed = ROAD_NW; break;
+ case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
+ case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
+ }
+ if (!IsTileType(tile, MP_STREET) || (needed & GetRoadBits(tile, ROADTYPE_TRAM)) == ROAD_NONE) {
+ /* The tram cannot turn here */
+ v->cur_speed = 0;
+ return;
+ }
+ } else {
+ tile = v->tile;
+ }
}
/* Get position data for first frame on the new tile */
- rdp = _road_drive_data[(dir + (_opt.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking];
+ rdp = _road_drive_data[v->u.road.roadtype][(dir + (_opt.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking];
x = TileX(tile) * TILE_SIZE + rdp[RVC_DEFAULT_START_FRAME].x;
y = TileY(tile) * TILE_SIZE + rdp[RVC_DEFAULT_START_FRAME].y;
@@ -1462,7 +1479,7 @@ again:
return;
}
- rdp = _road_drive_data[(_opt.road_side << RVS_DRIVE_SIDE) + dir];
+ rdp = _road_drive_data[v->u.road.roadtype][(_opt.road_side << RVS_DRIVE_SIDE) + dir];
x = TileX(v->tile) * TILE_SIZE + rdp[RVC_TURN_AROUND_START_FRAME].x;
y = TileY(v->tile) * TILE_SIZE + rdp[RVC_TURN_AROUND_START_FRAME].y;
diff --git a/src/roadveh_gui.cpp b/src/roadveh_gui.cpp
index b5f80b4f7..332a8042d 100644
--- a/src/roadveh_gui.cpp
+++ b/src/roadveh_gui.cpp
@@ -192,7 +192,7 @@ static void RoadVehViewWndProc(Window *w, WindowEvent *e)
bool is_localplayer = v->owner == _local_player;
SetWindowWidgetDisabledState(w, 7, !is_localplayer);
- SetWindowWidgetDisabledState(w, 8, !is_localplayer);
+ SetWindowWidgetDisabledState(w, 8, !is_localplayer || v->u.road.roadtype == ROADTYPE_TRAM);
SetWindowWidgetDisabledState(w, 11, !is_localplayer);
/* Disable refit button if vehicle not refittable */
SetWindowWidgetDisabledState(w, 12, !is_localplayer ||
diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp
index 026c503d7..b1338b5ab 100644
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -1266,9 +1266,13 @@ int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
if (build_over_road) {
if (IsTileOwner(tile, OWNER_TOWN) && !_patches.road_stop_on_town_road) return_cmd_error(STR_DRIVE_THROUGH_ERROR_ON_TOWN_ROAD);
if (GetRoadTileType(tile) != ROAD_TILE_NORMAL) return CMD_ERROR;
- if (!IsTileOwner(tile, OWNER_TOWN) && !CheckOwnership(GetRoadOwner(tile, ROADTYPE_ROAD)) && !CheckOwnership(GetRoadOwner(tile, ROADTYPE_TRAM))) return CMD_ERROR;
+
+ RoadTypes cur_rts = GetRoadTypes(tile);
+ if (!IsTileOwner(tile, OWNER_TOWN) && (
+ ((HASBIT(cur_rts, ROADTYPE_ROAD) && !CheckOwnership(GetRoadOwner(tile, ROADTYPE_ROAD)))) ||
+ ((HASBIT(cur_rts, ROADTYPE_TRAM) && !CheckOwnership(GetRoadOwner(tile, ROADTYPE_TRAM)))))) return CMD_ERROR;
/* Do not remove roadtypes! */
- if (rts != GetRoadTypes(tile) && rts != ROADTYPES_ROADTRAM) return CMD_ERROR;
+ rts |= GetRoadTypes(tile);
}
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
@@ -1986,7 +1990,15 @@ extern void DrawCanalWater(TileIndex tile);
static void DrawTile_Station(TileInfo *ti)
{
const DrawTileSprites *t = NULL;
- RailType railtype = GetRailType(ti->tile);
+ RailType railtype;
+ RoadTypes roadtypes;
+ if (IsRailwayStation(ti->tile)) {
+ railtype = GetRailType(ti->tile);
+ roadtypes = ROADTYPES_NONE;
+ } else {
+ roadtypes = GetRoadTypes(ti->tile);
+ railtype = RAILTYPE_BEGIN;
+ }
const RailtypeInfo *rti = GetRailTypeInfo(railtype);
uint32 relocation = 0;
const Station *st = NULL;
@@ -2045,6 +2057,12 @@ static void DrawTile_Station(TileInfo *ti)
if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC && IsStationTileElectrifiable(ti->tile)) DrawCatenary(ti);
+ if (HASBIT(roadtypes, ROADTYPE_TRAM)) {
+ Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y;
+ DrawGroundSprite((HASBIT(roadtypes, ROADTYPE_ROAD) ? SPR_TRAMWAY_OVERLAY : SPR_TRAMWAY_TRAM) + (axis ^ 1), PAL_NONE);
+ DrawTramCatenary(ti, axis == AXIS_X ? ROAD_X : ROAD_Y);
+ }
+
if (IsBuoyTile(ti->tile) && (ti->z != 0 || !IsTileOwner(ti->tile, OWNER_WATER))) DrawCanalWater(ti->tile);
const DrawTileSeqStruct *dtss;
@@ -2088,6 +2106,10 @@ void StationPickerDrawSprite(int x, int y, RailType railtype, RoadType roadtype,
SpriteID img = t->ground_sprite;
DrawSprite(img + rti->total_offset, HASBIT(img, PALETTE_MODIFIER_COLOR) ? pal : PAL_NONE, x, y);
+ if (roadtype == ROADTYPE_TRAM) {
+ DrawSprite(SPR_TRAMWAY_TRAM + (t->ground_sprite == SPR_ROAD_PAVED_STRAIGHT_X ? 1 : 0), PAL_NONE, x, y);
+ }
+
const DrawTileSeqStruct *dtss;
foreach_draw_tile_seq(dtss, t->seq) {
Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
@@ -2742,8 +2764,8 @@ static int32 ClearTile_Station(TileIndex tile, byte flags)
switch (GetStationType(tile)) {
case STATION_RAIL: return_cmd_error(STR_300B_MUST_DEMOLISH_RAILROAD);
case STATION_AIRPORT: return_cmd_error(STR_300E_MUST_DEMOLISH_AIRPORT_FIRST);
- case STATION_TRUCK: return_cmd_error(STR_3047_MUST_DEMOLISH_TRUCK_STATION);
- case STATION_BUS: return_cmd_error(STR_3046_MUST_DEMOLISH_BUS_STATION);
+ case STATION_TRUCK: return_cmd_error(HASBIT(GetRoadTypes(tile), ROADTYPE_TRAM) ? STR_3047_MUST_DEMOLISH_CARGO_TRAM_STATION : STR_3047_MUST_DEMOLISH_TRUCK_STATION);
+ case STATION_BUS: return_cmd_error(HASBIT(GetRoadTypes(tile), ROADTYPE_TRAM) ? STR_3046_MUST_DEMOLISH_PASSENGER_TRAM_STATION : STR_3046_MUST_DEMOLISH_BUS_STATION);
case STATION_BUOY: return_cmd_error(STR_306A_BUOY_IN_THE_WAY);
case STATION_DOCK: return_cmd_error(STR_304D_MUST_DEMOLISH_DOCK_FIRST);
case STATION_OILRIG:
diff --git a/src/table/files.h b/src/table/files.h
index 79522ab34..bd7b0a439 100644
--- a/src/table/files.h
+++ b/src/table/files.h
@@ -63,4 +63,5 @@ static MD5File files_openttd[] = {
{ "trkfoundw.grf", { 0x12, 0x33, 0x3f, 0xa3, 0xd1, 0x86, 0x8b, 0x04, 0x53, 0x18, 0x9c, 0xee, 0xf9, 0x2d, 0xf5, 0x95 } },
{ "roadstops.grf", { 0x8c, 0xd9, 0x45, 0x21, 0x28, 0x82, 0x96, 0x45, 0x33, 0x22, 0x7a, 0xb9, 0x0d, 0xf3, 0x67, 0x4a } },
{ "group.grf", { 0xe8, 0x52, 0x5f, 0x1c, 0x3e, 0xf9, 0x91, 0x9d, 0x0f, 0x70, 0x8c, 0x8a, 0x21, 0xa4, 0xc7, 0x02 } },
+ { "tramtrkw.grf", { 0x83, 0x0a, 0xf4, 0x9f, 0x29, 0x10, 0x48, 0xfd, 0x76, 0xe9, 0xda, 0xac, 0x5d, 0xa2, 0x30, 0x45 } },
};
diff --git a/src/table/road_land.h b/src/table/road_land.h
index 9e40b54bc..bf3f61693 100644
--- a/src/table/road_land.h
+++ b/src/table/road_land.h
@@ -32,6 +32,35 @@ static const DrawTileSprites _road_depot[] = {
{ 0xA4A, PAL_NONE, _road_depot_NW }
};
+static const DrawTileSeqStruct _tram_depot_NE[] = {
+ TILE_SEQ_LINE(SPR_TRAMWAY_BASE + 0x35 | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE, 0, 15, 16, 1)
+ TILE_SEQ_END()
+};
+
+static const DrawTileSeqStruct _tram_depot_SE[] = {
+ TILE_SEQ_LINE(SPR_TRAMWAY_BASE + 0x31, PAL_NONE, 0, 0, 1, 16)
+ TILE_SEQ_LINE(SPR_TRAMWAY_BASE + 0x32 | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE, 15, 0, 1, 16)
+ TILE_SEQ_END()
+};
+
+static const DrawTileSeqStruct _tram_depot_SW[] = {
+ TILE_SEQ_LINE(SPR_TRAMWAY_BASE + 0x33, PAL_NONE, 0, 0, 16, 1)
+ TILE_SEQ_LINE(SPR_TRAMWAY_BASE + 0x34 | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE, 0, 15, 16, 1)
+ TILE_SEQ_END()
+};
+
+static const DrawTileSeqStruct _tram_depot_NW[] = {
+ TILE_SEQ_LINE(SPR_TRAMWAY_BASE + 0x36 | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE, 15, 0, 1, 16)
+ TILE_SEQ_END()
+};
+
+static const DrawTileSprites _tram_depot[] = {
+ { 0xA4A, PAL_NONE, _tram_depot_NE },
+ { 0xA4A, PAL_NONE, _tram_depot_SE },
+ { 0xA4A, PAL_NONE, _tram_depot_SW },
+ { 0xA4A, PAL_NONE, _tram_depot_NW }
+};
+
#undef TILE_SEQ_BEGIN
#undef TILE_SEQ_LINE
#undef TILE_SEQ_END
@@ -42,7 +71,13 @@ static const SpriteID _road_tile_sprites_1[16] = {
0x543, 0x53C, 0x535, 0x538, 0x53D, 0x537, 0x53A, 0x536
};
+static const SpriteID _road_frontwire_sprites_1[16] = {
+ 0, 0x37, 0x37, 0x3F, 0x37, 0x37, 0x43, 0x37, 0x37, 0x3F, 0x37, 0x37, 0x3F, 0x37, 0x37, 0x37
+};
+static const SpriteID _road_backpole_sprites_1[16] = {
+ 0, 0x38, 0x39, 0x40, 0x38, 0x38, 0x43, 0x3E, 0x39, 0x41, 0x39, 0x3C, 0x42, 0x3B, 0x3D, 0x3A
+};
#define MAKELINE(a, b, c) { a, b, c },
#define ENDLINE { 0, 0, 0 }
diff --git a/src/table/roadveh.h b/src/table/roadveh.h
index 8f051e876..59ffe344a 100644
--- a/src/table/roadveh.h
+++ b/src/table/roadveh.h
@@ -1011,7 +1011,7 @@ static const RoadDriveEntry _roadveh_drive_data_59[] = {
{RDE_NEXT_TILE | DIAGDIR_SE, 0}
};
-static const RoadDriveEntry * const _road_drive_data[] = {
+static const RoadDriveEntry * const _road_road_drive_data[] = {
_roadveh_drive_data_0,
_roadveh_drive_data_1,
_roadveh_drive_data_2,
@@ -1077,3 +1077,386 @@ static const RoadDriveEntry * const _road_drive_data[] = {
NULL,
NULL,
};
+
+static const RoadDriveEntry _roadveh_tram_turn_ne_0[] = {
+ {15, 5},
+ {14, 5},
+ {13, 5},
+ {12, 5},
+ {11, 5},
+ {10, 5},
+ { 9, 5},
+ { 8, 5},
+ { 7, 5},
+ { 6, 5},
+ { 5, 5},
+ { 4, 5},
+ { 3, 5},
+ { 2, 5},
+ { 1, 5},
+ { 0, 5},
+ { 0, 6},
+ { 0, 7},
+ { 0, 8},
+ { 0, 9},
+ { 1, 9},
+ { 2, 9},
+ { 3, 9},
+ { 4, 9},
+ { 5, 9},
+ { 6, 9},
+ { 7, 9},
+ { 8, 9},
+ { 9, 9},
+ {10, 9},
+ {11, 9},
+ {12, 9},
+ {13, 9},
+ {14, 9},
+ {15, 9},
+ {RDE_NEXT_TILE | DIAGDIR_SW, 0}
+};
+
+static const RoadDriveEntry _roadveh_tram_turn_ne_1[] = {
+ {15, 9},
+ {14, 9},
+ {13, 9},
+ {12, 9},
+ {11, 9},
+ {10, 9},
+ { 9, 9},
+ { 8, 9},
+ { 7, 9},
+ { 6, 9},
+ { 5, 9},
+ { 4, 9},
+ { 3, 9},
+ { 2, 9},
+ { 1, 9},
+ { 0, 9},
+ { 0, 8},
+ { 0, 7},
+ { 0, 6},
+ { 0, 5},
+ { 1, 5},
+ { 2, 5},
+ { 3, 5},
+ { 4, 5},
+ { 5, 5},
+ { 6, 5},
+ { 7, 5},
+ { 8, 5},
+ { 9, 5},
+ {10, 5},
+ {11, 5},
+ {12, 5},
+ {13, 5},
+ {14, 5},
+ {15, 5},
+ {RDE_NEXT_TILE | DIAGDIR_SW, 0}
+};
+
+static const RoadDriveEntry _roadveh_tram_turn_se_0[] = {
+ {5, 0},
+ {5, 1},
+ {5, 2},
+ {5, 3},
+ {5, 4},
+ {5, 5},
+ {5, 6},
+ {5, 7},
+ {5, 8},
+ {5, 9},
+ {5, 10},
+ {5, 11},
+ {5, 12},
+ {5, 13},
+ {5, 14},
+ {5, 15},
+ {6, 15},
+ {7, 15},
+ {8, 15},
+ {9, 15},
+ {9, 14},
+ {9, 13},
+ {9, 12},
+ {9, 11},
+ {9, 10},
+ {9, 9},
+ {9, 8},
+ {9, 7},
+ {9, 6},
+ {9, 5},
+ {9, 4},
+ {9, 3},
+ {9, 2},
+ {9, 1},
+ {9, 0},
+ {RDE_TURNED | DIAGDIR_NW, 0}
+};
+
+static const RoadDriveEntry _roadveh_tram_turn_se_1[] = {
+ {9, 0},
+ {9, 1},
+ {9, 2},
+ {9, 3},
+ {9, 4},
+ {9, 5},
+ {9, 6},
+ {9, 7},
+ {9, 8},
+ {9, 9},
+ {9, 10},
+ {9, 11},
+ {9, 12},
+ {9, 13},
+ {9, 14},
+ {9, 15},
+ {8, 15},
+ {7, 15},
+ {6, 15},
+ {5, 15},
+ {5, 14},
+ {5, 13},
+ {5, 12},
+ {5, 11},
+ {5, 10},
+ {5, 9},
+ {5, 8},
+ {5, 7},
+ {5, 6},
+ {5, 5},
+ {5, 4},
+ {5, 3},
+ {5, 2},
+ {5, 1},
+ {5, 0},
+ {RDE_NEXT_TILE | DIAGDIR_NW, 0}
+};
+
+static const RoadDriveEntry _roadveh_tram_turn_sw_0[] = {
+ { 0, 9},
+ { 1, 9},
+ { 2, 9},
+ { 3, 9},
+ { 4, 9},
+ { 5, 9},
+ { 6, 9},
+ { 7, 9},
+ { 8, 9},
+ { 9, 9},
+ {10, 9},
+ {11, 9},
+ {12, 9},
+ {13, 9},
+ {14, 9},
+ {15, 9},
+ {15, 8},
+ {15, 7},
+ {15, 6},
+ {15, 5},
+ {14, 5},
+ {13, 5},
+ {12, 5},
+ {11, 5},
+ {10, 5},
+ { 9, 5},
+ { 8, 5},
+ { 7, 5},
+ { 6, 5},
+ { 5, 5},
+ { 4, 5},
+ { 3, 5},
+ { 2, 5},
+ { 1, 5},
+ { 0, 5},
+ {RDE_NEXT_TILE | DIAGDIR_NE, 0}
+};
+static const RoadDriveEntry _roadveh_tram_turn_sw_1[] = {
+ { 0, 5},
+ { 1, 5},
+ { 2, 5},
+ { 3, 5},
+ { 4, 5},
+ { 5, 5},
+ { 6, 5},
+ { 7, 5},
+ { 8, 5},
+ { 9, 5},
+ {10, 5},
+ {11, 5},
+ {12, 5},
+ {13, 5},
+ {14, 5},
+ {15, 5},
+ {15, 6},
+ {15, 7},
+ {15, 8},
+ {15, 9},
+ {14, 9},
+ {13, 9},
+ {12, 9},
+ {11, 9},
+ {10, 9},
+ { 9, 9},
+ { 8, 9},
+ { 7, 9},
+ { 6, 9},
+ { 5, 9},
+ { 4, 9},
+ { 3, 9},
+ { 2, 9},
+ { 1, 9},
+ { 0, 9},
+ {RDE_NEXT_TILE | DIAGDIR_NE, 0}
+};
+
+static const RoadDriveEntry _roadveh_tram_turn_nw_0[] = {
+ {9, 15},
+ {9, 14},
+ {9, 13},
+ {9, 12},
+ {9, 11},
+ {9, 10},
+ {9, 9},
+ {9, 8},
+ {9, 7},
+ {9, 6},
+ {9, 5},
+ {9, 4},
+ {9, 3},
+ {9, 2},
+ {9, 1},
+ {9, 0},
+ {8, 0},
+ {7, 0},
+ {6, 0},
+ {5, 0},
+ {5, 1},
+ {5, 2},
+ {5, 3},
+ {5, 4},
+ {5, 5},
+ {5, 6},
+ {5, 7},
+ {5, 8},
+ {5, 9},
+ {5, 10},
+ {5, 11},
+ {5, 12},
+ {5, 13},
+ {5, 14},
+ {5, 15},
+ {RDE_NEXT_TILE | DIAGDIR_SE, 0}
+};
+static const RoadDriveEntry _roadveh_tram_turn_nw_1[] = {
+ {5, 15},
+ {5, 14},
+ {5, 13},
+ {5, 12},
+ {5, 11},
+ {5, 10},
+ {5, 9},
+ {5, 8},
+ {5, 7},
+ {5, 6},
+ {5, 5},
+ {5, 4},
+ {5, 3},
+ {5, 2},
+ {5, 1},
+ {5, 0},
+ {6, 0},
+ {7, 0},
+ {8, 0},
+ {9, 0},
+ {9, 1},
+ {9, 2},
+ {9, 3},
+ {9, 4},
+ {9, 5},
+ {9, 6},
+ {9, 7},
+ {9, 8},
+ {9, 9},
+ {9, 10},
+ {9, 11},
+ {9, 12},
+ {9, 13},
+ {9, 14},
+ {9, 15},
+ {RDE_NEXT_TILE | DIAGDIR_SE, 0}
+};
+
+static const RoadDriveEntry * const _road_tram_drive_data[] = {
+ _roadveh_drive_data_0,
+ _roadveh_drive_data_1,
+ _roadveh_drive_data_2,
+ _roadveh_drive_data_3,
+ _roadveh_drive_data_4,
+ _roadveh_drive_data_5,
+ _roadveh_tram_turn_ne_0,
+ _roadveh_tram_turn_se_0,
+ _roadveh_drive_data_8,
+ _roadveh_drive_data_9,
+ _roadveh_drive_data_10,
+ _roadveh_drive_data_11,
+ _roadveh_drive_data_12,
+ _roadveh_drive_data_13,
+ _roadveh_tram_turn_sw_0,
+ _roadveh_tram_turn_nw_0,
+ _roadveh_drive_data_16,
+ _roadveh_drive_data_17,
+ _roadveh_drive_data_18,
+ _roadveh_drive_data_19,
+ _roadveh_drive_data_20,
+ _roadveh_drive_data_21,
+ _roadveh_tram_turn_ne_1,
+ _roadveh_tram_turn_se_1,
+ _roadveh_drive_data_24,
+ _roadveh_drive_data_25,
+ _roadveh_drive_data_26,
+ _roadveh_drive_data_27,
+ _roadveh_drive_data_28,
+ _roadveh_drive_data_29,
+ _roadveh_tram_turn_sw_1,
+ _roadveh_tram_turn_nw_1,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const RoadDriveEntry * const * const _road_drive_data[2] = {
+ _road_road_drive_data,
+ _road_tram_drive_data,
+};
diff --git a/src/table/sprites.h b/src/table/sprites.h
index 83d8e9377..75274205a 100644
--- a/src/table/sprites.h
+++ b/src/table/sprites.h
@@ -150,6 +150,24 @@ enum Sprites {
SPR_GROUP_REPLACE_OFF_SHIP = SPR_GROUP_BASE + 18,
SPR_GROUP_REPLACE_OFF_AIRCRAFT = SPR_GROUP_BASE + 19,
+ /* Tramway sprites */
+ SPR_TRAMWAY_BASE = SPR_GROUP_BASE + 20,
+ SPR_TRAMWAY_OVERLAY = SPR_TRAMWAY_BASE + 4,
+ SPR_TRAMWAY_TRAM = SPR_TRAMWAY_BASE + 27,
+ SPR_TRAMWAY_SLOPED_OFFSET = 11,
+ SPR_TRAMWAY_BUS_STOP_DT_Y_W = SPR_TRAMWAY_BASE + 25,
+ SPR_TRAMWAY_BUS_STOP_DT_Y_E = SPR_TRAMWAY_BASE + 23,
+ SPR_TRAMWAY_BUS_STOP_DT_X_W = SPR_TRAMWAY_BASE + 24,
+ SPR_TRAMWAY_BUS_STOP_DT_X_E = SPR_TRAMWAY_BASE + 26,
+ SPR_TRAMWAY_PAVED_STRAIGHT_Y = SPR_TRAMWAY_BASE + 46,
+ SPR_TRAMWAY_PAVED_STRAIGHT_X = SPR_TRAMWAY_BASE + 47,
+ SPR_TRAMWAY_BACK_WIRES_STRAIGHT = SPR_TRAMWAY_BASE + 55,
+ SPR_TRAMWAY_FRONT_WIRES_STRAIGHT = SPR_TRAMWAY_BASE + 56,
+ SPR_TRAMWAY_BACK_WIRES_SLOPED = SPR_TRAMWAY_BASE + 72,
+ SPR_TRAMWAY_FRONT_WIRES_SLOPED = SPR_TRAMWAY_BASE + 68,
+ SPR_TRAMWAY_TUNNEL_WIRES = SPR_TRAMWAY_BASE + 80,
+ SPR_TRAMWAY_BRIDGE = SPR_TRAMWAY_BASE + 107,
+
/* Manager face sprites */
SPR_GRADIENT = 874, // background gradient behind manager face
@@ -1178,6 +1196,8 @@ enum Sprites {
SPR_IMG_BRIDGE = 2594,
SPR_IMG_ROAD_TUNNEL = 2429,
SPR_IMG_REMOVE = 714,
+ SPR_IMG_TRAMWAY_NW = SPR_TRAMWAY_BASE + 0,
+ SPR_IMG_TRAMWAY_NE = SPR_TRAMWAY_BASE + 1,
/* rail_gui.c */
SPR_IMG_RAIL_NS = 1251,
@@ -1294,6 +1314,8 @@ enum CursorSprite {
/* road cursors */
SPR_CURSOR_ROAD_NESW = 1311,
SPR_CURSOR_ROAD_NWSE = 1312,
+ SPR_CURSOR_TRAMWAY_NESW = SPR_TRAMWAY_BASE + 2,
+ SPR_CURSOR_TRAMWAY_NWSE = SPR_TRAMWAY_BASE + 3,
SPR_CURSOR_ROAD_DEPOT = 1297,
SPR_CURSOR_BUS_STATION = 2725,
diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
index 4be63214b..1b84e09d0 100644
--- a/src/tunnelbridge_cmd.cpp
+++ b/src/tunnelbridge_cmd.cpp
@@ -859,6 +859,36 @@ uint GetBridgeFoundation(Slope tileh, Axis axis)
}
/**
+ * Draws the trambits over an already drawn (lower end) of a bridge.
+ * @param x the x of the bridge
+ * @param y the y of the bridge
+ * @param z the z of the bridge
+ * @param offset number representing whether to level or sloped and the direction
+ * @param overlay do we want to still see the road?
+ */
+static void DrawBridgeTramBits(int x, int y, byte z, int offset, bool overlay)
+{
+ static const SpriteID tram_offsets[2][6] = { { 107, 108, 109, 110, 111, 112 }, { 4, 5, 15, 16, 17, 18 } };
+ static const SpriteID back_offsets[6] = { 95, 95, 99, 102, 100, 101 };
+ static const SpriteID front_offsets[6] = { 97, 98, 103, 106, 104, 105 };
+
+ AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + tram_offsets[overlay][offset], PAL_NONE, x, y, 16, 16, offset >= 2 ? 1 : 0, z);
+
+ SpriteID front = SPR_TRAMWAY_BASE + front_offsets[offset];
+ SpriteID back = SPR_TRAMWAY_BASE + back_offsets[offset];
+ SpriteID pal = PAL_NONE;
+ if (HASBIT(_transparent_opt, TO_BUILDINGS)) {
+ SETBIT(front, PALETTE_MODIFIER_TRANSPARENT);
+ SETBIT(back, PALETTE_MODIFIER_TRANSPARENT);
+ pal = PALETTE_TO_TRANSPARENT;
+ }
+
+ AddSortableSpriteToDraw(back, pal, x, y, 16, 16, 0, z);
+ /* For sloped sprites the bounding box needs to be higher, as the pylons stop on a higher point */
+ AddSortableSpriteToDraw(front, pal, x, y, 16, 16, offset >= 2 ? 0x30 : 0x10, z);
+}
+
+/**
* Draws a tunnel of bridge tile.
* For tunnels, this is rather simple, as you only needa draw the entrance.
* Bridges are a bit more complex. base_offset is where the sprite selection comes into play
@@ -887,7 +917,17 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
image += GetTunnelDirection(ti->tile) * 2;
DrawGroundSprite(image, PAL_NONE);
- if (GetTunnelTransportType(ti->tile) == TRANSPORT_RAIL && GetRailType(ti->tile) == RAILTYPE_ELECTRIC) {
+ if (GetTunnelTransportType(ti->tile) == TRANSPORT_ROAD) {
+ DiagDirection dir = GetTunnelDirection(ti->tile);
+ RoadTypes rts = GetRoadTypes(ti->tile);
+
+ if (HASBIT(rts, ROADTYPE_TRAM)) {
+ static const SpriteID tunnel_sprites[2][4] = { { 28, 78, 79, 27 }, { 5, 76, 77, 4 } };
+
+ DrawGroundSprite(SPR_TRAMWAY_BASE + tunnel_sprites[rts - ROADTYPES_TRAM][dir], PAL_NONE);
+ AddSortableSpriteToDraw(SPR_TRAMWAY_TUNNEL_WIRES + dir, PAL_NONE, ti->x, ti->y, 16, 16, 16, (byte)ti->z);
+ }
+ } else if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) {
DrawCatenary(ti);
}
@@ -927,10 +967,6 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
DrawGroundSprite(SPR_FLAT_SNOWY_TILE + _tileh_to_sprite[ti->tileh], PAL_NONE);
}
- if (GetBridgeTransportType(ti->tile) == TRANSPORT_RAIL && GetRailType(ti->tile) == RAILTYPE_ELECTRIC) {
- DrawCatenary(ti);
- }
-
image = psid->sprite;
/* draw ramp */
@@ -945,9 +981,26 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
* it doesn't disappear behind it
*/
AddSortableSpriteToDraw(
- image, pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 1 : 8, ti->z
+ image, pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z
);
+ if (GetBridgeTransportType(ti->tile) == TRANSPORT_ROAD) {
+ RoadTypes rts = GetRoadTypes(ti->tile);
+
+ if (HASBIT(rts, ROADTYPE_TRAM)) {
+ uint offset = GetBridgeRampDirection(ti->tile);
+ if (ti->tileh != SLOPE_FLAT) {
+ offset = (offset + 1) & 1;
+ ti->z += TILE_HEIGHT;
+ } else {
+ offset += 2;
+ }
+ DrawBridgeTramBits(ti->x, ti->y, ti->z, offset, HASBIT(rts, ROADTYPE_ROAD));
+ }
+ } else if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) {
+ DrawCatenary(ti);
+ }
+
DrawBridgeMiddle(ti);
}
}
@@ -1023,7 +1076,8 @@ void DrawBridgeMiddle(const TileInfo* ti)
x = ti->x;
y = ti->y;
- z = GetBridgeHeight(rampsouth) - 3;
+ uint bridge_z = GetBridgeHeight(rampsouth);
+ z = bridge_z - 3;
image = psid->sprite;
if (HASBIT(_transparent_opt, TO_BRIDGES)) {
@@ -1048,7 +1102,13 @@ void DrawBridgeMiddle(const TileInfo* ti)
pal = psid->pal;
}
- if (GetRailType(rampsouth) == RAILTYPE_ELECTRIC) {
+ if (GetBridgeTransportType(rampsouth) == TRANSPORT_ROAD) {
+ RoadTypes rts = GetRoadTypes(rampsouth);
+
+ if (HASBIT(rts, ROADTYPE_TRAM)) {
+ DrawBridgeTramBits(x, y, bridge_z, axis ^ 1, HASBIT(rts, ROADTYPE_ROAD));
+ }
+ } else if (GetRailType(rampsouth) == RAILTYPE_ELECTRIC) {
DrawCatenary(ti);
}