diff --git a/bin/data/tramtrkw.grf b/bin/data/tramtrkw.grf new file mode 100644 index 0000000000..d4a38d1f8c Binary files /dev/null and b/bin/data/tramtrkw.grf differ diff --git a/readme.txt b/readme.txt index 41bb82da19..7b32a912ab 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 6ff742f0c5..5faad52d49 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 49b46ba28c..e01f17c9e0 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 97d146cad6..d48cd82fb7 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 34c1564d57..92c7ac9ce9 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 6095832ed0..9c04ec9d1a 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 4c875dce00..acb958246e 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 394dcc3700..b85017d2e4 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -814,6 +814,42 @@ static bool AlwaysDrawUnpavedRoads(TileIndex tile, Roadside roadside) roadside != ROADSIDE_BARREN && roadside != ROADSIDE_GRASS && roadside != ROADSIDE_GRASS_ROAD_WORKS)); } +/** + * 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 @@ -821,13 +857,15 @@ static bool AlwaysDrawUnpavedRoads(TileIndex tile, Roadside roadside) 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 3723f675f2..c5dbc9c2ae 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 9a00a6af4d..4381572ec4 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 b5f80b4f7e..332a8042d2 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 026c503d7a..b1338b5ab9 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 79522ab34c..bd7b0a439e 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 9e40b54bc9..bf3f616939 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 8f051e876d..59ffe344af 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 83d8e93775..75274205a4 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 4be63214b7..1b84e09d02 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -858,6 +858,36 @@ uint GetBridgeFoundation(Slope tileh, Axis axis) return i + 15; } +/** + * 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. @@ -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); }