From a8d9b4e040cf4fd4dd0ceb4e746985aafcb635f8 Mon Sep 17 00:00:00 2001 From: rubidium Date: Fri, 25 May 2007 22:07:40 +0000 Subject: [PATCH] (svn r9923) -Add: support for Action 0 Road vehicles, property 1C, bit 0. --- bin/data/tramtrkw.grf | Bin 0 -> 42018 bytes readme.txt | 1 + src/gfxinit.cpp | 3 + src/lang/english.txt | 26 ++- src/main_gui.cpp | 2 +- src/misc_gui.cpp | 1 + src/newgrf.cpp | 10 +- src/road.h | 6 +- src/road_cmd.cpp | 68 ++++++- src/road_gui.cpp | 65 ++++++- src/roadveh_cmd.cpp | 31 +++- src/roadveh_gui.cpp | 2 +- src/station_cmd.cpp | 32 +++- src/table/files.h | 1 + src/table/road_land.h | 35 ++++ src/table/roadveh.h | 385 ++++++++++++++++++++++++++++++++++++++- src/table/sprites.h | 22 +++ src/tunnelbridge_cmd.cpp | 76 +++++++- 18 files changed, 730 insertions(+), 36 deletions(-) create mode 100644 bin/data/tramtrkw.grf diff --git a/bin/data/tramtrkw.grf b/bin/data/tramtrkw.grf new file mode 100644 index 0000000000000000000000000000000000000000..d4a38d1f8c4a69f892d875d66961b98c070e8a50 GIT binary patch literal 42018 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 E09{oQE&u=k literal 0 HcmV?d00001 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); }